win32: stop trying to send audio data after device removal

This commit is contained in:
OV2 2022-02-14 01:05:57 +01:00
parent f1ac3dc6d3
commit d7dc9acf2f
4 changed files with 36 additions and 5 deletions

View File

@ -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;
}

View File

@ -44,4 +44,6 @@ class CWaveOut : public IS9xSoundOutput
void SetVolume(double volume);
std::vector<std::wstring> GetDeviceList();
int FindDeviceIndex(TCHAR *audio_device);
static void CALLBACK WaveCallback(HWAVEOUT hWave, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2);
};

View File

@ -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;
}

View File

@ -11,7 +11,7 @@
#include <windows.h>
#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(); }