要让声音精准送达,唯一的办法是让它不经过空气;虚拟声卡就是一根纯软件的数字转接线,而它带来的最大好处,是我们终于找到了一个不会被界面骗到的判据。
正常人说话 = 声带振动 → 推动空气 → 麦克风振膜 → 电信号。过程中声音是空气的波动,会被绕开、反射、吸收,与杂音混合。三重后果:
真实声卡有播放头(你插耳机那个)和录音头(你插麦克风那个)。虚拟声卡不连任何硬件,纯粹软件模拟,但播放头与录音头在内部直接相连 —— 这就是「虚拟线」。
送进播放头 → 不从真实设备出来 → 直接从录音头出来。对系统而言那一路就是「有个麦克风在响」。全程数字信号,零比特经过空气,所以永远无回声、无混响、无衰减。
| 线 | 方向 | 路径 |
|---|---|---|
| 面试官线 | 听 | 页面播放 → Hi-Fi Cable Input ═→ Hi-Fi Cable Output → 助手 iv 通道 |
| 答案线 | 说 | 桥接 TTS → CABLE Input ═→ CABLE Output → 平台麦克风 |
核心就是四个字:谁进谁出。
验收不靠眼睛看设置界面,而是拿真实信号测:
| 线 | peak RMS | 采样 | 状态 |
|---|---|---|---|
| Hi-Fi Cable(面试官线) | 0.2091 | 98 / 6055ms | PASS |
| CABLE(答案线) | 0.1703 | 97 / 6004ms | PASS |
| 判据 | > 0.001 | — | — |
证据:autobot/data/probe/verify_20261006-203959/line_probe_all.out.log
为什么必须实测:虚拟声卡是纯软件模拟的,可能状态好、名字对、能枚举,但内部某处没真正接通。此时所有界面证据都是绿的,信号却过不去。设备可见 ≠ 线导通。
getUserMedia,读的是系统默认设备。两者可以完全对不上。修法:addInitScript 在页面加载前拦下所有麦克风请求,强制改写为虚拟线 deviceId。
性质:没有修改平台任何一行代码,只是浏览器层做了一次翻译。
三项功能是正常通话功能,目的是改善通话质量:
但在我们的场景里,扬声器里放的正是我们要注入的答案。AEC 会精准匹配并减掉它 —— 等于亲手把自己的声音消掉。
讽刺之处:平台房间做防回声处理对真人面试是完全正确的设计,只是我们的场景不是真人外放。它没有失效,它非常认真地做错事。
数字音频有格式:采样率(每秒采样几次)与位深(每点几位)。设备间传输会做一次格式转换,转换不对的结果是——
不是失真,不是延迟,是彻底完全的静音。且软件层一切正常:设备在、名字对、能枚举、调用成功、无报错。
两种状态的区别是决定性的:设备消失 → 立刻知道去查安装;设备在但不出声 → 怀疑整个系统(线错、代码错、冲突),把错的假设全验证一遍,唯独想不到「重启一下就好」。我们为此查了整整一个下午。
两块声卡叫 Hi-Fi Cable 与 CABLE,名字都含 Cable。未锚定的字符串匹配会把两者都命中 —— 代码不报错、运行不报错、设备确实被找到,只是找错了对象。
修法:设备名匹配必须行首锚定。
设计原则:宁可匹配不上,也不能匹配错。
匹配不上 → 立刻知道「没找到设备」→ 去查;
匹配错 → 一路绿灯,安静地做错事。
这类「不报错的错误」是所有自动化系统最难对付的一类 bug。
README.md §4.2 / §5 定型架构 / §6 部署 5 件套;CODEBUDDY.md 音频闭环段与「求解平台不听页面下拉的两处关键注入」;实测证据 autobot/data/probe/verify_20261006-203959/。
EP03 · 单线与双线:一次取舍换来 85 个百分点 —— 为什么一根线省事却必然失败,单线期听对率从 100% 掉到 15%~62% 的完整过程。