diff --git a/SDL/audio/xaudio2_7.c b/SDL/audio/xaudio2_7.c index b8ed544af..146450f17 100644 --- a/SDL/audio/xaudio2_7.c +++ b/SDL/audio/xaudio2_7.c @@ -109,8 +109,27 @@ static unsigned _audio_get_frequency(void) return audio_frequency; } +static void nop(IXAudio2EngineCallback *this) +{ +} + +static bool _audio_init(void); + +static _Atomic bool needs_restart = false; + +static void critical_error(IXAudio2EngineCallback *this, HRESULT error) +{ + needs_restart = true; +} + + static size_t _audio_get_queue_length(void) { + if (needs_restart) { + _audio_init(); + if (!xaudio2) return 0; + _audio_set_paused(!playing); + } static XAUDIO2_VOICE_STATE state; IXAudio2SourceVoice_GetState(source_voice, &state); @@ -120,6 +139,12 @@ static size_t _audio_get_queue_length(void) static void _audio_queue_sample(GB_sample_t *sample) { if (!playing) return; + + if (needs_restart) { + _audio_init(); + if (!xaudio2) return; + _audio_set_paused(!playing); + } static XAUDIO2_BUFFER buffer = {.AudioBytes = sizeof(*sample) * BATCH_SIZE, }; sample_pool[pos] = *sample; @@ -133,6 +158,14 @@ static void _audio_queue_sample(GB_sample_t *sample) static bool _audio_init(void) { + if (needs_restart) { + needs_restart = false; + if (xaudio2) { + xaudio2->lpVtbl->Release(xaudio2); + xaudio2 = NULL; + } + } + HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); if (FAILED(hr)) { fprintf(stderr, "CoInitializeEx failed: %lx\n", hr); @@ -168,6 +201,19 @@ static bool _audio_init(void) return false; } + + static IXAudio2EngineCallbackVtbl callbacks = { + nop, + nop, + .OnCriticalError = critical_error + }; + + static IXAudio2EngineCallback callbackObject = { + .lpVtbl = &callbacks + }; + + IXAudio2SourceVoice_RegisterForCallbacks(xaudio2, &callbackObject); + return true; } diff --git a/SDL/audio/xaudio2_7.h b/SDL/audio/xaudio2_7.h index 298715650..649f41067 100644 --- a/SDL/audio/xaudio2_7.h +++ b/SDL/audio/xaudio2_7.h @@ -49,6 +49,21 @@ typedef struct IXAudio2 { typedef struct IXAudio2Vtbl IXAudio2Vtbl; typedef void *IXAudio2MasteringVoice; +#undef INTERFACE +#define INTERFACE IXAudio2EngineCallback +DECLARE_INTERFACE(IXAudio2EngineCallback) +{ + // Called by XAudio2 just before an audio processing pass begins. + STDMETHOD_(void, OnProcessingPassStart) (THIS) PURE; + + // Called just after an audio processing pass ends. + STDMETHOD_(void, OnProcessingPassEnd) (THIS) PURE; + + // 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. + STDMETHOD_(void, OnCriticalError) (THIS_ HRESULT Error) PURE; +}; + #undef INTERFACE #define INTERFACE IXAudio2 @@ -61,8 +76,8 @@ struct IXAudio2Vtbl { STDMETHOD(Initialize) (THIS_ UINT32 Flags, XAUDIO2_PROCESSOR XAudio2Processor) PURE; - void *RegisterForCallbacks; - void *UnregisterForCallbacks; + STDMETHOD(RegisterForCallbacks) (THIS_ __in IXAudio2EngineCallback *pCallback) PURE; + void *UnregisterForCallbacks; STDMETHOD(CreateSourceVoice) (THIS_ __deref_out IXAudio2SourceVoice **ppSourceVoice, __in const WAVEFORMATEX *pSourceFormat, @@ -91,6 +106,7 @@ DEFINE_CLSID(XAudio2, 5a508685, a254, 4fba, 9b, 82, 9a, 24, b0, 03, 06, af); DEFINE_IID(IXAudio2, 8bcf1f58, 9fe7, 4583, 8a, c6, e2, ad, c4, 65, c8, bb); +#define IXAudio2SourceVoice_RegisterForCallbacks(This, pCallback) ((This)->lpVtbl->RegisterForCallbacks(This,pCallback)) #define IXAudio2SourceVoice_Start(This,Flags,OperationSet) ((This)->lpVtbl->Start(This,Flags,OperationSet)) #define IXAudio2SourceVoice_Stop(This,Flags,OperationSet) ((This)->lpVtbl->Stop(This,Flags,OperationSet)) #define IXAudio2SourceVoice_SubmitSourceBuffer(This,pBuffer,pBufferWMA) ((This)->lpVtbl->SubmitSourceBuffer(This,pBuffer,pBufferWMA))