c++ OpenAL:如何重用在其他OpenAL设备上创建的音频缓冲区?

5ktev3wc  于 2023-03-14  发布在  其他
关注(0)|答案(1)|浏览(131)

根据OpenAL编程指南:

  • 可以在设备或上下文上创建音频缓冲区
  • 上下文只能有一个设备
  • 在一台设备上创建的缓冲区在另一台设备上不可用

Device和Context是OpenAL中的关键词。Device不是OpenAL术语中的声卡,而是一个单一的输出,例如蓝牙耳机。
目前在我的应用程序中,我在开始时加载多个音频文件,并在需要时从缓冲区播放它们。这是最佳的方法,因为我不需要在需要播放时加载文件。
现在当我更换音频设备时,所有的事情都变得复杂了(音频输出)on the fly.这种情况发生在用户连接蓝牙耳机的时候,因为OpenAL设备与输出sink连接我必须关闭旧设备并打开当前的蓝牙输出sink.当我这样做时初始化中加载的所有缓冲区都不再有效,他们不能被播放。看起来我必须重新加载所有的应用程序声音时,设备被改变。这看起来非常不理想的做法。当然,我可以只存储音频缓冲区,并在设备切换只是初始化OpenAL的内部缓冲区,但仍然看起来丑陋的做法。
做这件事的最好方法是什么?

ygya80vv

ygya80vv1#

有两种方法可以解决这个问题,除了编写自己的代码,这将重新加载新设备上的所有缓冲区。

使用重新打开扩展

这个问题已经用ALC_SOFT_reopen_device扩展解决了,它是在2021.03左右引入的,在1.20版本中完成,这就是它的工作原理:

int reopenDevice(const char* deviceName)
{
    auto ctx = alcGetCurrentContext();
    auto device = alcGetContextsDevice(ctx);
    if(nullptr == device)
    {
        return -2;
    }

    if(alcIsExtensionPresent(device, "ALC_SOFT_reopen_device"))
    {
        ALCboolean (ALC_APIENTRY*alcReopenDeviceSOFT)(ALCdevice *device, const ALCchar *name, const ALCint *attribs);
        alcReopenDeviceSOFT = reinterpret_cast<ALCboolean (ALC_APIENTRY*)(ALCdevice *device, const ALCchar *name, const ALCint *attribs)>(alcGetProcAddress(device, "alcReopenDeviceSOFT"));

        if(alcReopenDeviceSOFT(device, deviceName, NULL))
        {
            return 0;
        }

        return -3;
    }

    return -1;
}

它将打开一个新的设备,并确保一切都在旧的工作。

使用OSS后端

从v1.20开始,后端被切换到OSS。使用新的后端,OpenAL的设备总是指向/dev/dsp(在Linux中),并且改变输出接收器不会改变OpenAL的设备。因此,要解决这个问题,需要升级到最低v1.20,并安装Linux的osspd包。

相关问题