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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.15 09:04:34