From d5e648dc2f497a424d8cb289a7bbd7025c84d441 Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Wed, 21 Aug 2013 10:16:08 -0500 Subject: [PATCH] dsound: For capture, use MMDevAPI event API instead of timers. --- dlls/dsound/capture.c | 98 +++++++++++++++++++++++++++++++------------- dlls/dsound/dsound.c | 24 ----------- dlls/dsound/dsound_private.h | 1 - 3 files changed, 70 insertions(+), 53 deletions(-) diff --git a/dlls/dsound/capture.c b/dlls/dsound/capture.c index 63bda556b90..40f1702b646 100644 --- a/dlls/dsound/capture.c +++ b/dlls/dsound/capture.c @@ -59,6 +59,8 @@ typedef struct IDirectSoundCaptureBufferImpl /* IDirectSoundNotify fields */ DSBPOSITIONNOTIFY *notifies; int nrofnotifies; + HANDLE thread; + HANDLE sleepev; } IDirectSoundCaptureBufferImpl; /* DirectSoundCaptureDevice implementation structure */ @@ -72,7 +74,6 @@ struct DirectSoundCaptureDevice WAVEFORMATEX *pwfx; IDirectSoundCaptureBufferImpl *capture_buffer; DWORD state; - UINT timerID; CRITICAL_SECTION lock; IMMDevice *mmdevice; IAudioClient *client; @@ -80,12 +81,20 @@ struct DirectSoundCaptureDevice struct list entry; }; +static DWORD WINAPI DSOUND_capture_thread(void *user); static void capturebuffer_destroy(IDirectSoundCaptureBufferImpl *This) { if (This->device->state == STATE_CAPTURING) This->device->state = STATE_STOPPING; + if(This->thread){ + SetEvent(This->sleepev); + WaitForSingleObject(This->thread, INFINITE); + CloseHandle(This->thread); + } + CloseHandle(This->sleepev); + HeapFree(GetProcessHeap(),0, This->pdscbd); if (This->device->client) { @@ -739,8 +748,8 @@ static HRESULT IDirectSoundCaptureBufferImpl_Create( } err = IAudioClient_Initialize(device->client, - AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_NOPERSIST, - 200 * 100000, 50000, device->pwfx, NULL); + AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_NOPERSIST | AUDCLNT_STREAMFLAGS_EVENTCALLBACK, + 200 * 100000, 0, device->pwfx, NULL); if(FAILED(err)){ WARN("Initialize failed: %08x\n", err); IAudioClient_Release(device->client); @@ -753,12 +762,27 @@ static HRESULT IDirectSoundCaptureBufferImpl_Create( return err; } + This->sleepev = CreateEventW(NULL, 0, 0, NULL); + + err = IAudioClient_SetEventHandle(device->client, This->sleepev); + if(FAILED(err)){ + WARN("SetEventHandle failed: %08x\n", err); + IAudioClient_Release(device->client); + device->client = NULL; + CloseHandle(This->sleepev); + HeapFree(GetProcessHeap(), 0, This->pdscbd); + This->device->capture_buffer = 0; + HeapFree( GetProcessHeap(), 0, This ); + return err; + } + err = IAudioClient_GetService(device->client, &IID_IAudioCaptureClient, (void**)&device->capture); if(FAILED(err)){ WARN("GetService failed: %08x\n", err); IAudioClient_Release(device->client); device->client = NULL; + CloseHandle(This->sleepev); HeapFree(GetProcessHeap(), 0, This->pdscbd); This->device->capture_buffer = 0; HeapFree( GetProcessHeap(), 0, This ); @@ -776,6 +800,7 @@ static HRESULT IDirectSoundCaptureBufferImpl_Create( device->client = NULL; IAudioCaptureClient_Release(device->capture); device->capture = NULL; + CloseHandle(This->sleepev); HeapFree(GetProcessHeap(), 0, This->pdscbd); This->device->capture_buffer = 0; HeapFree( GetProcessHeap(), 0, This ); @@ -783,6 +808,7 @@ static HRESULT IDirectSoundCaptureBufferImpl_Create( } device->buffer = newbuf; device->buflen = buflen; + This->thread = CreateThread(NULL, 0, DSOUND_capture_thread, This, 0, NULL); } IDirectSoundCaptureBuffer_AddRef(&This->IDirectSoundCaptureBuffer8_iface); @@ -830,9 +856,6 @@ static ULONG DirectSoundCaptureDevice_Release( if (!ref) { TRACE("deleting object\n"); - timeKillEvent(device->timerID); - timeEndPeriod(DS_TIME_RES); - EnterCriticalSection(&DSOUND_capturers_lock); list_remove(&device->entry); LeaveCriticalSection(&DSOUND_capturers_lock); @@ -851,29 +874,19 @@ static ULONG DirectSoundCaptureDevice_Release( return ref; } -static void CALLBACK DSOUND_capture_timer(UINT timerID, UINT msg, DWORD_PTR user, - DWORD_PTR dw1, DWORD_PTR dw2) +static HRESULT DSOUND_capture_data(DirectSoundCaptureDevice *device) { - DirectSoundCaptureDevice *device = (DirectSoundCaptureDevice*)user; + HRESULT hr; UINT32 packet_frames, packet_bytes, avail_bytes, skip_bytes = 0; DWORD flags; BYTE *buf; - HRESULT hr; - - if(!device->ref) - return; - EnterCriticalSection(&device->lock); - - if(!device->capture_buffer || device->state == STATE_STOPPED){ - LeaveCriticalSection(&device->lock); - return; - } + if(!device->capture_buffer || device->state == STATE_STOPPED) + return S_FALSE; if(device->state == STATE_STOPPING){ device->state = STATE_STOPPED; - LeaveCriticalSection(&device->lock); - return; + return S_FALSE; } if(device->state == STATE_STARTING) @@ -882,9 +895,8 @@ static void CALLBACK DSOUND_capture_timer(UINT timerID, UINT msg, DWORD_PTR user hr = IAudioCaptureClient_GetBuffer(device->capture, &buf, &packet_frames, &flags, NULL, NULL); if(FAILED(hr)){ - LeaveCriticalSection(&device->lock); WARN("GetBuffer failed: %08x\n", hr); - return; + return hr; } packet_bytes = packet_frames * device->pwfx->nBlockAlign; @@ -917,12 +929,44 @@ static void CALLBACK DSOUND_capture_timer(UINT timerID, UINT msg, DWORD_PTR user hr = IAudioCaptureClient_ReleaseBuffer(device->capture, packet_frames); if(FAILED(hr)){ - LeaveCriticalSection(&device->lock); WARN("ReleaseBuffer failed: %08x\n", hr); - return; + return hr; } - LeaveCriticalSection(&device->lock); + return S_OK; +} + +static DWORD WINAPI DSOUND_capture_thread(void *user) +{ + IDirectSoundCaptureBufferImpl *buffer = user; + HRESULT hr; + DWORD ret, wait_ms; + REFERENCE_TIME period; + + hr = IAudioClient_GetDevicePeriod(buffer->device->client, &period, NULL); + if(FAILED(hr)){ + WARN("GetDevicePeriod failed: %08x\n", hr); + wait_ms = 5; + }else + wait_ms = MulDiv(5, period, 10000); + + while(buffer->ref){ + ret = WaitForSingleObject(buffer->sleepev, wait_ms); + + if(!buffer->device->ref) + break; + + if(ret == WAIT_OBJECT_0){ + EnterCriticalSection(&buffer->device->lock); + + DSOUND_capture_data(buffer->device); + + LeaveCriticalSection(&buffer->device->lock); + }else if(ret != WAIT_TIMEOUT) + WARN("WaitForSingleObject failed: %u\n", GetLastError()); + } + + return 0; } static struct _TestFormat { @@ -1020,8 +1064,6 @@ static HRESULT DirectSoundCaptureDevice_Initialize( } IAudioClient_Release(client); - device->timerID = DSOUND_create_timer(DSOUND_capture_timer, (DWORD_PTR)device); - list_add_tail(&DSOUND_capturers, &device->entry); *ppDevice = device; diff --git a/dlls/dsound/dsound.c b/dlls/dsound/dsound.c index 381d0e10538..986168ba0e9 100644 --- a/dlls/dsound/dsound.c +++ b/dlls/dsound/dsound.c @@ -735,30 +735,6 @@ BOOL DSOUND_check_supported(IAudioClient *client, DWORD rate, return hr == S_OK; } -UINT DSOUND_create_timer(LPTIMECALLBACK cb, DWORD_PTR user) -{ - UINT triggertime = DS_TIME_DEL, res = DS_TIME_RES, id; - TIMECAPS time; - - timeGetDevCaps(&time, sizeof(TIMECAPS)); - TRACE("Minimum timer resolution: %u, max timer: %u\n", time.wPeriodMin, time.wPeriodMax); - if (triggertime < time.wPeriodMin) - triggertime = time.wPeriodMin; - if (res < time.wPeriodMin) - res = time.wPeriodMin; - if (timeBeginPeriod(res) == TIMERR_NOCANDO) - WARN("Could not set minimum resolution, don't expect sound\n"); - id = timeSetEvent(triggertime, res, cb, user, TIME_PERIODIC | TIME_KILL_SYNCHRONOUS); - if (!id) - { - WARN("Timer not created! Retrying without TIME_KILL_SYNCHRONOUS\n"); - id = timeSetEvent(triggertime, res, cb, user, TIME_PERIODIC); - if (!id) - ERR("Could not create timer, sound playback will not occur\n"); - } - return id; -} - HRESULT DirectSoundDevice_Initialize(DirectSoundDevice ** ppDevice, LPCGUID lpcGUID) { HRESULT hr = DS_OK; diff --git a/dlls/dsound/dsound_private.h b/dlls/dsound/dsound_private.h index 1a3900c4870..a8f5f42a7f1 100644 --- a/dlls/dsound/dsound_private.h +++ b/dlls/dsound/dsound_private.h @@ -261,6 +261,5 @@ HRESULT get_mmdevice(EDataFlow flow, const GUID *tgt, IMMDevice **device) DECLSP BOOL DSOUND_check_supported(IAudioClient *client, DWORD rate, DWORD depth, WORD channels) DECLSPEC_HIDDEN; -UINT DSOUND_create_timer(LPTIMECALLBACK cb, DWORD_PTR user) DECLSPEC_HIDDEN; HRESULT enumerate_mmdevices(EDataFlow flow, GUID *guids, LPDSENUMCALLBACKW cb, void *user) DECLSPEC_HIDDEN; -- 2.11.4.GIT