From 35296c1f3357cf4ee17f2a6ad58c1ff3e550070d Mon Sep 17 00:00:00 2001 From: Kevin Mitchell Date: Mon, 21 Dec 2015 00:02:21 -0800 Subject: ao_wasapi: non-fatal error handling for COM marshalling Also make sure that CoReleaseMarshalData is called if errors occur before unmarshalling. --- audio/out/ao_wasapi.c | 2 +- audio/out/ao_wasapi_utils.c | 116 ++++++++++++++++++++++++-------------------- audio/out/ao_wasapi_utils.h | 2 +- 3 files changed, 65 insertions(+), 55 deletions(-) (limited to 'audio') diff --git a/audio/out/ao_wasapi.c b/audio/out/ao_wasapi.c index 2fcb2e9bba..bafeae1d63 100644 --- a/audio/out/ao_wasapi.c +++ b/audio/out/ao_wasapi.c @@ -290,7 +290,7 @@ static int init(struct ao *ao) return -1; } - wasapi_setup_proxies(state); + wasapi_receive_proxies(state); MP_DBG(ao, "Init wasapi done\n"); return 0; } diff --git a/audio/out/ao_wasapi_utils.c b/audio/out/ao_wasapi_utils.c index 235d0db8c7..9f672b24f5 100755 --- a/audio/out/ao_wasapi_utils.c +++ b/audio/out/ao_wasapi_utils.c @@ -1006,28 +1006,27 @@ exit_label: return hr; } -HRESULT wasapi_setup_proxies(struct wasapi_state *state) { - HRESULT hr; - -#define UNMARSHAL(type, to, from) do { \ - hr = CoGetInterfaceAndReleaseStream((from), &(type), (void **)&(to)); \ - (from) = NULL; \ - EXIT_ON_ERROR(hr); \ -} while (0) - - UNMARSHAL(IID_ISimpleAudioVolume, state->pAudioVolumeProxy, - state->sAudioVolume); - UNMARSHAL(IID_IAudioEndpointVolume, state->pEndpointVolumeProxy, - state->sEndpointVolume); - UNMARSHAL(IID_IAudioSessionControl, state->pSessionControlProxy, - state->sSessionControl); - -#undef UNMARSHAL - - return S_OK; +static void *unmarshal(struct wasapi_state *state, REFIID type, IStream **from) +{ + if (!*from) + return NULL; + void *to_proxy = NULL; + HRESULT hr = CoGetInterfaceAndReleaseStream(*from, type, &to_proxy); + *from = NULL; // the stream is released even on failure + EXIT_ON_ERROR(hr); + return to_proxy; exit_label: - MP_ERR(state, "Error reading COM proxy: %s\n", mp_HRESULT_to_str(hr)); - return hr; + MP_WARN(state, "Error reading COM proxy: %s\n", mp_HRESULT_to_str(hr)); + return to_proxy; +} + +void wasapi_receive_proxies(struct wasapi_state *state) { + state->pAudioVolumeProxy = unmarshal(state, &IID_ISimpleAudioVolume, + &state->sAudioVolume); + state->pEndpointVolumeProxy = unmarshal(state, &IID_IAudioEndpointVolume, + &state->sEndpointVolume); + state->pSessionControlProxy = unmarshal(state, &IID_IAudioSessionControl, + &state->sSessionControl); } void wasapi_release_proxies(wasapi_state *state) { @@ -1039,38 +1038,50 @@ void wasapi_release_proxies(wasapi_state *state) { IAudioSessionControl_Release(state->pSessionControlProxy)); } -static HRESULT create_proxies(struct wasapi_state *state) { - HRESULT hr; - -#define MARSHAL(type, to, from) do { \ - hr = CreateStreamOnHGlobal(NULL, TRUE, &(to)); \ - EXIT_ON_ERROR(hr); \ - hr = CoMarshalInterThreadInterfaceInStream(&(type), \ - (IUnknown *)(from), \ - &(to)); \ - EXIT_ON_ERROR(hr); \ -} while (0) - - MARSHAL(IID_ISimpleAudioVolume, state->sAudioVolume, - state->pAudioVolume); - MARSHAL(IID_IAudioEndpointVolume, state->sEndpointVolume, - state->pEndpointVolume); - MARSHAL(IID_IAudioSessionControl, state->sSessionControl, - state->pSessionControl); - - return S_OK; +// Must call CoReleaseMarshalData to decrement marshalled object's reference +// count. +#define SAFE_RELEASE_INTERFACE_STREAM(stream) do { \ + if ((stream) != NULL) { \ + CoReleaseMarshalData((stream)); \ + IStream_Release((stream)); \ + (stream) = NULL; \ + } \ + } while(0) + +static IStream *marshal(struct wasapi_state *state, + REFIID type, void *from_obj) +{ + if (!from_obj) + return NULL; + IStream *to; + HRESULT hr = CreateStreamOnHGlobal(NULL, TRUE, &to); + EXIT_ON_ERROR(hr); + hr = CoMarshalInterThreadInterfaceInStream(type, (IUnknown *)from_obj, &to); + EXIT_ON_ERROR(hr); + return to; exit_label: - MP_ERR(state, "Error creating COM proxy: %s\n", mp_HRESULT_to_str(hr)); - return hr; + SAFE_RELEASE_INTERFACE_STREAM(to); + MP_WARN(state, "Error creating COM proxy stream: %s\n", + mp_HRESULT_to_str(hr)); + return to; } -static void destroy_proxies(struct wasapi_state *state) { - SAFE_RELEASE(state->sAudioVolume, - IStream_Release(state->sAudioVolume)); - SAFE_RELEASE(state->sEndpointVolume, - IStream_Release(state->sEndpointVolume)); - SAFE_RELEASE(state->sSessionControl, - IStream_Release(state->sSessionControl)); +static void create_proxy_streams(struct wasapi_state *state) { + state->sAudioVolume = marshal(state, &IID_ISimpleAudioVolume, + state->pAudioVolume); + state->sEndpointVolume = marshal(state, &IID_IAudioEndpointVolume, + state->pEndpointVolume); + state->sSessionControl = marshal(state, &IID_IAudioSessionControl, + state->pSessionControl); +} + +static void destroy_proxy_streams(struct wasapi_state *state) { + // This is only to handle error conditions. + // During normal operation, these will already have been released by + // unmarshaling. + SAFE_RELEASE_INTERFACE_STREAM(state->sAudioVolume); + SAFE_RELEASE_INTERFACE_STREAM(state->sEndpointVolume); + SAFE_RELEASE_INTERFACE_STREAM(state->sSessionControl); } void wasapi_dispatch(struct ao *ao) @@ -1152,8 +1163,7 @@ retry: ; EXIT_ON_ERROR(hr); MP_DBG(ao, "Creating proxies\n"); - hr = create_proxies(state); - EXIT_ON_ERROR(hr); + create_proxy_streams(state); wasapi_change_init(ao, false); @@ -1174,7 +1184,7 @@ void wasapi_thread_uninit(struct ao *ao) IAudioClient_Stop(state->pAudioClient); wasapi_change_uninit(ao); - destroy_proxies(state); + destroy_proxy_streams(state); SAFE_RELEASE(state->pRenderClient, IAudioRenderClient_Release(state->pRenderClient)); SAFE_RELEASE(state->pAudioClock, IAudioClock_Release(state->pAudioClock)); diff --git a/audio/out/ao_wasapi_utils.h b/audio/out/ao_wasapi_utils.h index deaffd77e4..8e6b4318d3 100755 --- a/audio/out/ao_wasapi_utils.h +++ b/audio/out/ao_wasapi_utils.h @@ -43,7 +43,7 @@ void wasapi_dispatch(struct ao *ao); HRESULT wasapi_thread_init(struct ao *ao); void wasapi_thread_uninit(struct ao *ao); -HRESULT wasapi_setup_proxies(wasapi_state *state); +void wasapi_receive_proxies(wasapi_state *state); void wasapi_release_proxies(wasapi_state *state); #endif -- cgit v1.2.3