一轮 iPhone 真机联调里发现并修掉的一组问题,多数是既有缺陷,两处是我在 本轮前期改出来的回归(已在注释里标明,避免以后再踩)。 同传播报路由(AzureTtsHelper.swift,phone_call 分支) 这一支被改坏过三次,结论固定在注释里: ① 最早 `.defaultToSpeaker` + `overrideOutputAudioPort(.speaker)` → 连了 A2DP 也被强拽到外放;元凶是那次 override(已删)。 ② 修 ① 时把 `.defaultToSpeaker` 一并删了 → 删过头:`.playAndRecord` 的 默认输出是**听筒**,没耳机时译文几乎听不见(「翻译出来了但不播报」)。 ③ 补回 `.defaultToSpeaker` 且 mode 设成 `.videoChat`(为了 AEC) → `.videoChat` 本身偏好内置扬声器,连了耳机又被拽到外放,绕回 ①。 现在按**有没有耳机**分两支:有耳机走 `.default` + 仅 A2DP;没耳机走 `.videoChat` + `.defaultToSpeaker`(外放且开回声消除)。分支口径与采集侧 MicrophoneCapture 启用 voice processing 的条件完全一致,两边不再打架。 没有这个 AEC 时,外放的译文会被自己的麦克风收回去,ASR 当成新一句再翻一遍。 现场录音(bes_recording_service.dart) - 时长改为按**已写入的数据量**算(32 字节 = 1ms),与 WAV 头一致, 因此界面时长与文件实际播放长度永远相等。墙钟算不准:耳机收到 AA 59 后 要 1.8~6.5 秒才上行首帧,还会把等待期缓存的音频一次性补推,实测数据量 比「首帧到停止」的墙钟窗口还多 21~45%,从哪头计时都对不齐。 真机验证:音频19.15s/墙钟18.88s、音频18.72s/墙钟18.69s, 等效采样率均为 16000Hz 整、0 丢帧。 - 修 `_updateLevel` 的 `asInt16List(offsetInBytes, …)`:原生来的 Uint8List 是带 offset 的视图,偏移为奇数时必抛 RangeError。原来藏在 try 里被吞掉, 表现是波形/电平一直不动(数据本身没丢)。改成按小端手工拼 int16, 与 BesCallRecordingService._writeStereo 同一修法。 ⚠️ 本轮我一度把它挪到写入之前且未包 try,一抛异常整个 _onPcm 中断、 音频一帧都写不进去(实测 6990 次未捕获异常)——现在它排在写入成功之后 并单独包 try,波形挂了绝不能影响录音。 - 音频写入排成 Future 队列。Stream.listen 的 async 回调不会被等待, 每秒上百帧必然重叠,而 RandomAccessFile 同一时刻只允许一个异步操作。 (事后核对通话录音同样写法却没丢数据,所以这条是防御性的,不是主因。) 识别异常与状态收口(translation_controller.dart) - 新增 _abortRecognition:catch / error / canceled 三条异常路径统一回滚, **把录音一起停掉**。此前 `isRecording` 全文件只有一处 `= true`、从来没被 置回 false,识别挂了右上角还在计时;异常路径更是连 stopRecording 都不调。 标记同时收口进 stopRecording,所有停止路径都覆盖得到。 - startRecognition 点击即点亮 isPreparing(view 早已绑好按钮反馈,只是从来 没人设过它,点下去毫无视觉变化,就是「点了没反应」)。 - `await _modeInitFuture` 补 3 秒超时。它是本轮前期为消除语言竞态加的, 但没有超时——iOS 首次要激活音频会话、连着蓝牙还要等音频路由,一旦迟迟 不返回点击就永久卡住。把「可能用错语言」换成「可能完全卡住」是坏交易, 超时后走兜底 initialize,至少起得来。 - 三段耗时打点提到 warning 级:release 的日志级别就是 warning,用 info 打 在真机上一条都留不下。 其它 - Logger 在非 release 下同时 print 一份:`developer.log` 只进 VM service 的 logging stream,`flutter run` 控制台看不到、调试态下 idevicesyslog 也抓不到, 真机排查时加了一堆打点却一条都看不见。 - 连接握手不再自动跑 probeCommands:每条间隔 400ms、一轮十几秒,期间 SPP 通道被占满,用户点录音/翻译的指令只能排队。需要重扫时手动调。 本次在固件 0.0.3 上的扫描结果记进注释(0x0B/0C/0D/0F/10/19 有回包, 但取值都不像电量百分比,电量命令仍未定位到)。 - 通话状态变化打出触发它的原始字节,便于排查「刚连上就被判成通话中」。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>