From d7dc9acf2f8de78f058904c5390e6fc646ec9aad Mon Sep 17 00:00:00 2001 From: OV2 Date: Mon, 14 Feb 2022 01:05:57 +0100 Subject: [PATCH] win32: stop trying to send audio data after device removal --- win32/CWaveOut.cpp | 17 +++++++++++++---- win32/CWaveOut.h | 2 ++ win32/CXAudio2.cpp | 3 +++ win32/CXAudio2.h | 19 ++++++++++++++++++- 4 files changed, 36 insertions(+), 5 deletions(-) diff --git a/win32/CWaveOut.cpp b/win32/CWaveOut.cpp index 7ba04949..df1071e0 100644 --- a/win32/CWaveOut.cpp +++ b/win32/CWaveOut.cpp @@ -20,17 +20,25 @@ CWaveOut::~CWaveOut(void) DeInitSoundOutput(); } -void CALLBACK WaveCallback(HWAVEOUT hWave, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2) +void CALLBACK CWaveOut::WaveCallback(HWAVEOUT hWave, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2) { + CWaveOut *wo = (CWaveOut*)dwUser; if (uMsg == WOM_DONE) { - InterlockedDecrement(((volatile LONG *)dwUser)); + InterlockedDecrement(&wo->bufferCount); SetEvent(GUI.SoundSyncEvent); } + else if (uMsg == WOM_CLOSE) // also sent on device removals + { + // this stops any output from being sent to the non existing device + wo->initDone = false; + } } bool CWaveOut::SetupSound() { + DeInitSoundOutput(); + WAVEFORMATEX wfx; wfx.wFormatTag = WAVE_FORMAT_PCM; wfx.nChannels = 2; @@ -43,7 +51,7 @@ bool CWaveOut::SetupSound() // subtract -1, we added "Default" as first index - Default will yield -1, which is WAVE_MAPPER int device_index = FindDeviceIndex(GUI.AudioDevice) - 1; - waveOutOpen(&hWaveOut, device_index, &wfx, (DWORD_PTR)WaveCallback, (DWORD_PTR)&bufferCount, CALLBACK_FUNCTION); + waveOutOpen(&hWaveOut, device_index, &wfx, (DWORD_PTR)WaveCallback, (DWORD_PTR)this, CALLBACK_FUNCTION); UINT32 blockTime = GUI.SoundBufferSize / blockCount; singleBufferSamples = (Settings.SoundPlaybackRate * blockTime) / 1000; @@ -91,7 +99,7 @@ bool CWaveOut::InitSoundOutput() void CWaveOut::DeInitSoundOutput() { - if (!initDone) + if (!hWaveOut) return; StopPlayback(); @@ -109,6 +117,7 @@ void CWaveOut::DeInitSoundOutput() waveHeaders.clear(); waveOutClose(hWaveOut); + hWaveOut = NULL; initDone = false; } diff --git a/win32/CWaveOut.h b/win32/CWaveOut.h index 833283bd..01fb7e3e 100644 --- a/win32/CWaveOut.h +++ b/win32/CWaveOut.h @@ -44,4 +44,6 @@ class CWaveOut : public IS9xSoundOutput void SetVolume(double volume); std::vector GetDeviceList(); int FindDeviceIndex(TCHAR *audio_device); + + static void CALLBACK WaveCallback(HWAVEOUT hWave, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2); }; diff --git a/win32/CXAudio2.cpp b/win32/CXAudio2.cpp index 4323e5d2..c4302a36 100644 --- a/win32/CXAudio2.cpp +++ b/win32/CXAudio2.cpp @@ -108,6 +108,8 @@ bool CXAudio2::InitXAudio2(void) if(initDone) return true; + DeInitXAudio2(); + HRESULT hr; if ( FAILED(hr = XAudio2Create( &pXAudio2, 0 , XAUDIO2_DEFAULT_PROCESSOR ) ) ) { DXTRACE_ERR_MSGBOX(TEXT("Unable to create XAudio2 object."),hr); @@ -115,6 +117,7 @@ bool CXAudio2::InitXAudio2(void) return false; } initDone = true; + pXAudio2->RegisterForCallbacks(this); return true; } diff --git a/win32/CXAudio2.h b/win32/CXAudio2.h index ea520796..10c9f8eb 100644 --- a/win32/CXAudio2.h +++ b/win32/CXAudio2.h @@ -11,7 +11,7 @@ #include #include "IS9xSoundOutput.h" -class CXAudio2 : public IXAudio2VoiceCallback, public IS9xSoundOutput +class CXAudio2 : public IXAudio2VoiceCallback, public IXAudio2EngineCallback, public IS9xSoundOutput { private: IXAudio2SourceVoice *pSourceVoice; @@ -56,6 +56,23 @@ public: STDMETHODIMP_(void) OnVoiceProcessingPassStart(UINT32 BytesRequired) {} + // inherited from IXAudio2EngineCallback - we only use OnCriticalError + + // Called by XAudio2 just before an audio processing pass begins. + STDMETHODIMP_(void) OnProcessingPassStart() {} + + // Called just after an audio processing pass ends. + STDMETHODIMP_(void) OnProcessingPassEnd() {} + + // Called in the event of a critical system error which requires XAudio2 + // to be closed down and restarted. The error code is given in Error. + STDMETHODIMP_(void) OnCriticalError(HRESULT Error) + { + // this stops any output from being sent to the non existing device + initDone = false; + } + + // Inherited from IS9xSoundOutput bool InitSoundOutput(void) { return InitXAudio2(); } void DeInitSoundOutput(void) { DeInitXAudio2(); }