1
0
mirror of https://github.com/mpv-player/mpv synced 2025-05-01 15:50:33 +00:00

ao_wasapi: non-fatal error handling for COM marshalling

Also make sure that CoReleaseMarshalData is called if errors occur before
unmarshalling.
This commit is contained in:
Kevin Mitchell 2015-12-21 00:02:21 -08:00
parent 3ae726e8dd
commit 35296c1f33
3 changed files with 64 additions and 54 deletions

View File

@ -290,7 +290,7 @@ static int init(struct ao *ao)
return -1; return -1;
} }
wasapi_setup_proxies(state); wasapi_receive_proxies(state);
MP_DBG(ao, "Init wasapi done\n"); MP_DBG(ao, "Init wasapi done\n");
return 0; return 0;
} }

View File

@ -1006,28 +1006,27 @@ exit_label:
return hr; return hr;
} }
HRESULT wasapi_setup_proxies(struct wasapi_state *state) { static void *unmarshal(struct wasapi_state *state, REFIID type, IStream **from)
HRESULT hr; {
if (!*from)
#define UNMARSHAL(type, to, from) do { \ return NULL;
hr = CoGetInterfaceAndReleaseStream((from), &(type), (void **)&(to)); \ void *to_proxy = NULL;
(from) = NULL; \ HRESULT hr = CoGetInterfaceAndReleaseStream(*from, type, &to_proxy);
EXIT_ON_ERROR(hr); \ *from = NULL; // the stream is released even on failure
} while (0) EXIT_ON_ERROR(hr);
return to_proxy;
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;
exit_label: exit_label:
MP_ERR(state, "Error reading COM proxy: %s\n", mp_HRESULT_to_str(hr)); MP_WARN(state, "Error reading COM proxy: %s\n", mp_HRESULT_to_str(hr));
return 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) { void wasapi_release_proxies(wasapi_state *state) {
@ -1039,38 +1038,50 @@ void wasapi_release_proxies(wasapi_state *state) {
IAudioSessionControl_Release(state->pSessionControlProxy)); IAudioSessionControl_Release(state->pSessionControlProxy));
} }
static HRESULT create_proxies(struct wasapi_state *state) { // Must call CoReleaseMarshalData to decrement marshalled object's reference
HRESULT hr; // count.
#define SAFE_RELEASE_INTERFACE_STREAM(stream) do { \
#define MARSHAL(type, to, from) do { \ if ((stream) != NULL) { \
hr = CreateStreamOnHGlobal(NULL, TRUE, &(to)); \ CoReleaseMarshalData((stream)); \
EXIT_ON_ERROR(hr); \ IStream_Release((stream)); \
hr = CoMarshalInterThreadInterfaceInStream(&(type), \ (stream) = NULL; \
(IUnknown *)(from), \ } \
&(to)); \
EXIT_ON_ERROR(hr); \
} while(0) } while(0)
MARSHAL(IID_ISimpleAudioVolume, state->sAudioVolume, static IStream *marshal(struct wasapi_state *state,
state->pAudioVolume); REFIID type, void *from_obj)
MARSHAL(IID_IAudioEndpointVolume, state->sEndpointVolume, {
state->pEndpointVolume); if (!from_obj)
MARSHAL(IID_IAudioSessionControl, state->sSessionControl, return NULL;
state->pSessionControl); IStream *to;
HRESULT hr = CreateStreamOnHGlobal(NULL, TRUE, &to);
return S_OK; EXIT_ON_ERROR(hr);
hr = CoMarshalInterThreadInterfaceInStream(type, (IUnknown *)from_obj, &to);
EXIT_ON_ERROR(hr);
return to;
exit_label: exit_label:
MP_ERR(state, "Error creating COM proxy: %s\n", mp_HRESULT_to_str(hr)); SAFE_RELEASE_INTERFACE_STREAM(to);
return hr; 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) { static void create_proxy_streams(struct wasapi_state *state) {
SAFE_RELEASE(state->sAudioVolume, state->sAudioVolume = marshal(state, &IID_ISimpleAudioVolume,
IStream_Release(state->sAudioVolume)); state->pAudioVolume);
SAFE_RELEASE(state->sEndpointVolume, state->sEndpointVolume = marshal(state, &IID_IAudioEndpointVolume,
IStream_Release(state->sEndpointVolume)); state->pEndpointVolume);
SAFE_RELEASE(state->sSessionControl, state->sSessionControl = marshal(state, &IID_IAudioSessionControl,
IStream_Release(state->sSessionControl)); 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) void wasapi_dispatch(struct ao *ao)
@ -1152,8 +1163,7 @@ retry: ;
EXIT_ON_ERROR(hr); EXIT_ON_ERROR(hr);
MP_DBG(ao, "Creating proxies\n"); MP_DBG(ao, "Creating proxies\n");
hr = create_proxies(state); create_proxy_streams(state);
EXIT_ON_ERROR(hr);
wasapi_change_init(ao, false); wasapi_change_init(ao, false);
@ -1174,7 +1184,7 @@ void wasapi_thread_uninit(struct ao *ao)
IAudioClient_Stop(state->pAudioClient); IAudioClient_Stop(state->pAudioClient);
wasapi_change_uninit(ao); wasapi_change_uninit(ao);
destroy_proxies(state); destroy_proxy_streams(state);
SAFE_RELEASE(state->pRenderClient, IAudioRenderClient_Release(state->pRenderClient)); SAFE_RELEASE(state->pRenderClient, IAudioRenderClient_Release(state->pRenderClient));
SAFE_RELEASE(state->pAudioClock, IAudioClock_Release(state->pAudioClock)); SAFE_RELEASE(state->pAudioClock, IAudioClock_Release(state->pAudioClock));

View File

@ -43,7 +43,7 @@ void wasapi_dispatch(struct ao *ao);
HRESULT wasapi_thread_init(struct ao *ao); HRESULT wasapi_thread_init(struct ao *ao);
void wasapi_thread_uninit(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); void wasapi_release_proxies(wasapi_state *state);
#endif #endif