一、工作背景与目标
因为线上会议系统在高并发场景下仍缺少“实时字幕”关键体验,所以本周的核心任务是把语音转写功能完整嵌入到前端,完成一个实时的语音转录,为后续会议内的AI助手提供可分析文本,并且修复用户反馈最集中的“结束会议无响应”问题,从而提升会议可用性与易用性。
二、主要工作
本周的开发可以拆解为两条并行链:功能接入链与稳定性修复链。
1. 先说接入链——我们通过 Web Speech API 新建 recognition 实例,并且因为浏览器只允许在用户交互后启动,所以把 startTranscription() 嵌入麦克风开启流程;又因为需要拿到中间结果,所以把 continuous=true 与 interimResults=true 同时打开。这样做之后,系统能够在用户说话尚未停顿时就把 partial 文本实时渲染,而一旦 isFinal 触发,又能无缝追加到 final 文本流中。其次,为了让字幕在任何底色画面上都保持可读性,我们把浮窗的背景改为 rgba(0,0,0,0.75),并且显式设置 color:#fff,同时保留五分之一透明度,既不会遮挡视频,也能保证白字对比度。最后,为防止首次转写为空字符串导致 v-if 阻断渲染,我们改用 v-show 并加入双字段判空条件,从而保证浮窗稳定挂载。
2. 再看修复链——“结束会议”之所以失效,是因为 use-event.js 在第 199 行调用 emit('hangup') 时拿到的并不是函数。根因是组件侧既没有 defineEmits(),也没有把返回的 emit 注入到 useEvent。我先在顶层声明 const emit = defineEmits(['hangup']),接着把它随同 pcMap 等参数一起传给 useEvent,并且在 hangup() 内部显式追加 emit('hangup'),这样既能通知父组件路由退出,也能让后端广播的挂断事件在本端正确处理。随着这三行补齐,控制台的 TypeError: emit is not a function 消失,挂断流程顺畅执行,会议状态能即时回收。顺带修正了 :id="im_${item.uuid}" 少反引号的模板错误,避免未来再触发难以定位的 DOM 异常。

最终效果:挂断后跳转回会议信息页面,可以退出或重新入会。

3. 最后,修复“关闭麦克风”后浏览器仍在转写问题
-
浏览器为 Web Speech API(
SpeechRecognition)单独打开一次麦克风硬件;与此同时,你自己用getUserMedia采集的麦克风轨道只服务于 WebRTC 发送。 -
因为这两次采集彼此独立,“关闭麦克风”只会停掉 WebRTC 里的那条 AudioTrack,并不会触碰 SpeechRecognition 的采集流程。结果就是:
-
对方听不到声音(轨道没了);
-
但本地转写仍在继续(SpeechRecognition 仍持有麦克风句柄)
-
解决方案:静音同时关闭语音转写。

function handleCloseMicro () {
- closeMicro();
+ stopTranscription(); // ← 新增:同步停掉 SpeechRecognition
+ closeMicro(); // 原有逻辑
… // 后续移除 Track 的代码保持不变
}
“麦克风按钮”真正成为 统一的主开关:
关闭 ⇒ 既不发送音频,也不转写;
打开 ⇒ 同时恢复音频发送与实时转写。
三、解决的关键问题与效果
虽然改动行数不多,但因为并且覆盖了“从新功能引入到稳定性保障”的完整链路,所以收益显著。具体而言:
-
过去只有本地录制回放才能查看内容;现在所有与会者都能实时看到字幕,因为字幕浮窗默认固定在右下角,所以不再需要分屏对照;
-
过去用户挂断时偶发白屏或卡在房间;现在无论是自己点击、还是对端触发,都能立刻回到首页并断开 WebRTC 连接,后台资源占用回到初始状态;
-
对齐麦克风和转录线程,由麦克风开关统一控制
-
这个实时字幕的实现为我们后期AI助手在会议中根据正在进行会议的内容进行回答的基础。


261

被折叠的 条评论
为什么被折叠?



