Fix XAudio2.7 hanging on device disconnection

This commit is contained in:
Lior Halphon 2023-12-23 20:42:21 +02:00
parent e89df2df43
commit c9fb3b3ec6
2 changed files with 64 additions and 2 deletions

View File

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

View File

@ -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))