[PATCH 3/3] dsound: For capture, use MMDevAPI event API instead of timers

Andrew Eikum aeikum at codeweavers.com
Wed Aug 21 10:16:08 CDT 2013


---
 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 63bda55..40f1702 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 381d0e1..986168b 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 1a3900c..a8f5f42 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;
-- 
1.8.3.4




More information about the wine-patches mailing list