From: Davide Beatrici git@davidebeatrici.dev
--- dlls/mmdevapi/client.c | 183 ++++++++++++++++++++++++++++++++++ dlls/mmdevapi/session.c | 28 ++++++ dlls/winepulse.drv/mmdevdrv.c | 170 +++---------------------------- 3 files changed, 226 insertions(+), 155 deletions(-)
diff --git a/dlls/mmdevapi/client.c b/dlls/mmdevapi/client.c index acc3868ce6a..219d4753afa 100644 --- a/dlls/mmdevapi/client.c +++ b/dlls/mmdevapi/client.c @@ -36,6 +36,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(mmdevapi); extern void sessions_lock(void) DECLSPEC_HIDDEN; extern void sessions_unlock(void) DECLSPEC_HIDDEN;
+extern struct audio_session_wrapper *session_wrapper_create(struct audio_client *client) DECLSPEC_HIDDEN; + void set_stream_volumes(struct audio_client *This) { struct set_volumes_params params; @@ -78,6 +80,20 @@ static inline struct audio_client *impl_from_IAudioStreamVolume(IAudioStreamVolu return CONTAINING_RECORD(iface, struct audio_client, IAudioStreamVolume_iface); }
+static DWORD CALLBACK timer_loop_func(void *user) +{ + struct timer_loop_params params; + struct audio_client *This = user; + + SetThreadDescription(GetCurrentThread(), L"audio_client_timer"); + + params.stream = This->stream; + + WINE_UNIX_CALL(timer_loop, ¶ms); + + return 0; +} + static HRESULT WINAPI capture_QueryInterface(IAudioCaptureClient *iface, REFIID riid, void **ppv) { struct audio_client *This = impl_from_IAudioCaptureClient(iface); @@ -346,6 +362,173 @@ const IAudioClock2Vtbl AudioClock2_Vtbl = clock2_GetDevicePosition };
+HRESULT WINAPI client_GetDevicePeriod(IAudioClient3 *iface, REFERENCE_TIME *defperiod, + REFERENCE_TIME *minperiod) +{ + struct audio_client *This = impl_from_IAudioClient3(iface); + struct get_device_period_params params; + + TRACE("(%p)->(%p, %p)\n", This, defperiod, minperiod); + + if (!defperiod && !minperiod) + return E_POINTER; + + params.device = This->device_name; + params.flow = This->dataflow; + params.def_period = defperiod; + params.min_period = minperiod; + + WINE_UNIX_CALL(get_device_period, ¶ms); + + return S_OK; +} + +HRESULT WINAPI client_Start(IAudioClient3 *iface) +{ + struct audio_client *This = impl_from_IAudioClient3(iface); + struct start_params params; + + TRACE("(%p)\n", This); + + sessions_lock(); + + if (!This->stream) { + sessions_unlock(); + return AUDCLNT_E_NOT_INITIALIZED; + } + + params.stream = This->stream; + + WINE_UNIX_CALL(start, ¶ms); + + if (SUCCEEDED(params.result) && !This->timer_thread) { + This->timer_thread = CreateThread(NULL, 0, timer_loop_func, This, 0, NULL); + SetThreadPriority(This->timer_thread, THREAD_PRIORITY_TIME_CRITICAL); + } + + sessions_unlock(); + + return params.result; +} + +HRESULT WINAPI client_Stop(IAudioClient3 *iface) +{ + struct audio_client *This = impl_from_IAudioClient3(iface); + struct stop_params params; + + TRACE("(%p)\n", This); + + if (!This->stream) + return AUDCLNT_E_NOT_INITIALIZED; + + params.stream = This->stream; + + WINE_UNIX_CALL(stop, ¶ms); + + return params.result; +} + +HRESULT WINAPI client_Reset(IAudioClient3 *iface) +{ + struct audio_client *This = impl_from_IAudioClient3(iface); + struct reset_params params; + + TRACE("(%p)\n", This); + + if (!This->stream) + return AUDCLNT_E_NOT_INITIALIZED; + + params.stream = This->stream; + + WINE_UNIX_CALL(reset, ¶ms); + + return params.result; +} + +HRESULT WINAPI client_SetEventHandle(IAudioClient3 *iface, HANDLE event) +{ + struct audio_client *This = impl_from_IAudioClient3(iface); + struct set_event_handle_params params; + + TRACE("(%p)->(%p)\n", This, event); + + if (!event) + return E_INVALIDARG; + + if (!This->stream) + return AUDCLNT_E_NOT_INITIALIZED; + + params.stream = This->stream; + params.event = event; + + WINE_UNIX_CALL(set_event_handle, ¶ms); + + return params.result; +} + +HRESULT WINAPI client_GetService(IAudioClient3 *iface, REFIID riid, void **ppv) +{ + struct audio_client *This = impl_from_IAudioClient3(iface); + + TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv); + + if (!ppv) + return E_POINTER; + + *ppv = NULL; + + sessions_lock(); + + if (!This->stream) { + sessions_unlock(); + return AUDCLNT_E_NOT_INITIALIZED; + } + + if (IsEqualIID(riid, &IID_IAudioRenderClient)) { + if (This->dataflow != eRender) { + sessions_unlock(); + return AUDCLNT_E_WRONG_ENDPOINT_TYPE; + } + *ppv = &This->IAudioRenderClient_iface; + } else if (IsEqualIID(riid, &IID_IAudioCaptureClient)) { + if (This->dataflow != eCapture) { + sessions_unlock(); + return AUDCLNT_E_WRONG_ENDPOINT_TYPE; + } + *ppv = &This->IAudioCaptureClient_iface; + } else if (IsEqualIID(riid, &IID_IAudioClock)) { + *ppv = &This->IAudioClock_iface; + } else if (IsEqualIID(riid, &IID_IAudioStreamVolume)) { + *ppv = &This->IAudioStreamVolume_iface; + } else if (IsEqualIID(riid, &IID_IAudioSessionControl) || + IsEqualIID(riid, &IID_IChannelAudioVolume) || + IsEqualIID(riid, &IID_ISimpleAudioVolume)) { + if (!This->session_wrapper) { + This->session_wrapper = session_wrapper_create(This); + if (!This->session_wrapper) { + sessions_unlock(); + return E_OUTOFMEMORY; + } + } + if (IsEqualIID(riid, &IID_IAudioSessionControl)) + *ppv = &This->session_wrapper->IAudioSessionControl2_iface; + else if (IsEqualIID(riid, &IID_IChannelAudioVolume)) + *ppv = &This->session_wrapper->IChannelAudioVolume_iface; + else if (IsEqualIID(riid, &IID_ISimpleAudioVolume)) + *ppv = &This->session_wrapper->ISimpleAudioVolume_iface; + } + + if (*ppv) { + IUnknown_AddRef((IUnknown*)*ppv); + sessions_unlock(); + return S_OK; + } + + sessions_unlock(); + + return E_NOINTERFACE; +} + HRESULT WINAPI client_IsOffloadCapable(IAudioClient3 *iface, AUDIO_STREAM_CATEGORY category, BOOL *offload_capable) { diff --git a/dlls/mmdevapi/session.c b/dlls/mmdevapi/session.c index 81cea5b3482..fa012392108 100644 --- a/dlls/mmdevapi/session.c +++ b/dlls/mmdevapi/session.c @@ -1,4 +1,9 @@ /* + * Copyright 2011-2012 Maarten Lankhorst + * Copyright 2010-2011 Maarten Lankhorst for CodeWeavers + * Copyright 2011 Andrew Eikum for CodeWeavers + * Copyright 2022 Huw Davies + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either @@ -545,3 +550,26 @@ const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl = simplevolume_SetMute, simplevolume_GetMute }; + +struct audio_session_wrapper *session_wrapper_create(struct audio_client *client) +{ + struct audio_session_wrapper *ret; + + ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct audio_session_wrapper)); + if (!ret) + return NULL; + + ret->IAudioSessionControl2_iface.lpVtbl = &AudioSessionControl2_Vtbl; + ret->IChannelAudioVolume_iface.lpVtbl = &ChannelAudioVolume_Vtbl; + ret->ISimpleAudioVolume_iface.lpVtbl = &SimpleAudioVolume_Vtbl; + + ret->ref = !client; + ret->client = client; + + if (client) { + ret->session = client->session; + IAudioClient3_AddRef(&client->IAudioClient3_iface); + } + + return ret; +} diff --git a/dlls/winepulse.drv/mmdevdrv.c b/dlls/winepulse.drv/mmdevdrv.c index def79d7f961..417d6653d30 100644 --- a/dlls/winepulse.drv/mmdevdrv.c +++ b/dlls/winepulse.drv/mmdevdrv.c @@ -274,16 +274,6 @@ static WCHAR *get_application_name(BOOL query_app_name) return wcsdup(name); }
-static DWORD WINAPI pulse_timer_cb(void *user) -{ - struct timer_loop_params params; - ACImpl *This = user; - params.stream = This->stream; - SetThreadDescription(GetCurrentThread(), L"winepulse_timer_loop"); - pulse_call(timer_loop, ¶ms); - return 0; -} - static void set_stream_volumes(ACImpl *This) { struct set_volumes_params params; @@ -926,150 +916,20 @@ static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient3 *iface, return params.result; }
-static HRESULT WINAPI AudioClient_GetDevicePeriod(IAudioClient3 *iface, - REFERENCE_TIME *defperiod, REFERENCE_TIME *minperiod) -{ - struct get_device_period_params params; - ACImpl *This = impl_from_IAudioClient3(iface); - - TRACE("(%p)->(%p, %p)\n", This, defperiod, minperiod); - - if (!defperiod && !minperiod) - return E_POINTER; - - params.flow = This->dataflow; - params.device = This->device_name; - params.def_period = defperiod; - params.min_period = minperiod; +extern HRESULT WINAPI client_GetDevicePeriod(IAudioClient3 *iface, + REFERENCE_TIME *defperiod, REFERENCE_TIME *minperiod);
- pulse_call(get_device_period, ¶ms); +extern HRESULT WINAPI client_Start(IAudioClient3 *iface);
- return params.result; -} +extern HRESULT WINAPI client_Stop(IAudioClient3 *iface);
-static HRESULT WINAPI AudioClient_Start(IAudioClient3 *iface) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - struct start_params params; - HRESULT hr; +extern HRESULT WINAPI client_Reset(IAudioClient3 *iface);
- TRACE("(%p)\n", This); +extern HRESULT WINAPI client_SetEventHandle(IAudioClient3 *iface, + HANDLE event);
- if (!This->stream) - return AUDCLNT_E_NOT_INITIALIZED; - - params.stream = This->stream; - pulse_call(start, ¶ms); - if (FAILED(hr = params.result)) - return hr; - - if (!This->timer_thread) { - This->timer_thread = CreateThread(NULL, 0, pulse_timer_cb, This, 0, NULL); - SetThreadPriority(This->timer_thread, THREAD_PRIORITY_TIME_CRITICAL); - } - - return S_OK; -} - -static HRESULT WINAPI AudioClient_Stop(IAudioClient3 *iface) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - struct stop_params params; - - TRACE("(%p)\n", This); - - if (!This->stream) - return AUDCLNT_E_NOT_INITIALIZED; - - params.stream = This->stream; - pulse_call(stop, ¶ms); - return params.result; -} - -static HRESULT WINAPI AudioClient_Reset(IAudioClient3 *iface) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - struct reset_params params; - - TRACE("(%p)\n", This); - - if (!This->stream) - return AUDCLNT_E_NOT_INITIALIZED; - - params.stream = This->stream; - pulse_call(reset, ¶ms); - return params.result; -} - -static HRESULT WINAPI AudioClient_SetEventHandle(IAudioClient3 *iface, - HANDLE event) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - struct set_event_handle_params params; - - TRACE("(%p)->(%p)\n", This, event); - - if (!event) - return E_INVALIDARG; - if (!This->stream) - return AUDCLNT_E_NOT_INITIALIZED; - - params.stream = This->stream; - params.event = event; - pulse_call(set_event_handle, ¶ms); - return params.result; -} - -static HRESULT WINAPI AudioClient_GetService(IAudioClient3 *iface, REFIID riid, - void **ppv) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - - TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv); - - if (!ppv) - return E_POINTER; - *ppv = NULL; - - if (!This->stream) - return AUDCLNT_E_NOT_INITIALIZED; - - if (IsEqualIID(riid, &IID_IAudioRenderClient)) { - if (This->dataflow != eRender) - return AUDCLNT_E_WRONG_ENDPOINT_TYPE; - *ppv = &This->IAudioRenderClient_iface; - } else if (IsEqualIID(riid, &IID_IAudioCaptureClient)) { - if (This->dataflow != eCapture) - return AUDCLNT_E_WRONG_ENDPOINT_TYPE; - *ppv = &This->IAudioCaptureClient_iface; - } else if (IsEqualIID(riid, &IID_IAudioClock)) { - *ppv = &This->IAudioClock_iface; - } else if (IsEqualIID(riid, &IID_IAudioStreamVolume)) { - *ppv = &This->IAudioStreamVolume_iface; - } else if (IsEqualIID(riid, &IID_IAudioSessionControl) || - IsEqualIID(riid, &IID_IChannelAudioVolume) || - IsEqualIID(riid, &IID_ISimpleAudioVolume)) { - if (!This->session_wrapper) { - This->session_wrapper = AudioSessionWrapper_Create(This); - if (!This->session_wrapper) - return E_OUTOFMEMORY; - } - if (IsEqualIID(riid, &IID_IAudioSessionControl)) - *ppv = &This->session_wrapper->IAudioSessionControl2_iface; - else if (IsEqualIID(riid, &IID_IChannelAudioVolume)) - *ppv = &This->session_wrapper->IChannelAudioVolume_iface; - else if (IsEqualIID(riid, &IID_ISimpleAudioVolume)) - *ppv = &This->session_wrapper->ISimpleAudioVolume_iface; - } - - if (*ppv) { - IUnknown_AddRef((IUnknown*)*ppv); - return S_OK; - } - - FIXME("stub %s\n", debugstr_guid(riid)); - return E_NOINTERFACE; -} +extern HRESULT WINAPI client_GetService(IAudioClient3 *iface, REFIID riid, + void **ppv);
extern HRESULT WINAPI client_IsOffloadCapable(IAudioClient3 *iface, AUDIO_STREAM_CATEGORY category, BOOL *offload_capable); @@ -1103,12 +963,12 @@ static const IAudioClient3Vtbl AudioClient3_Vtbl = AudioClient_GetCurrentPadding, AudioClient_IsFormatSupported, AudioClient_GetMixFormat, - AudioClient_GetDevicePeriod, - AudioClient_Start, - AudioClient_Stop, - AudioClient_Reset, - AudioClient_SetEventHandle, - AudioClient_GetService, + client_GetDevicePeriod, + client_Start, + client_Stop, + client_Reset, + client_SetEventHandle, + client_GetService, client_IsOffloadCapable, client_SetClientProperties, client_GetBufferSizeLimits,