audio.src 不能直接赋值 MediaStream 或动态流,必须用 srcObject;MSE 流需通过 URL.createObjectURL(MediaSource) 绑定,且 MediaStream 与 MSE 互斥不可混用。

audio.src 指向动态流(如 WebRTC MediaStream 或 MSE)时不能直接赋值
浏览器不支持把 MediaStream 或 URL.createObjectURL() 生成的流式 URL 直接塞进 src 属性——它只认静态资源或 Blob URL,且必须是完整可寻址的媒体文件。强行写 audio.src = stream 会静默失败,控制台无报错但播放器卡在“加载中”状态。
MediaStream 必须用 srcObject 而非 src
这是最常踩的坑:动态音视频流(比如麦克风输入、远程 WebRTC 音频)必须走 srcObject 属性,而不是 src。两者互斥,设了 srcObject 后 src 会被自动清空。
-
audio.srcObject = stream是唯一正确方式,stream是MediaStream实例 - 不要调用
audio.load()—— 它对srcObject无效,反而可能中断流 - 首次播放仍需用户手势触发(如 click),即使流已就绪;否则
play()会抛NotAllowedError - 切换流时直接赋新
srcObject即可,旧流自动释放(无需手动getTracks().forEach(t => t.stop()),除非你还要复用轨道)
MSE(Media Source Extensions)流要用 URL.createObjectURL + MediaSource
如果你的“动态流”其实是分段加载的 HLS/DASH 或自定义 chunk 流(比如从 WebSocket 接收音频帧),就得走 MSE 路线。这时 src 不再指向原始 URL,而是指向一个由 MediaSource 生成的 Blob URL。
- 先创建
MediaSource实例:const ms = new MediaSource() - 绑定到
audio.src:audio.src = URL.createObjectURL(ms) - 监听
ms.sourceopen事件,在回调里创建SourceBuffer并 append 数据 - 注意 MIME type 必须匹配,例如 MP3 流要写
audio/mp4(不是audio/mpeg)——MSE 只支持部分类型,MP3 实际需封装为 ISOBMFF(即 .mp4 容器)
常见错误:把 fetch 流误当“动态流”直接赋给 src
有人用 fetch(url).then(r => r.body) 拿到 ReadableStream,然后试图 audio.src = r.body。这完全不行——src 只接受字符串 URL,不接受任何流对象。可行路径只有两条:
立即学习“前端免费学习笔记(深入)”;
- 转成 Blob 再生成 URL:
r.blob().then(b => audio.src = URL.createObjectURL(b))(适合整段下载完再播) - 走 MSE:用
ReadableStream.getReader()拆 chunk,喂给SourceBuffer.appendBuffer()(适合边下边播) - 别忘了服务器响应必须带
Content-Type(如audio/mpeg),否则blob()可能生成空内容
src 切换共存。一旦你用了 srcObject,就不能再回头设 src;反之亦然。选哪条路,得在初始化时就定死。



















