Rodger-Wang
|
c03738fb80
|
client/services:EMAI 接入科大讯飞对话,同声翻译改走微软端到端(讯飞 AST / RTASR 拼接),SparkChain 插件补齐 AST、听写、合成与大模型调用;服务端新增讯飞 sparkchat、openaichat、ost 适配。构建号 1.0.3+94
|
14 hours ago |
Rodger-Wang
|
2007b59825
|
client/services:测试服 AI 只允许科大讯飞,缺微软配置时提示而不崩溃。构建号 1.0.3+48
同声翻译在密钥未下发时不再反复挂微软听写,避免安卓栈溢出。文本和同声在有 SparkChain 密钥时优先走端上讯飞。
Co-authored-by: Cursor <cursoragent@cursor.com>
|
5 days ago |
Rodger-Wang
|
7b38a975fa
|
client:切后台时同声、通话和耳机 AI 不再断连,同声改走耳机麦,结束对话不再把没在播的音乐拉起来。构建号 1.0.3+37
Co-authored-by: Cursor <cursoragent@cursor.com>
|
1 week ago |
Rodger-Wang
|
5036ab4c3f
|
client: 修通话翻译「德语/意大利语一开就卡死、只有中英正常」——并发初始化+默认参数兜底
不是语种问题,是竞态。原生阿里初始化天然 >=1.2s(A 路 init → delay(1200) →
B 路 init),期间只要再来一次 initialize/dispose,「代数」就变了,前一次返回
false;Dart 拿到 false 把 _isInitialized 清掉;接着 recognizeCallback() 看到
「未初始化」就调**无参** initialize()——默认值 provider=azure + [zh-CN,en-US],
把刚握手成功的阿里 zh→de 会话整个换成 Azure 中英三段拼装。此后原生 provider
停在 azure、Azure 识别器一直在跑,每次 dispose 都慢几秒,下一轮更容易撞进
1.2s 窗口,**退出重进也不会好**。中英「正常」只是因为默认值恰好是中英。
修在三层,缺一层都会复发:
- azure_ast_service.dart:initialize() 串行化(_initInFlight);记住最近一次的
provider/语言表;recognizeCallback / startContinuousTranslation 走
_ensureInitialized——先等在途初始化,仍没成就**按上次参数**补一次,
永远不用默认值,没有可复用参数就直接报错。
- translation_controller.dart:_initializeCallModeTranslationService 串行链;
isPreparing 期间忽略重复点开始;_attachBesCallTranslationBridge 开桥前先等
初始化真正落地(10s 上限)——原来靠 _modeInitFuture 3s 超时硬往下走,
桥开在原生初始化之前。
- AzureSpeechPlugin.kt/.swift:被新一代取代时打出阶段与代数、A/B 任一失败打
结果,排查先找这两行。iOS 另修一处独有差异:原先 A/B 无论成败都回 true,
Dart 以为就绪、桥照开而实际一路是空的,现在按真实结果回。
Redmi K90 Pro Max 验证:连开 9 场(it/de/en/ja/fr/ko×2/en,含切语言、关闭重开、
退出重进)全部阿里 3.5,初始化各 1.2s,87 句译文,0 错误,断粮 0 次。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
4 weeks ago |
Rodger-Wang
|
7ce56f693d
|
client: 通话翻译音频链路修复(iOS GATT 写入、后台保活、状态竞态)
iOS 上恒玄走的是 GATT over BR/EDR 而非 BLE,之前按 BLE 模型处理导致一连串问题。
本次改动都有真机数据支撑(2026-09-21 压测)。
GATT 写入(bluetooth_manager)
- 写类型改为优先 .withoutResponse。ATT 是请求-响应协议,带应答写每包等 ACK,
追不上下行 50 包/秒,表现为音频越听越滞后。
- canSendWriteWithoutResponse 只作观测、不作门槛。它是 CoreBluetooth 为 BLE
设计的提示,在 BR/EDR GATT 上不反映真实能力(实测 100% 为 false 却零丢弃);
拿它当闸门会死锁:不写就不回调,不回调就永不翻真,实测 548 包只出去 11 个。
- 控制命令无条件直发、不排队。排到积压音频后面会让 AA 09/AA 06/queryCallState
全部发不出去,曾被误判成「固件换了命令号」。
- 不再对标准电池服务 0x180F 做任何 ATT 操作:它在 Echo-one 上是空壳(值恒为 0),
而挂在它上面的读/订阅会把整条 ATT 通道堵死。
后台存活(translation)
- 通话翻译期间持有 BackgroundKeepalive。两路音频全走耳机 GATT,手机侧没有
AVAudioSession 的实际 I/O,UIBackgroundModes=audio 不成立,切后台几十秒后
上行被掐断:WebSocket 还连着,但服务端收不到语音,靠默认 VAD 每 30 秒强切一句,
吐出空译文或幻觉 —— 表现为「切后台后只剩译文、原文全没」。
- BackgroundKeepalive 不再无条件把音频类别改成 .playback,避免踩掉通话翻译
正在跑的 .playAndRecord 录音链路。
状态竞态(azure_speech / device_hub)
- markReady 的就绪状态记在插件上、建桥时继承。建桥与 AST 异步初始化是两条独立
路径,初始化先完成时那句 optional chaining 打在 nil 上静默丢失,之后 ready
恒为 false、上行帧全积在环形缓冲里,表现为「打开通话翻译没反应,再开一次才好」。
- DeviceHub.inCall 改以会话快照为准。事件会随 worker 在断连时被 dispose 而丢失,
重连后 ever 又不回调当前值,且后续重复赋同值不触发,永远不会自愈。
可观测性
- 下行发送器与 GATT 写入的日志从 NSLog 改为 os_log(release/profile 包里
idevicesyslog 只收得到 os_log),并经 DeviceSession.diagnostics() 暴露给 Dart,
写入文件日志后可用 devicectl 直接拉取,不依赖 usbmuxd。
- 新增 inCall 变化、闸门拦截、通话状态翻转、前后台切换四处观测点。
其它
- DeviceSession 新增 diagnostics()(默认空表);SmartcarSession 因是 implements
而非 extends,同步补了实现。
- CLAUDE.md 记录本次全部实测结论,含 BB 8E 为通话状态权威、BB 02/03 是噪声
(已知问题,本次未改判定)。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
4 weeks ago |