Module: wine Branch: master Commit: 357f0e9a493cd0a6a90cd89367548b57759a5297 URL: https://gitlab.winehq.org/wine/wine/-/commit/357f0e9a493cd0a6a90cd89367548b5...
Author: Davide Beatrici git@davidebeatrici.dev Date: Sat Apr 8 06:08:18 2023 +0200
winecoreaudio: Implement and call timer_loop in unixlib.
---
dlls/winecoreaudio.drv/coreaudio.c | 41 ++++++++++++++++++++++-- dlls/winecoreaudio.drv/mmdevdrv.c | 65 +++++++++++--------------------------- 2 files changed, 57 insertions(+), 49 deletions(-)
diff --git a/dlls/winecoreaudio.drv/coreaudio.c b/dlls/winecoreaudio.drv/coreaudio.c index 4191958b1ca..aef678e7ca7 100644 --- a/dlls/winecoreaudio.drv/coreaudio.c +++ b/dlls/winecoreaudio.drv/coreaudio.c @@ -87,7 +87,7 @@ struct coreaudio_stream AUDCLNT_SHAREMODE share; HANDLE event;
- BOOL playing; + BOOL playing, please_quit; REFERENCE_TIME period; UINT32 period_frames; UINT32 bufsize_frames, resamp_bufsize_frames; @@ -745,6 +745,12 @@ static NTSTATUS unix_release_stream( void *args ) struct coreaudio_stream *stream = handle_get_stream(params->stream); SIZE_T size;
+ if(params->timer_thread){ + stream->please_quit = TRUE; + NtWaitForSingleObject(params->timer_thread, FALSE, NULL); + NtClose(params->timer_thread); + } + if(stream->unit){ AudioOutputUnitStop(stream->unit); AudioComponentInstanceDispose(stream->unit); @@ -1370,6 +1376,35 @@ static NTSTATUS unix_reset(void *args) return STATUS_SUCCESS; }
+static NTSTATUS unix_timer_loop(void *args) +{ + struct timer_loop_params *params = args; + struct coreaudio_stream *stream = handle_get_stream(params->stream); + LARGE_INTEGER delay, next, last; + int adjust; + + delay.QuadPart = -stream->period; + NtQueryPerformanceCounter(&last, NULL); + next.QuadPart = last.QuadPart + stream->period; + + while(!stream->please_quit){ + NtSetEvent(stream->event, NULL); + NtDelayExecution(FALSE, &delay); + NtQueryPerformanceCounter(&last, NULL); + + adjust = next.QuadPart - last.QuadPart; + if(adjust > stream->period / 2) + adjust = stream->period / 2; + else if(adjust < -stream->period / 2) + adjust = -stream->period / 2; + + delay.QuadPart = -(stream->period + adjust); + next.QuadPart += stream->period; + } + + return STATUS_SUCCESS; +} + static NTSTATUS unix_get_render_buffer(void *args) { struct get_render_buffer_params *params = args; @@ -1688,7 +1723,7 @@ unixlib_entry_t __wine_unix_call_funcs[] = unix_start, unix_stop, unix_reset, - unix_not_implemented, + unix_timer_loop, unix_get_render_buffer, unix_release_render_buffer, unix_get_capture_buffer, @@ -2050,7 +2085,7 @@ unixlib_entry_t __wine_unix_call_wow64_funcs[] = unix_start, unix_stop, unix_reset, - unix_not_implemented, + unix_timer_loop, unix_wow64_get_render_buffer, unix_release_render_buffer, unix_wow64_get_capture_buffer, diff --git a/dlls/winecoreaudio.drv/mmdevdrv.c b/dlls/winecoreaudio.drv/mmdevdrv.c index e40b3c0f019..97492440535 100644 --- a/dlls/winecoreaudio.drv/mmdevdrv.c +++ b/dlls/winecoreaudio.drv/mmdevdrv.c @@ -91,8 +91,7 @@ struct ACImpl { IUnknown *pUnkFTMarshal;
EDataFlow dataflow; - UINT32 channel_count, period_ms; - HANDLE event; + UINT32 channel_count; float *vols;
HANDLE timer; @@ -127,8 +126,6 @@ typedef struct _SessionMgr {
static WCHAR drv_key_devicesW[256];
-static HANDLE g_timer_q; - static CRITICAL_SECTION g_sessions_lock; static CRITICAL_SECTION_DEBUG g_sessions_lock_debug = { @@ -212,15 +209,11 @@ BOOL WINAPI DllMain(HINSTANCE dll, DWORD reason, void *reserved) swprintf(drv_key_devicesW, ARRAY_SIZE(drv_key_devicesW), L"Software\Wine\Drivers\%s\devices", filename);
- g_timer_q = CreateTimerQueue(); - if(!g_timer_q) - return FALSE; break; } case DLL_PROCESS_DETACH: if (reserved) break; DeleteCriticalSection(&g_sessions_lock); - CloseHandle(g_timer_q); break; } return TRUE; @@ -516,28 +509,17 @@ static ULONG WINAPI AudioClient_AddRef(IAudioClient3 *iface) static ULONG WINAPI AudioClient_Release(IAudioClient3 *iface) { ACImpl *This = impl_from_IAudioClient3(iface); - struct release_stream_params params; ULONG ref; - ref = InterlockedDecrement(&This->ref); TRACE("(%p) Refcount now %lu\n", This, ref); if(!ref){ - if(This->timer){ - HANDLE event; - BOOL wait; - event = CreateEventW(NULL, TRUE, FALSE, NULL); - wait = !DeleteTimerQueueTimer(g_timer_q, This->timer, event); - wait = wait && GetLastError() == ERROR_IO_PENDING; - if(event && wait) - WaitForSingleObject(event, INFINITE); - CloseHandle(event); - } if(This->stream){ + struct release_stream_params params; params.stream = This->stream; - params.timer_thread = NULL; + params.timer_thread = This->timer; UNIX_CALL(release_stream, ¶ms); - } - if(This->session){ + This->stream = 0; + EnterCriticalSection(&g_sessions_lock); list_remove(&This->entry); LeaveCriticalSection(&g_sessions_lock); @@ -752,7 +734,6 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface, }
This->channel_count = fmt->nChannels; - This->period_ms = period / 10000;
This->vols = HeapAlloc(GetProcessHeap(), 0, This->channel_count * sizeof(float)); if(!This->vols){ @@ -922,18 +903,21 @@ static HRESULT WINAPI AudioClient_GetDevicePeriod(IAudioClient3 *iface, return S_OK; }
-void CALLBACK ca_period_cb(void *user, BOOLEAN timer) +static DWORD WINAPI ca_timer_thread(void *user) { + struct timer_loop_params params; ACImpl *This = user; - - if(This->event) - SetEvent(This->event); + params.stream = This->stream; + SetThreadDescription(GetCurrentThread(), L"winecoreaudio_timer_loop"); + UNIX_CALL(timer_loop, ¶ms); + return 0; }
static HRESULT WINAPI AudioClient_Start(IAudioClient3 *iface) { ACImpl *This = impl_from_IAudioClient3(iface); struct start_params params; + HRESULT hr;
TRACE("(%p)\n", This);
@@ -942,19 +926,15 @@ static HRESULT WINAPI AudioClient_Start(IAudioClient3 *iface)
params.stream = This->stream; UNIX_CALL(start, ¶ms); + if(FAILED(hr = params.result)) + return hr;
- if(SUCCEEDED(params.result)){ - if(This->event && !This->timer){ - if(!CreateTimerQueueTimer(&This->timer, g_timer_q, ca_period_cb, This, 0, - This->period_ms, WT_EXECUTEINTIMERTHREAD)){ - This->timer = NULL; - IAudioClient3_Stop(iface); - WARN("Unable to create timer: %lu\n", GetLastError()); - return E_OUTOFMEMORY; - } - } + if(!This->timer) { + This->timer = CreateThread(NULL, 0, ca_timer_thread, This, 0, NULL); + SetThreadPriority(This->timer, THREAD_PRIORITY_TIME_CRITICAL); } - return params.result; + + return S_OK; }
static HRESULT WINAPI AudioClient_Stop(IAudioClient3 *iface) @@ -1004,13 +984,6 @@ static HRESULT WINAPI AudioClient_SetEventHandle(IAudioClient3 *iface, params.stream = This->stream; params.event = event; UNIX_CALL(set_event_handle, ¶ms); - - if(SUCCEEDED(params.result)){ - EnterCriticalSection(&g_sessions_lock); - This->event = event; - LeaveCriticalSection(&g_sessions_lock); - } - return params.result; }