Как я могу определить, когда можно безопасно воссоздать мастеринговый голос после критической ошибки?

Мое приложение использует XAudio2 для воспроизведения звука. Когда он вызывает CreateMasteringVoice он передает NULL параметру szDeviceId, который согласно эта страница документации выполняет следующие действия:

Если вы указали параметр NULL или szDeviceId для IXAudio2::CreateMasteringVoice, система использует виртуальный аудиоклиент для представления конечной точки аудио. В этом случае, если базовое устройство рендеринга WASAPI становится недоступным, система автоматически выбирает новое устройство рендеринга звука для рендеринга, обработка звука продолжается, а OnCriticalError не возникает.

Однако я обнаружил, что если все аудиоустройства удалены или отключены, то OnCriticalError все еще вызывается, и в этот момент, если я когда-нибудь захочу, чтобы звук снова работал в моем приложении, ему нужно вызвать CreateMasteringVoice еще раз, когда хотя бы одно аудиоустройство будет подключено и включено.

Итак, мой вопрос: как мое приложение сообщает, когда оно должно воссоздать основной голос? (То есть, когда есть хотя бы одно работающее аудиоустройство.) Есть ли лучший способ, кроме как неоднократно пытаться воссоздать мастеринговый голос, пока он не увенчается успехом?

Обратите внимание, что я не могу проверить результат GetDeviceCount, потому что он был удален с версии XAudio2 2.8.


person Walt D    schedule 09.01.2018    source источник


Ответы (1)


Виртуальная голосовая миграция XAudio 2.8 в Windows 10 делает ее менее распространенной, но вам все равно нужно обрабатывать 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();
}
person Chuck Walbourn    schedule 10.01.2018
comment
Ах, спасибо! Я не знал, что могу прослушивать изменения устройства. - person Walt D; 10.01.2018