MediaRecorder 必须传入 MediaStream 实例,否则构造失败;它可来自 getUserMedia、captureStream、手动组合轨道等,但需至少一个活动音频轨道,且须主动管理轨道生命周期以防中断或泄漏。

必须需要 MediaStream,没有它,MediaRecorder 根本无法初始化或启动。这不是可选项,而是底层依赖——就像发动机需要燃油,MediaRecorder 的输入源只能是 MediaStream 对象。
为什么 MediaRecorder 一定要传 MediaStream
MediaRecorder 的构造函数签名就是 new MediaRecorder(stream, options),第一个参数强制要求是 MediaStream 实例。浏览器不会接受 null、undefined、AudioContext、MediaSource 或任何其他类型。
常见错误现象:
- 直接传
audioContext.createMediaStreamDestination().stream—— 行得通,但这是绕路:它本质仍是生成了一个合法的MediaStream; - 试图用
fetch()或File对象初始化 —— 报错TypeError: Failed to construct 'MediaRecorder': parameter 1 is not of type 'MediaStream'; - 传入已关闭的流(比如
stream.getTracks()[0].stop()后再传)—— 构造不报错,但start()会立刻抛InvalidStateError。
getUserMedia 是最常用但非唯一来源
虽然 navigator.mediaDevices.getUserMedia({ audio: true }) 是获取麦克风流的标准方式,但 MediaStream 还可以来自:
把任意文章或文档内容转换成精美的全屏翻页 HTML 演示文件(幻灯片风格)。当用户发来一篇文章、文档链接、Markdown 内容、或粘贴的文本,并且希望生成演示用的 HTML 时触发。支持任意内容来源:iWiki 链接、KM 链接、本地文件路径、直接粘贴的文本。生成的 HTML 文件保存到本地工作区,并通过企微直接发送给用户。触发词示例:帮我把这篇文章做成PPT、转成演示文档、生成HTML幻灯片、做个演示、转成可以演示的格式、article to deck、make a slide。
立即学习“前端免费学习笔记(深入)”;
-
canvas.captureStream()(录屏+音频需额外混音); -
new MediaStream([track1, track2])(手动组合多个MediaStreamTrack,比如把 Web Audio 输出和麦克风输入合成); -
RTCPeerConnection.getReceivers().map(r => r.track?.getMediaStream())(远端音频流); -
mediaElement.captureStream()(从<video></video>或<audio></audio>元素捕获实时播放流)。
注意:所有这些流都必须至少含一个活动的 audio 轨道,否则 MediaRecorder 会静默失败或只生成空数据。
媒体流生命周期管理不当会导致录音中断或内存泄漏
流对象本身不自动释放,尤其在单页应用中反复启停录音时容易堆积 inactive 轨道。
- 调用
mediaRecorder.stop()不会自动停止底层流的轨道; - 必须显式调用
stream.getTracks().forEach(track => track.stop()),否则麦克风灯常亮、CPU 持续占用; - 若流来自
captureStream()且关联 canvas 已销毁,但未 stop 轨道,可能触发DOMException: The object is no longer valid; - 长时间录音(>5 分钟)建议分段
start(1000)+ 定期stop(),避免单次dataavailable事件携带过大Blob导致内存峰值。
最容易被忽略的一点:流的 active 状态不是只看是否“正在采集”,而是由所有轨道的 enabled 和 readyState 共同决定。哪怕只是某个轨道被意外 mute 或断开,MediaRecorder 就可能产出静音片段或提前终止 —— 这类问题往往要靠监听 stream.onaddtrack 和 track.onended 才能及时发现。


















