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

基于MediaRecorder与Shazam API的音频识别失效问题排查

问题排查:Shazam API无法识别录制音频的原因及修复方案

核心问题分析

你的代码无法被Shazam API识别的根本原因是录制的音频格式完全不符合API要求:

  • 你使用MediaRecorder的THREE_GPP输出格式和AMR_NB编码器,生成的是带容器的压缩音频文件(3GP格式),而非API要求的原始无封装16位PCM小端数据
  • AMR_NB编码器会强制将采样率降到8kHz(即使你设置了44100Hz),且属于可变比特率的有损压缩格式,和API要求的参数完全不匹配
  • 你直接读取3GP文件的二进制数据转Base64,本质是把整个封装文件传给API,而非原始音频样本

修复方案

需要改用AudioRecord类直接录制原始PCM数据(MediaRecorder会自动做封装和编码,无法获取原始PCM),以下是修正后的代码实现:

1. 替换为原始PCM录制类

class RawAudioRecorder {
    private var audioRecord: AudioRecord? = null
    private var isRecording = false

    fun startRecording(): ByteArray {
        // 严格匹配API要求的参数:44100Hz、单声道、16位PCM小端
        val sampleRate = 44100
        val channelConfig = AudioFormat.CHANNEL_IN_MONO
        val audioFormat = AudioFormat.ENCODING_PCM_16BIT
        val minBufferSize = AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioFormat)

        audioRecord = AudioRecord(
            MediaRecorder.AudioSource.MIC,
            sampleRate,
            channelConfig,
            audioFormat,
            minBufferSize * 2 // 扩大缓冲区避免录制溢出
        )

        // 预分配5秒的PCM数据空间:44100样本/秒 * 2字节/样本 *5秒 = 441000字节
        val audioData = ByteArray(44100 * 2 * 5)
        var readOffset = 0

        audioRecord?.startRecording()
        isRecording = true

        // 持续读取PCM数据直到达到预设长度或停止录制
        while (isRecording && readOffset < audioData.size) {
            val bytesRead = audioRecord?.read(audioData, readOffset, audioData.size - readOffset) ?: 0
            if (bytesRead < 0) break // 读取错误时终止
            readOffset += bytesRead
        }

        stopRecording()
        // 返回实际录制的有效数据
        return audioData.copyOf(readOffset)
    }

    fun stopRecording() {
        isRecording = false
        audioRecord?.stop()
        audioRecord?.release()
        audioRecord = null
    }
}

2. 修改录制处理逻辑

private suspend fun launchAudioRecording(context: Context): String {
    Log.d("SearchingSongScreen", "Starting raw PCM recording")
    val recorder = RawAudioRecorder()
    
    // 在IO线程执行录制,避免阻塞UI线程
    val rawPcmData = withContext(Dispatchers.IO) {
        recorder.startRecording()
    }

    Log.d("SearchingSongScreen", "Recorded ${rawPcmData.size} bytes of raw PCM")
    // 使用NO_WRAP避免Base64编码产生换行符,防止API解析失败
    return Base64.encodeToString(rawPcmData, Base64.NO_WRAP)
}

3. 关键验证点

  • Android的ENCODING_PCM_16BIT默认就是小端字节序,符合API要求
  • 5秒的PCM数据大小约为430KB,小于API限制的500KB
  • 可以将录制的PCM数据添加WAV头后保存为文件,用音频工具(如Audacity)检查参数是否正确:44100Hz、单声道、16位

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 06:43:25