You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用JavaScript捕获音频并立即播放时持续出现NotSupportedError错误求助

使用JavaScript捕获音频并立即播放时持续出现NotSupportedError错误求助

我现在遇到一个头疼的问题:用JavaScript捕获音频后尝试播放,第一个音频片段可能能正常工作,但后续所有的片段都无法播放,浏览器一直抛出NotSupportedError: Failed to load because no supported source was found.。我换了Chrome、Safari,还换了两台笔记本,问题都一模一样。

控制台输出的错误信息如下:

untitled.html:40 Blob {size: 81199, type: 'audio/webm'}
untitled.html:46 Playback failed: NotSupportedError: Failed to load because no supported source was found.
(anonymous) @ untitled.html:46
Promise.catch
playAudio @ untitled.html:46
mediaRecorder.ondataavailable @ untitled.html:27
untitled.html:40 Blob {size: 81536, type: 'audio/webm'}
untitled.html:46 Playback failed: NotSupportedError: Failed to load because no supported source was found.

我用来测试的HTML代码如下(保存为.html文件即可直接运行):

<html>
<head>
  <title>Example</title>
</head>

<script>

  let audioStream;
  let mediaRecorder;


  navigator.mediaDevices.getUserMedia({
    video: true,
    audio: true
  })
    .then(stream => {
      audioStream = new MediaStream(stream.getAudioTracks());
      mediaRecorder = new MediaRecorder(audioStream, {
        mimeType: "audio/webm"
      });



      mediaRecorder.ondataavailable = (event) => {

        if (event.data.size > 0) {
          playAudio(event.data);
        }
      };

      mediaRecorder.start(5000);
    })
    .catch(err => {
      console.error(err);
    });

  const playAudio = (audioChunk) => {
    const audioBlob = new Blob([audioChunk], { type: "audio/webm" }); // Ensure correct MIME type
    const audioUrl = URL.createObjectURL(audioBlob);
    console.log(audioBlob);

    const audioElement = document.createElement("audio");
    audioElement.src = audioUrl;
    audioElement.controls = true;
    document.body.appendChild(audioElement);
    audioElement.play().catch((e) => console.error("Playback failed:", e));
  };
</script>
</html>

问题根源

你遇到的问题核心在于MediaRecorder的时间切片产生的片段不是完整的WebM文件:

  • 当你调用mediaRecorder.start(5000)时,浏览器会每隔5秒触发一次ondataavailable事件,返回一个音频片段(chunk)。
  • WebM格式需要完整的文件头(包含编码信息、轨道定义等元数据)才能被浏览器识别,而这个文件头只存在于第一个返回的chunk中。后续的chunk都是没有文件头的纯媒体数据块,浏览器无法解析这种不完整的结构,所以会抛出“不支持的源”错误。

解决方案

根据你的需求,这里提供两种可行的解决思路:

方案1:收集所有片段,录制结束后播放完整音频

如果你的需求是录制完成后再播放完整内容,那么可以先把所有ondataavailable返回的chunk收集起来,直到调用mediaRecorder.stop()后,再将所有chunk拼接成一个完整的Blob进行播放:

<html>
<head>
  <title>Example - 录制完成后播放完整音频</title>
</head>

<script>
  let audioStream;
  let mediaRecorder;
  let audioChunks = []; // 存储所有音频片段

  navigator.mediaDevices.getUserMedia({
    video: true,
    audio: true
  })
    .then(stream => {
      audioStream = new MediaStream(stream.getAudioTracks());
      mediaRecorder = new MediaRecorder(audioStream, {
        mimeType: "audio/webm"
      });

      mediaRecorder.ondataavailable = (event) => {
        if (event.data.size > 0) {
          audioChunks.push(event.data); // 收集片段
        }
      };

      mediaRecorder.onstop = () => {
        // 拼接所有片段为完整的Blob
        const fullAudioBlob = new Blob(audioChunks, { type: "audio/webm" });
        playAudio(fullAudioBlob);
        audioChunks = []; // 重置数组,方便下次录制
      };

      mediaRecorder.start(5000);
      // 示例:录制15秒后自动停止
      setTimeout(() => mediaRecorder.stop(), 15000);
    })
    .catch(err => {
      console.error(err);
    });

  const playAudio = (audioBlob) => {
    const audioUrl = URL.createObjectURL(audioBlob);
    console.log(audioBlob);

    const audioElement = document.createElement("audio");
    audioElement.src = audioUrl;
    audioElement.controls = true;
    document.body.appendChild(audioElement);
    audioElement.play().catch((e) => console.error("Playback failed:", e));
  };
</script>
</html>

方案2:使用MediaSource Extensions实现实时片段播放

如果你的需求是实时播放每个5秒的切片,那么需要使用MediaSource Extensions API,它允许你动态向媒体元素添加无文件头的媒体片段:

<html>
<head>
  <title>Example - 实时播放音频切片</title>
</head>

<script>
  let audioStream;
  let mediaRecorder;
  let mediaSource;
  let sourceBuffer;

  // 初始化MediaSource,用于动态加载媒体片段
  function initMediaSource() {
    mediaSource = new MediaSource();
    const audioElement = document.createElement("audio");
    audioElement.controls = true;
    audioElement.src = URL.createObjectURL(mediaSource);
    document.body.appendChild(audioElement);

    mediaSource.addEventListener('sourceopen', () => {
      // 注意指定编码格式,确保和MediaRecorder一致
      sourceBuffer = mediaSource.addSourceBuffer('audio/webm; codecs="opus"');
      sourceBuffer.mode = 'sequence'; // 设置为序列模式,允许连续添加片段
    });
  }

  navigator.mediaDevices.getUserMedia({
    video: true,
    audio: true
  })
    .then(stream => {
      initMediaSource();
      audioStream = new MediaStream(stream.getAudioTracks());
      mediaRecorder = new MediaRecorder(audioStream, {
        mimeType: "audio/webm; codecs=opus"
      });

      mediaRecorder.ondataavailable = (event) => {
        if (event.data.size > 0 && sourceBuffer && !sourceBuffer.updating) {
          // 将Blob转换为ArrayBuffer后添加到SourceBuffer
          event.data.arrayBuffer().then(buffer => {
            sourceBuffer.appendBuffer(buffer);
          }).catch(e => console.error("添加片段失败:", e));
        }
      };

      mediaRecorder.start(5000);
    })
    .catch(err => {
      console.error(err);
    });
</script>
</html>

额外注意事项

  • 编码格式一致性:确保MediaRecorder和MediaSource使用的MIME类型完全一致(比如audio/webm; codecs=opus),Opus是WebM音频兼容性最好的编码。
  • Safari兼容性:Safari对WebM的MediaRecorder支持有限,如果需要兼容Safari,可以尝试使用audio/mp4作为MIME类型(需要Safari 14.1及以上版本)。

备注:内容来源于stack exchange,提问作者Donny van V

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.14 10:23:03