0

我的应用程序使用 XAudio2 播放音频。当它调用CreateMasteringVoice它时,它传递NULLszDeviceId参数,根据此文档页面,该参数执行以下操作:

如果您为 IXAudio2::CreateMasteringVoice 指定 NULL 或 szDeviceId 参数,则系统使用虚拟音频客户端来表示音频端点。在这种情况下,如果底层 WASAPI 渲染设备不可用,系统会自动选择新的音频渲染设备进行渲染,音频处理继续进行,并且不会引发 OnCriticalError。

但是,我发现如果所有的音频设备都被删除或禁用,那么OnCriticalError仍然会被调用,此时,如果我想让音频再次在我的应用程序中工作,它需要CreateMasteringVoice在至少有一个音频时再次调用设备已插入并启用。

所以我的问题是,我的应用程序如何判断何时应该重新创建母带声音?(即,当至少有一个正常工作的音频设备时。)除了反复尝试重新创建母带声音直到成功之外,还有什么更好的方法吗?

请注意,我无法检查结果,GetDeviceCount因为从 XAudio2 2.8 开始已将其删除。

4

1 回答 1

1

Windows 10 中的 XAudio 2.8 虚拟语音迁移使其不太常见,但您仍然需要处理OnCriticalError场景。通常,只要将新的音频设备添加到系统中,您就会尝试重置语音。

在 Win32 桌面应用程序中:

#include <Dbt.h>

HDEVNOTIFY g_hNewAudio = nullptr;

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{

case WM_CREATE:
    if (!g_hNewAudio)
    {
        // Ask for notification of new audio devices
        DEV_BROADCAST_DEVICEINTERFACE filter = { 0 };
        filter.dbcc_size = sizeof(filter);
        filter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
        filter.dbcc_classguid = KSCATEGORY_AUDIO;

        g_hNewAudio = RegisterDeviceNotification(hWnd, &filter, DEVICE_NOTIFY_WINDOW_HANDLE);
    }
    break;

case WM_CLOSE:
    if (g_hNewAudio)
    {
        UnregisterDeviceNotification(g_hNewAudio);
        g_hNewAudio = nullptr;
    }
    DestroyWindow(hWnd);
    break;

case WM_DEVICECHANGE:
    switch (wParam)
    {
    case DBT_DEVICEARRIVAL:
    {
        auto pDev = reinterpret_cast<PDEV_BROADCAST_HDR>(lParam);
        if (pDev)
        {
            if (pDev->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE)
            {
                auto pInter = reinterpret_cast<const PDEV_BROADCAST_DEVICEINTERFACE>(pDev);
                if (pInter->dbcc_classguid == KSCATEGORY_AUDIO)
                {
                    if (g_game)
                        g_game->NewAudioDevice();
                }
            }
        }
    }
    break;

    case DBT_DEVICEREMOVECOMPLETE:
    {
        auto pDev = reinterpret_cast<PDEV_BROADCAST_HDR>(lParam);
        if (pDev)
        {
            if (pDev->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE)
            {
                auto pInter = reinterpret_cast<const PDEV_BROADCAST_DEVICEINTERFACE>(pDev);
                if (pInter->dbcc_classguid == KSCATEGORY_AUDIO)
                {
                    if (g_game)
                        g_game->NewAudioDevice();
                }
            }
        }
    }
    break;
    }
    return 0;

在 UWP 应用中,你使用DeviceWatcher

Windows::Devices::Enumeration::DeviceWatcher^ m_audioWatcher;

virtual void Initialize(CoreApplicationView^ applicationView)
{
    m_audioWatcher = DeviceInformation::CreateWatcher(DeviceClass::AudioRender);

    m_audioWatcher->Added += ref new TypedEventHandler<DeviceWatcher^, DeviceInformation^>(this, &ViewProvider::OnAudioDeviceAdded);
    m_audioWatcher->Updated += ref new TypedEventHandler<DeviceWatcher^, DeviceInformationUpdate^>(this, &ViewProvider::OnAudioDeviceUpdated);

    m_audioWatcher->Start();
}

void OnAudioDeviceAdded(Windows::Devices::Enumeration::DeviceWatcher^ sender, Windows::Devices::Enumeration::DeviceInformation^ args)
{
    m_game->NewAudioDevice();
}

void OnAudioDeviceUpdated(Windows::Devices::Enumeration::DeviceWatcher^ sender, Windows::Devices::Enumeration::DeviceInformationUpdate^ args)
{
    m_game->NewAudioDevice();
}
于 2018-01-10T08:31:39.543 回答