- 音视频
- 即时通讯
- 教育
- 前端
- 桌面应用
【免费下载链接】flat
Project flat is the Web, Windows and macOS client of Agora Flat open source classroom.
本文以 Agora Flat 开源教室项目 v1.6.0 版本的官方发布说明(docs/releases/v1.6.0/en.md)为骨架,结合仓库源码逐一拆解该版本的两项新特性、两项交互改进与五处缺陷修复的底层实现。读完本文,你将理解 Flat 课件插入链路(图片/音视频/文档分派逻辑)、Agora OAuth 登录流程、回放控制台交互、音频设备记忆机制与国际化切换原理,并能定位到每项能力对应的源码文件,便于二次开发与问题排查。
版本概览
v1.6.0 是 Agora Flat 开源项目(Web、Windows、macOS 三端客户端)的一个功能型发布版本,改动集中在课堂协作体验与账号体系两条主线:
| 类别 | 内容 |
|---|---|
| 新增特性 | 支持课件无感切换与流畅书写;支持 Agora 登录 |
| 交互改进 | 调整录播课(回放)的交互;默认选中上次使用的音频/视频设备 |
| 缺陷修复 | 云盘超过 50 个文件后新上传文件显示异常;云盘预览图不居中;语音通话回声异常;中英文切换异常;激光笔显示异常 |
下文按“新增 → 改进 → 修复”的顺序展开,每一项都给出仓库内的源码证据路径。
一、新增特性:课件无感切换与流畅书写
“课件无感切换”指的是在课堂中切换、插入课件时不再打断当前书写状态,插入完成后可立即继续流畅书写。这一体验由 Fastboard 课件插入服务支撑,其核心实现位于 service-providers/fastboard/src/file-insert.ts 的FastboardFileInsert类。
1.1 按文件类型分派插入链路
FastboardFileInsert.insert()是课件插入的入口,它根据文件扩展名把插入请求分派到三条不同的处理路径:
- 图片(jpg/jpeg/png/webp):调用
insertImage(),按比例缩放后插入白板; - 音视频(mp3/mp4):调用
insertMedia(),以媒体播放器应用形式挂载; - 文档(doc/docx/ppt/pptx/pdf):调用
insertDocs(),先校验转换任务状态再渲染为白板场景。
不支持的格式会抛出[cloud storage]: insert unknown format错误,并通过toaster弹出“无法插入课件”的提示(对应 i18n keyunable-to-insert-courseware)。从源码看,该服务同时接收flatI18n、toaster与region依赖注入,说明插入链路与国际化、错误提示和地域配置(转换服务区域)是解耦的。
1.2 图片插入:等比缩放与落点换算
insertImage()(同文件第 72-137 行)先读取图片原始尺寸,若宽度超过window.innerWidth * 0.6则等比缩小,保证课件图片不会超出可视区域;随后通过convertToPointInWorld()把用户点击位置换算为白板世界坐标,在相机视野中心或指定坐标处调用insertImage()+completeImageUpload()完成插入,最后把工具切回选择器(ApplianceNames.selector)以便继续书写。
1.3 文档插入:转换状态驱动的无感切换
文档链路最能体现“无感”设计。insertDocs()(同文件第 151-252 行)在插入前会调用queryConvertingTaskStatus()轮询云端转换任务的真实状态:
- 状态为
Fail:提示无法插入并直接返回; - 状态未
Finished:弹出“正在转码”的警告(i18n keyin-the-process-of-transcoding-tips),不做其他打断性操作; - 状态已完成:根据转换产物类型选择挂载方式——旧版 PPTX 动态转换走
Slide应用(通过extractLegacySlideParams()从ppt://cdn/.../dynamicConvert/{taskId}/...的 URL 中提取 taskId),普通文档走DocsViewer,新版 Projector PPTX 转换走fastboardApp.insertDocs()原生插入。
整个流程在插入动作与书写状态之间没有强制重置或重载,转换完成后课件即刻出现在当前场景中,因此书写不被打断。该分派实现与云盘侧转换任务状态管理器(见下文修复项)相互印证。
二、新增特性:支持 Agora 登录
v1.6.0 为账号体系引入了 Agora OAuth 登录入口,实现位于 packages/flat-pages/src/LoginPage/agoraLogin.ts。
2.1 登录流程与参数构成
agoraLogin的执行逻辑分两步:先用setAuthUUID()向后端登记一次性的authUUID(用于防 CSRF 的 state 参数),再跳转到 Agora SSO 授权页。授权 URL 由getAgoraURL()生成:
https://sso2.agora.io/api/v0/oauth/authorize?response_type=code&client_id={clientId}&redirect_uri={redirect_uri}&scope=basic_info&state={authUUID}&toPage=signup其中clientId取自globalStore.serverRegionConfig?.agora.clientId(即服务器地域配置中的 Agora 应用 ID),redirect_uri来自FLAT_SERVER_LOGIN.AGORA_CALLBACK常量。若地域配置缺失,会打印missing server region config警告。
2.2 登录面板的挂载方式
在 packages/flat-pages/src/LoginPage/index.tsx 中,登录按钮列表由process.env.LOGIN_METHODS.split(",")驱动,Agora 登录作为其中一种 provider 与手机号/邮箱密码、微信扫码等登录方式并列,由handleLogin分发调用,登录结果统一交给onLoginResult处理。这意味着部署方可以通过环境变量LOGIN_METHODS决定是否开放 Agora 登录入口。
三、交互改进:调整录播课(回放)的交互
回放(Replay)交互在 v1.6.0 中做了整体调优,对应页面与状态层分别为 packages/flat-pages/src/ReplayPage/index.tsx 与 packages/flat-stores/src/classroom-replay-store/index.ts。
3.1 回放控制台
ReplayList.tsx 实现了回放控制条:进度条(Slider)以录制的beginTime/endTime为边界;播放/暂停、后退/快进 15 秒(fastForward(±15_000))按钮直接驱动ClassroomReplayStore;右上角下拉菜单用于在多段录制(recordings)之间切换,并支持复制分享链接。时间显示使用HH:mm:ss格式化。
3.2 多轨同步播放器
状态层核心是ClassroomReplayStore.loadRecording():通过replayFastboard()创建白板回放播放器,用WhiteboardPlayer包裹白板、用NativeVideoPlayer包裹云端录制视频,最后统一交给SyncPlayer做多轨同步;播放/暂停/跳转(seek,带 100ms 防抖)全部作用于syncPlayer。回放期间的白板光标(cursor: true)、滚动视图(viewMode: "scroll")与onStageUsers上台状态同步也在此初始化——这些正是“回放交互调整”落地的数据基础。
页面层 ReplayWhiteboard.tsx 负责把 fastboard 绑定到容器并跟随暗色模式(setPrefersColorScheme),ReplayVideo.tsx 负责挂载视频元素,两者共同构成了回放页的“白板 + 视频”双画布布局。
四、交互改进:默认选中上次使用的音视频设备
v1.6.0 让课堂加入时自动恢复用户上次选择的摄像头、麦克风与扬声器设备,而非每次回退到系统默认设备。
4.1 偏好存储
设备选择记录存放在 packages/flat-stores/src/preferences-store.ts 的PreferencesStore中:cameraId、microphoneId、speakerId三个字段分别保存三类设备的deviceId,并经由autoPersistStore以PreferencesStore为 key 持久化到本地存储(带LS_VERSION = 1的版本控制,不匹配时自动清除)。
4.2 课堂加入时的设备恢复
在 packages/flat-stores/src/classroom-store/index.ts 的加入房间流程中,joinRoom成功后会依次执行:
if (preferencesStore.cameraId) { await this.rtc.setCameraID(preferencesStore.cameraId); } if (preferencesStore.microphoneId) { await this.rtc.setMicID(preferencesStore.microphoneId); } if (preferencesStore.speakerId) { await this.rtc.setSpeakerID(preferencesStore.speakerId); }设备 ID 只有在确实变更时才真正下发(避免无意义的引擎调用),并通过事件camera-changed/mic-changed/speaker-changed通知 UI 同步状态。该逻辑同时支撑桌面端(agora-rtc-electron.ts 的setCameraID/setMicID/setSpeakerID,内部对应setVideoDevice/setAudioRecordingDevice/setAudioPlaybackDevice)与 Web 端(agora-rtc-web.ts 的device-changed监听自动同步)。
五、缺陷修复
5.1 云盘超过 50 个文件后新上传文件显示异常
云盘列表由 packages/flat-stores/src/cloud-storage-store/index.ts 的CloudStorageStore管理。列表数据通过listFiles({ page: 1, order: "DESC", directoryPath })分页拉取,并启动一个 10 秒间隔的Scheduler定时调用refreshFiles()(实现见同文件第 436-509 行)来刷新文件信息;refreshFiles会把远端数据与本地filesMap做差量合并,并对处于转码中的whiteboardProjector/whiteboardConvert文件排队查询转换状态。
文件数超过 50 后出现的“新上传文件显示异常”,从实现上看与分页边界及filesMap的合并策略直接相关:旧列表中的文件按createAt倒序排序,新上传文件会被正确合并入filesMap并置顶。该版本的修复保证了分页场景下新文件状态(含转码进度)的刷新不丢失、不重复,配合convert-status-manager的ConvertStatusManager对已完成/失败任务的清理(cancelTask),避免状态轮询积压导致的列表错乱。
5.2 云盘预览图不居中显示
云盘文件预览(图片)此前存在加载后不居中的问题,修复后预览容器内的图片按容器尺寸适配并居中渲染。预览能力由file服务提供(服务接口定义见 packages/flat-services/src/services/file),云盘侧通过fileService?.preview(file)(见CloudStorageStore.previewCourseware)触发。该修复属于 UI 布局层调整,涉及预览组件的定位与尺寸计算,确保不同分辨率下图片均处于视觉中心。
5.3 语音通话回声异常
回声问题源于音频采集与播放链路,修复点在 RTC 层的音频处理配置。Flat 的音频由 service-providers/agora-rtc/agora-rtc-electron/src/agora-rtc-electron.ts 封装 Agora 引擎处理,回声抑制(AEC)等音频处理策略在引擎初始化与加入房间阶段生效。该版本通过调整音频配置(如回声消除与降噪参数)消除了语音通话中“自己听到自己声音”的异常回声,修复同时覆盖了桌面端与 Web 端(agora-rtc-web.ts)。
5.4 中英文切换异常
国际化层由 packages/flat-i18n/src/flat-i18n.ts 的FlatI18n单例实现:基于i18next+I18nextBrowserLanguageDetector,内置en与zh-CN两套语言资源(locales),fallbackLng为en。语言切换通过changeLanguage()触发i18next的languageChanged事件,同时把<html lang>属性与插值变量(defaultVariables)一并更新。
此前的中英文切换异常表现为语言切换后部分文案不刷新或资源错位。该版本修复了切换过程中语言资源与变量注入的顺序问题,确保language$状态更新后各页面(如 LoginPage/index.tsx 中根据语言与FLAT_REGION动态选择隐私政策与服务协议 URL 的逻辑)能正确响应语言变化。
5.5 激光笔显示异常
激光笔(laser pointer)是白板授课工具之一,快捷键映射定义在 service-providers/fastboard/src/index.ts 的自定义hotKeys中:changeToLaserPointer: "z",与选择器(s)、画笔(p)、矩形(r)、椭圆(c)、文本(t)、直线(l)、箭头(a)、抓手(h)等工具并列。
激光笔显示异常通常表现为远程端无法正确渲染激光轨迹或颜色失真。该修复针对白板应用中激光笔的渲染同步逻辑,确保使用激光笔指划时远端画面能即时、正确地呈现激光轨迹。修复后的快捷键与渲染行为均可通过上述hotKeys配置自定义验证。
六、升级与验证建议
- 桌面端(Windows/macOS)用户升级到 v1.6.0 后,可依次验证:云盘上传第 51 个以上文件时列表刷新、插入图片/PPT/PDF 课件的无感切换、Agora 账号登录、设备选择记忆(设置页或设备测试页切换设备后重进课堂)、中英文切换与语音通话无回声。
- 开发者可对照本文给出的源码路径定位对应模块:课件插入链路 file-insert.ts、回放状态层 classroom-replay-store/index.ts、云盘列表刷新 cloud-storage-store/index.ts、偏好持久化 preferences-store.ts。
- 上述行为均以当前仓库(v1.6.0 之后的代码演进)为准;若需核对发布说明原文,可直接阅读 docs/releases/v1.6.0/en.md。
- 音视频
- 即时通讯
- 教育
- 前端
- 桌面应用
【免费下载链接】flat
Project flat is the Web, Windows and macOS client of Agora Flat open source classroom.
相关推荐
ng-zorro-antd Graph 自定义节点样式实战:从 foreignObject 模板到交互控制
ng zorro antd Graph 自定义节点样式实战:从 foreignObject 模板到交互控制 Graph(流程图)是 ng zorro antd
音视频即时通讯教育前端桌面应用Agora Flat v1.4.0 版本解析:多课件预览与课堂交互体验升级的实现细节
Agora Flat v1.4.0 版本解析:多课件预览与课堂交互体验升级的实现细节 导读 本文基于 Agora Flat 开源课堂(Web / Windows
音视频即时通讯教育前端桌面应用F´ (F Prime) DpManager 组件基于规则的单元测试:Abstract State、规则组与随机场景解析
F´ F Prime DpManager 组件基于规则的单元测试:Abstract State、规则组与随机场景解析 导读 本文以 Svc/DpManager/
音视频即时通讯教育前端桌面应用
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考