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

React+Web Audio API录制音频调用Shazam API无结果求助

排查React音频录制适配Shazam Rapid API的问题

核心问题定位

Python+PyAudio录制的音频能正常被API识别,说明前端录制的音频格式细节未完全匹配API要求,重点从以下几个维度排查:

1. 音频容器与原始PCM的差异

Shazam songs/v2/detect接口要求的是无容器的原始PCM字节流,但前端MediaRecorder(包括extendable-media-recorder)默认会给音频添加容器头(比如WebM/MP4),哪怕配置了PCM格式,也会带容器信息,导致API无法解析。而PyAudio录制的是纯PCM数据,没有额外容器。

解决方案:

放弃MediaRecorder,改用Web Audio API直接抓取原始PCM样本:

  • 强制配置采样率44100Hz、单声道、16位小端有符号整数格式
  • 将Web Audio默认输出的Float32样本转换为16位PCM字节流

2. 音频样本格式转换错误

Web Audio API的音频样本默认是Float32类型(范围-1到1),如果直接转字节会不符合API要求的16位PCM格式。必须先将Float32映射到16位有符号整数范围(-32768到32767)。

转换代码示例:

// 将Float32音频样本转为16位小端PCM字节数组
function float32To16BitPCM(input) {
  const output = new Int16Array(input.length);
  for (let i = 0; i < input.length; i++) {
    const clamped = Math.max(-1, Math.min(1, input[i]));
    output[i] = clamped < 0 ? clamped * 0x8000 : clamped * 0x7FFF;
  }
  return new Uint8Array(output.buffer);
}

3. 完整纯PCM录制流程实现

用ScriptProcessorNode(或现代的AudioWorklet)实现无容器PCM录制:

let audioContext;
let scriptProcessor;
let audioChunks = [];

// 启动录制
async function startRecording() {
  const stream = await navigator.mediaDevices.getUserMedia({ 
    audio: {
      sampleRate: 44100,
      channelCount: 1,
      echoCancellation: false,
      noiseSuppression: false // 关闭降噪,保留原始音频特征
    }
  });
  
  audioContext = new AudioContext({ sampleRate: 44100 });
  const source = audioContext.createMediaStreamSource(stream);
  scriptProcessor = audioContext.createScriptProcessor(4096, 1, 1);

  source.connect(scriptProcessor);
  scriptProcessor.connect(audioContext.destination);

  scriptProcessor.onaudioprocess = (e) => {
    const inputBuffer = e.inputBuffer.getChannelData(0);
    const pcmBytes = float32To16BitPCM(inputBuffer);
    audioChunks.push(pcmBytes);
  };
}

// 停止录制并生成Base64
function stopRecording() {
  scriptProcessor.disconnect();
  audioContext.close();
  
  // 合并所有PCM字节
  const totalLength = audioChunks.reduce((sum, chunk) => sum + chunk.length, 0);
  const combined = new Uint8Array(totalLength);
  let offset = 0;
  for (const chunk of audioChunks) {
    combined.set(chunk, offset);
    offset += chunk.length;
  }
  
  // 转Base64(无额外换行符)
  const base64 = btoa(String.fromCharCode(...combined));
  // 传给后端调用API
  sendToBackend(base64);
}

4. 对齐Python录制的关键参数

对比你的Python工作代码,确保前端完全匹配以下参数:

  • 采样率:44100Hz
  • 声道数:单声道
  • 位深:16位有符号整数
  • 字节序:小端
  • 音频时长:至少2-3秒有效音频(跳过开头静音)

Python代码的核心逻辑参考:

import pyaudio
import base64

FORMAT = pyaudio.paInt16
CHANNELS = 1
RATE = 44100
CHUNK = 1024
RECORD_SECONDS = 3

p = pyaudio.PyAudio()
stream = p.open(format=FORMAT, channels=CHANNELS, rate=RATE, input=True, frames_per_buffer=CHUNK)

frames = []
for i in range(0, int(RATE / CHUNK * RECORD_SECONDS)):
    data = stream.read(CHUNK)
    frames.append(data)

stream.stop_stream()
stream.close()
p.terminate()

audio_bytes = b''.join(frames)
base64_audio = base64.b64encode(audio_bytes).decode('utf-8')

额外排查点

  • 后端接收Base64后,确保直接解码为原始字节数组,无额外转码或添加容器头操作
  • 用Audacity等工具对比前端和Python录制的音频,检查波形、格式参数是否完全一致
  • 录制时关闭浏览器的降噪、回声消除功能,避免API无法提取音频特征

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 00:05:20