Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/quartz/systemclock.c | 121 +++++++++++++++++++++----------- dlls/quartz/tests/systemclock.c | 108 +++++++++++++++++++++++++++- 2 files changed, 186 insertions(+), 43 deletions(-)
diff --git a/dlls/quartz/systemclock.c b/dlls/quartz/systemclock.c index 652008cd01..77e569d437 100644 --- a/dlls/quartz/systemclock.c +++ b/dlls/quartz/systemclock.c @@ -38,7 +38,9 @@ struct advise_sink struct system_clock { IReferenceClock IReferenceClock_iface; - LONG ref; + IUnknown IUnknown_inner; + IUnknown *outer_unk; + LONG refcount;
BOOL thread_created; HANDLE thread, notify_event, stop_event; @@ -48,6 +50,72 @@ struct system_clock struct list sinks; };
+static inline struct system_clock *impl_from_IUnknown(IUnknown *iface) +{ + return CONTAINING_RECORD(iface, struct system_clock, IUnknown_inner); +} + +static HRESULT WINAPI system_clock_inner_QueryInterface(IUnknown *iface, REFIID iid, void **out) +{ + struct system_clock *clock = impl_from_IUnknown(iface); + TRACE("clock %p, iid %s, out %p.\n", clock, debugstr_guid(iid), out); + + if (IsEqualGUID(iid, &IID_IUnknown)) + *out = iface; + else if (IsEqualGUID(iid, &IID_IReferenceClock)) + *out = &clock->IReferenceClock_iface; + else + { + WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); + *out = NULL; + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown *)*out); + return S_OK; +} + +static ULONG WINAPI system_clock_inner_AddRef(IUnknown *iface) +{ + struct system_clock *clock = impl_from_IUnknown(iface); + ULONG refcount = InterlockedIncrement(&clock->refcount); + + TRACE("%p increasing refcount to %u.\n", clock, refcount); + + return refcount; +} + +static ULONG WINAPI system_clock_inner_Release(IUnknown *iface) +{ + struct system_clock *clock = impl_from_IUnknown(iface); + ULONG refcount = InterlockedDecrement(&clock->refcount); + + TRACE("%p decreasing refcount to %u.\n", clock, refcount); + + if (!refcount) + { + if (clock->thread) + { + SetEvent(clock->stop_event); + WaitForSingleObject(clock->thread, INFINITE); + CloseHandle(clock->thread); + CloseHandle(clock->notify_event); + CloseHandle(clock->stop_event); + } + clock->cs.DebugInfo->Spare[0] = 0; + DeleteCriticalSection(&clock->cs); + heap_free(clock); + } + return refcount; +} + +static const IUnknownVtbl system_clock_inner_vtbl = +{ + system_clock_inner_QueryInterface, + system_clock_inner_AddRef, + system_clock_inner_Release, +}; + static inline struct system_clock *impl_from_IReferenceClock(IReferenceClock *iface) { return CONTAINING_RECORD(iface, struct system_clock, IReferenceClock_iface); @@ -112,52 +180,19 @@ static void notify_thread(struct system_clock *clock) static HRESULT WINAPI SystemClockImpl_QueryInterface(IReferenceClock *iface, REFIID iid, void **out) { struct system_clock *clock = impl_from_IReferenceClock(iface); - TRACE("clock %p, iid %s, out %p.\n", clock, debugstr_guid(iid), out); - - if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_IReferenceClock)) - { - IReferenceClock_AddRef(iface); - *out = iface; - return S_OK; - } - - WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); - *out = NULL; - return E_NOINTERFACE; + return IUnknown_QueryInterface(clock->outer_unk, iid, out); }
static ULONG WINAPI SystemClockImpl_AddRef(IReferenceClock *iface) { struct system_clock *clock = impl_from_IReferenceClock(iface); - ULONG refcount = InterlockedIncrement(&clock->ref); - - TRACE("%p increasing refcount to %u.\n", clock, refcount); - - return refcount; + return IUnknown_AddRef(clock->outer_unk); }
static ULONG WINAPI SystemClockImpl_Release(IReferenceClock *iface) { struct system_clock *clock = impl_from_IReferenceClock(iface); - ULONG refcount = InterlockedDecrement(&clock->ref); - - TRACE("%p decreasing refcount to %u.\n", clock, refcount); - - if (!refcount) - { - if (clock->thread) - { - SetEvent(clock->stop_event); - WaitForSingleObject(clock->thread, INFINITE); - CloseHandle(clock->thread); - CloseHandle(clock->notify_event); - CloseHandle(clock->stop_event); - } - clock->cs.DebugInfo->Spare[0] = 0; - DeleteCriticalSection(&clock->cs); - heap_free(clock); - } - return refcount; + return IUnknown_Release(clock->outer_unk); }
static HRESULT WINAPI SystemClockImpl_GetTime(IReferenceClock *iface, REFERENCE_TIME *time) @@ -281,7 +316,7 @@ static HRESULT WINAPI SystemClockImpl_Unadvise(IReferenceClock *iface, DWORD_PTR return S_FALSE; }
-static const IReferenceClockVtbl SystemClock_Vtbl = +static const IReferenceClockVtbl SystemClock_vtbl = { SystemClockImpl_QueryInterface, SystemClockImpl_AddRef, @@ -304,10 +339,16 @@ HRESULT QUARTZ_CreateSystemClock(IUnknown *outer, void **out) return E_OUTOFMEMORY; }
- object->IReferenceClock_iface.lpVtbl = &SystemClock_Vtbl; + object->IReferenceClock_iface.lpVtbl = &SystemClock_vtbl; + object->IUnknown_inner.lpVtbl = &system_clock_inner_vtbl; + object->outer_unk = outer ? outer : &object->IUnknown_inner; + object->refcount = 1; list_init(&object->sinks); InitializeCriticalSection(&object->cs); object->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": SystemClockImpl.cs");
- return SystemClockImpl_QueryInterface(&object->IReferenceClock_iface, &IID_IReferenceClock, out); + TRACE("Created system clock %p.\n", object); + *out = &object->IUnknown_inner; + + return S_OK; } diff --git a/dlls/quartz/tests/systemclock.c b/dlls/quartz/tests/systemclock.c index fa1ab6856b..08faa1ef73 100644 --- a/dlls/quartz/tests/systemclock.c +++ b/dlls/quartz/tests/systemclock.c @@ -26,11 +26,18 @@ static ULONGLONG (WINAPI *pGetTickCount64)(void);
static IReferenceClock *create_system_clock(void) { - IReferenceClock *filter = NULL; + IReferenceClock *clock = NULL; HRESULT hr = CoCreateInstance(&CLSID_SystemClock, NULL, CLSCTX_INPROC_SERVER, - &IID_IReferenceClock, (void **)&filter); + &IID_IReferenceClock, (void **)&clock); ok(hr == S_OK, "Got hr %#x.\n", hr); - return filter; + return clock; +} + +static ULONG get_refcount(void *iface) +{ + IUnknown *unknown = iface; + IUnknown_AddRef(unknown); + return IUnknown_Release(unknown); }
#define check_interface(a, b, c) check_interface_(__LINE__, a, b, c) @@ -62,6 +69,100 @@ static void test_interfaces(void) ok(!ref, "Got outstanding refcount %d.\n", ref); }
+static const GUID test_iid = {0x33333333}; +static LONG outer_ref = 1; + +static HRESULT WINAPI outer_QueryInterface(IUnknown *iface, REFIID iid, void **out) +{ + if (IsEqualGUID(iid, &IID_IUnknown) + || IsEqualGUID(iid, &IID_IReferenceClock) + || IsEqualGUID(iid, &test_iid)) + { + *out = (IUnknown *)0xdeadbeef; + return S_OK; + } + ok(0, "unexpected call %s\n", wine_dbgstr_guid(iid)); + return E_NOINTERFACE; +} + +static ULONG WINAPI outer_AddRef(IUnknown *iface) +{ + return InterlockedIncrement(&outer_ref); +} + +static ULONG WINAPI outer_Release(IUnknown *iface) +{ + return InterlockedDecrement(&outer_ref); +} + +static const IUnknownVtbl outer_vtbl = +{ + outer_QueryInterface, + outer_AddRef, + outer_Release, +}; + +static IUnknown test_outer = {&outer_vtbl}; + +static void test_aggregation(void) +{ + IReferenceClock *clock, *clock2; + IUnknown *unk, *unk2; + HRESULT hr; + ULONG ref; + + clock = (IReferenceClock *)0xdeadbeef; + hr = CoCreateInstance(&CLSID_SystemClock, &test_outer, CLSCTX_INPROC_SERVER, + &IID_IReferenceClock, (void **)&clock); + ok(hr == E_NOINTERFACE, "Got hr %#x.\n", hr); + ok(!clock, "Got interface %p.\n", clock); + + hr = CoCreateInstance(&CLSID_SystemClock, &test_outer, CLSCTX_INPROC_SERVER, + &IID_IUnknown, (void **)&unk); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(outer_ref == 1, "Got unexpected refcount %d.\n", outer_ref); + ok(unk != &test_outer, "Returned IUnknown should not be outer IUnknown.\n"); + ref = get_refcount(unk); + ok(ref == 1, "Got unexpected refcount %d.\n", ref); + + ref = IUnknown_AddRef(unk); + ok(ref == 2, "Got unexpected refcount %d.\n", ref); + ok(outer_ref == 1, "Got unexpected refcount %d.\n", outer_ref); + + ref = IUnknown_Release(unk); + ok(ref == 1, "Got unexpected refcount %d.\n", ref); + ok(outer_ref == 1, "Got unexpected refcount %d.\n", outer_ref); + + hr = IUnknown_QueryInterface(unk, &IID_IUnknown, (void **)&unk2); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(unk2 == unk, "Got unexpected IUnknown %p.\n", unk2); + IUnknown_Release(unk2); + + hr = IUnknown_QueryInterface(unk, &IID_IReferenceClock, (void **)&clock); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IReferenceClock_QueryInterface(clock, &IID_IUnknown, (void **)&unk2); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(unk2 == (IUnknown *)0xdeadbeef, "Got unexpected IUnknown %p.\n", unk2); + + hr = IReferenceClock_QueryInterface(clock, &IID_IReferenceClock, (void **)&clock2); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(clock2 == (IReferenceClock *)0xdeadbeef, "Got unexpected IReferenceClock %p.\n", clock2); + + hr = IUnknown_QueryInterface(unk, &test_iid, (void **)&unk2); + ok(hr == E_NOINTERFACE, "Got hr %#x.\n", hr); + ok(!unk2, "Got unexpected IUnknown %p.\n", unk2); + + hr = IReferenceClock_QueryInterface(clock, &test_iid, (void **)&unk2); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(unk2 == (IUnknown *)0xdeadbeef, "Got unexpected IUnknown %p.\n", unk2); + + IReferenceClock_Release(clock); + ref = IUnknown_Release(unk); + ok(!ref, "Got unexpected refcount %d.\n", ref); + ok(outer_ref == 1, "Got unexpected refcount %d.\n", outer_ref); +} + static void test_get_time(void) { IReferenceClock *clock = create_system_clock(); @@ -185,6 +286,7 @@ START_TEST(systemclock) pGetTickCount64 = (void *)GetProcAddress(GetModuleHandleA("kernel32.dll"), "GetTickCount64");
test_interfaces(); + test_aggregation(); test_get_time(); test_advise();
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/quartz/dsoundrender.c | 115 +++++++++++++++++------------------ dlls/quartz/main.c | 4 +- dlls/quartz/quartz_private.h | 2 +- 3 files changed, 58 insertions(+), 63 deletions(-)
diff --git a/dlls/quartz/dsoundrender.c b/dlls/quartz/dsoundrender.c index 22be95047f..d8eccd9c54 100644 --- a/dlls/quartz/dsoundrender.c +++ b/dlls/quartz/dsoundrender.c @@ -39,10 +39,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(quartz); */ static const REFERENCE_TIME DSoundRenderer_Max_Fill = 150 * 10000;
-static const IBasicAudioVtbl IBasicAudio_Vtbl; -static const IReferenceClockVtbl IReferenceClock_Vtbl; -static const IAMDirectSoundVtbl IAMDirectSound_Vtbl; - typedef struct DSoundRenderImpl { struct strmbase_renderer renderer; @@ -561,62 +557,6 @@ static const struct strmbase_renderer_ops renderer_ops = .renderer_query_interface = dsound_render_query_interface, };
-HRESULT DSoundRender_create(IUnknown *outer, void **out) -{ - static const WCHAR sink_name[] = {'A','u','d','i','o',' ','I','n','p','u','t',' ','p','i','n',' ','(','r','e','n','d','e','r','e','d',')',0}; - - HRESULT hr; - DSoundRenderImpl * pDSoundRender; - - *out = NULL; - - pDSoundRender = CoTaskMemAlloc(sizeof(DSoundRenderImpl)); - if (!pDSoundRender) - return E_OUTOFMEMORY; - ZeroMemory(pDSoundRender, sizeof(DSoundRenderImpl)); - - hr = strmbase_renderer_init(&pDSoundRender->renderer, - outer, &CLSID_DSoundRender, sink_name, &renderer_ops); - - pDSoundRender->IBasicAudio_iface.lpVtbl = &IBasicAudio_Vtbl; - pDSoundRender->IReferenceClock_iface.lpVtbl = &IReferenceClock_Vtbl; - pDSoundRender->IAMDirectSound_iface.lpVtbl = &IAMDirectSound_Vtbl; - - if (SUCCEEDED(hr)) - { - hr = DirectSoundCreate8(NULL, &pDSoundRender->dsound, NULL); - if (FAILED(hr)) - ERR("Cannot create Direct Sound object (%x)\n", hr); - else - hr = IDirectSound8_SetCooperativeLevel(pDSoundRender->dsound, GetDesktopWindow(), DSSCL_PRIORITY); - if (SUCCEEDED(hr)) { - IDirectSoundBuffer *buf; - DSBUFFERDESC buf_desc; - memset(&buf_desc,0,sizeof(DSBUFFERDESC)); - buf_desc.dwSize = sizeof(DSBUFFERDESC); - buf_desc.dwFlags = DSBCAPS_PRIMARYBUFFER; - hr = IDirectSound8_CreateSoundBuffer(pDSoundRender->dsound, &buf_desc, &buf, NULL); - if (SUCCEEDED(hr)) { - IDirectSoundBuffer_Play(buf, 0, 0, DSBPLAY_LOOPING); - IDirectSoundBuffer_Release(buf); - } - hr = S_OK; - } - } - - if (SUCCEEDED(hr)) - { - *out = &pDSoundRender->renderer.filter.IUnknown_inner; - } - else - { - strmbase_renderer_cleanup(&pDSoundRender->renderer); - CoTaskMemFree(pDSoundRender); - } - - return hr; -} - /*** IUnknown methods ***/ static HRESULT WINAPI Basicaudio_QueryInterface(IBasicAudio *iface, REFIID riid, @@ -1142,3 +1082,58 @@ static const IAMDirectSoundVtbl IAMDirectSound_Vtbl = AMDirectSound_SetFocusWindow, AMDirectSound_GetFocusWindow }; + +HRESULT dsound_render_create(IUnknown *outer, void **out) +{ + static const DSBUFFERDESC buffer_desc = { + .dwSize = sizeof(DSBUFFERDESC), + .dwFlags = DSBCAPS_PRIMARYBUFFER, + }; + + IDirectSoundBuffer *buffer; + DSoundRenderImpl *object; + HRESULT hr; + + if (!(object = CoTaskMemAlloc(sizeof(*object)))) + return E_OUTOFMEMORY; + memset(object, 0, sizeof(*object)); + + if (FAILED(hr = strmbase_renderer_init(&object->renderer, outer, + &CLSID_DSoundRender, L"Audio Input pin (rendered)", &renderer_ops))) + { + CoTaskMemFree(object); + return hr; + } + + object->IBasicAudio_iface.lpVtbl = &IBasicAudio_Vtbl; + object->IReferenceClock_iface.lpVtbl = &IReferenceClock_Vtbl; + object->IAMDirectSound_iface.lpVtbl = &IAMDirectSound_Vtbl; + + if (FAILED(hr = DirectSoundCreate8(NULL, &object->dsound, NULL))) + { + strmbase_renderer_cleanup(&object->renderer); + CoTaskMemFree(object); + return hr; + } + + if (FAILED(hr = IDirectSound8_SetCooperativeLevel(object->dsound, + GetDesktopWindow(), DSSCL_PRIORITY))) + { + IDirectSound8_Release(object->dsound); + strmbase_renderer_cleanup(&object->renderer); + CoTaskMemFree(object); + return hr; + } + + if (SUCCEEDED(hr = IDirectSound8_CreateSoundBuffer(object->dsound, + &buffer_desc, &buffer, NULL))) + { + IDirectSoundBuffer_Play(buffer, 0, 0, DSBPLAY_LOOPING); + IDirectSoundBuffer_Release(buffer); + } + + TRACE("Created DirectSound renderer %p.\n", object); + *out = &object->renderer.filter.IUnknown_inner; + + return S_OK; +} diff --git a/dlls/quartz/main.c b/dlls/quartz/main.c index 9540fa9293..33c70d7592 100644 --- a/dlls/quartz/main.c +++ b/dlls/quartz/main.c @@ -73,8 +73,8 @@ static const struct object_creation_info object_creation[] = { &CLSID_VideoMixingRenderer, VMR7Impl_create }, { &CLSID_VideoMixingRenderer9, VMR9Impl_create }, { &CLSID_VideoRendererDefault, VideoRendererDefault_create }, - { &CLSID_DSoundRender, DSoundRender_create }, - { &CLSID_AudioRender, DSoundRender_create }, + { &CLSID_DSoundRender, dsound_render_create }, + { &CLSID_AudioRender, dsound_render_create }, { &CLSID_AVIDec, AVIDec_create }, { &CLSID_SystemClock, QUARTZ_CreateSystemClock }, { &CLSID_ACMWrapper, ACMWrapper_create }, diff --git a/dlls/quartz/quartz_private.h b/dlls/quartz/quartz_private.h index f3ba39fba9..791bec7db6 100644 --- a/dlls/quartz/quartz_private.h +++ b/dlls/quartz/quartz_private.h @@ -40,6 +40,7 @@ #define MEDIATIME_FROM_BYTES(x) ((LONGLONG)(x) * 10000000) #define BYTES_FROM_MEDIATIME(time) ((time) / 10000000)
+HRESULT dsound_render_create(IUnknown *outer, void **out) DECLSPEC_HIDDEN; HRESULT filter_graph_create(IUnknown *outer, void **out) DECLSPEC_HIDDEN; HRESULT filter_graph_no_thread_create(IUnknown *outer, void **out) DECLSPEC_HIDDEN; HRESULT FilterMapper2_create(IUnknown *pUnkOuter, LPVOID *ppObj) DECLSPEC_HIDDEN; @@ -47,7 +48,6 @@ HRESULT FilterMapper_create(IUnknown *pUnkOuter, LPVOID *ppObj) DECLSPEC_HIDDEN; HRESULT AsyncReader_create(IUnknown * pUnkOuter, LPVOID * ppv) DECLSPEC_HIDDEN; HRESULT StdMemAllocator_create(IUnknown * pUnkOuter, LPVOID * ppv) DECLSPEC_HIDDEN; HRESULT AVIDec_create(IUnknown * pUnkOuter, LPVOID * ppv) DECLSPEC_HIDDEN; -HRESULT DSoundRender_create(IUnknown * pUnkOuter, LPVOID * ppv) DECLSPEC_HIDDEN; HRESULT VideoRenderer_create(IUnknown * pUnkOuter, LPVOID * ppv) DECLSPEC_HIDDEN; HRESULT VideoRendererDefault_create(IUnknown * pUnkOuter, LPVOID * ppv) DECLSPEC_HIDDEN; HRESULT QUARTZ_CreateSystemClock(IUnknown * pUnkOuter, LPVOID * ppv) DECLSPEC_HIDDEN;
For several reasons.
Firstly, the reference clock should still function when the filter is not running.
Secondly, IDirectSoundBuffer::GetPositions() in practice returns very coarse positions, both on Windows and on Wine. On my hardware, the resolution is about 10ms, which, while suitable for the DirectSound renderer and probably also any video renderers, is nevertheless actually coarser than GetTickCount().
Thirdly, testing supports that the native DirectSound renderer returns a timestamp from IReferenceClock::GetTime() that is more accurate than IDirectSoundBuffer::GetPositions(). In fact, after dumping a large number of different clock sources, I came to the conclusion that it is probably using timeGetTime() as a source. On Wine that's identical to GetTickCount(), so we may as well just delegate directly to the system clock.
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/quartz/dsoundrender.c | 301 ++----------------------------------- 1 file changed, 14 insertions(+), 287 deletions(-)
diff --git a/dlls/quartz/dsoundrender.c b/dlls/quartz/dsoundrender.c index d8eccd9c54..02a4fb4e1b 100644 --- a/dlls/quartz/dsoundrender.c +++ b/dlls/quartz/dsoundrender.c @@ -44,8 +44,8 @@ typedef struct DSoundRenderImpl struct strmbase_renderer renderer;
IBasicAudio IBasicAudio_iface; - IReferenceClock IReferenceClock_iface; IAMDirectSound IAMDirectSound_iface; + IUnknown *system_clock;
IDirectSound8 *dsound; LPDIRECTSOUNDBUFFER dsbuffer; @@ -57,9 +57,6 @@ typedef struct DSoundRenderImpl
LONG volume; LONG pan; - - DWORD threadid; - HANDLE advisethread, thread_wait; } DSoundRenderImpl;
static inline DSoundRenderImpl *impl_from_strmbase_renderer(struct strmbase_renderer *iface) @@ -77,11 +74,6 @@ static inline DSoundRenderImpl *impl_from_IBasicAudio(IBasicAudio *iface) return CONTAINING_RECORD(iface, DSoundRenderImpl, IBasicAudio_iface); }
-static inline DSoundRenderImpl *impl_from_IReferenceClock(IReferenceClock *iface) -{ - return CONTAINING_RECORD(iface, DSoundRenderImpl, IReferenceClock_iface); -} - static inline DSoundRenderImpl *impl_from_IAMDirectSound(IAMDirectSound *iface) { return CONTAINING_RECORD(iface, DSoundRenderImpl, IAMDirectSound_iface); @@ -145,16 +137,12 @@ static HRESULT DSoundRender_GetWritePos(DSoundRenderImpl *This, DWORD *ret_write WAVEFORMATEX *wfx = (WAVEFORMATEX *)This->renderer.sink.pin.mt.pbFormat; DWORD writepos, min_writepos, playpos; REFERENCE_TIME max_lag = 50 * 10000; - REFERENCE_TIME min_lag = 25 * 10000; REFERENCE_TIME cur, writepos_t, delta_t;
DSoundRender_UpdatePositions(This, &writepos, &min_writepos); playpos = This->last_playpos; - if (This->renderer.filter.pClock == &This->IReferenceClock_iface) { - max_lag = min_lag; - cur = This->play_time + time_from_pos(This, playpos); - cur -= This->renderer.stream_start; - } else if (This->renderer.filter.pClock) { + if (This->renderer.filter.pClock) + { IReferenceClock_GetTime(This->renderer.filter.pClock, &cur); cur -= This->renderer.stream_start; } else @@ -463,13 +451,6 @@ static HRESULT WINAPI DSoundRender_BreakConnect(struct strmbase_renderer *iface)
TRACE("(%p)->()\n", iface);
- if (This->threadid) { - PostThreadMessageW(This->threadid, WM_APP, 0, 0); - LeaveCriticalSection(&This->renderer.filter.csFilter); - WaitForSingleObject(This->advisethread, INFINITE); - EnterCriticalSection(&This->renderer.filter.csFilter); - CloseHandle(This->advisethread); - } if (This->dsbuffer) IDirectSoundBuffer_Release(This->dsbuffer); This->dsbuffer = NULL; @@ -506,13 +487,6 @@ static void dsound_render_destroy(struct strmbase_renderer *iface) { DSoundRenderImpl *filter = impl_from_strmbase_renderer(iface);
- if (filter->threadid) - { - PostThreadMessageW(filter->threadid, WM_APP, 0, 0); - WaitForSingleObject(filter->advisethread, INFINITE); - CloseHandle(filter->advisethread); - } - if (filter->dsbuffer) IDirectSoundBuffer_Release(filter->dsbuffer); filter->dsbuffer = NULL; @@ -531,7 +505,7 @@ static HRESULT dsound_render_query_interface(struct strmbase_renderer *iface, RE if (IsEqualGUID(iid, &IID_IBasicAudio)) *out = &filter->IBasicAudio_iface; else if (IsEqualGUID(iid, &IID_IReferenceClock)) - *out = &filter->IReferenceClock_iface; + return IUnknown_QueryInterface(filter->system_clock, iid, out); else if (IsEqualGUID(iid, &IID_IAMDirectSound)) *out = &filter->IAMDirectSound_iface; else @@ -709,262 +683,6 @@ 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 = {NULL}; - 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(&This->IReferenceClock_iface, &curtime); - if (SUCCEEDED(hr)) { - TRACE("Time: %s\n", wine_dbgstr_longlong(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 %s < %s\n", cur, wine_dbgstr_longlong(cur->start), wine_dbgstr_longlong(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, - REFIID riid, - LPVOID*ppvObj) -{ - DSoundRenderImpl *This = impl_from_IReferenceClock(iface); - - TRACE("(%p/%p)->(%s, %p)\n", This, iface, debugstr_guid(riid), ppvObj); - - return BaseFilterImpl_QueryInterface(&This->renderer.filter.IBaseFilter_iface, riid, ppvObj); -} - -static ULONG WINAPI ReferenceClock_AddRef(IReferenceClock *iface) -{ - DSoundRenderImpl *This = impl_from_IReferenceClock(iface); - - TRACE("(%p/%p)->()\n", This, iface); - - return BaseFilterImpl_AddRef(&This->renderer.filter.IBaseFilter_iface); -} - -static ULONG WINAPI ReferenceClock_Release(IReferenceClock *iface) -{ - DSoundRenderImpl *This = impl_from_IReferenceClock(iface); - - TRACE("(%p/%p)->()\n", This, iface); - - return BaseFilterImpl_Release(&This->renderer.filter.IBaseFilter_iface); -} - -/*** IReferenceClock methods ***/ -static HRESULT WINAPI ReferenceClock_GetTime(IReferenceClock *iface, - REFERENCE_TIME *pTime) -{ - DSoundRenderImpl *This = impl_from_IReferenceClock(iface); - HRESULT hr = E_FAIL; - - TRACE("(%p/%p)->(%p)\n", This, iface, pTime); - if (!pTime) - return E_POINTER; - - if (This->dsbuffer) { - DWORD writepos1, writepos2; - EnterCriticalSection(&This->renderer.filter.csFilter); - DSoundRender_UpdatePositions(This, &writepos1, &writepos2); - if (This->renderer.sink.pin.mt.pbFormat) - { - *pTime = This->play_time + time_from_pos(This, This->last_playpos); - hr = S_OK; - } - else - { - ERR("pInputPin Disconnected\n"); - hr = E_FAIL; - } - LeaveCriticalSection(&This->renderer.filter.csFilter); - } - if (FAILED(hr)) - WARN("Could not get reference time (%x)!\n", hr); - - return hr; -} - -static HRESULT WINAPI ReferenceClock_AdviseTime(IReferenceClock *iface, - REFERENCE_TIME rtBaseTime, - REFERENCE_TIME rtStreamTime, - HEVENT hEvent, - DWORD_PTR *pdwAdviseCookie) -{ - DSoundRenderImpl *This = impl_from_IReferenceClock(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); - - if (when <= 0) - return E_INVALIDARG; - - if (!pdwAdviseCookie) - return E_POINTER; - - EnterCriticalSection(&This->renderer.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->renderer.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 rtStartTime, - REFERENCE_TIME rtPeriodTime, - HSEMAPHORE hSemaphore, - DWORD_PTR *pdwAdviseCookie) -{ - DSoundRenderImpl *This = impl_from_IReferenceClock(iface); - struct dsoundrender_timer *t; - - TRACE("(%p/%p)->(%s, %s, %p, %p)\n", This, iface, wine_dbgstr_longlong(rtStartTime), wine_dbgstr_longlong(rtPeriodTime), (void*)hSemaphore, pdwAdviseCookie); - - if (rtStartTime <= 0 || rtPeriodTime <= 0) - return E_INVALIDARG; - - if (!pdwAdviseCookie) - return E_POINTER; - - EnterCriticalSection(&This->renderer.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->renderer.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, - DWORD_PTR dwAdviseCookie) -{ - DSoundRenderImpl *This = impl_from_IReferenceClock(iface); - - 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 = -{ - ReferenceClock_QueryInterface, - ReferenceClock_AddRef, - ReferenceClock_Release, - ReferenceClock_GetTime, - ReferenceClock_AdviseTime, - ReferenceClock_AdvisePeriodic, - ReferenceClock_Unadvise -}; - /*** IUnknown methods ***/ static HRESULT WINAPI AMDirectSound_QueryInterface(IAMDirectSound *iface, REFIID riid, @@ -1105,12 +823,20 @@ HRESULT dsound_render_create(IUnknown *outer, void **out) return hr; }
+ if (FAILED(hr = QUARTZ_CreateSystemClock(&object->renderer.filter.IUnknown_inner, + (void **)&object->system_clock))) + { + strmbase_renderer_cleanup(&object->renderer); + CoTaskMemFree(object); + return hr; + } + object->IBasicAudio_iface.lpVtbl = &IBasicAudio_Vtbl; - object->IReferenceClock_iface.lpVtbl = &IReferenceClock_Vtbl; object->IAMDirectSound_iface.lpVtbl = &IAMDirectSound_Vtbl;
if (FAILED(hr = DirectSoundCreate8(NULL, &object->dsound, NULL))) { + IUnknown_Release(object->system_clock); strmbase_renderer_cleanup(&object->renderer); CoTaskMemFree(object); return hr; @@ -1120,6 +846,7 @@ HRESULT dsound_render_create(IUnknown *outer, void **out) GetDesktopWindow(), DSSCL_PRIORITY))) { IDirectSound8_Release(object->dsound); + IUnknown_Release(object->system_clock); strmbase_renderer_cleanup(&object->renderer); CoTaskMemFree(object); return hr;
This more closely resembles the threading model prescribed by the DirectX SDK documentation. In particular, the page "Flushing Data" recommends that IPin::BeginFlush() do the following steps in order:
1. take the filter lock 2. signal the streaming thread to complete 3. take the streaming lock, if necessary
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/strmbase/renderer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/dlls/strmbase/renderer.c b/dlls/strmbase/renderer.c index 0ef9c5b225..cacbb90e59 100644 --- a/dlls/strmbase/renderer.c +++ b/dlls/strmbase/renderer.c @@ -133,8 +133,8 @@ static HRESULT WINAPI BaseRenderer_InputPin_EndFlush(IPin * iface)
TRACE("iface %p.\n", iface);
- EnterCriticalSection(&pFilter->csRenderLock); EnterCriticalSection(&pFilter->filter.csFilter); + EnterCriticalSection(&pFilter->csRenderLock); pFilter->eos = FALSE; hr = BaseInputPinImpl_EndFlush(iface); if (SUCCEEDED(hr)) @@ -146,8 +146,8 @@ static HRESULT WINAPI BaseRenderer_InputPin_EndFlush(IPin * iface) if (pFilter->pFuncsTable->pfnEndFlush) hr = pFilter->pFuncsTable->pfnEndFlush(pFilter); } - LeaveCriticalSection(&pFilter->filter.csFilter); LeaveCriticalSection(&pFilter->csRenderLock); + LeaveCriticalSection(&pFilter->filter.csFilter); return hr; }