exoplayer 代码片段逻辑分析
private fun getDefaultBufferSizeInBytes(audioFormat: AudioProcessor.AudioFormat): Int { val outputPcmFrameSize = Util.getPcmFrameSize(audioFormat.encoding, audioFormat.channelCount) val minBufferSize = AudioTrack.getMinBufferSize( audioFormat.sampleRate, Util.getAudioTrackChannelConfig(audioFormat.channelCount), audioFormat.encoding ) Assertions.checkState(minBufferSize != ERROR_BAD_VALUE) val multipliedBufferSize = minBufferSize * EXO_BUFFER_MULTIPLICATION_FACTOR val minAppBufferSize = durationUsToFrames(EXO_MIN_BUFFER_DURATION_US).toInt() * outputPcmFrameSize val maxAppBufferSize = max( minBufferSize.toLong(), durationUsToFrames(EXO_MAX_BUFFER_DURATION_US) * outputPcmFrameSize ).toInt() val bufferSizeInFrames = Util.constrainValue( multipliedBufferSize, minAppBufferSize, maxAppBufferSize ) / outputPcmFrameSize return bufferSizeInFrames * outputPcmFrameSize }
这段代码是用于计算 默认音频缓冲区大小 的方法,通常用于 AudioTrack 配置,以确保音频播放流畅且延迟低。它的作用是:
1. 计算 PCM 帧大小
2. 获取 AudioTrack 最小缓冲区
3. 扩展缓冲区大小,确保应用层缓冲区适合不同场景
4. 在合理范围内调整缓冲区大小
详细解析
1. 获取 PCM 帧大小
val outputPcmFrameSize = Util.getPcmFrameSize(audioFormat.encoding, audioFormat.channelCount)
• Util.getPcmFrameSize(encoding, channelCount) 计算 每个 PCM 采样帧的字节大小。
• 示例:
• PCM 16-bit,双声道:2 (bytes per sample) × 2 (channels) = 4 bytes per frame
• PCM 8-bit,单声道:1 (bytes per sample) × 1 (channel) = 1 byte per frame
2. 获取 AudioTrack 允许的最小缓冲区
val minBufferSize = AudioTrack.getMinBufferSize( audioFormat.sampleRate, Util.getAudioTrackChannelConfig(audioFormat.channelCount), audioFormat.encoding )
• AudioTrack.getMinBufferSize() 获取 Android 系统推荐的最小音频缓冲区大小(以字节为单位)。
• Util.getAudioTrackChannelConfig(audioFormat.channelCount) 转换声道数到 AudioTrack 配置,如:
• 单声道(1 channel):AudioFormat.CHANNEL_OUT_MONO
• 立体声(2 channels):AudioFormat.CHANNEL_OUT_STEREO
• audioFormat.encoding 是音频格式,如 ENCODING_PCM_16BIT。
如果 getMinBufferSize() 返回 ERROR_BAD_VALUE,表示格式不支持,程序会抛出异常:
Assertions.checkState(minBufferSize != ERROR_BAD_VALUE)
3. 扩展缓冲区大小
val multipliedBufferSize = minBufferSize * EXO_BUFFER_MULTIPLICATION_FACTOR
• EXO_BUFFER_MULTIPLICATION_FACTOR 用于扩展缓冲区大小,确保播放不卡顿。
• 为什么扩展?
• Android 提供的 minBufferSize 可能不足以处理所有场景,比如较高的 sampleRate 可能需要更大缓冲区。
• 例如,如果 minBufferSize = 8192 且 EXO_BUFFER_MULTIPLICATION_FACTOR = 4,则 multipliedBufferSize = 32768。
4. 计算 minAppBufferSize
val minAppBufferSize = durationUsToFrames(EXO_MIN_BUFFER_DURATION_US).toInt() * outputPcmFrameSize
• EXO_MIN_BUFFER_DURATION_US 是 最小缓冲区持续时间(单位:微秒),比如 250000(250ms)。
• durationUsToFrames(EXO_MIN_BUFFER_DURATION_US) 将持续时间转换为帧数。
• frames = (采样率 × 持续时间) / 1_000_000
• 例如 44100 Hz,250ms:
frames = (44100 × 250000) / 1_000_000 = 11025 frames
• 计算出的帧数再 乘以 outputPcmFrameSize,得到以 字节为单位 的缓冲区大小。
5. 计算 maxAppBufferSize
val maxAppBufferSize = max( minBufferSize.toLong(), durationUsToFrames(EXO_MAX_BUFFER_DURATION_US) * outputPcmFrameSize ).toInt()
• EXO_MAX_BUFFER_DURATION_US 是最大缓冲区持续时间(比如 750ms)。
• 计算方法同 minAppBufferSize,但这里取 minBufferSize 和 maxBufferSize 的最大值,保证缓冲区足够大。
6. 计算最终的缓冲区大小
val bufferSizeInFrames = Util.constrainValue( multipliedBufferSize, minAppBufferSize, maxAppBufferSize ) / outputPcmFrameSize return bufferSizeInFrames * outputPcmFrameSize
• Util.constrainValue(value, min, max) 确保 multipliedBufferSize 在 minAppBufferSize 和 maxAppBufferSize 之间。
• 最后转换回字节单位,返回最终的缓冲区大小。
完整流程示例
假设:
• 采样率:44100 Hz
• 声道数:2(立体声)
• 格式:PCM 16-bit
• EXO_MIN_BUFFER_DURATION_US = 250_000(250ms)
• EXO_MAX_BUFFER_DURATION_US = 750_000(750ms)
• EXO_BUFFER_MULTIPLICATION_FACTOR = 4
那么:
1. 计算 PCM 帧大小
outputPcmFrameSize = 2 bytes * 2 channels = 4 bytes
2. 获取 minBufferSize
minBufferSize = AudioTrack.getMinBufferSize(44100, CHANNEL_OUT_STEREO, ENCODING_PCM_16BIT) minBufferSize = 8192 bytes
3. 扩展缓冲区
multipliedBufferSize = 8192 * 4 = 32768 bytes
4. 计算 minAppBufferSize
minAppBufferSize = (44100 × 250_000 / 1_000_000) * 4 = 11025 * 4 = 44100 bytes
5. 计算 maxAppBufferSize
maxAppBufferSize = max(8192, (44100 × 750_000 / 1_000_000) * 4) = max(8192, 33075 * 4) = max(8192, 132300) = 132300 bytes
6. 计算最终缓冲区大小
bufferSizeInFrames = constrainValue(32768, 44100, 132300) / 4 = 44100 / 4 = 11025 frames return 11025 * 4 = 44100 bytes
最终缓冲区大小:44100 bytes(44 KB)。
总结
• 目的是计算合适的音频缓冲区大小,既不会太小(导致音频中断),也不会太大(增加延迟)。
• 确保 AudioTrack 可以流畅播放,避免 Buffer Underrun(缓冲区数据不足)。
• 动态调整,基于音频采样率、格式和最小/最大缓冲区大小。
这段代码优化了 音频播放的稳定性 和 低延迟性,在 ExoPlayer 音频处理流程中非常重要。 🎵