[PATCH] quartz: Add support for advise functions in dsoundrender

Maarten Lankhorst m.b.lankhorst at gmail.com
Tue Nov 30 05:52:48 CST 2010


---
 dlls/quartz/dsoundrender.c |  182 +++++++++++++++++++++++++++++++++++++++++---
 1 files changed, 171 insertions(+), 11 deletions(-)

diff --git a/dlls/quartz/dsoundrender.c b/dlls/quartz/dsoundrender.c
index 3805ea9..fcc25e7 100644
--- a/dlls/quartz/dsoundrender.c
+++ b/dlls/quartz/dsoundrender.c
@@ -78,6 +78,9 @@ typedef struct DSoundRenderImpl
 
     LONG volume;
     LONG pan;
+
+    DWORD threadid;
+    HANDLE advisethread, thread_wait;
 } DSoundRenderImpl;
 
 static REFERENCE_TIME time_from_pos(DSoundRenderImpl *This, DWORD pos) {
@@ -551,13 +554,18 @@ static ULONG WINAPI DSoundRender_Release(IBaseFilter * iface)
     {
         IPin *pConnectedTo;
 
+        if (This->threadid) {
+            PostThreadMessageW(This->threadid, WM_APP, 0, 0);
+            WaitForSingleObject(This->advisethread, INFINITE);
+            CloseHandle(This->advisethread);
+        }
+
         if (This->dsbuffer)
             IDirectSoundBuffer_Release(This->dsbuffer);
         This->dsbuffer = NULL;
         if (This->dsound)
             IDirectSound_Release(This->dsound);
         This->dsound = NULL;
-       
         if (SUCCEEDED(IPin_ConnectedTo((IPin *)This->pInputPin, &pConnectedTo)))
         {
             IPin_Disconnect(pConnectedTo);
@@ -823,6 +831,11 @@ static HRESULT WINAPI DSoundRender_InputPin_Disconnect(IPin * iface)
     TRACE("(%p)->()\n", iface);
 
     DSImpl = (DSoundRenderImpl*)This->pinInfo.pFilter;
+    if (DSImpl->threadid) {
+        PostThreadMessageW(DSImpl->threadid, WM_APP, 0, 0);
+        WaitForSingleObject(DSImpl->advisethread, INFINITE);
+        CloseHandle(DSImpl->advisethread);
+    }
     if (DSImpl->dsbuffer)
         IDirectSoundBuffer_Release(DSImpl->dsbuffer);
     DSImpl->dsbuffer = NULL;
@@ -1093,6 +1106,95 @@ static const IBasicAudioVtbl IBasicAudio_Vtbl =
     Basicaudio_get_Balance
 };
 
+struct dsoundrender_timer {
+    struct dsoundrender_timer *next;
+    REFERENCE_TIME start;
+    REFERENCE_TIME periodicity;
+    HANDLE handle;
+    DWORD cookie;
+};
+static LONG cookie_counter = 1;
+
+static DWORD WINAPI DSoundAdviseThread(LPVOID lpParam) {
+    DSoundRenderImpl *This = lpParam;
+    struct dsoundrender_timer head = { };
+    MSG msg;
+
+    TRACE("(%p): Main Loop\n", This);
+
+    PeekMessageW(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
+    SetEvent(This->thread_wait);
+
+    while (1)
+    {
+        HRESULT hr;
+        REFERENCE_TIME curtime = 0;
+        BOOL ret;
+        struct dsoundrender_timer *prev = &head, *cur;
+
+        hr = IReferenceClock_GetTime((IReferenceClock*) &This->IReferenceClock_vtbl, &curtime);
+        if (FAILED(hr)) {
+            FIXME("Could not get time: %08x\n", hr);
+            continue;
+        }
+        TRACE("Time: %Li\n", curtime);
+        while (prev->next) {
+            cur = prev->next;
+            if (cur->start > curtime) {
+                TRACE("Skipping %p\n", cur);
+                prev = cur;
+            } else if (cur->periodicity) {
+                while (cur->start <= curtime) {
+                    cur->start += cur->periodicity;
+                    ReleaseSemaphore(cur->handle, 1, NULL);
+                }
+                prev = cur;
+            } else {
+                struct dsoundrender_timer *next = cur->next;
+                TRACE("Firing %p %Li < %Li\n", cur, cur->start, curtime);
+                SetEvent(cur->handle);
+                HeapFree(GetProcessHeap(), 0, cur);
+                prev->next = next;
+            }
+        }
+        if (!head.next)
+            ret = GetMessageW(&msg, INVALID_HANDLE_VALUE, WM_APP, WM_APP + 4);
+        else
+            ret = PeekMessageW(&msg, INVALID_HANDLE_VALUE, WM_APP, WM_APP + 4, PM_REMOVE);
+        while (ret) {
+            switch (LOWORD(msg.message) - WM_APP) {
+                case 0: TRACE("Exiting\n"); return 0;
+                case 1:
+                case 2: {
+                    struct dsoundrender_timer *t = (struct dsoundrender_timer *)msg.wParam;
+                    if (LOWORD(msg.message) - WM_APP == 1)
+                        TRACE("Adding one-shot timer %p\n", t);
+                    else
+                        TRACE("Adding periodic timer %p\n", t);
+                    t->next = head.next;
+                    head.next = t;
+                    break;
+                }
+                case 3:
+                    prev = &head;
+                    while (prev->next) {
+                        cur = prev->next;
+                        if (cur->cookie == msg.wParam) {
+                            struct dsoundrender_timer *next = cur->next;
+                            HeapFree(GetProcessHeap(), 0, cur);
+                            prev->next = next;
+                            break;
+                        }
+                        prev = cur;
+                    }
+                    break;
+            }
+            ret = PeekMessageW(&msg, INVALID_HANDLE_VALUE, WM_APP, WM_APP + 4, PM_REMOVE);
+        }
+        MsgWaitForMultipleObjects(0, NULL, 5, QS_POSTMESSAGE, 0);
+    }
+    return 0;
+}
 
 /*** IUnknown methods ***/
 static HRESULT WINAPI ReferenceClock_QueryInterface(IReferenceClock *iface,
@@ -1144,7 +1246,7 @@ static HRESULT WINAPI ReferenceClock_GetTime(IReferenceClock *iface,
         hr = S_OK;
     }
     if (FAILED(hr))
-        ERR("Could not get reference time (%x)!\n", hr);
+        WARN("Could not get reference time (%x)!\n", hr);
 
     return hr;
 }
@@ -1156,23 +1258,79 @@ static HRESULT WINAPI ReferenceClock_AdviseTime(IReferenceClock *iface,
                                                 DWORD_PTR *pdwAdviseCookie)
 {
     ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
+    REFERENCE_TIME when = rtBaseTime + rtStreamTime;
+    REFERENCE_TIME future;
+    TRACE("(%p/%p)->(%s, %s, %p, %p)\n", This, iface, wine_dbgstr_longlong(rtBaseTime), wine_dbgstr_longlong(rtStreamTime), (void*)hEvent, pdwAdviseCookie);
 
-    FIXME("(%p/%p)->(%s, %s, %p, %p): stub!\n", This, iface, wine_dbgstr_longlong(rtBaseTime), wine_dbgstr_longlong(rtStreamTime), (void*)hEvent, pdwAdviseCookie);
+    if (when <= 0)
+        return E_INVALIDARG;
 
-    return E_NOTIMPL;
+    if (!pdwAdviseCookie)
+        return E_POINTER;
+
+    EnterCriticalSection(&This->filter.csFilter);
+    future = when - This->play_time;
+    if (!This->threadid && This->dsbuffer) {
+        This->thread_wait = CreateEventW(0, 0, 0, 0);
+        This->advisethread = CreateThread(NULL, 0, DSoundAdviseThread, This, 0, &This->threadid);
+        WaitForSingleObject(This->thread_wait, INFINITE);
+        CloseHandle(This->thread_wait);
+    }
+    LeaveCriticalSection(&This->filter.csFilter);
+    /* If it's in the past or the next millisecond, trigger immediately  */
+    if (future <= 10000) {
+        SetEvent((HANDLE)hEvent);
+        *pdwAdviseCookie = 0;
+    } else {
+        struct dsoundrender_timer *t = HeapAlloc(GetProcessHeap(), 0, sizeof(*t));
+        t->next = NULL;
+        t->start = when;
+        t->periodicity = 0;
+        t->handle = (HANDLE)hEvent;
+        t->cookie = InterlockedIncrement(&cookie_counter);
+        PostThreadMessageW(This->threadid, WM_APP+1, (WPARAM)t, 0);
+        *pdwAdviseCookie = t->cookie;
+    }
+
+    return S_OK;
 }
 
 static HRESULT WINAPI ReferenceClock_AdvisePeriodic(IReferenceClock *iface,
-                                                    REFERENCE_TIME rtBaseTime,
-                                                    REFERENCE_TIME rtStreamTime,
+                                                    REFERENCE_TIME rtStartTime,
+                                                    REFERENCE_TIME rtPeriodTime,
                                                     HSEMAPHORE hSemaphore,
                                                     DWORD_PTR *pdwAdviseCookie)
 {
     ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
+    struct dsoundrender_timer *t;
 
-    FIXME("(%p/%p)->(%s, %s, %p, %p): stub!\n", This, iface, wine_dbgstr_longlong(rtBaseTime), wine_dbgstr_longlong(rtStreamTime), (void*)hSemaphore, pdwAdviseCookie);
+    TRACE("(%p/%p)->(%s, %s, %p, %p)\n", This, iface, wine_dbgstr_longlong(rtStartTime), wine_dbgstr_longlong(rtPeriodTime), (void*)hSemaphore, pdwAdviseCookie);
 
-    return E_NOTIMPL;
+    if (rtStartTime <= 0 || rtPeriodTime <= 0)
+        return E_INVALIDARG;
+
+    if (!pdwAdviseCookie)
+        return E_POINTER;
+
+    EnterCriticalSection(&This->filter.csFilter);
+    if (!This->threadid && This->dsbuffer) {
+        This->thread_wait = CreateEventW(0, 0, 0, 0);
+        This->advisethread = CreateThread(NULL, 0, DSoundAdviseThread, This, 0, &This->threadid);
+        WaitForSingleObject(This->thread_wait, INFINITE);
+        CloseHandle(This->thread_wait);
+    }
+    LeaveCriticalSection(&This->filter.csFilter);
+
+    t = HeapAlloc(GetProcessHeap(), 0, sizeof(*t));
+    t->next = NULL;
+    t->start = rtStartTime;
+    t->periodicity = rtPeriodTime;
+    t->handle = (HANDLE)hSemaphore;
+    t->cookie = InterlockedIncrement(&cookie_counter);
+    PostThreadMessageW(This->threadid, WM_APP+1, (WPARAM)t, 0);
+    *pdwAdviseCookie = t->cookie;
+
+    return S_OK;
 }
 
 static HRESULT WINAPI ReferenceClock_Unadvise(IReferenceClock *iface,
@@ -1180,9 +1338,11 @@ static HRESULT WINAPI ReferenceClock_Unadvise(IReferenceClock *iface,
 {
     ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
 
-    FIXME("(%p/%p)->(%p): stub!\n", This, iface, (void*)dwAdviseCookie);
-
-    return S_FALSE;
+    TRACE("(%p/%p)->(%p)\n", This, iface, (void*)dwAdviseCookie);
+    if (!This->advisethread || !dwAdviseCookie)
+        return S_FALSE;
+    PostThreadMessageW(This->threadid, WM_APP+3, dwAdviseCookie, 0);
+    return S_OK;
 }
 
 static const IReferenceClockVtbl IReferenceClock_Vtbl =
-- 
1.7.1




More information about the wine-patches mailing list