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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 15:33:28