quartz: Add support for advise functions in dsoundrender.
This commit is contained in:
parent
4bdf39ea51
commit
4881a354c2
|
@ -78,6 +78,9 @@ typedef struct DSoundRenderImpl
|
||||||
|
|
||||||
LONG volume;
|
LONG volume;
|
||||||
LONG pan;
|
LONG pan;
|
||||||
|
|
||||||
|
DWORD threadid;
|
||||||
|
HANDLE advisethread, thread_wait;
|
||||||
} DSoundRenderImpl;
|
} DSoundRenderImpl;
|
||||||
|
|
||||||
static REFERENCE_TIME time_from_pos(DSoundRenderImpl *This, DWORD pos) {
|
static REFERENCE_TIME time_from_pos(DSoundRenderImpl *This, DWORD pos) {
|
||||||
|
@ -551,13 +554,18 @@ static ULONG WINAPI DSoundRender_Release(IBaseFilter * iface)
|
||||||
{
|
{
|
||||||
IPin *pConnectedTo;
|
IPin *pConnectedTo;
|
||||||
|
|
||||||
|
if (This->threadid) {
|
||||||
|
PostThreadMessageW(This->threadid, WM_APP, 0, 0);
|
||||||
|
WaitForSingleObject(This->advisethread, INFINITE);
|
||||||
|
CloseHandle(This->advisethread);
|
||||||
|
}
|
||||||
|
|
||||||
if (This->dsbuffer)
|
if (This->dsbuffer)
|
||||||
IDirectSoundBuffer_Release(This->dsbuffer);
|
IDirectSoundBuffer_Release(This->dsbuffer);
|
||||||
This->dsbuffer = NULL;
|
This->dsbuffer = NULL;
|
||||||
if (This->dsound)
|
if (This->dsound)
|
||||||
IDirectSound_Release(This->dsound);
|
IDirectSound_Release(This->dsound);
|
||||||
This->dsound = NULL;
|
This->dsound = NULL;
|
||||||
|
|
||||||
if (SUCCEEDED(IPin_ConnectedTo((IPin *)This->pInputPin, &pConnectedTo)))
|
if (SUCCEEDED(IPin_ConnectedTo((IPin *)This->pInputPin, &pConnectedTo)))
|
||||||
{
|
{
|
||||||
IPin_Disconnect(pConnectedTo);
|
IPin_Disconnect(pConnectedTo);
|
||||||
|
@ -823,6 +831,11 @@ static HRESULT WINAPI DSoundRender_InputPin_Disconnect(IPin * iface)
|
||||||
TRACE("(%p)->()\n", iface);
|
TRACE("(%p)->()\n", iface);
|
||||||
|
|
||||||
DSImpl = (DSoundRenderImpl*)This->pinInfo.pFilter;
|
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)
|
if (DSImpl->dsbuffer)
|
||||||
IDirectSoundBuffer_Release(DSImpl->dsbuffer);
|
IDirectSoundBuffer_Release(DSImpl->dsbuffer);
|
||||||
DSImpl->dsbuffer = NULL;
|
DSImpl->dsbuffer = NULL;
|
||||||
|
@ -1093,6 +1106,95 @@ static const IBasicAudioVtbl IBasicAudio_Vtbl =
|
||||||
Basicaudio_get_Balance
|
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 ***/
|
/*** IUnknown methods ***/
|
||||||
static HRESULT WINAPI ReferenceClock_QueryInterface(IReferenceClock *iface,
|
static HRESULT WINAPI ReferenceClock_QueryInterface(IReferenceClock *iface,
|
||||||
|
@ -1144,7 +1246,7 @@ static HRESULT WINAPI ReferenceClock_GetTime(IReferenceClock *iface,
|
||||||
hr = S_OK;
|
hr = S_OK;
|
||||||
}
|
}
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
ERR("Could not get reference time (%x)!\n", hr);
|
WARN("Could not get reference time (%x)!\n", hr);
|
||||||
|
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
@ -1156,23 +1258,79 @@ static HRESULT WINAPI ReferenceClock_AdviseTime(IReferenceClock *iface,
|
||||||
DWORD_PTR *pdwAdviseCookie)
|
DWORD_PTR *pdwAdviseCookie)
|
||||||
{
|
{
|
||||||
ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
|
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,
|
static HRESULT WINAPI ReferenceClock_AdvisePeriodic(IReferenceClock *iface,
|
||||||
REFERENCE_TIME rtBaseTime,
|
REFERENCE_TIME rtStartTime,
|
||||||
REFERENCE_TIME rtStreamTime,
|
REFERENCE_TIME rtPeriodTime,
|
||||||
HSEMAPHORE hSemaphore,
|
HSEMAPHORE hSemaphore,
|
||||||
DWORD_PTR *pdwAdviseCookie)
|
DWORD_PTR *pdwAdviseCookie)
|
||||||
{
|
{
|
||||||
ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
|
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,
|
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);
|
ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
|
||||||
|
|
||||||
FIXME("(%p/%p)->(%p): stub!\n", This, iface, (void*)dwAdviseCookie);
|
TRACE("(%p/%p)->(%p)\n", This, iface, (void*)dwAdviseCookie);
|
||||||
|
if (!This->advisethread || !dwAdviseCookie)
|
||||||
return S_FALSE;
|
return S_FALSE;
|
||||||
|
PostThreadMessageW(This->threadid, WM_APP+3, dwAdviseCookie, 0);
|
||||||
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const IReferenceClockVtbl IReferenceClock_Vtbl =
|
static const IReferenceClockVtbl IReferenceClock_Vtbl =
|
||||||
|
|
Loading…
Reference in New Issue