在出现严重错误后,我如何确定何时可以安全地重新创建母带处理声音?
How can I determine when it's safe to recreate the mastering voice after a critical error?
我的应用程序使用 XAudio2 播放音频。当它调用 CreateMasteringVoice
it passes NULL
to the szDeviceId
parameter, which according to this documentation page 时执行以下操作:
If you specified NULL or szDeviceId parameter to
IXAudio2::CreateMasteringVoice, then the system uses a Virtual Audio
Client to represent the audio endpoint. In this case, if the
underlying WASAPI rendering device becomes unavailable, the system
automatically selects a new audio rendering device for rendering,
audio processing continues, and OnCriticalError is not raised.
但是,我发现如果 所有 的音频设备被移除或禁用,那么 OnCriticalError
仍然被调用,此时,如果我想要音频再次在我的应用程序中工作,它需要在至少插入并启用一个音频设备后再次调用 CreateMasteringVoice
。
所以我的问题是,我的应用程序如何告诉何时它应该重新创建母带语音? (即,当至少有一个功能正常的音频设备时。)除了反复尝试重新创建掌握声音直到成功之外,还有什么更好的方法吗?
请注意,我无法检查 GetDeviceCount
的结果,因为它已从 XAudio2 2.8 中删除。
Windows10 中的 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();
}
我的应用程序使用 XAudio2 播放音频。当它调用 CreateMasteringVoice
it passes NULL
to the szDeviceId
parameter, which according to this documentation page 时执行以下操作:
If you specified NULL or szDeviceId parameter to IXAudio2::CreateMasteringVoice, then the system uses a Virtual Audio Client to represent the audio endpoint. In this case, if the underlying WASAPI rendering device becomes unavailable, the system automatically selects a new audio rendering device for rendering, audio processing continues, and OnCriticalError is not raised.
但是,我发现如果 所有 的音频设备被移除或禁用,那么 OnCriticalError
仍然被调用,此时,如果我想要音频再次在我的应用程序中工作,它需要在至少插入并启用一个音频设备后再次调用 CreateMasteringVoice
。
所以我的问题是,我的应用程序如何告诉何时它应该重新创建母带语音? (即,当至少有一个功能正常的音频设备时。)除了反复尝试重新创建掌握声音直到成功之外,还有什么更好的方法吗?
请注意,我无法检查 GetDeviceCount
的结果,因为它已从 XAudio2 2.8 中删除。
Windows10 中的 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();
}