OpenAL中AL_BUFFERS_PROCESSED始终为0导致音频流播放中断
OpenAL中AL_BUFFERS_PROCESSED始终为0导致音频流播放中断
看起来你遇到的问题挺典型的——音频刚响一下就中断,而且AL_BUFFERS_PROCESSED一直返回0,导致没办法循环填充新的音频缓冲。我帮你梳理下代码里的几个关键问题,以及对应的修复方案:
核心问题分析
1. Source停止后未重启,且断言强制锁定播放状态
你的代码里有一行assert(state == AL_PLAYING);,这会在音频源播放完所有队列缓冲后直接触发断言(Debug模式下)。如果是Release模式,断言会被忽略,此时音频源已经进入AL_STOPPED状态,OpenAL不会再处理后续的缓冲,自然AL_BUFFERS_PROCESSED会一直显示0。
OpenAL的音频源在播放完所有已队列的缓冲后,会自动停止,这时候你需要主动检查状态并重启它,而不是用断言卡死流程。
2. 未实时更新已处理缓冲的数量
你在循环开头只获取一次buffersProcessed的数值,然后在内部循环里直接减1。但在处理缓冲的过程中,可能又有新的缓冲播放完成,这时候你就会错过这些已处理的缓冲,导致无法及时重新队列新数据。
修改后的代码示例
针对上面的问题,调整stream函数如下:
void AudioDevice::stream() { // 初始化队列缓冲的原有代码保持不变 for (int i = 0; i < numberOfBuffers; i++) { sampleStreamable->process(data, frames); alBufferData(buffers[i], format, data, frames * sizeof(int16_t), sampleRate); assert(alGetError() == AL_NO_ERROR); alSourceQueueBuffers(source, 1, &buffers[i]); assert(alGetError() == AL_NO_ERROR); } ALint queuedBuffers; alGetSourcei(source, AL_BUFFERS_QUEUED, &queuedBuffers); assert(alGetError() == AL_NO_ERROR); assert(queuedBuffers > 0); alSourcePlay(source); assert(alGetError() == AL_NO_ERROR); streaming = true; index = 0; while (streaming) { alGetSourcei(source, AL_SOURCE_STATE, &state); assert(alGetError() == AL_NO_ERROR); // 检查音频源状态,如果停止且还有缓冲队列,就重启播放 if (state != AL_PLAYING && state != AL_PAUSED) { alGetSourcei(source, AL_BUFFERS_QUEUED, &queuedBuffers); if (queuedBuffers > 0) { alSourcePlay(source); } else { // 没有缓冲可播放,终止流 streaming = false; continue; } } // 每次循环都重新查询最新的已处理缓冲数量 alGetSourcei(source, AL_BUFFERS_PROCESSED, &buffersProcessed); assert(alGetError() == AL_NO_ERROR); while (buffersProcessed > 0) { alSourceUnqueueBuffers(source, 1, &buffers[index]); assert(alGetError() == AL_NO_ERROR); sampleStreamable->process(data, frames); alBufferData(buffers[index], format, data, frames * sizeof(int16_t), sampleRate); assert(alGetError() == AL_NO_ERROR); alSourceQueueBuffers(source, 1, &buffers[index]); assert(alGetError() == AL_NO_ERROR); index = (index + 1) % numberOfBuffers; // 处理完一个缓冲后,再次查询最新的已处理数量 alGetSourcei(source, AL_BUFFERS_PROCESSED, &buffersProcessed); assert(alGetError() == AL_NO_ERROR); } usleep(10 * 1000); } }
额外检查点
除了代码修改,你还可以排查这几个地方:
- 确认
SampleStreamable::process函数正确填充了data数组,没有输出静音或者长度不足的音频数据; - 验证OpenAL设备的格式匹配:
AL_FORMAT_MONO16对应16位单声道,你的data是int16_t数组,缓冲大小计算frames * sizeof(int16_t)是正确的; - 确保
usleep(10 * 1000)的等待时间合理——你的4096帧在48kHz采样率下约85ms,10ms的轮询间隔是合适的,不需要调整。
备注:内容来源于stack exchange,提问作者patrick
相关产品推荐
相关产品推荐

