2 * Direct Sound Audio Renderer
4 * Copyright 2004 Christian Costa
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include "quartz_private.h"
24 #include "control_private.h"
37 #include "wine/unicode.h"
38 #include "wine/debug.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(quartz
);
42 /* NOTE: buffer can still be filled completely,
43 * but we start waiting until only this amount is buffered
45 static const REFERENCE_TIME DSoundRenderer_Max_Fill
= 150 * 10000;
47 static const WCHAR wcsInputPinName
[] = {'i','n','p','u','t',' ','p','i','n',0};
49 static const IBaseFilterVtbl DSoundRender_Vtbl
;
50 static const IPinVtbl DSoundRender_InputPin_Vtbl
;
51 static const IBasicAudioVtbl IBasicAudio_Vtbl
;
52 static const IReferenceClockVtbl IReferenceClock_Vtbl
;
53 static const IMediaSeekingVtbl IMediaSeeking_Vtbl
;
54 static const IAMDirectSoundVtbl IAMDirectSound_Vtbl
;
55 static const IAMFilterMiscFlagsVtbl IAMFilterMiscFlags_Vtbl
;
56 static const IQualityControlVtbl DSoundRender_QualityControl_Vtbl
= {
57 QualityControlImpl_QueryInterface
,
58 QualityControlImpl_AddRef
,
59 QualityControlImpl_Release
,
60 QualityControlImpl_Notify
,
61 QualityControlImpl_SetSink
64 typedef struct DSoundRenderImpl
68 const IBasicAudioVtbl
*IBasicAudio_vtbl
;
69 const IReferenceClockVtbl
*IReferenceClock_vtbl
;
70 const IAMDirectSoundVtbl
*IAMDirectSound_vtbl
;
71 const IAMFilterMiscFlagsVtbl
*IAMFilterMiscFlags_vtbl
;
72 IUnknown
*seekthru_unk
;
74 BaseInputPin
* pInputPin
;
75 QualityControlImpl qcimpl
;
77 IDirectSound8
*dsound
;
78 LPDIRECTSOUNDBUFFER dsbuffer
;
81 DWORD last_playpos
, writepos
;
83 REFERENCE_TIME play_time
;
85 HANDLE state_change
, blocked
;
91 HANDLE advisethread
, thread_wait
;
94 static REFERENCE_TIME
time_from_pos(DSoundRenderImpl
*This
, DWORD pos
) {
95 WAVEFORMATEX
*wfx
= (WAVEFORMATEX
*)This
->pInputPin
->pin
.mtCurrent
.pbFormat
;
96 REFERENCE_TIME ret
= 10000000;
97 ret
= ret
* pos
/ wfx
->nAvgBytesPerSec
;
101 static DWORD
pos_from_time(DSoundRenderImpl
*This
, REFERENCE_TIME time
) {
102 WAVEFORMATEX
*wfx
= (WAVEFORMATEX
*)This
->pInputPin
->pin
.mtCurrent
.pbFormat
;
103 REFERENCE_TIME ret
= time
;
104 ret
*= wfx
->nSamplesPerSec
;
106 ret
*= wfx
->nBlockAlign
;
110 static void DSoundRender_UpdatePositions(DSoundRenderImpl
*This
, DWORD
*seqwritepos
, DWORD
*minwritepos
) {
111 WAVEFORMATEX
*wfx
= (WAVEFORMATEX
*)This
->pInputPin
->pin
.mtCurrent
.pbFormat
;
113 DWORD size1
, size2
, playpos
, writepos
, old_writepos
, old_playpos
, adv
;
114 BOOL writepos_set
= This
->writepos
< This
->buf_size
;
116 /* Update position and zero */
117 old_writepos
= This
->writepos
;
118 old_playpos
= This
->last_playpos
;
119 if (old_writepos
<= old_playpos
)
120 old_writepos
+= This
->buf_size
;
122 IDirectSoundBuffer_GetCurrentPosition(This
->dsbuffer
, &playpos
, &writepos
);
123 if (old_playpos
> playpos
) {
124 adv
= This
->buf_size
+ playpos
- old_playpos
;
125 This
->play_time
+= time_from_pos(This
, This
->buf_size
);
127 adv
= playpos
- old_playpos
;
128 This
->last_playpos
= playpos
;
130 TRACE("Moving from %u to %u: clearing %u bytes\n", old_playpos
, playpos
, adv
);
131 IDirectSoundBuffer_Lock(This
->dsbuffer
, old_playpos
, adv
, (void**)&buf1
, &size1
, (void**)&buf2
, &size2
, 0);
132 memset(buf1
, wfx
->wBitsPerSample
== 8 ? 128 : 0, size1
);
133 memset(buf2
, wfx
->wBitsPerSample
== 8 ? 128 : 0, size2
);
134 IDirectSoundBuffer_Unlock(This
->dsbuffer
, buf1
, size1
, buf2
, size2
);
136 *minwritepos
= writepos
;
137 if (!writepos_set
|| old_writepos
< writepos
) {
139 This
->writepos
= This
->buf_size
;
140 FIXME("Underrun of data occurred!\n");
142 *seqwritepos
= writepos
;
144 *seqwritepos
= This
->writepos
;
147 static HRESULT
DSoundRender_GetWritePos(DSoundRenderImpl
*This
, DWORD
*ret_writepos
, REFERENCE_TIME write_at
, DWORD
*pfree
, DWORD
*skip
)
149 WAVEFORMATEX
*wfx
= (WAVEFORMATEX
*)This
->pInputPin
->pin
.mtCurrent
.pbFormat
;
150 DWORD writepos
, min_writepos
, playpos
;
151 REFERENCE_TIME max_lag
= 50 * 10000;
152 REFERENCE_TIME min_lag
= 25 * 10000;
153 REFERENCE_TIME cur
, writepos_t
, delta_t
;
155 DSoundRender_UpdatePositions(This
, &writepos
, &min_writepos
);
156 playpos
= This
->last_playpos
;
157 if (This
->filter
.pClock
== (IReferenceClock
*)&This
->IReferenceClock_vtbl
) {
159 cur
= This
->play_time
+ time_from_pos(This
, playpos
);
160 cur
-= This
->filter
.rtStreamStart
;
161 } else if (This
->filter
.pClock
) {
162 IReferenceClock_GetTime(This
->filter
.pClock
, &cur
);
163 cur
-= This
->filter
.rtStreamStart
;
167 if (writepos
== min_writepos
)
172 *ret_writepos
= writepos
;
176 if (writepos
>= playpos
)
177 writepos_t
= cur
+ time_from_pos(This
, writepos
- playpos
);
179 writepos_t
= cur
+ time_from_pos(This
, This
->buf_size
+ writepos
- playpos
);
181 /* write_at: Starting time of sample */
182 /* cur: current time of play position */
183 /* writepos_t: current time of our pointer play position */
184 delta_t
= write_at
- writepos_t
;
185 if (delta_t
>= -max_lag
&& delta_t
<= max_lag
) {
186 TRACE("Continuing from old position\n");
187 *ret_writepos
= writepos
;
188 } else if (delta_t
< 0) {
189 REFERENCE_TIME past
, min_writepos_t
;
190 WARN("Delta too big %i/%i, overwriting old data or even skipping\n", (int)delta_t
/ 10000, (int)max_lag
/ 10000);
191 if (min_writepos
>= playpos
)
192 min_writepos_t
= cur
+ time_from_pos(This
, min_writepos
- playpos
);
194 min_writepos_t
= cur
+ time_from_pos(This
, This
->buf_size
- playpos
+ min_writepos
);
195 past
= min_writepos_t
- write_at
;
197 DWORD skipbytes
= pos_from_time(This
, past
);
198 WARN("Skipping %u bytes\n", skipbytes
);
200 *ret_writepos
= min_writepos
;
202 DWORD aheadbytes
= pos_from_time(This
, -past
);
203 WARN("Advancing %u bytes\n", aheadbytes
);
204 *ret_writepos
= (min_writepos
+ aheadbytes
) % This
->buf_size
;
206 } else /* delta_t > 0 */ {
208 WARN("Delta too big %i/%i, too far ahead\n", (int)delta_t
/ 10000, (int)max_lag
/ 10000);
209 aheadbytes
= pos_from_time(This
, delta_t
);
210 WARN("Advancing %u bytes\n", aheadbytes
);
211 if (delta_t
>= DSoundRenderer_Max_Fill
)
213 *ret_writepos
= (min_writepos
+ aheadbytes
) % This
->buf_size
;
216 if (playpos
> *ret_writepos
)
217 *pfree
= playpos
- *ret_writepos
;
218 else if (playpos
== *ret_writepos
)
219 *pfree
= This
->buf_size
- wfx
->nBlockAlign
;
221 *pfree
= This
->buf_size
+ playpos
- *ret_writepos
;
222 if (time_from_pos(This
, This
->buf_size
- *pfree
) >= DSoundRenderer_Max_Fill
) {
223 TRACE("Blocked: too full %i / %i\n", (int)(time_from_pos(This
, This
->buf_size
- *pfree
)/10000), (int)(DSoundRenderer_Max_Fill
/ 10000));
229 static HRESULT
DSoundRender_HandleEndOfStream(DSoundRenderImpl
*This
)
232 IMediaEventSink
*pEventSink
;
237 DSoundRender_UpdatePositions(This
, &pos1
, &pos2
);
242 LeaveCriticalSection(&This
->filter
.csFilter
);
243 WaitForSingleObject(This
->blocked
, 10);
244 EnterCriticalSection(&This
->filter
.csFilter
);
246 if (This
->pInputPin
->flushing
||
247 This
->filter
.state
!= State_Running
) {
248 SetEvent(This
->state_change
);
253 if (!This
->filter
.filterInfo
.pGraph
)
256 hr
= IFilterGraph_QueryInterface(This
->filter
.filterInfo
.pGraph
, &IID_IMediaEventSink
, (LPVOID
*)&pEventSink
);
259 hr
= IMediaEventSink_Notify(pEventSink
, EC_COMPLETE
, S_OK
, (LONG_PTR
)This
);
260 IMediaEventSink_Release(pEventSink
);
265 static HRESULT
DSoundRender_SendSampleData(DSoundRenderImpl
* This
, REFERENCE_TIME tStart
, REFERENCE_TIME tStop
, const BYTE
*data
, DWORD size
)
269 while (size
&& This
->filter
.state
!= State_Stopped
) {
270 DWORD writepos
, skip
= 0, free
, size1
, size2
, ret
;
273 if (This
->filter
.state
== State_Running
)
274 hr
= DSoundRender_GetWritePos(This
, &writepos
, tStart
, &free
, &skip
);
280 LeaveCriticalSection(&This
->filter
.csFilter
);
281 ret
= WaitForSingleObject(This
->blocked
, 10);
282 EnterCriticalSection(&This
->filter
.csFilter
);
284 if (This
->pInputPin
->flushing
||
285 This
->filter
.state
== State_Stopped
) {
286 SetEvent(This
->state_change
);
287 return This
->filter
.state
== State_Paused
? S_OK
: VFW_E_WRONG_STATE
;
289 if (ret
!= WAIT_TIMEOUT
)
296 FIXME("Sample dropped %u of %u bytes\n", skip
, size
);
302 hr
= IDirectSoundBuffer_Lock(This
->dsbuffer
, writepos
, min(free
, size
), (void**)&buf1
, &size1
, (void**)&buf2
, &size2
, 0);
304 ERR("Unable to lock sound buffer! (%x)\n", hr
);
307 memcpy(buf1
, data
, size1
);
309 memcpy(buf2
, data
+size1
, size2
);
310 IDirectSoundBuffer_Unlock(This
->dsbuffer
, buf1
, size1
, buf2
, size2
);
311 This
->writepos
= (writepos
+ size1
+ size2
) % This
->buf_size
;
312 TRACE("Wrote %u bytes at %u, next at %u - (%u/%u)\n", size1
+size2
, writepos
, This
->writepos
, free
, size
);
313 data
+= size1
+ size2
;
314 size
-= size1
+ size2
;
319 static HRESULT WINAPI
DSoundRender_Receive(BaseInputPin
*pin
, IMediaSample
* pSample
)
321 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)pin
->pin
.pinInfo
.pFilter
;
322 LPBYTE pbSrcStream
= NULL
;
323 LONG cbSrcStream
= 0;
324 REFERENCE_TIME tStart
, tStop
;
328 TRACE("%p %p\n", pin
, pSample
);
330 /* Slightly incorrect, Pause completes when a frame is received so we should signal
331 * pause completion here, but for sound playing a single frame doesn't make sense
334 EnterCriticalSection(&This
->filter
.csFilter
);
336 if (This
->pInputPin
->end_of_stream
|| This
->pInputPin
->flushing
)
338 LeaveCriticalSection(&This
->filter
.csFilter
);
342 if (This
->filter
.state
== State_Stopped
)
344 LeaveCriticalSection(&This
->filter
.csFilter
);
345 return VFW_E_WRONG_STATE
;
348 if (IMediaSample_GetMediaType(pSample
, &amt
) == S_OK
)
350 AM_MEDIA_TYPE
*orig
= &This
->pInputPin
->pin
.mtCurrent
;
351 WAVEFORMATEX
*origfmt
= (WAVEFORMATEX
*)orig
->pbFormat
;
352 WAVEFORMATEX
*newfmt
= (WAVEFORMATEX
*)amt
->pbFormat
;
354 if (origfmt
->wFormatTag
== newfmt
->wFormatTag
&&
355 origfmt
->nChannels
== newfmt
->nChannels
&&
356 origfmt
->nBlockAlign
== newfmt
->nBlockAlign
&&
357 origfmt
->wBitsPerSample
== newfmt
->wBitsPerSample
&&
358 origfmt
->cbSize
== newfmt
->cbSize
)
360 if (origfmt
->nSamplesPerSec
!= newfmt
->nSamplesPerSec
)
362 hr
= IDirectSoundBuffer_SetFrequency(This
->dsbuffer
,
363 newfmt
->nSamplesPerSec
);
366 LeaveCriticalSection(&This
->filter
.csFilter
);
367 return VFW_E_TYPE_NOT_ACCEPTED
;
370 CopyMediaType(orig
, amt
);
371 IMediaSample_SetMediaType(pSample
, NULL
);
376 LeaveCriticalSection(&This
->filter
.csFilter
);
377 return VFW_E_TYPE_NOT_ACCEPTED
;
381 hr
= IMediaSample_GetPointer(pSample
, &pbSrcStream
);
384 ERR("Cannot get pointer to sample data (%x)\n", hr
);
385 LeaveCriticalSection(&This
->filter
.csFilter
);
389 if (IMediaSample_GetMediaTime(pSample
, &tStart
, &tStop
) == S_OK
)
390 MediaSeekingPassThru_RegisterMediaTime(This
->seekthru_unk
, tStart
);
391 hr
= IMediaSample_GetTime(pSample
, &tStart
, &tStop
);
393 ERR("Cannot get sample time (%x)\n", hr
);
397 IMediaSample_IsDiscontinuity(pSample
);
399 if (IMediaSample_IsPreroll(pSample
) == S_OK
)
402 LeaveCriticalSection(&This
->filter
.csFilter
);
406 cbSrcStream
= IMediaSample_GetActualDataLength(pSample
);
407 TRACE("Sample data ptr = %p, size = %d\n", pbSrcStream
, cbSrcStream
);
409 SetEvent(This
->state_change
);
410 hr
= DSoundRender_SendSampleData(This
, tStart
, tStop
, pbSrcStream
, cbSrcStream
);
411 if (This
->filter
.state
== State_Running
&& This
->filter
.pClock
&& tStart
>= 0) {
412 REFERENCE_TIME jitter
, now
= 0;
414 IReferenceClock_GetTime(This
->filter
.pClock
, &now
);
415 jitter
= now
- This
->filter
.rtStreamStart
- tStart
;
416 if (jitter
<= -DSoundRenderer_Max_Fill
)
417 jitter
+= DSoundRenderer_Max_Fill
;
420 q
.Type
= (jitter
> 0 ? Famine
: Flood
);
423 q
.TimeStamp
= tStart
;
424 IQualityControl_Notify((IQualityControl
*)&This
->qcimpl
, (IBaseFilter
*)This
, q
);
426 LeaveCriticalSection(&This
->filter
.csFilter
);
430 static HRESULT WINAPI
DSoundRender_CheckMediaType(BasePin
*iface
, const AM_MEDIA_TYPE
* pmt
)
432 WAVEFORMATEX
* format
;
434 if (!IsEqualIID(&pmt
->majortype
, &MEDIATYPE_Audio
))
437 format
= (WAVEFORMATEX
*)pmt
->pbFormat
;
438 TRACE("Format = %p\n", format
);
439 TRACE("wFormatTag = %x %x\n", format
->wFormatTag
, WAVE_FORMAT_PCM
);
440 TRACE("nChannels = %d\n", format
->nChannels
);
441 TRACE("nSamplesPerSec = %d\n", format
->nAvgBytesPerSec
);
442 TRACE("nAvgBytesPerSec = %d\n", format
->nAvgBytesPerSec
);
443 TRACE("nBlockAlign = %d\n", format
->nBlockAlign
);
444 TRACE("wBitsPerSample = %d\n", format
->wBitsPerSample
);
446 if (!IsEqualIID(&pmt
->subtype
, &MEDIASUBTYPE_PCM
))
452 static IPin
* WINAPI
DSoundRender_GetPin(BaseFilter
*iface
, int pos
)
454 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
456 if (pos
>= 1 || pos
< 0)
459 IPin_AddRef((IPin
*)This
->pInputPin
);
460 return (IPin
*)This
->pInputPin
;
463 static LONG WINAPI
DSoundRender_GetPinCount(BaseFilter
*iface
)
465 /* Our pins are static */
469 static const BaseFilterFuncTable BaseFuncTable
= {
471 DSoundRender_GetPinCount
474 static const BasePinFuncTable input_BaseFuncTable
= {
475 DSoundRender_CheckMediaType
,
477 BasePinImpl_GetMediaTypeVersion
,
478 BasePinImpl_GetMediaType
481 static const BaseInputPinFuncTable input_BaseInputFuncTable
= {
486 HRESULT
DSoundRender_create(IUnknown
* pUnkOuter
, LPVOID
* ppv
)
490 DSoundRenderImpl
* pDSoundRender
;
492 TRACE("(%p, %p)\n", pUnkOuter
, ppv
);
497 return CLASS_E_NOAGGREGATION
;
499 pDSoundRender
= CoTaskMemAlloc(sizeof(DSoundRenderImpl
));
501 return E_OUTOFMEMORY
;
502 ZeroMemory(pDSoundRender
, sizeof(DSoundRenderImpl
));
504 BaseFilter_Init(&pDSoundRender
->filter
, &DSoundRender_Vtbl
, &CLSID_DSoundRender
, (DWORD_PTR
)(__FILE__
": DSoundRenderImpl.csFilter"), &BaseFuncTable
);
506 pDSoundRender
->IBasicAudio_vtbl
= &IBasicAudio_Vtbl
;
507 pDSoundRender
->IReferenceClock_vtbl
= &IReferenceClock_Vtbl
;
508 pDSoundRender
->IAMDirectSound_vtbl
= &IAMDirectSound_Vtbl
;
509 pDSoundRender
->IAMFilterMiscFlags_vtbl
= &IAMFilterMiscFlags_Vtbl
;
511 /* construct input pin */
512 piInput
.dir
= PINDIR_INPUT
;
513 piInput
.pFilter
= (IBaseFilter
*)pDSoundRender
;
514 lstrcpynW(piInput
.achName
, wcsInputPinName
, sizeof(piInput
.achName
) / sizeof(piInput
.achName
[0]));
515 hr
= BaseInputPin_Construct(&DSoundRender_InputPin_Vtbl
, &piInput
, &input_BaseFuncTable
, &input_BaseInputFuncTable
, &pDSoundRender
->filter
.csFilter
, NULL
, (IPin
**)&pDSoundRender
->pInputPin
);
519 hr
= DirectSoundCreate8(NULL
, &pDSoundRender
->dsound
, NULL
);
521 ERR("Cannot create Direct Sound object (%x)\n", hr
);
523 hr
= IDirectSound_SetCooperativeLevel(pDSoundRender
->dsound
, GetDesktopWindow(), DSSCL_PRIORITY
);
525 IDirectSoundBuffer
*buf
;
526 DSBUFFERDESC buf_desc
;
527 memset(&buf_desc
,0,sizeof(DSBUFFERDESC
));
528 buf_desc
.dwSize
= sizeof(DSBUFFERDESC
);
529 buf_desc
.dwFlags
= DSBCAPS_PRIMARYBUFFER
;
530 hr
= IDirectSound_CreateSoundBuffer(pDSoundRender
->dsound
, &buf_desc
, &buf
, NULL
);
532 IDirectSoundBuffer_Play(buf
, 0, 0, DSBPLAY_LOOPING
);
533 IUnknown_Release(buf
);
541 ISeekingPassThru
*passthru
;
542 pDSoundRender
->state_change
= CreateEventW(NULL
, TRUE
, TRUE
, NULL
);
543 pDSoundRender
->blocked
= CreateEventW(NULL
, TRUE
, TRUE
, NULL
);
544 hr
= CoCreateInstance(&CLSID_SeekingPassThru
, (IUnknown
*)pDSoundRender
, CLSCTX_INPROC_SERVER
, &IID_IUnknown
, (void**)&pDSoundRender
->seekthru_unk
);
545 if (!pDSoundRender
->state_change
|| !pDSoundRender
->blocked
|| FAILED(hr
))
547 IUnknown_Release((IUnknown
*)pDSoundRender
);
548 return HRESULT_FROM_WIN32(GetLastError());
551 IUnknown_QueryInterface(pDSoundRender
->seekthru_unk
, &IID_ISeekingPassThru
, (void**)&passthru
);
552 ISeekingPassThru_Init(passthru
, TRUE
, (IPin
*)pDSoundRender
->pInputPin
);
553 ISeekingPassThru_Release(passthru
);
554 QualityControlImpl_init(&pDSoundRender
->qcimpl
, (IPin
*)pDSoundRender
->pInputPin
, (IBaseFilter
*)pDSoundRender
);
555 pDSoundRender
->qcimpl
.lpVtbl
= &DSoundRender_QualityControl_Vtbl
;
556 *ppv
= pDSoundRender
;
560 if (pDSoundRender
->pInputPin
)
561 IPin_Release((IPin
*)pDSoundRender
->pInputPin
);
562 BaseFilterImpl_Release((IBaseFilter
*)pDSoundRender
);
563 CoTaskMemFree(pDSoundRender
);
569 static HRESULT WINAPI
DSoundRender_QueryInterface(IBaseFilter
* iface
, REFIID riid
, LPVOID
* ppv
)
571 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
572 TRACE("(%p, %p)->(%s, %p)\n", This
, iface
, qzdebugstr_guid(riid
), ppv
);
576 if (IsEqualIID(riid
, &IID_IUnknown
))
578 else if (IsEqualIID(riid
, &IID_IPersist
))
580 else if (IsEqualIID(riid
, &IID_IMediaFilter
))
582 else if (IsEqualIID(riid
, &IID_IBaseFilter
))
584 else if (IsEqualIID(riid
, &IID_IBasicAudio
))
585 *ppv
= &This
->IBasicAudio_vtbl
;
586 else if (IsEqualIID(riid
, &IID_IReferenceClock
))
587 *ppv
= &This
->IReferenceClock_vtbl
;
588 else if (IsEqualIID(riid
, &IID_IMediaSeeking
))
589 return IUnknown_QueryInterface(This
->seekthru_unk
, riid
, ppv
);
590 else if (IsEqualIID(riid
, &IID_IAMDirectSound
))
591 *ppv
= &This
->IAMDirectSound_vtbl
;
592 else if (IsEqualIID(riid
, &IID_IAMFilterMiscFlags
))
593 *ppv
= &This
->IAMFilterMiscFlags_vtbl
;
594 else if (IsEqualIID(riid
, &IID_IQualityControl
))
595 *ppv
= &This
->qcimpl
;
599 IUnknown_AddRef((IUnknown
*)(*ppv
));
603 if (!IsEqualIID(riid
, &IID_IPin
) && !IsEqualIID(riid
, &IID_IVideoWindow
))
604 FIXME("No interface for %s!\n", qzdebugstr_guid(riid
));
606 return E_NOINTERFACE
;
609 static ULONG WINAPI
DSoundRender_Release(IBaseFilter
* iface
)
611 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
612 ULONG refCount
= BaseFilterImpl_Release(iface
);
614 TRACE("(%p)->() Release from %d\n", This
, refCount
+ 1);
620 if (This
->threadid
) {
621 PostThreadMessageW(This
->threadid
, WM_APP
, 0, 0);
622 WaitForSingleObject(This
->advisethread
, INFINITE
);
623 CloseHandle(This
->advisethread
);
627 IDirectSoundBuffer_Release(This
->dsbuffer
);
628 This
->dsbuffer
= NULL
;
630 IDirectSound_Release(This
->dsound
);
632 if (SUCCEEDED(IPin_ConnectedTo((IPin
*)This
->pInputPin
, &pConnectedTo
)))
634 IPin_Disconnect(pConnectedTo
);
635 IPin_Release(pConnectedTo
);
637 IPin_Disconnect((IPin
*)This
->pInputPin
);
639 IPin_Release((IPin
*)This
->pInputPin
);
641 This
->IBasicAudio_vtbl
= NULL
;
642 if (This
->seekthru_unk
)
643 IUnknown_Release(This
->seekthru_unk
);
645 CloseHandle(This
->state_change
);
646 CloseHandle(This
->blocked
);
648 TRACE("Destroying Audio Renderer\n");
657 /** IMediaFilter methods **/
659 static HRESULT WINAPI
DSoundRender_Stop(IBaseFilter
* iface
)
662 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
664 TRACE("(%p/%p)->()\n", This
, iface
);
666 EnterCriticalSection(&This
->filter
.csFilter
);
668 hr
= IDirectSoundBuffer_Stop(This
->dsbuffer
);
670 This
->filter
.state
= State_Stopped
;
672 /* Complete our transition */
673 This
->writepos
= This
->buf_size
;
674 SetEvent(This
->state_change
);
675 SetEvent(This
->blocked
);
676 MediaSeekingPassThru_ResetMediaTime(This
->seekthru_unk
);
678 LeaveCriticalSection(&This
->filter
.csFilter
);
683 static HRESULT WINAPI
DSoundRender_Pause(IBaseFilter
* iface
)
686 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
688 TRACE("(%p/%p)->()\n", This
, iface
);
690 EnterCriticalSection(&This
->filter
.csFilter
);
691 if (This
->filter
.state
!= State_Paused
)
693 if (This
->filter
.state
== State_Stopped
)
695 This
->pInputPin
->end_of_stream
= 0;
696 ResetEvent(This
->state_change
);
699 hr
= IDirectSoundBuffer_Stop(This
->dsbuffer
);
701 This
->filter
.state
= State_Paused
;
703 ResetEvent(This
->blocked
);
705 LeaveCriticalSection(&This
->filter
.csFilter
);
710 static HRESULT WINAPI
DSoundRender_Run(IBaseFilter
* iface
, REFERENCE_TIME tStart
)
713 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
715 TRACE("(%p/%p)->(%s)\n", This
, iface
, wine_dbgstr_longlong(tStart
));
717 EnterCriticalSection(&This
->filter
.csFilter
);
718 if (This
->pInputPin
->pin
.pConnectedTo
)
720 This
->filter
.rtStreamStart
= tStart
;
721 QualityControlRender_Start(&This
->qcimpl
, tStart
);
722 if (This
->filter
.state
== State_Paused
)
724 /* Unblock our thread, state changing from paused to running doesn't need a reset for state change */
725 SetEvent(This
->blocked
);
727 else if (This
->filter
.state
== State_Stopped
)
729 ResetEvent(This
->state_change
);
730 This
->pInputPin
->end_of_stream
= 0;
732 IDirectSoundBuffer_Play(This
->dsbuffer
, 0, 0, DSBPLAY_LOOPING
);
733 ResetEvent(This
->blocked
);
734 } else if (This
->filter
.filterInfo
.pGraph
) {
735 IMediaEventSink
*pEventSink
;
736 hr
= IFilterGraph_QueryInterface(This
->filter
.filterInfo
.pGraph
, &IID_IMediaEventSink
, (LPVOID
*)&pEventSink
);
739 hr
= IMediaEventSink_Notify(pEventSink
, EC_COMPLETE
, S_OK
, (LONG_PTR
)This
);
740 IMediaEventSink_Release(pEventSink
);
745 This
->filter
.state
= State_Running
;
746 LeaveCriticalSection(&This
->filter
.csFilter
);
751 static HRESULT WINAPI
DSoundRender_GetState(IBaseFilter
* iface
, DWORD dwMilliSecsTimeout
, FILTER_STATE
*pState
)
754 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
756 TRACE("(%p/%p)->(%d, %p)\n", This
, iface
, dwMilliSecsTimeout
, pState
);
758 if (WaitForSingleObject(This
->state_change
, dwMilliSecsTimeout
) == WAIT_TIMEOUT
)
759 hr
= VFW_S_STATE_INTERMEDIATE
;
763 BaseFilterImpl_GetState(iface
, dwMilliSecsTimeout
, pState
);
768 /** IBaseFilter implementation **/
770 static HRESULT WINAPI
DSoundRender_FindPin(IBaseFilter
* iface
, LPCWSTR Id
, IPin
**ppPin
)
772 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
774 TRACE("(%p/%p)->(%s,%p)\n", This
, iface
, debugstr_w(Id
), ppPin
);
776 FIXME("DSoundRender::FindPin(...)\n");
778 /* FIXME: critical section */
783 static const IBaseFilterVtbl DSoundRender_Vtbl
=
785 DSoundRender_QueryInterface
,
786 BaseFilterImpl_AddRef
,
787 DSoundRender_Release
,
788 BaseFilterImpl_GetClassID
,
792 DSoundRender_GetState
,
793 BaseFilterImpl_SetSyncSource
,
794 BaseFilterImpl_GetSyncSource
,
795 BaseFilterImpl_EnumPins
,
796 DSoundRender_FindPin
,
797 BaseFilterImpl_QueryFilterInfo
,
798 BaseFilterImpl_JoinFilterGraph
,
799 BaseFilterImpl_QueryVendorInfo
802 static HRESULT WINAPI
DSoundRender_InputPin_ReceiveConnection(IPin
* iface
, IPin
* pReceivePin
, const AM_MEDIA_TYPE
* pmt
)
804 BaseInputPin
*This
= (BaseInputPin
*)iface
;
805 PIN_DIRECTION pindirReceive
;
806 DSoundRenderImpl
*DSImpl
;
809 TRACE("(%p)->(%p, %p)\n", This
, pReceivePin
, pmt
);
810 dump_AM_MEDIA_TYPE(pmt
);
812 EnterCriticalSection(This
->pin
.pCritSec
);
814 DSImpl
= (DSoundRenderImpl
*)This
->pin
.pinInfo
.pFilter
;
816 if (This
->pin
.pConnectedTo
)
817 hr
= VFW_E_ALREADY_CONNECTED
;
819 if (SUCCEEDED(hr
) && This
->pin
.pFuncsTable
->pfnCheckMediaType((BasePin
*)This
, pmt
) != S_OK
)
820 hr
= VFW_E_TYPE_NOT_ACCEPTED
;
824 IPin_QueryDirection(pReceivePin
, &pindirReceive
);
826 if (pindirReceive
!= PINDIR_OUTPUT
)
828 ERR("Can't connect from non-output pin\n");
829 hr
= VFW_E_INVALID_DIRECTION
;
835 WAVEFORMATEX
*format
;
836 DSBUFFERDESC buf_desc
;
838 TRACE("MajorType %s\n", debugstr_guid(&pmt
->majortype
));
839 TRACE("SubType %s\n", debugstr_guid(&pmt
->subtype
));
840 TRACE("Format %s\n", debugstr_guid(&pmt
->formattype
));
841 TRACE("Size %d\n", pmt
->cbFormat
);
843 format
= (WAVEFORMATEX
*)pmt
->pbFormat
;
845 DSImpl
->buf_size
= format
->nAvgBytesPerSec
;
847 memset(&buf_desc
,0,sizeof(DSBUFFERDESC
));
848 buf_desc
.dwSize
= sizeof(DSBUFFERDESC
);
849 buf_desc
.dwFlags
= DSBCAPS_CTRLVOLUME
| DSBCAPS_CTRLPAN
|
850 DSBCAPS_CTRLFREQUENCY
| DSBCAPS_GLOBALFOCUS
|
851 DSBCAPS_GETCURRENTPOSITION2
;
852 buf_desc
.dwBufferBytes
= DSImpl
->buf_size
;
853 buf_desc
.lpwfxFormat
= format
;
854 hr
= IDirectSound_CreateSoundBuffer(DSImpl
->dsound
, &buf_desc
, &DSImpl
->dsbuffer
, NULL
);
855 DSImpl
->writepos
= DSImpl
->buf_size
;
857 ERR("Can't create sound buffer (%x)\n", hr
);
862 hr
= IDirectSoundBuffer_SetVolume(DSImpl
->dsbuffer
, DSImpl
->volume
);
864 ERR("Can't set volume to %d (%x)\n", DSImpl
->volume
, hr
);
866 hr
= IDirectSoundBuffer_SetPan(DSImpl
->dsbuffer
, DSImpl
->pan
);
868 ERR("Can't set pan to %d (%x)\n", DSImpl
->pan
, hr
);
874 CopyMediaType(&This
->pin
.mtCurrent
, pmt
);
875 This
->pin
.pConnectedTo
= pReceivePin
;
876 IPin_AddRef(pReceivePin
);
878 else if (hr
!= VFW_E_ALREADY_CONNECTED
)
880 if (DSImpl
->dsbuffer
)
881 IDirectSoundBuffer_Release(DSImpl
->dsbuffer
);
882 DSImpl
->dsbuffer
= NULL
;
885 LeaveCriticalSection(This
->pin
.pCritSec
);
890 static HRESULT WINAPI
DSoundRender_InputPin_Disconnect(IPin
* iface
)
892 BasePin
*This
= (BasePin
*)iface
;
893 DSoundRenderImpl
*DSImpl
;
895 TRACE("(%p)->()\n", iface
);
897 DSImpl
= (DSoundRenderImpl
*)This
->pinInfo
.pFilter
;
898 if (DSImpl
->threadid
) {
899 PostThreadMessageW(DSImpl
->threadid
, WM_APP
, 0, 0);
900 WaitForSingleObject(DSImpl
->advisethread
, INFINITE
);
901 CloseHandle(DSImpl
->advisethread
);
903 if (DSImpl
->dsbuffer
)
904 IDirectSoundBuffer_Release(DSImpl
->dsbuffer
);
905 DSImpl
->dsbuffer
= NULL
;
907 return BasePinImpl_Disconnect(iface
);
910 static HRESULT WINAPI
DSoundRender_InputPin_EndOfStream(IPin
* iface
)
912 BaseInputPin
* This
= (BaseInputPin
*)iface
;
913 DSoundRenderImpl
*me
= (DSoundRenderImpl
*)This
->pin
.pinInfo
.pFilter
;
916 EnterCriticalSection(This
->pin
.pCritSec
);
918 TRACE("(%p/%p)->()\n", This
, iface
);
919 hr
= BaseInputPinImpl_EndOfStream(iface
);
923 LeaveCriticalSection(This
->pin
.pCritSec
);
927 hr
= DSoundRender_HandleEndOfStream(me
);
928 MediaSeekingPassThru_EOS(me
->seekthru_unk
);
929 SetEvent(me
->state_change
);
930 LeaveCriticalSection(This
->pin
.pCritSec
);
935 static HRESULT WINAPI
DSoundRender_InputPin_BeginFlush(IPin
* iface
)
937 BaseInputPin
*This
= (BaseInputPin
*)iface
;
938 DSoundRenderImpl
*pFilter
= (DSoundRenderImpl
*)This
->pin
.pinInfo
.pFilter
;
943 EnterCriticalSection(This
->pin
.pCritSec
);
944 hr
= BaseInputPinImpl_BeginFlush(iface
);
945 SetEvent(pFilter
->blocked
);
946 LeaveCriticalSection(This
->pin
.pCritSec
);
951 static HRESULT WINAPI
DSoundRender_InputPin_EndFlush(IPin
* iface
)
953 BaseInputPin
*This
= (BaseInputPin
*)iface
;
954 DSoundRenderImpl
*pFilter
= (DSoundRenderImpl
*)This
->pin
.pinInfo
.pFilter
;
959 EnterCriticalSection(This
->pin
.pCritSec
);
960 if (pFilter
->in_loop
) {
961 ResetEvent(pFilter
->state_change
);
962 LeaveCriticalSection(This
->pin
.pCritSec
);
963 WaitForSingleObject(pFilter
->state_change
, -1);
964 EnterCriticalSection(This
->pin
.pCritSec
);
966 if (pFilter
->filter
.state
!= State_Stopped
)
967 ResetEvent(pFilter
->blocked
);
969 if (pFilter
->dsbuffer
)
975 IDirectSoundBuffer_Lock(pFilter
->dsbuffer
, 0, 0, (LPVOID
*)&buffer
, &size
, NULL
, NULL
, DSBLOCK_ENTIREBUFFER
);
976 memset(buffer
, 0, size
);
977 IDirectSoundBuffer_Unlock(pFilter
->dsbuffer
, buffer
, size
, NULL
, 0);
978 pFilter
->writepos
= pFilter
->buf_size
;
980 QualityControlRender_Start(&pFilter
->qcimpl
, pFilter
->filter
.rtStreamStart
);
981 hr
= BaseInputPinImpl_EndFlush(iface
);
982 LeaveCriticalSection(This
->pin
.pCritSec
);
983 MediaSeekingPassThru_ResetMediaTime(pFilter
->seekthru_unk
);
988 static const IPinVtbl DSoundRender_InputPin_Vtbl
=
990 BaseInputPinImpl_QueryInterface
,
992 BaseInputPinImpl_Release
,
993 BaseInputPinImpl_Connect
,
994 DSoundRender_InputPin_ReceiveConnection
,
995 DSoundRender_InputPin_Disconnect
,
996 BasePinImpl_ConnectedTo
,
997 BasePinImpl_ConnectionMediaType
,
998 BasePinImpl_QueryPinInfo
,
999 BasePinImpl_QueryDirection
,
1000 BasePinImpl_QueryId
,
1001 BaseInputPinImpl_QueryAccept
,
1002 BasePinImpl_EnumMediaTypes
,
1003 BasePinImpl_QueryInternalConnections
,
1004 DSoundRender_InputPin_EndOfStream
,
1005 DSoundRender_InputPin_BeginFlush
,
1006 DSoundRender_InputPin_EndFlush
,
1007 BaseInputPinImpl_NewSegment
1010 /*** IUnknown methods ***/
1011 static HRESULT WINAPI
Basicaudio_QueryInterface(IBasicAudio
*iface
,
1014 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
1016 TRACE("(%p/%p)->(%s (%p), %p)\n", This
, iface
, debugstr_guid(riid
), riid
, ppvObj
);
1018 return DSoundRender_QueryInterface((IBaseFilter
*)This
, riid
, ppvObj
);
1021 static ULONG WINAPI
Basicaudio_AddRef(IBasicAudio
*iface
) {
1022 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
1024 TRACE("(%p/%p)->()\n", This
, iface
);
1026 return BaseFilterImpl_AddRef((IBaseFilter
*)This
);
1029 static ULONG WINAPI
Basicaudio_Release(IBasicAudio
*iface
) {
1030 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
1032 TRACE("(%p/%p)->()\n", This
, iface
);
1034 return DSoundRender_Release((IBaseFilter
*)This
);
1037 /*** IDispatch methods ***/
1038 static HRESULT WINAPI
Basicaudio_GetTypeInfoCount(IBasicAudio
*iface
,
1040 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
1042 TRACE("(%p/%p)->(%p): stub !!!\n", This
, iface
, pctinfo
);
1047 static HRESULT WINAPI
Basicaudio_GetTypeInfo(IBasicAudio
*iface
,
1050 ITypeInfo
**ppTInfo
) {
1051 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
1053 TRACE("(%p/%p)->(%d, %d, %p): stub !!!\n", This
, iface
, iTInfo
, lcid
, ppTInfo
);
1058 static HRESULT WINAPI
Basicaudio_GetIDsOfNames(IBasicAudio
*iface
,
1064 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
1066 TRACE("(%p/%p)->(%s (%p), %p, %d, %d, %p): stub !!!\n", This
, iface
, debugstr_guid(riid
), riid
, rgszNames
, cNames
, lcid
, rgDispId
);
1071 static HRESULT WINAPI
Basicaudio_Invoke(IBasicAudio
*iface
,
1072 DISPID dispIdMember
,
1076 DISPPARAMS
*pDispParams
,
1078 EXCEPINFO
*pExepInfo
,
1080 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
1082 TRACE("(%p/%p)->(%d, %s (%p), %d, %04x, %p, %p, %p, %p): stub !!!\n", This
, iface
, dispIdMember
, debugstr_guid(riid
), riid
, lcid
, wFlags
, pDispParams
, pVarResult
, pExepInfo
, puArgErr
);
1087 /*** IBasicAudio methods ***/
1088 static HRESULT WINAPI
Basicaudio_put_Volume(IBasicAudio
*iface
,
1090 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
1092 TRACE("(%p/%p)->(%d)\n", This
, iface
, lVolume
);
1094 if (lVolume
> DSBVOLUME_MAX
|| lVolume
< DSBVOLUME_MIN
)
1095 return E_INVALIDARG
;
1097 if (This
->dsbuffer
) {
1098 if (FAILED(IDirectSoundBuffer_SetVolume(This
->dsbuffer
, lVolume
)))
1102 This
->volume
= lVolume
;
1106 static HRESULT WINAPI
Basicaudio_get_Volume(IBasicAudio
*iface
,
1108 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
1110 TRACE("(%p/%p)->(%p)\n", This
, iface
, plVolume
);
1115 *plVolume
= This
->volume
;
1119 static HRESULT WINAPI
Basicaudio_put_Balance(IBasicAudio
*iface
,
1121 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
1123 TRACE("(%p/%p)->(%d)\n", This
, iface
, lBalance
);
1125 if (lBalance
< DSBPAN_LEFT
|| lBalance
> DSBPAN_RIGHT
)
1126 return E_INVALIDARG
;
1128 if (This
->dsbuffer
) {
1129 if (FAILED(IDirectSoundBuffer_SetPan(This
->dsbuffer
, lBalance
)))
1133 This
->pan
= lBalance
;
1137 static HRESULT WINAPI
Basicaudio_get_Balance(IBasicAudio
*iface
,
1139 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
1141 TRACE("(%p/%p)->(%p)\n", This
, iface
, plBalance
);
1146 *plBalance
= This
->pan
;
1150 static const IBasicAudioVtbl IBasicAudio_Vtbl
=
1152 Basicaudio_QueryInterface
,
1155 Basicaudio_GetTypeInfoCount
,
1156 Basicaudio_GetTypeInfo
,
1157 Basicaudio_GetIDsOfNames
,
1159 Basicaudio_put_Volume
,
1160 Basicaudio_get_Volume
,
1161 Basicaudio_put_Balance
,
1162 Basicaudio_get_Balance
1165 struct dsoundrender_timer
{
1166 struct dsoundrender_timer
*next
;
1167 REFERENCE_TIME start
;
1168 REFERENCE_TIME periodicity
;
1172 static LONG cookie_counter
= 1;
1174 static DWORD WINAPI
DSoundAdviseThread(LPVOID lpParam
) {
1175 DSoundRenderImpl
*This
= lpParam
;
1176 struct dsoundrender_timer head
= { };
1179 TRACE("(%p): Main Loop\n", This
);
1181 PeekMessageW(&msg
, NULL
, WM_USER
, WM_USER
, PM_NOREMOVE
);
1182 SetEvent(This
->thread_wait
);
1187 REFERENCE_TIME curtime
= 0;
1189 struct dsoundrender_timer
*prev
= &head
, *cur
;
1191 hr
= IReferenceClock_GetTime((IReferenceClock
*) &This
->IReferenceClock_vtbl
, &curtime
);
1193 FIXME("Could not get time: %08x\n", hr
);
1196 TRACE("Time: %s\n", wine_dbgstr_longlong(curtime
));
1197 while (prev
->next
) {
1199 if (cur
->start
> curtime
) {
1200 TRACE("Skipping %p\n", cur
);
1202 } else if (cur
->periodicity
) {
1203 while (cur
->start
<= curtime
) {
1204 cur
->start
+= cur
->periodicity
;
1205 ReleaseSemaphore(cur
->handle
, 1, NULL
);
1209 struct dsoundrender_timer
*next
= cur
->next
;
1210 TRACE("Firing %p %s < %s\n", cur
, wine_dbgstr_longlong(cur
->start
), wine_dbgstr_longlong(curtime
));
1211 SetEvent(cur
->handle
);
1212 HeapFree(GetProcessHeap(), 0, cur
);
1217 ret
= GetMessageW(&msg
, INVALID_HANDLE_VALUE
, WM_APP
, WM_APP
+ 4);
1219 ret
= PeekMessageW(&msg
, INVALID_HANDLE_VALUE
, WM_APP
, WM_APP
+ 4, PM_REMOVE
);
1221 switch (LOWORD(msg
.message
) - WM_APP
) {
1222 case 0: TRACE("Exiting\n"); return 0;
1225 struct dsoundrender_timer
*t
= (struct dsoundrender_timer
*)msg
.wParam
;
1226 if (LOWORD(msg
.message
) - WM_APP
== 1)
1227 TRACE("Adding one-shot timer %p\n", t
);
1229 TRACE("Adding periodic timer %p\n", t
);
1230 t
->next
= head
.next
;
1236 while (prev
->next
) {
1238 if (cur
->cookie
== msg
.wParam
) {
1239 struct dsoundrender_timer
*next
= cur
->next
;
1240 HeapFree(GetProcessHeap(), 0, cur
);
1248 ret
= PeekMessageW(&msg
, INVALID_HANDLE_VALUE
, WM_APP
, WM_APP
+ 4, PM_REMOVE
);
1250 MsgWaitForMultipleObjects(0, NULL
, 5, QS_POSTMESSAGE
, 0);
1255 /*** IUnknown methods ***/
1256 static HRESULT WINAPI
ReferenceClock_QueryInterface(IReferenceClock
*iface
,
1260 ICOM_THIS_MULTI(DSoundRenderImpl
, IReferenceClock_vtbl
, iface
);
1262 TRACE("(%p/%p)->(%s (%p), %p)\n", This
, iface
, debugstr_guid(riid
), riid
, ppvObj
);
1264 return DSoundRender_QueryInterface((IBaseFilter
*)This
, riid
, ppvObj
);
1267 static ULONG WINAPI
ReferenceClock_AddRef(IReferenceClock
*iface
)
1269 ICOM_THIS_MULTI(DSoundRenderImpl
, IReferenceClock_vtbl
, iface
);
1271 TRACE("(%p/%p)->()\n", This
, iface
);
1273 return BaseFilterImpl_AddRef((IBaseFilter
*)This
);
1276 static ULONG WINAPI
ReferenceClock_Release(IReferenceClock
*iface
)
1278 ICOM_THIS_MULTI(DSoundRenderImpl
, IReferenceClock_vtbl
, iface
);
1280 TRACE("(%p/%p)->()\n", This
, iface
);
1282 return DSoundRender_Release((IBaseFilter
*)This
);
1285 /*** IReferenceClock methods ***/
1286 static HRESULT WINAPI
ReferenceClock_GetTime(IReferenceClock
*iface
,
1287 REFERENCE_TIME
*pTime
)
1289 ICOM_THIS_MULTI(DSoundRenderImpl
, IReferenceClock_vtbl
, iface
);
1290 HRESULT hr
= E_FAIL
;
1292 TRACE("(%p/%p)->(%p)\n", This
, iface
, pTime
);
1296 if (This
->dsbuffer
) {
1297 DWORD writepos1
, writepos2
;
1298 EnterCriticalSection(&This
->filter
.csFilter
);
1299 DSoundRender_UpdatePositions(This
, &writepos1
, &writepos2
);
1300 *pTime
= This
->play_time
+ time_from_pos(This
, This
->last_playpos
);
1301 LeaveCriticalSection(&This
->filter
.csFilter
);
1305 WARN("Could not get reference time (%x)!\n", hr
);
1310 static HRESULT WINAPI
ReferenceClock_AdviseTime(IReferenceClock
*iface
,
1311 REFERENCE_TIME rtBaseTime
,
1312 REFERENCE_TIME rtStreamTime
,
1314 DWORD_PTR
*pdwAdviseCookie
)
1316 ICOM_THIS_MULTI(DSoundRenderImpl
, IReferenceClock_vtbl
, iface
);
1317 REFERENCE_TIME when
= rtBaseTime
+ rtStreamTime
;
1318 REFERENCE_TIME future
;
1319 TRACE("(%p/%p)->(%s, %s, %p, %p)\n", This
, iface
, wine_dbgstr_longlong(rtBaseTime
), wine_dbgstr_longlong(rtStreamTime
), (void*)hEvent
, pdwAdviseCookie
);
1322 return E_INVALIDARG
;
1324 if (!pdwAdviseCookie
)
1327 EnterCriticalSection(&This
->filter
.csFilter
);
1328 future
= when
- This
->play_time
;
1329 if (!This
->threadid
&& This
->dsbuffer
) {
1330 This
->thread_wait
= CreateEventW(0, 0, 0, 0);
1331 This
->advisethread
= CreateThread(NULL
, 0, DSoundAdviseThread
, This
, 0, &This
->threadid
);
1332 WaitForSingleObject(This
->thread_wait
, INFINITE
);
1333 CloseHandle(This
->thread_wait
);
1335 LeaveCriticalSection(&This
->filter
.csFilter
);
1336 /* If it's in the past or the next millisecond, trigger immediately */
1337 if (future
<= 10000) {
1338 SetEvent((HANDLE
)hEvent
);
1339 *pdwAdviseCookie
= 0;
1341 struct dsoundrender_timer
*t
= HeapAlloc(GetProcessHeap(), 0, sizeof(*t
));
1345 t
->handle
= (HANDLE
)hEvent
;
1346 t
->cookie
= InterlockedIncrement(&cookie_counter
);
1347 PostThreadMessageW(This
->threadid
, WM_APP
+1, (WPARAM
)t
, 0);
1348 *pdwAdviseCookie
= t
->cookie
;
1354 static HRESULT WINAPI
ReferenceClock_AdvisePeriodic(IReferenceClock
*iface
,
1355 REFERENCE_TIME rtStartTime
,
1356 REFERENCE_TIME rtPeriodTime
,
1357 HSEMAPHORE hSemaphore
,
1358 DWORD_PTR
*pdwAdviseCookie
)
1360 ICOM_THIS_MULTI(DSoundRenderImpl
, IReferenceClock_vtbl
, iface
);
1361 struct dsoundrender_timer
*t
;
1363 TRACE("(%p/%p)->(%s, %s, %p, %p)\n", This
, iface
, wine_dbgstr_longlong(rtStartTime
), wine_dbgstr_longlong(rtPeriodTime
), (void*)hSemaphore
, pdwAdviseCookie
);
1365 if (rtStartTime
<= 0 || rtPeriodTime
<= 0)
1366 return E_INVALIDARG
;
1368 if (!pdwAdviseCookie
)
1371 EnterCriticalSection(&This
->filter
.csFilter
);
1372 if (!This
->threadid
&& This
->dsbuffer
) {
1373 This
->thread_wait
= CreateEventW(0, 0, 0, 0);
1374 This
->advisethread
= CreateThread(NULL
, 0, DSoundAdviseThread
, This
, 0, &This
->threadid
);
1375 WaitForSingleObject(This
->thread_wait
, INFINITE
);
1376 CloseHandle(This
->thread_wait
);
1378 LeaveCriticalSection(&This
->filter
.csFilter
);
1380 t
= HeapAlloc(GetProcessHeap(), 0, sizeof(*t
));
1382 t
->start
= rtStartTime
;
1383 t
->periodicity
= rtPeriodTime
;
1384 t
->handle
= (HANDLE
)hSemaphore
;
1385 t
->cookie
= InterlockedIncrement(&cookie_counter
);
1386 PostThreadMessageW(This
->threadid
, WM_APP
+1, (WPARAM
)t
, 0);
1387 *pdwAdviseCookie
= t
->cookie
;
1392 static HRESULT WINAPI
ReferenceClock_Unadvise(IReferenceClock
*iface
,
1393 DWORD_PTR dwAdviseCookie
)
1395 ICOM_THIS_MULTI(DSoundRenderImpl
, IReferenceClock_vtbl
, iface
);
1397 TRACE("(%p/%p)->(%p)\n", This
, iface
, (void*)dwAdviseCookie
);
1398 if (!This
->advisethread
|| !dwAdviseCookie
)
1400 PostThreadMessageW(This
->threadid
, WM_APP
+3, dwAdviseCookie
, 0);
1404 static const IReferenceClockVtbl IReferenceClock_Vtbl
=
1406 ReferenceClock_QueryInterface
,
1407 ReferenceClock_AddRef
,
1408 ReferenceClock_Release
,
1409 ReferenceClock_GetTime
,
1410 ReferenceClock_AdviseTime
,
1411 ReferenceClock_AdvisePeriodic
,
1412 ReferenceClock_Unadvise
1415 /*** IUnknown methods ***/
1416 static HRESULT WINAPI
AMDirectSound_QueryInterface(IAMDirectSound
*iface
,
1420 ICOM_THIS_MULTI(DSoundRenderImpl
, IAMDirectSound_vtbl
, iface
);
1422 TRACE("(%p/%p)->(%s (%p), %p)\n", This
, iface
, debugstr_guid(riid
), riid
, ppvObj
);
1424 return DSoundRender_QueryInterface((IBaseFilter
*)This
, riid
, ppvObj
);
1427 static ULONG WINAPI
AMDirectSound_AddRef(IAMDirectSound
*iface
)
1429 ICOM_THIS_MULTI(DSoundRenderImpl
, IAMDirectSound_vtbl
, iface
);
1431 TRACE("(%p/%p)->()\n", This
, iface
);
1433 return BaseFilterImpl_AddRef((IBaseFilter
*)This
);
1436 static ULONG WINAPI
AMDirectSound_Release(IAMDirectSound
*iface
)
1438 ICOM_THIS_MULTI(DSoundRenderImpl
, IAMDirectSound_vtbl
, iface
);
1440 TRACE("(%p/%p)->()\n", This
, iface
);
1442 return DSoundRender_Release((IBaseFilter
*)This
);
1445 /*** IAMDirectSound methods ***/
1446 static HRESULT WINAPI
AMDirectSound_GetDirectSoundInterface(IAMDirectSound
*iface
, IDirectSound
**ds
)
1448 ICOM_THIS_MULTI(DSoundRenderImpl
, IAMDirectSound_vtbl
, iface
);
1450 FIXME("(%p/%p)->(%p): stub\n", This
, iface
, ds
);
1455 static HRESULT WINAPI
AMDirectSound_GetPrimaryBufferInterface(IAMDirectSound
*iface
, IDirectSoundBuffer
**buf
)
1457 ICOM_THIS_MULTI(DSoundRenderImpl
, IAMDirectSound_vtbl
, iface
);
1459 FIXME("(%p/%p)->(%p): stub\n", This
, iface
, buf
);
1464 static HRESULT WINAPI
AMDirectSound_GetSecondaryBufferInterface(IAMDirectSound
*iface
, IDirectSoundBuffer
**buf
)
1466 ICOM_THIS_MULTI(DSoundRenderImpl
, IAMDirectSound_vtbl
, iface
);
1468 FIXME("(%p/%p)->(%p): stub\n", This
, iface
, buf
);
1473 static HRESULT WINAPI
AMDirectSound_ReleaseDirectSoundInterface(IAMDirectSound
*iface
, IDirectSound
*ds
)
1475 ICOM_THIS_MULTI(DSoundRenderImpl
, IAMDirectSound_vtbl
, iface
);
1477 FIXME("(%p/%p)->(%p): stub\n", This
, iface
, ds
);
1482 static HRESULT WINAPI
AMDirectSound_ReleasePrimaryBufferInterface(IAMDirectSound
*iface
, IDirectSoundBuffer
*buf
)
1484 ICOM_THIS_MULTI(DSoundRenderImpl
, IAMDirectSound_vtbl
, iface
);
1486 FIXME("(%p/%p)->(%p): stub\n", This
, iface
, buf
);
1491 static HRESULT WINAPI
AMDirectSound_ReleaseSecondaryBufferInterface(IAMDirectSound
*iface
, IDirectSoundBuffer
*buf
)
1493 ICOM_THIS_MULTI(DSoundRenderImpl
, IAMDirectSound_vtbl
, iface
);
1495 FIXME("(%p/%p)->(%p): stub\n", This
, iface
, buf
);
1500 static HRESULT WINAPI
AMDirectSound_SetFocusWindow(IAMDirectSound
*iface
, HWND hwnd
, BOOL bgsilent
)
1502 ICOM_THIS_MULTI(DSoundRenderImpl
, IAMDirectSound_vtbl
, iface
);
1504 FIXME("(%p/%p)->(%p,%d): stub\n", This
, iface
, hwnd
, bgsilent
);
1509 static HRESULT WINAPI
AMDirectSound_GetFocusWindow(IAMDirectSound
*iface
, HWND hwnd
)
1511 ICOM_THIS_MULTI(DSoundRenderImpl
, IAMDirectSound_vtbl
, iface
);
1513 FIXME("(%p/%p)->(%p): stub\n", This
, iface
, hwnd
);
1518 static const IAMDirectSoundVtbl IAMDirectSound_Vtbl
=
1520 AMDirectSound_QueryInterface
,
1521 AMDirectSound_AddRef
,
1522 AMDirectSound_Release
,
1523 AMDirectSound_GetDirectSoundInterface
,
1524 AMDirectSound_GetPrimaryBufferInterface
,
1525 AMDirectSound_GetSecondaryBufferInterface
,
1526 AMDirectSound_ReleaseDirectSoundInterface
,
1527 AMDirectSound_ReleasePrimaryBufferInterface
,
1528 AMDirectSound_ReleaseSecondaryBufferInterface
,
1529 AMDirectSound_SetFocusWindow
,
1530 AMDirectSound_GetFocusWindow
1533 static DSoundRenderImpl
*from_IAMFilterMiscFlags(IAMFilterMiscFlags
*iface
) {
1534 return (DSoundRenderImpl
*)((char*)iface
- offsetof(DSoundRenderImpl
, IAMFilterMiscFlags_vtbl
));
1537 static HRESULT WINAPI
AMFilterMiscFlags_QueryInterface(IAMFilterMiscFlags
*iface
, REFIID riid
, void **ppv
) {
1538 DSoundRenderImpl
*This
= from_IAMFilterMiscFlags(iface
);
1539 return IUnknown_QueryInterface((IUnknown
*)This
, riid
, ppv
);
1542 static ULONG WINAPI
AMFilterMiscFlags_AddRef(IAMFilterMiscFlags
*iface
) {
1543 DSoundRenderImpl
*This
= from_IAMFilterMiscFlags(iface
);
1544 return IUnknown_AddRef((IUnknown
*)This
);
1547 static ULONG WINAPI
AMFilterMiscFlags_Release(IAMFilterMiscFlags
*iface
) {
1548 DSoundRenderImpl
*This
= from_IAMFilterMiscFlags(iface
);
1549 return IUnknown_Release((IUnknown
*)This
);
1552 static ULONG WINAPI
AMFilterMiscFlags_GetMiscFlags(IAMFilterMiscFlags
*iface
) {
1553 return AM_FILTER_MISC_FLAGS_IS_RENDERER
;
1556 static const IAMFilterMiscFlagsVtbl IAMFilterMiscFlags_Vtbl
= {
1557 AMFilterMiscFlags_QueryInterface
,
1558 AMFilterMiscFlags_AddRef
,
1559 AMFilterMiscFlags_Release
,
1560 AMFilterMiscFlags_GetMiscFlags