#include <iostream>
#include <wrl.h>
#include <mfapi.h>
#include <XAudio2.h>
#pragma comment(lib, "mfplat.lib")
struct MyXAudio2EngineCallback : public IXAudio2EngineCallback {
void STDMETHODCALLTYPE OnProcessingPassEnd() override {}
void STDMETHODCALLTYPE OnProcessingPassStart() override {}
void STDMETHODCALLTYPE OnCriticalError(HRESULT Error) {
std::cerr << "OnCriticalError finished\n";
}
};
class AudioEngine {
public:
AudioEngine() {
auto mDLL = LoadLibraryEx(L"XAudio2_7.DLL", nullptr, 0x00000800 /* LOAD_LIBRARY_SEARCH_SYSTEM32 */);
if (!mDLL) {
std::cerr << "Error: XAudio 2.7 not installed on system (June 2010)\n";
}
auto hr = MFStartup(MF_VERSION);
if (FAILED(hr)) {
std::cerr << "Error: Unable to start the Windows Media Foundation!\n";
}
engineCallback = std::make_unique<MyXAudio2EngineCallback>();
createEngine();
}
bool recreateEngine() {
destroyEngine();
return createEngine();
}
private:
bool createEngine() {
auto hr = XAudio2Create(dev.ReleaseAndGetAddressOf(), 0, XAUDIO2_DEFAULT_PROCESSOR);
if (FAILED(hr)) {
std::cerr << "Error: Unable to create the XAudio2 engine!\n";
return false;
}
hr = dev->CreateMasteringVoice(&masterVoice, 0U, 0U, 0U, 0);
if (FAILED(hr)) {
std::cerr << "Error: Unable to create the XAudio2 mastering voice!\n";
dev.Reset();
return false;
}
dev->RegisterForCallbacks(engineCallback.get());
return true;
}
void destroyEngine() {
if (dev) {
dev->UnregisterForCallbacks(engineCallback.get());
dev->StopEngine();
}
if (masterVoice) {
masterVoice->DestroyVoice();
masterVoice = nullptr;
}
dev.Reset();
}
private:
Microsoft::WRL::ComPtr<IXAudio2> dev;
IXAudio2MasteringVoice* masterVoice = nullptr;
std::unique_ptr<MyXAudio2EngineCallback> engineCallback;
};
int main() {
auto* engine = new AudioEngine();
while (true) {
Sleep(300);
engine->recreateEngine();
}
return 0;
}
Мы используем XAudio2_7 lib в нашем проекте. Я должен воссоздавать аудио движок каждый раз, когда я подключаю / отключаю наушники. Иногда при отключении наушников OnCriticalError не поднимается. IMMNotificationClient дает мне возможность обнаружить, что аудиоустройство по умолчанию изменено, и я пытаюсь воссоздать движок. Вызов DestroyVoice для основного или исходного голоса иногда приводит к зависанию приложения.
Это минимальный рабочий пример, в котором я могу воспроизвести проблему. Вместо использования IMMNotificationClient (для обнаружения изменения устройства по умолчанию) я воссоздаю движок каждые 300 мс. Когда я начинаю подключать / отключать наушники, иногда приложение зависает при вызове dev-> StopEngine (). Такое случается редко.