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(); }