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:
parent
3ae726e8dd
commit
35296c1f33
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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));
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user