Android AudioTrack调用releaseBuffer()因欠载报错致禁用问题求助
解决AudioTrack欠载(underrun)导致releaseBuffer()报错的问题
针对你遇到的releaseBuffer() track xxx disabled due to previous underrun, restarting错误,本质是音频缓冲区未能及时得到数据填充,不同厂商的音频硬件抽象层(HAL)实现差异导致三星设备对低延迟场景的调度更敏感。以下是具体解决方案:
1. 替换硬编码缓冲区大小为系统推荐值
硬编码的bufferSize可能不符合设备的实际音频硬件要求,尤其是开启低延迟模式时,系统有更精准的缓冲区计算逻辑。改用AudioTrack.getMinBufferSize()获取最小缓冲区,再根据场景增加冗余:
// 计算系统推荐的最小缓冲区大小 val minBufferSize = AudioTrack.getMinBufferSize( sampleRate, channelConfig, audioFormat ) // 低延迟场景可增加1.5-2倍的冗余,避免频繁欠载 val adjustedBufferSize = (minBufferSize * 1.5).toInt() audioTrack = AudioTrack.Builder() // ... 其他配置不变 .setBufferSizeInBytes(adjustedBufferSize) .build()
API 26及以上可使用getPreferredBufferSize()获取更适配低延迟的缓冲区大小:
val format = AudioFormat.Builder() .setEncoding(audioFormat) .setSampleRate(sampleRate) .setChannelMask(channelConfig) .build() val attributes = AudioAttributes.Builder() .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION) .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH) .build() val preferredBufferSize = AudioTrack.getPreferredBufferSize(format, attributes)
2. 调整PerformanceMode适配场景
PERFORMANCE_MODE_LOW_LATENCY会强制系统使用极小的缓冲区,对线程调度要求极高。如果你的场景并非严格的实时语音通话(比如普通语音播放),可以切换到普通模式:
audioTrack = AudioTrack.Builder() // ... 其他配置不变 .setPerformanceMode(AudioTrack.PERFORMANCE_MODE_NORMAL) .build()
若必须低延迟,可尝试结合setSessionId()复用音频会话,减少系统调度开销。
3. 提升音频写入线程的优先级
音频写入线程被系统抢占是欠载的常见原因,需将线程优先级设为音频专用级别:
val playbackThread = Thread { // 设置线程优先级为音频级别 android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_AUDIO) // 此处执行音频数据写入逻辑 while (isPlaying) { // 读取/生成PCM数据 val data = getNextAudioData() if (data.isNotEmpty()) { audioTrack.write(data, 0, data.size) } } } playbackThread.start()
4. 实现欠载后的自动恢复逻辑
当AudioTrack因欠载被禁用时,需主动重启恢复播放:
// 监听播放状态 audioTrack.setPlaybackPositionUpdateListener(object : AudioTrack.OnPlaybackPositionUpdateListener { override fun onMarkerReached(track: AudioTrack) {} override fun onPeriodicNotification(track: AudioTrack) { // 检查当前播放状态 if (track.playState == AudioTrack.PLAYSTATE_STOPPED && isPlaying) { // 重启AudioTrack track.release() initAudioTrack() // 重新初始化AudioTrack track.play() // 补充缺失的数据 fillBuffer() } } }) // 设置周期检测间隔 audioTrack.setPositionNotificationPeriod(minBufferSize / 2)
5. 优化音频数据的生成/读取效率
如果数据来自网络或文件,确保数据生成速度不低于播放速度:
- 使用缓存队列预加载至少1-2个缓冲区的数据
- 避免在写入线程中执行耗时操作(如IO、解码),单独用线程处理数据生成,再通过队列传递给写入线程
内容的提问来源于stack exchange,提问作者Hasan Altay
相关产品推荐
相关产品推荐

