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

使用AudioContext获取音频块采样率时解码失败的原因及解决方法

问题分析与修复方案

问题原因

  • MediaRecorder.start(1000)触发的ondataavailable回调返回的单个音频块不是完整的WebM文件:WebM格式需要包含文件头、编码元数据等完整结构,只有第一个chunk可能携带基础容器信息,后续的chunk只是纯音频数据片段,缺少解码必需的容器结构,导致decodeAudioData无法解析。
  • 每次仅用当前的e.data创建Blob,没有累积之前的音频数据,无法形成可解码的完整媒体文件结构。

修复方案

方案一:直接从媒体轨道获取采样率(推荐,无需解码)

录制过程中音频采样率是固定的,不需要每次解码chunk,直接从MediaStream的AudioTrack里获取采样率即可,性能更高:

async function getSampleRate() {
  try {
    const constraints = {
      audio: {
        channelCount: 1
      }
    };
    const stream = await navigator.mediaDevices.getUserMedia(constraints);
    // 从音频轨道获取采样率
    const audioTrack = stream.getAudioTracks()[0];
    const sampleRate = audioTrack.getSettings().sampleRate;
    console.log('固定采样率:', sampleRate);

    mediaRecorder = new MediaRecorder(stream, {
      mimeType: 'audio/webm'
    });

    mediaRecorder.start(1000);

    // 后续如果需要处理音频数据,依然可以监听ondataavailable,但不需要再解码拿采样率
    mediaRecorder.ondataavailable = (e) => {
      console.log('收到音频块,采样率:', sampleRate);
    };

    mediaRecorder.onstop = () => {
      console.log('Recording stopped');
    };
  } catch (error) {
    console.error('Error accessing microphone:', error);
  }
}

getSampleRate()

方案二:累积音频块后解码(如果需要验证每个阶段的采样率)

如果必须通过解码来确认采样率,需要累积所有chunk直到形成完整的可解码文件,或者至少保留文件头信息:

async function getSampleRate() {
  try {
    const constraints = {
      audio: {
        channelCount: 1
      }
    };
    const stream = await navigator.mediaDevices.getUserMedia(constraints);
    mediaRecorder = new MediaRecorder(stream, {
      mimeType: 'audio/webm'
    });

    const audioContext = new(window.AudioContext || window.webkitAudioContext)();
    let audioChunks = []; // 累积所有音频块

    const handleDataAvailable = async(e) => {
      audioChunks.push(e.data);
      // 每次累积后尝试解码完整的Blob
      const audioBlob = new Blob(audioChunks, { type: 'audio/webm' });
      const response = await fetch(URL.createObjectURL(audioBlob));
      const audioArrayBuffer = await response.arrayBuffer();
      
      try {
        const audioBuffer = await audioContext.decodeAudioData(audioArrayBuffer);
        const sampleRate = audioBuffer.sampleRate;
        console.log('当前采样率:', sampleRate);
      } catch (decodeError) {
        // 忽略中间chunk的解码错误,直到累积足够数据
        console.log('当前块无法解码,继续累积');
      }
    };

    mediaRecorder.ondataavailable = handleDataAvailable;
    mediaRecorder.start(1000);

    mediaRecorder.onstop = () => {
      console.log('Recording stopped');
      // 停止后可以解码完整的音频文件
      const fullBlob = new Blob(audioChunks, { type: 'audio/webm' });
      fetch(URL.createObjectURL(fullBlob))
        .then(res => res.arrayBuffer())
        .then(buf => audioContext.decodeAudioData(buf))
        .then(buffer => console.log('完整音频采样率:', buffer.sampleRate));
    };
  } catch (error) {
    console.error('Error accessing microphone:', error);
  }
}

getSampleRate()

内容的提问来源于stack exchange,提问作者seriously

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 03:07:45