Commit 6d74a0f
fix(voice): session 启动失败后等麦克风 settle 再 teardown,修复重试点麦无反应 (#1548)
* fix(voice): session 启动失败后等麦克风初始化 settle 再 teardown
start_session 失败时 Promise.all 会立刻 reject 触发外层 catch 做 UI
teardown,但 startMicCapture 往往还在 await getUserMedia/AudioWorklet,
随后才 settle,会把 S.isRecording 和浮动麦按钮重新写成"录音中"。结果
没有真实 session 却显示在录音,下一次点麦被浮动按钮当作 toggle-off
(关麦)静默吞掉,看不到任何 banner 或提示。
改为失败路径在 rethrow 前先 await startMicCapture 彻底 settle,让外层
catch 的 teardown 收尾,状态归零(非录音、按钮 off),重试点麦能真正
重新发起 session。顺带修掉失败路径上 stopRecording 因 isRecording 尚
未置位而提前 return、导致麦克风流泄漏的问题。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(voice): 给失败路径的 startMicCapture 等待加超时上限
上一版无界 await micCapturePromise:若 startMicCapture 卡在 getUserMedia
权限弹窗(用户忽略),promise 永久 pending,外层 teardown 永远到不了,
mic 按钮卡 disabled、isMicStarting 不复位——把幽灵录音态换成了永久卡死态。
改成 Promise.race 3s 超时。settle 在界内则照常等它收尾;卡死则超时后照常
teardown——此时 startMicCapture 尚未走到置 isRecording 那步,无录音态可复活。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(voice): 用 token 守卫的补充 teardown 取代有界等待
上一版 Promise.race 3s 超时在两个边界互相矛盾:mic 初始化超过 3s 时超时
会漏掉、让幽灵录音态复活(Codex P2);而无界等待又会在 getUserMedia 权限
弹窗被忽略时卡死 teardown(前一个 Codex P2)。任何有限超时都堵不住其中
一个窗口。
改为:失败立刻 rethrow 让外层 catch 即时 teardown(无卡死),同时挂一个
带 token 守卫的补充 teardown——startMicCapture 无论多晚 settle,只要它确实
写下了幽灵录音态(isRecording 为真且 voiceChatActive 为假),且期间没有更
新的开麦尝试(token 未变),就再清一次。token 变了或已有在线 session(如
CHARACTER_DISCONNECTED 自动重启成功)则不动,避免误杀新 session。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(voice): 改为先确认 session 再开麦,从根上消除幽灵录音竞态
前两版试图在外层 catch 里追平并发的 startMicCapture(先有界等待、后
token 守卫的补充 teardown),但因为 isRecording/stream/按钮是共享状态、
无归属标记,并发尝试无法靠单个 bool 区分,每补一个边界 Codex 就能再找出
一个:超时漏掉慢初始化、卡死在被忽略的权限弹窗、重试后旧 capture 落地仍
留幽灵态。
改为串行:先 await sessionStartPromise,成功后才 await startMicCapture——
与 CHARACTER_DISCONNECTED 自动重启路径(app-websocket.js)一致的写法。
session 启动失败时 startMicCapture 根本不会被调用,不存在"mic 在 teardown
之后才 settle、把 UI 写回录音中"的竞态,by construction 无幽灵态、无卡死、
无需 token/补充 teardown。代价是失去几毫秒的开麦并行(权限已预授予,可忽略)。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(voice): 给点击瞬间的 syncFloatingMicButtonState 调用补 typeof 守卫
mic 点击 handler 里这处是点击瞬间立即执行、早于任何安全检查的首个调用,
也是全项目里唯一没带 typeof 守卫的 syncFloatingMicButtonState 调用。虽然
按钮创建晚于 app-ui 加载、实际不会未定义,但与全项目约定对齐,消除隐患。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Hongzhi Wen <cartabio.coder1@gmail.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>1 parent a4d4dc6 commit 6d74a0f
1 file changed
Lines changed: 10 additions & 6 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1376 | 1376 | | |
1377 | 1377 | | |
1378 | 1378 | | |
1379 | | - | |
| 1379 | + | |
1380 | 1380 | | |
1381 | 1381 | | |
1382 | 1382 | | |
| |||
1496 | 1496 | | |
1497 | 1497 | | |
1498 | 1498 | | |
1499 | | - | |
| 1499 | + | |
1500 | 1500 | | |
1501 | 1501 | | |
1502 | 1502 | | |
1503 | 1503 | | |
1504 | | - | |
1505 | | - | |
1506 | | - | |
1507 | | - | |
| 1504 | + | |
| 1505 | + | |
| 1506 | + | |
| 1507 | + | |
| 1508 | + | |
| 1509 | + | |
1508 | 1510 | | |
1509 | 1511 | | |
1510 | 1512 | | |
1511 | 1513 | | |
1512 | 1514 | | |
| 1515 | + | |
| 1516 | + | |
1513 | 1517 | | |
1514 | 1518 | | |
1515 | 1519 | | |
| |||
0 commit comments