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

自定义Android应用集成Alexa Voice Service及MP3播放问题排查

解决AVS响应MP3文件MediaPlayer.prepare()报错问题

看起来你已经在AVS集成的路上走了不少关键步骤——成功登录获取token、实现本地录音功能、发送请求并收到AVS响应,现在卡在了播放返回的MP3文件这一步。针对MediaPlayer.prepare()报错的问题,咱们一步步排查解决:

1. 先确认MP3文件本身是否有效

这是最基础的排查点:

  • 把你保存的speech2.mp3导出到电脑,用系统播放器或者专业音频工具(比如Audacity)打开试试。如果文件打不开、播放失真,说明AVS响应的解析或文件保存过程出了问题。
  • 重点检查multipart响应的解析逻辑:AVS返回的是multipart格式的响应,你需要正确识别boundary,只提取音频类型的part数据,别把multipart的头信息或其他JSON部分的内容写入MP3文件里。可以用OkHttp的MultipartReader来规范解析,示例代码如下:
fun parseAVSResponse(response: Response) {
    val body = response.body ?: return
    val contentType = body.contentType() ?: return
    val boundary = getBoundary(contentType.toString()) ?: return
    val reader = MultipartReader(body.source(), boundary)
    
    while (reader.hasNext()) {
        val part = reader.nextPart()
        val contentTypeHeader = part.headers["Content-Type"]
        
        // 只处理音频类型的part
        if (contentTypeHeader?.contains("audio/mpeg") == true) {
            val audioFile = File(appcontext?.getExternalFilesDir(Environment.DIRECTORY_MUSIC), "speech2.mp3")
            val sink = audioFile.sink().buffer()
            sink.writeAll(part.source())
            sink.close()
            break
        }
        // 跳过非音频的part(比如JSON响应)
        part.source().skip(Long.MAX_VALUE)
    }
}

2. 修复存储权限问题

Android 10及以上版本对外部存储的访问做了严格限制,直接写入根目录可能会遇到权限问题,导致文件写入不完整或无法读取:

  • 改用应用私有存储目录,比如getExternalFilesDir(),这个目录不需要额外申请权限,代码示例:
// 替换原来的文件路径
val audioFile = File(appcontext?.getExternalFilesDir(Environment.DIRECTORY_MUSIC), "speech2.mp3")

3. 优化MediaPlayer的使用逻辑

你的playRecord()代码缺少错误捕获和资源释放,而且没有设置合适的音频属性,这也可能导致prepare失败:

fun playRecord() {
    doAsync {
        val appContext = appcontext ?: return@doAsync
        val audioFile = File(appContext.getExternalFilesDir(Environment.DIRECTORY_MUSIC), "speech2.mp3")
        
        if (!audioFile.exists()) {
            appContext.runOnUiThread { toast("音频文件不存在") }
            return@doAsync
        }

        val mediaPlayer = MediaPlayer()
        try {
            // 设置合适的音频属性
            val audioAttributes = AudioAttributes.Builder()
                .setUsage(AudioAttributes.USAGE_MEDIA)
                .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
                .build()
            mediaPlayer.setAudioAttributes(audioAttributes)
            
            mediaPlayer.setDataSource(audioFile.path)
            mediaPlayer.prepare()
            mediaPlayer.start()
            
            // 播放完成后释放资源
            mediaPlayer.setOnCompletionListener { mp ->
                mp.release()
            }
        } catch (e: IOException) {
            Log.e("SoundRecorder", "播放失败: ${e.message}", e)
            appContext.runOnUiThread { toast("播放失败: ${e.message}") }
            mediaPlayer.release()
        }
    }
}

4. 额外检查:AVS请求的音频格式是否合规

AVS要求上传的音频必须是PCM 16bit、16kHz采样率、单声道,你的录音代码里已经设置了这些参数,但要确保发送请求时没有修改格式(比如不要把PCM转换成其他格式再发送)。

按照上面的步骤排查,应该能解决prepare报错的问题。如果还是不行,建议打印IOException的具体堆栈信息,这能帮你定位更细节的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 06:45:39