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"
36 #include "wine/unicode.h"
37 #include "wine/debug.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(quartz
);
41 /* NOTE: buffer can still be filled completely,
42 * but we start waiting until only this amount is buffered
44 static const REFERENCE_TIME DSoundRenderer_Max_Fill
= 150 * 10000;
46 static const IBaseFilterVtbl DSoundRender_Vtbl
;
47 static const IBasicAudioVtbl IBasicAudio_Vtbl
;
48 static const IReferenceClockVtbl IReferenceClock_Vtbl
;
49 static const IMediaSeekingVtbl IMediaSeeking_Vtbl
;
50 static const IAMDirectSoundVtbl IAMDirectSound_Vtbl
;
51 static const IAMFilterMiscFlagsVtbl IAMFilterMiscFlags_Vtbl
;
53 typedef struct DSoundRenderImpl
55 BaseRenderer renderer
;
57 IBasicAudio IBasicAudio_iface
;
58 IReferenceClock IReferenceClock_iface
;
59 IAMDirectSound IAMDirectSound_iface
;
60 IAMFilterMiscFlags IAMFilterMiscFlags_iface
;
62 IDirectSound8
*dsound
;
63 LPDIRECTSOUNDBUFFER dsbuffer
;
66 DWORD last_playpos
, writepos
;
68 REFERENCE_TIME play_time
;
76 HANDLE advisethread
, thread_wait
;
79 static inline DSoundRenderImpl
*impl_from_BaseRenderer(BaseRenderer
*iface
)
81 return CONTAINING_RECORD(iface
, DSoundRenderImpl
, renderer
);
84 static inline DSoundRenderImpl
*impl_from_IBaseFilter(IBaseFilter
*iface
)
86 return CONTAINING_RECORD(iface
, DSoundRenderImpl
, renderer
.filter
.IBaseFilter_iface
);
89 static inline DSoundRenderImpl
*impl_from_IBasicAudio(IBasicAudio
*iface
)
91 return CONTAINING_RECORD(iface
, DSoundRenderImpl
, IBasicAudio_iface
);
94 static inline DSoundRenderImpl
*impl_from_IReferenceClock(IReferenceClock
*iface
)
96 return CONTAINING_RECORD(iface
, DSoundRenderImpl
, IReferenceClock_iface
);
99 static inline DSoundRenderImpl
*impl_from_IAMDirectSound(IAMDirectSound
*iface
)
101 return CONTAINING_RECORD(iface
, DSoundRenderImpl
, IAMDirectSound_iface
);
104 static inline DSoundRenderImpl
*impl_from_IAMFilterMiscFlags(IAMFilterMiscFlags
*iface
)
106 return CONTAINING_RECORD(iface
, DSoundRenderImpl
, IAMFilterMiscFlags_iface
);
109 static REFERENCE_TIME
time_from_pos(DSoundRenderImpl
*This
, DWORD pos
) {
110 WAVEFORMATEX
*wfx
= (WAVEFORMATEX
*)This
->renderer
.pInputPin
->pin
.mtCurrent
.pbFormat
;
111 REFERENCE_TIME ret
= 10000000;
112 ret
= ret
* pos
/ wfx
->nAvgBytesPerSec
;
116 static DWORD
pos_from_time(DSoundRenderImpl
*This
, REFERENCE_TIME time
) {
117 WAVEFORMATEX
*wfx
= (WAVEFORMATEX
*)This
->renderer
.pInputPin
->pin
.mtCurrent
.pbFormat
;
118 REFERENCE_TIME ret
= time
;
119 ret
*= wfx
->nSamplesPerSec
;
121 ret
*= wfx
->nBlockAlign
;
125 static void DSoundRender_UpdatePositions(DSoundRenderImpl
*This
, DWORD
*seqwritepos
, DWORD
*minwritepos
) {
126 WAVEFORMATEX
*wfx
= (WAVEFORMATEX
*)This
->renderer
.pInputPin
->pin
.mtCurrent
.pbFormat
;
128 DWORD size1
, size2
, playpos
, writepos
, old_writepos
, old_playpos
, adv
;
129 BOOL writepos_set
= This
->writepos
< This
->buf_size
;
131 /* Update position and zero */
132 old_writepos
= This
->writepos
;
133 old_playpos
= This
->last_playpos
;
134 if (old_writepos
<= old_playpos
)
135 old_writepos
+= This
->buf_size
;
137 IDirectSoundBuffer_GetCurrentPosition(This
->dsbuffer
, &playpos
, &writepos
);
138 if (old_playpos
> playpos
) {
139 adv
= This
->buf_size
+ playpos
- old_playpos
;
140 This
->play_time
+= time_from_pos(This
, This
->buf_size
);
142 adv
= playpos
- old_playpos
;
143 This
->last_playpos
= playpos
;
145 TRACE("Moving from %u to %u: clearing %u bytes\n", old_playpos
, playpos
, adv
);
146 IDirectSoundBuffer_Lock(This
->dsbuffer
, old_playpos
, adv
, (void**)&buf1
, &size1
, (void**)&buf2
, &size2
, 0);
147 memset(buf1
, wfx
->wBitsPerSample
== 8 ? 128 : 0, size1
);
148 memset(buf2
, wfx
->wBitsPerSample
== 8 ? 128 : 0, size2
);
149 IDirectSoundBuffer_Unlock(This
->dsbuffer
, buf1
, size1
, buf2
, size2
);
151 *minwritepos
= writepos
;
152 if (!writepos_set
|| old_writepos
< writepos
) {
154 This
->writepos
= This
->buf_size
;
155 FIXME("Underrun of data occurred!\n");
157 *seqwritepos
= writepos
;
159 *seqwritepos
= This
->writepos
;
162 static HRESULT
DSoundRender_GetWritePos(DSoundRenderImpl
*This
, DWORD
*ret_writepos
, REFERENCE_TIME write_at
, DWORD
*pfree
, DWORD
*skip
)
164 WAVEFORMATEX
*wfx
= (WAVEFORMATEX
*)This
->renderer
.pInputPin
->pin
.mtCurrent
.pbFormat
;
165 DWORD writepos
, min_writepos
, playpos
;
166 REFERENCE_TIME max_lag
= 50 * 10000;
167 REFERENCE_TIME min_lag
= 25 * 10000;
168 REFERENCE_TIME cur
, writepos_t
, delta_t
;
170 DSoundRender_UpdatePositions(This
, &writepos
, &min_writepos
);
171 playpos
= This
->last_playpos
;
172 if (This
->renderer
.filter
.pClock
== &This
->IReferenceClock_iface
) {
174 cur
= This
->play_time
+ time_from_pos(This
, playpos
);
175 cur
-= This
->renderer
.filter
.rtStreamStart
;
176 } else if (This
->renderer
.filter
.pClock
) {
177 IReferenceClock_GetTime(This
->renderer
.filter
.pClock
, &cur
);
178 cur
-= This
->renderer
.filter
.rtStreamStart
;
182 if (writepos
== min_writepos
)
187 *ret_writepos
= writepos
;
191 if (writepos
>= playpos
)
192 writepos_t
= cur
+ time_from_pos(This
, writepos
- playpos
);
194 writepos_t
= cur
+ time_from_pos(This
, This
->buf_size
+ writepos
- playpos
);
196 /* write_at: Starting time of sample */
197 /* cur: current time of play position */
198 /* writepos_t: current time of our pointer play position */
199 delta_t
= write_at
- writepos_t
;
200 if (delta_t
>= -max_lag
&& delta_t
<= max_lag
) {
201 TRACE("Continuing from old position\n");
202 *ret_writepos
= writepos
;
203 } else if (delta_t
< 0) {
204 REFERENCE_TIME past
, min_writepos_t
;
205 WARN("Delta too big %i/%i, overwriting old data or even skipping\n", (int)delta_t
/ 10000, (int)max_lag
/ 10000);
206 if (min_writepos
>= playpos
)
207 min_writepos_t
= cur
+ time_from_pos(This
, min_writepos
- playpos
);
209 min_writepos_t
= cur
+ time_from_pos(This
, This
->buf_size
- playpos
+ min_writepos
);
210 past
= min_writepos_t
- write_at
;
212 DWORD skipbytes
= pos_from_time(This
, past
);
213 WARN("Skipping %u bytes\n", skipbytes
);
215 *ret_writepos
= min_writepos
;
217 DWORD aheadbytes
= pos_from_time(This
, -past
);
218 WARN("Advancing %u bytes\n", aheadbytes
);
219 *ret_writepos
= (min_writepos
+ aheadbytes
) % This
->buf_size
;
221 } else /* delta_t > 0 */ {
223 WARN("Delta too big %i/%i, too far ahead\n", (int)delta_t
/ 10000, (int)max_lag
/ 10000);
224 aheadbytes
= pos_from_time(This
, delta_t
);
225 WARN("Advancing %u bytes\n", aheadbytes
);
226 if (delta_t
>= DSoundRenderer_Max_Fill
)
228 *ret_writepos
= (min_writepos
+ aheadbytes
) % This
->buf_size
;
231 if (playpos
> *ret_writepos
)
232 *pfree
= playpos
- *ret_writepos
;
233 else if (playpos
== *ret_writepos
)
234 *pfree
= This
->buf_size
- wfx
->nBlockAlign
;
236 *pfree
= This
->buf_size
+ playpos
- *ret_writepos
;
237 if (time_from_pos(This
, This
->buf_size
- *pfree
) >= DSoundRenderer_Max_Fill
) {
238 TRACE("Blocked: too full %i / %i\n", (int)(time_from_pos(This
, This
->buf_size
- *pfree
)/10000), (int)(DSoundRenderer_Max_Fill
/ 10000));
244 static HRESULT
DSoundRender_HandleEndOfStream(DSoundRenderImpl
*This
)
247 IMediaEventSink
*pEventSink
;
252 DSoundRender_UpdatePositions(This
, &pos1
, &pos2
);
257 LeaveCriticalSection(&This
->renderer
.filter
.csFilter
);
258 LeaveCriticalSection(&This
->renderer
.csRenderLock
);
259 WaitForSingleObject(This
->blocked
, 10);
260 EnterCriticalSection(&This
->renderer
.filter
.csFilter
);
261 EnterCriticalSection(&This
->renderer
.csRenderLock
);
263 if (This
->renderer
.pInputPin
->flushing
||
264 This
->renderer
.filter
.state
!= State_Running
) {
265 SetEvent(This
->renderer
.evComplete
);
270 if (!This
->renderer
.filter
.filterInfo
.pGraph
)
273 hr
= IFilterGraph_QueryInterface(This
->renderer
.filter
.filterInfo
.pGraph
, &IID_IMediaEventSink
, (LPVOID
*)&pEventSink
);
276 hr
= IMediaEventSink_Notify(pEventSink
, EC_COMPLETE
, S_OK
, (LONG_PTR
)This
);
277 IMediaEventSink_Release(pEventSink
);
282 static HRESULT
DSoundRender_SendSampleData(DSoundRenderImpl
* This
, REFERENCE_TIME tStart
, REFERENCE_TIME tStop
, const BYTE
*data
, DWORD size
)
286 while (size
&& This
->renderer
.filter
.state
!= State_Stopped
) {
287 DWORD writepos
, skip
= 0, free
, size1
, size2
, ret
;
290 if (This
->renderer
.filter
.state
== State_Running
)
291 hr
= DSoundRender_GetWritePos(This
, &writepos
, tStart
, &free
, &skip
);
297 LeaveCriticalSection(&This
->renderer
.csRenderLock
);
298 ret
= WaitForSingleObject(This
->blocked
, 10);
299 EnterCriticalSection(&This
->renderer
.csRenderLock
);
301 if (This
->renderer
.pInputPin
->flushing
||
302 This
->renderer
.filter
.state
== State_Stopped
) {
303 SetEvent(This
->renderer
.evComplete
);
304 return This
->renderer
.filter
.state
== State_Paused
? S_OK
: VFW_E_WRONG_STATE
;
306 if (ret
!= WAIT_TIMEOUT
)
313 FIXME("Sample dropped %u of %u bytes\n", skip
, size
);
319 hr
= IDirectSoundBuffer_Lock(This
->dsbuffer
, writepos
, min(free
, size
), (void**)&buf1
, &size1
, (void**)&buf2
, &size2
, 0);
321 ERR("Unable to lock sound buffer! (%x)\n", hr
);
324 memcpy(buf1
, data
, size1
);
326 memcpy(buf2
, data
+size1
, size2
);
327 IDirectSoundBuffer_Unlock(This
->dsbuffer
, buf1
, size1
, buf2
, size2
);
328 This
->writepos
= (writepos
+ size1
+ size2
) % This
->buf_size
;
329 TRACE("Wrote %u bytes at %u, next at %u - (%u/%u)\n", size1
+size2
, writepos
, This
->writepos
, free
, size
);
330 data
+= size1
+ size2
;
331 size
-= size1
+ size2
;
336 static HRESULT WINAPI
DSoundRender_ShouldDrawSampleNow(BaseRenderer
*This
, IMediaSample
*pMediaSample
, REFERENCE_TIME
*pStartTime
, REFERENCE_TIME
*pEndTime
)
338 /* We time ourselves do not use the base renderers timing */
343 static HRESULT WINAPI
DSoundRender_PrepareReceive(BaseRenderer
*iface
, IMediaSample
*pSample
)
345 DSoundRenderImpl
*This
= impl_from_BaseRenderer(iface
);
349 if (IMediaSample_GetMediaType(pSample
, &amt
) == S_OK
)
351 AM_MEDIA_TYPE
*orig
= &This
->renderer
.pInputPin
->pin
.mtCurrent
;
352 WAVEFORMATEX
*origfmt
= (WAVEFORMATEX
*)orig
->pbFormat
;
353 WAVEFORMATEX
*newfmt
= (WAVEFORMATEX
*)amt
->pbFormat
;
355 if (origfmt
->wFormatTag
== newfmt
->wFormatTag
&&
356 origfmt
->nChannels
== newfmt
->nChannels
&&
357 origfmt
->nBlockAlign
== newfmt
->nBlockAlign
&&
358 origfmt
->wBitsPerSample
== newfmt
->wBitsPerSample
&&
359 origfmt
->cbSize
== newfmt
->cbSize
)
361 if (origfmt
->nSamplesPerSec
!= newfmt
->nSamplesPerSec
)
363 hr
= IDirectSoundBuffer_SetFrequency(This
->dsbuffer
,
364 newfmt
->nSamplesPerSec
);
366 return VFW_E_TYPE_NOT_ACCEPTED
;
368 CopyMediaType(orig
, amt
);
369 IMediaSample_SetMediaType(pSample
, NULL
);
373 return VFW_E_TYPE_NOT_ACCEPTED
;
378 static HRESULT WINAPI
DSoundRender_DoRenderSample(BaseRenderer
*iface
, IMediaSample
* pSample
)
380 DSoundRenderImpl
*This
= impl_from_BaseRenderer(iface
);
381 LPBYTE pbSrcStream
= NULL
;
382 LONG cbSrcStream
= 0;
383 REFERENCE_TIME tStart
, tStop
;
386 TRACE("%p %p\n", iface
, pSample
);
388 /* Slightly incorrect, Pause completes when a frame is received so we should signal
389 * pause completion here, but for sound playing a single frame doesn't make sense
392 hr
= IMediaSample_GetPointer(pSample
, &pbSrcStream
);
395 ERR("Cannot get pointer to sample data (%x)\n", hr
);
399 hr
= IMediaSample_GetTime(pSample
, &tStart
, &tStop
);
401 ERR("Cannot get sample time (%x)\n", hr
);
405 IMediaSample_IsDiscontinuity(pSample
);
407 if (IMediaSample_IsPreroll(pSample
) == S_OK
)
413 cbSrcStream
= IMediaSample_GetActualDataLength(pSample
);
414 TRACE("Sample data ptr = %p, size = %d\n", pbSrcStream
, cbSrcStream
);
416 hr
= DSoundRender_SendSampleData(This
, tStart
, tStop
, pbSrcStream
, cbSrcStream
);
417 if (This
->renderer
.filter
.state
== State_Running
&& This
->renderer
.filter
.pClock
&& tStart
>= 0) {
418 REFERENCE_TIME jitter
, now
= 0;
420 IReferenceClock_GetTime(This
->renderer
.filter
.pClock
, &now
);
421 jitter
= now
- This
->renderer
.filter
.rtStreamStart
- tStart
;
422 if (jitter
<= -DSoundRenderer_Max_Fill
)
423 jitter
+= DSoundRenderer_Max_Fill
;
426 q
.Type
= (jitter
> 0 ? Famine
: Flood
);
429 q
.TimeStamp
= tStart
;
430 IQualityControl_Notify((IQualityControl
*)This
->renderer
.qcimpl
, (IBaseFilter
*)This
, q
);
435 static HRESULT WINAPI
DSoundRender_CheckMediaType(BaseRenderer
*iface
, const AM_MEDIA_TYPE
* pmt
)
437 WAVEFORMATEX
* format
;
439 if (!IsEqualIID(&pmt
->majortype
, &MEDIATYPE_Audio
))
442 format
= (WAVEFORMATEX
*)pmt
->pbFormat
;
443 TRACE("Format = %p\n", format
);
444 TRACE("wFormatTag = %x %x\n", format
->wFormatTag
, WAVE_FORMAT_PCM
);
445 TRACE("nChannels = %d\n", format
->nChannels
);
446 TRACE("nSamplesPerSec = %d\n", format
->nAvgBytesPerSec
);
447 TRACE("nAvgBytesPerSec = %d\n", format
->nAvgBytesPerSec
);
448 TRACE("nBlockAlign = %d\n", format
->nBlockAlign
);
449 TRACE("wBitsPerSample = %d\n", format
->wBitsPerSample
);
451 if (!IsEqualIID(&pmt
->subtype
, &MEDIASUBTYPE_PCM
))
457 static VOID WINAPI
DSoundRender_OnStopStreaming(BaseRenderer
* iface
)
459 DSoundRenderImpl
*This
= impl_from_BaseRenderer(iface
);
461 TRACE("(%p/%p)->()\n", This
, iface
);
463 IDirectSoundBuffer_Stop(This
->dsbuffer
);
464 This
->writepos
= This
->buf_size
;
465 SetEvent(This
->blocked
);
468 static VOID WINAPI
DSoundRender_OnStartStreaming(BaseRenderer
* iface
)
470 DSoundRenderImpl
*This
= impl_from_BaseRenderer(iface
);
472 TRACE("(%p)\n", This
);
474 if (This
->renderer
.pInputPin
->pin
.pConnectedTo
)
476 if (This
->renderer
.filter
.state
== State_Paused
)
478 /* Unblock our thread, state changing from paused to running doesn't need a reset for state change */
479 SetEvent(This
->blocked
);
481 else if (This
->renderer
.filter
.state
== State_Stopped
)
483 ResetEvent(This
->renderer
.evComplete
);
484 This
->renderer
.pInputPin
->end_of_stream
= 0;
486 IDirectSoundBuffer_Play(This
->dsbuffer
, 0, 0, DSBPLAY_LOOPING
);
487 ResetEvent(This
->blocked
);
491 static HRESULT WINAPI
DSoundRender_CompleteConnect(BaseRenderer
* iface
, IPin
* pReceivePin
)
493 DSoundRenderImpl
*This
= impl_from_BaseRenderer(iface
);
494 const AM_MEDIA_TYPE
* pmt
= &This
->renderer
.pInputPin
->pin
.mtCurrent
;
496 WAVEFORMATEX
*format
;
497 DSBUFFERDESC buf_desc
;
499 TRACE("(%p)->(%p)\n", This
, pReceivePin
);
500 dump_AM_MEDIA_TYPE(pmt
);
502 TRACE("MajorType %s\n", debugstr_guid(&pmt
->majortype
));
503 TRACE("SubType %s\n", debugstr_guid(&pmt
->subtype
));
504 TRACE("Format %s\n", debugstr_guid(&pmt
->formattype
));
505 TRACE("Size %d\n", pmt
->cbFormat
);
507 format
= (WAVEFORMATEX
*)pmt
->pbFormat
;
509 This
->buf_size
= format
->nAvgBytesPerSec
;
511 memset(&buf_desc
,0,sizeof(DSBUFFERDESC
));
512 buf_desc
.dwSize
= sizeof(DSBUFFERDESC
);
513 buf_desc
.dwFlags
= DSBCAPS_CTRLVOLUME
| DSBCAPS_CTRLPAN
|
514 DSBCAPS_CTRLFREQUENCY
| DSBCAPS_GLOBALFOCUS
|
515 DSBCAPS_GETCURRENTPOSITION2
;
516 buf_desc
.dwBufferBytes
= This
->buf_size
;
517 buf_desc
.lpwfxFormat
= format
;
518 hr
= IDirectSound_CreateSoundBuffer(This
->dsound
, &buf_desc
, &This
->dsbuffer
, NULL
);
519 This
->writepos
= This
->buf_size
;
521 ERR("Can't create sound buffer (%x)\n", hr
);
525 hr
= IDirectSoundBuffer_SetVolume(This
->dsbuffer
, This
->volume
);
527 ERR("Can't set volume to %d (%x)\n", This
->volume
, hr
);
529 hr
= IDirectSoundBuffer_SetPan(This
->dsbuffer
, This
->pan
);
531 ERR("Can't set pan to %d (%x)\n", This
->pan
, hr
);
535 if (FAILED(hr
) && hr
!= VFW_E_ALREADY_CONNECTED
)
538 IDirectSoundBuffer_Release(This
->dsbuffer
);
539 This
->dsbuffer
= NULL
;
545 static HRESULT WINAPI
DSoundRender_BreakConnect(BaseRenderer
* iface
)
547 DSoundRenderImpl
*This
= impl_from_BaseRenderer(iface
);
549 TRACE("(%p)->()\n", iface
);
551 if (This
->threadid
) {
552 PostThreadMessageW(This
->threadid
, WM_APP
, 0, 0);
553 WaitForSingleObject(This
->advisethread
, INFINITE
);
554 CloseHandle(This
->advisethread
);
557 IDirectSoundBuffer_Release(This
->dsbuffer
);
558 This
->dsbuffer
= NULL
;
563 static HRESULT WINAPI
DSoundRender_EndOfStream(BaseRenderer
* iface
)
565 DSoundRenderImpl
*This
= impl_from_BaseRenderer(iface
);
568 TRACE("(%p)->()\n",iface
);
570 hr
= BaseRendererImpl_EndOfStream(iface
);
577 hr
= DSoundRender_HandleEndOfStream(This
);
582 static HRESULT WINAPI
DSoundRender_BeginFlush(BaseRenderer
* iface
)
584 DSoundRenderImpl
*This
= impl_from_BaseRenderer(iface
);
587 BaseRendererImpl_BeginFlush(iface
);
588 SetEvent(This
->blocked
);
593 static HRESULT WINAPI
DSoundRender_EndFlush(BaseRenderer
* iface
)
595 DSoundRenderImpl
*This
= impl_from_BaseRenderer(iface
);
599 BaseRendererImpl_EndFlush(iface
);
601 ResetEvent(This
->renderer
.evComplete
);
602 LeaveCriticalSection(This
->renderer
.pInputPin
->pin
.pCritSec
);
603 LeaveCriticalSection(&This
->renderer
.filter
.csFilter
);
604 LeaveCriticalSection(&This
->renderer
.csRenderLock
);
605 WaitForSingleObject(This
->renderer
.evComplete
, -1);
606 EnterCriticalSection(This
->renderer
.pInputPin
->pin
.pCritSec
);
607 EnterCriticalSection(&This
->renderer
.filter
.csFilter
);
608 EnterCriticalSection(&This
->renderer
.csRenderLock
);
610 if (This
->renderer
.filter
.state
!= State_Stopped
)
611 ResetEvent(This
->blocked
);
619 IDirectSoundBuffer_Lock(This
->dsbuffer
, 0, 0, (LPVOID
*)&buffer
, &size
, NULL
, NULL
, DSBLOCK_ENTIREBUFFER
);
620 memset(buffer
, 0, size
);
621 IDirectSoundBuffer_Unlock(This
->dsbuffer
, buffer
, size
, NULL
, 0);
622 This
->writepos
= This
->buf_size
;
628 static const BaseRendererFuncTable BaseFuncTable
= {
629 DSoundRender_CheckMediaType
,
630 DSoundRender_DoRenderSample
,
635 DSoundRender_OnStartStreaming
,
636 DSoundRender_OnStopStreaming
,
640 DSoundRender_ShouldDrawSampleNow
,
641 DSoundRender_PrepareReceive
,
643 DSoundRender_CompleteConnect
,
644 DSoundRender_BreakConnect
,
645 DSoundRender_EndOfStream
,
646 DSoundRender_BeginFlush
,
647 DSoundRender_EndFlush
,
650 HRESULT
DSoundRender_create(IUnknown
* pUnkOuter
, LPVOID
* ppv
)
653 DSoundRenderImpl
* pDSoundRender
;
655 TRACE("(%p, %p)\n", pUnkOuter
, ppv
);
660 return CLASS_E_NOAGGREGATION
;
662 pDSoundRender
= CoTaskMemAlloc(sizeof(DSoundRenderImpl
));
664 return E_OUTOFMEMORY
;
665 ZeroMemory(pDSoundRender
, sizeof(DSoundRenderImpl
));
667 hr
= BaseRenderer_Init(&pDSoundRender
->renderer
, &DSoundRender_Vtbl
, (IUnknown
*)pDSoundRender
, &CLSID_DSoundRender
, (DWORD_PTR
)(__FILE__
": DSoundRenderImpl.csFilter"), &BaseFuncTable
);
669 pDSoundRender
->IBasicAudio_iface
.lpVtbl
= &IBasicAudio_Vtbl
;
670 pDSoundRender
->IReferenceClock_iface
.lpVtbl
= &IReferenceClock_Vtbl
;
671 pDSoundRender
->IAMDirectSound_iface
.lpVtbl
= &IAMDirectSound_Vtbl
;
672 pDSoundRender
->IAMFilterMiscFlags_iface
.lpVtbl
= &IAMFilterMiscFlags_Vtbl
;
676 hr
= DirectSoundCreate8(NULL
, &pDSoundRender
->dsound
, NULL
);
678 ERR("Cannot create Direct Sound object (%x)\n", hr
);
680 hr
= IDirectSound_SetCooperativeLevel(pDSoundRender
->dsound
, GetDesktopWindow(), DSSCL_PRIORITY
);
682 IDirectSoundBuffer
*buf
;
683 DSBUFFERDESC buf_desc
;
684 memset(&buf_desc
,0,sizeof(DSBUFFERDESC
));
685 buf_desc
.dwSize
= sizeof(DSBUFFERDESC
);
686 buf_desc
.dwFlags
= DSBCAPS_PRIMARYBUFFER
;
687 hr
= IDirectSound_CreateSoundBuffer(pDSoundRender
->dsound
, &buf_desc
, &buf
, NULL
);
689 IDirectSoundBuffer_Play(buf
, 0, 0, DSBPLAY_LOOPING
);
690 IUnknown_Release(buf
);
698 pDSoundRender
->blocked
= CreateEventW(NULL
, TRUE
, TRUE
, NULL
);
700 if (!pDSoundRender
->blocked
|| FAILED(hr
))
702 IUnknown_Release((IUnknown
*)pDSoundRender
);
703 return HRESULT_FROM_WIN32(GetLastError());
706 *ppv
= pDSoundRender
;
710 BaseRendererImpl_Release(&pDSoundRender
->renderer
.filter
.IBaseFilter_iface
);
711 CoTaskMemFree(pDSoundRender
);
717 static HRESULT WINAPI
DSoundRender_QueryInterface(IBaseFilter
* iface
, REFIID riid
, LPVOID
* ppv
)
719 DSoundRenderImpl
*This
= impl_from_IBaseFilter(iface
);
720 TRACE("(%p, %p)->(%s, %p)\n", This
, iface
, qzdebugstr_guid(riid
), ppv
);
724 if (IsEqualIID(riid
, &IID_IBasicAudio
))
725 *ppv
= &This
->IBasicAudio_iface
;
726 else if (IsEqualIID(riid
, &IID_IReferenceClock
))
727 *ppv
= &This
->IReferenceClock_iface
;
728 else if (IsEqualIID(riid
, &IID_IAMDirectSound
))
729 *ppv
= &This
->IAMDirectSound_iface
;
730 else if (IsEqualIID(riid
, &IID_IAMFilterMiscFlags
))
731 *ppv
= &This
->IAMFilterMiscFlags_iface
;
735 hr
= BaseRendererImpl_QueryInterface(iface
, riid
, ppv
);
742 IUnknown_AddRef((IUnknown
*)(*ppv
));
746 if (!IsEqualIID(riid
, &IID_IPin
) && !IsEqualIID(riid
, &IID_IVideoWindow
))
747 FIXME("No interface for %s!\n", qzdebugstr_guid(riid
));
749 return E_NOINTERFACE
;
752 static ULONG WINAPI
DSoundRender_Release(IBaseFilter
* iface
)
754 DSoundRenderImpl
*This
= impl_from_IBaseFilter(iface
);
755 ULONG refCount
= BaseRendererImpl_Release(iface
);
757 TRACE("(%p)->() Release from %d\n", This
, refCount
+ 1);
761 if (This
->threadid
) {
762 PostThreadMessageW(This
->threadid
, WM_APP
, 0, 0);
763 WaitForSingleObject(This
->advisethread
, INFINITE
);
764 CloseHandle(This
->advisethread
);
768 IDirectSoundBuffer_Release(This
->dsbuffer
);
769 This
->dsbuffer
= NULL
;
771 IDirectSound_Release(This
->dsound
);
774 This
->IBasicAudio_iface
.lpVtbl
= NULL
;
776 CloseHandle(This
->blocked
);
778 TRACE("Destroying Audio Renderer\n");
787 static const IBaseFilterVtbl DSoundRender_Vtbl
=
789 DSoundRender_QueryInterface
,
790 BaseFilterImpl_AddRef
,
791 DSoundRender_Release
,
792 BaseFilterImpl_GetClassID
,
793 BaseRendererImpl_Stop
,
794 BaseRendererImpl_Pause
,
795 BaseRendererImpl_Run
,
796 BaseRendererImpl_GetState
,
797 BaseRendererImpl_SetSyncSource
,
798 BaseFilterImpl_GetSyncSource
,
799 BaseFilterImpl_EnumPins
,
800 BaseRendererImpl_FindPin
,
801 BaseFilterImpl_QueryFilterInfo
,
802 BaseFilterImpl_JoinFilterGraph
,
803 BaseFilterImpl_QueryVendorInfo
806 /*** IUnknown methods ***/
807 static HRESULT WINAPI
Basicaudio_QueryInterface(IBasicAudio
*iface
,
810 DSoundRenderImpl
*This
= impl_from_IBasicAudio(iface
);
812 TRACE("(%p/%p)->(%s (%p), %p)\n", This
, iface
, debugstr_guid(riid
), riid
, ppvObj
);
814 return DSoundRender_QueryInterface(&This
->renderer
.filter
.IBaseFilter_iface
, riid
, ppvObj
);
817 static ULONG WINAPI
Basicaudio_AddRef(IBasicAudio
*iface
) {
818 DSoundRenderImpl
*This
= impl_from_IBasicAudio(iface
);
820 TRACE("(%p/%p)->()\n", This
, iface
);
822 return BaseFilterImpl_AddRef(&This
->renderer
.filter
.IBaseFilter_iface
);
825 static ULONG WINAPI
Basicaudio_Release(IBasicAudio
*iface
) {
826 DSoundRenderImpl
*This
= impl_from_IBasicAudio(iface
);
828 TRACE("(%p/%p)->()\n", This
, iface
);
830 return DSoundRender_Release(&This
->renderer
.filter
.IBaseFilter_iface
);
833 /*** IDispatch methods ***/
834 static HRESULT WINAPI
Basicaudio_GetTypeInfoCount(IBasicAudio
*iface
,
836 DSoundRenderImpl
*This
= impl_from_IBasicAudio(iface
);
838 TRACE("(%p/%p)->(%p): stub !!!\n", This
, iface
, pctinfo
);
843 static HRESULT WINAPI
Basicaudio_GetTypeInfo(IBasicAudio
*iface
,
846 ITypeInfo
**ppTInfo
) {
847 DSoundRenderImpl
*This
= impl_from_IBasicAudio(iface
);
849 TRACE("(%p/%p)->(%d, %d, %p): stub !!!\n", This
, iface
, iTInfo
, lcid
, ppTInfo
);
854 static HRESULT WINAPI
Basicaudio_GetIDsOfNames(IBasicAudio
*iface
,
860 DSoundRenderImpl
*This
= impl_from_IBasicAudio(iface
);
862 TRACE("(%p/%p)->(%s (%p), %p, %d, %d, %p): stub !!!\n", This
, iface
, debugstr_guid(riid
), riid
, rgszNames
, cNames
, lcid
, rgDispId
);
867 static HRESULT WINAPI
Basicaudio_Invoke(IBasicAudio
*iface
,
872 DISPPARAMS
*pDispParams
,
876 DSoundRenderImpl
*This
= impl_from_IBasicAudio(iface
);
878 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
);
883 /*** IBasicAudio methods ***/
884 static HRESULT WINAPI
Basicaudio_put_Volume(IBasicAudio
*iface
,
886 DSoundRenderImpl
*This
= impl_from_IBasicAudio(iface
);
888 TRACE("(%p/%p)->(%d)\n", This
, iface
, lVolume
);
890 if (lVolume
> DSBVOLUME_MAX
|| lVolume
< DSBVOLUME_MIN
)
893 if (This
->dsbuffer
) {
894 if (FAILED(IDirectSoundBuffer_SetVolume(This
->dsbuffer
, lVolume
)))
898 This
->volume
= lVolume
;
902 static HRESULT WINAPI
Basicaudio_get_Volume(IBasicAudio
*iface
,
904 DSoundRenderImpl
*This
= impl_from_IBasicAudio(iface
);
906 TRACE("(%p/%p)->(%p)\n", This
, iface
, plVolume
);
911 *plVolume
= This
->volume
;
915 static HRESULT WINAPI
Basicaudio_put_Balance(IBasicAudio
*iface
,
917 DSoundRenderImpl
*This
= impl_from_IBasicAudio(iface
);
919 TRACE("(%p/%p)->(%d)\n", This
, iface
, lBalance
);
921 if (lBalance
< DSBPAN_LEFT
|| lBalance
> DSBPAN_RIGHT
)
924 if (This
->dsbuffer
) {
925 if (FAILED(IDirectSoundBuffer_SetPan(This
->dsbuffer
, lBalance
)))
929 This
->pan
= lBalance
;
933 static HRESULT WINAPI
Basicaudio_get_Balance(IBasicAudio
*iface
,
935 DSoundRenderImpl
*This
= impl_from_IBasicAudio(iface
);
937 TRACE("(%p/%p)->(%p)\n", This
, iface
, plBalance
);
942 *plBalance
= This
->pan
;
946 static const IBasicAudioVtbl IBasicAudio_Vtbl
=
948 Basicaudio_QueryInterface
,
951 Basicaudio_GetTypeInfoCount
,
952 Basicaudio_GetTypeInfo
,
953 Basicaudio_GetIDsOfNames
,
955 Basicaudio_put_Volume
,
956 Basicaudio_get_Volume
,
957 Basicaudio_put_Balance
,
958 Basicaudio_get_Balance
961 struct dsoundrender_timer
{
962 struct dsoundrender_timer
*next
;
963 REFERENCE_TIME start
;
964 REFERENCE_TIME periodicity
;
968 static LONG cookie_counter
= 1;
970 static DWORD WINAPI
DSoundAdviseThread(LPVOID lpParam
) {
971 DSoundRenderImpl
*This
= lpParam
;
972 struct dsoundrender_timer head
= { };
975 TRACE("(%p): Main Loop\n", This
);
977 PeekMessageW(&msg
, NULL
, WM_USER
, WM_USER
, PM_NOREMOVE
);
978 SetEvent(This
->thread_wait
);
983 REFERENCE_TIME curtime
= 0;
985 struct dsoundrender_timer
*prev
= &head
, *cur
;
987 hr
= IReferenceClock_GetTime(&This
->IReferenceClock_iface
, &curtime
);
989 FIXME("Could not get time: %08x\n", hr
);
992 TRACE("Time: %s\n", wine_dbgstr_longlong(curtime
));
995 if (cur
->start
> curtime
) {
996 TRACE("Skipping %p\n", cur
);
998 } else if (cur
->periodicity
) {
999 while (cur
->start
<= curtime
) {
1000 cur
->start
+= cur
->periodicity
;
1001 ReleaseSemaphore(cur
->handle
, 1, NULL
);
1005 struct dsoundrender_timer
*next
= cur
->next
;
1006 TRACE("Firing %p %s < %s\n", cur
, wine_dbgstr_longlong(cur
->start
), wine_dbgstr_longlong(curtime
));
1007 SetEvent(cur
->handle
);
1008 HeapFree(GetProcessHeap(), 0, cur
);
1013 ret
= GetMessageW(&msg
, INVALID_HANDLE_VALUE
, WM_APP
, WM_APP
+ 4);
1015 ret
= PeekMessageW(&msg
, INVALID_HANDLE_VALUE
, WM_APP
, WM_APP
+ 4, PM_REMOVE
);
1017 switch (LOWORD(msg
.message
) - WM_APP
) {
1018 case 0: TRACE("Exiting\n"); return 0;
1021 struct dsoundrender_timer
*t
= (struct dsoundrender_timer
*)msg
.wParam
;
1022 if (LOWORD(msg
.message
) - WM_APP
== 1)
1023 TRACE("Adding one-shot timer %p\n", t
);
1025 TRACE("Adding periodic timer %p\n", t
);
1026 t
->next
= head
.next
;
1032 while (prev
->next
) {
1034 if (cur
->cookie
== msg
.wParam
) {
1035 struct dsoundrender_timer
*next
= cur
->next
;
1036 HeapFree(GetProcessHeap(), 0, cur
);
1044 ret
= PeekMessageW(&msg
, INVALID_HANDLE_VALUE
, WM_APP
, WM_APP
+ 4, PM_REMOVE
);
1046 MsgWaitForMultipleObjects(0, NULL
, 5, QS_POSTMESSAGE
, 0);
1051 /*** IUnknown methods ***/
1052 static HRESULT WINAPI
ReferenceClock_QueryInterface(IReferenceClock
*iface
,
1056 DSoundRenderImpl
*This
= impl_from_IReferenceClock(iface
);
1058 TRACE("(%p/%p)->(%s (%p), %p)\n", This
, iface
, debugstr_guid(riid
), riid
, ppvObj
);
1060 return DSoundRender_QueryInterface(&This
->renderer
.filter
.IBaseFilter_iface
, riid
, ppvObj
);
1063 static ULONG WINAPI
ReferenceClock_AddRef(IReferenceClock
*iface
)
1065 DSoundRenderImpl
*This
= impl_from_IReferenceClock(iface
);
1067 TRACE("(%p/%p)->()\n", This
, iface
);
1069 return BaseFilterImpl_AddRef(&This
->renderer
.filter
.IBaseFilter_iface
);
1072 static ULONG WINAPI
ReferenceClock_Release(IReferenceClock
*iface
)
1074 DSoundRenderImpl
*This
= impl_from_IReferenceClock(iface
);
1076 TRACE("(%p/%p)->()\n", This
, iface
);
1078 return DSoundRender_Release(&This
->renderer
.filter
.IBaseFilter_iface
);
1081 /*** IReferenceClock methods ***/
1082 static HRESULT WINAPI
ReferenceClock_GetTime(IReferenceClock
*iface
,
1083 REFERENCE_TIME
*pTime
)
1085 DSoundRenderImpl
*This
= impl_from_IReferenceClock(iface
);
1086 HRESULT hr
= E_FAIL
;
1088 TRACE("(%p/%p)->(%p)\n", This
, iface
, pTime
);
1092 if (This
->dsbuffer
) {
1093 DWORD writepos1
, writepos2
;
1094 EnterCriticalSection(&This
->renderer
.filter
.csFilter
);
1095 DSoundRender_UpdatePositions(This
, &writepos1
, &writepos2
);
1096 *pTime
= This
->play_time
+ time_from_pos(This
, This
->last_playpos
);
1097 LeaveCriticalSection(&This
->renderer
.filter
.csFilter
);
1101 WARN("Could not get reference time (%x)!\n", hr
);
1106 static HRESULT WINAPI
ReferenceClock_AdviseTime(IReferenceClock
*iface
,
1107 REFERENCE_TIME rtBaseTime
,
1108 REFERENCE_TIME rtStreamTime
,
1110 DWORD_PTR
*pdwAdviseCookie
)
1112 DSoundRenderImpl
*This
= impl_from_IReferenceClock(iface
);
1113 REFERENCE_TIME when
= rtBaseTime
+ rtStreamTime
;
1114 REFERENCE_TIME future
;
1115 TRACE("(%p/%p)->(%s, %s, %p, %p)\n", This
, iface
, wine_dbgstr_longlong(rtBaseTime
), wine_dbgstr_longlong(rtStreamTime
), (void*)hEvent
, pdwAdviseCookie
);
1118 return E_INVALIDARG
;
1120 if (!pdwAdviseCookie
)
1123 EnterCriticalSection(&This
->renderer
.filter
.csFilter
);
1124 future
= when
- This
->play_time
;
1125 if (!This
->threadid
&& This
->dsbuffer
) {
1126 This
->thread_wait
= CreateEventW(0, 0, 0, 0);
1127 This
->advisethread
= CreateThread(NULL
, 0, DSoundAdviseThread
, This
, 0, &This
->threadid
);
1128 WaitForSingleObject(This
->thread_wait
, INFINITE
);
1129 CloseHandle(This
->thread_wait
);
1131 LeaveCriticalSection(&This
->renderer
.filter
.csFilter
);
1132 /* If it's in the past or the next millisecond, trigger immediately */
1133 if (future
<= 10000) {
1134 SetEvent((HANDLE
)hEvent
);
1135 *pdwAdviseCookie
= 0;
1137 struct dsoundrender_timer
*t
= HeapAlloc(GetProcessHeap(), 0, sizeof(*t
));
1141 t
->handle
= (HANDLE
)hEvent
;
1142 t
->cookie
= InterlockedIncrement(&cookie_counter
);
1143 PostThreadMessageW(This
->threadid
, WM_APP
+1, (WPARAM
)t
, 0);
1144 *pdwAdviseCookie
= t
->cookie
;
1150 static HRESULT WINAPI
ReferenceClock_AdvisePeriodic(IReferenceClock
*iface
,
1151 REFERENCE_TIME rtStartTime
,
1152 REFERENCE_TIME rtPeriodTime
,
1153 HSEMAPHORE hSemaphore
,
1154 DWORD_PTR
*pdwAdviseCookie
)
1156 DSoundRenderImpl
*This
= impl_from_IReferenceClock(iface
);
1157 struct dsoundrender_timer
*t
;
1159 TRACE("(%p/%p)->(%s, %s, %p, %p)\n", This
, iface
, wine_dbgstr_longlong(rtStartTime
), wine_dbgstr_longlong(rtPeriodTime
), (void*)hSemaphore
, pdwAdviseCookie
);
1161 if (rtStartTime
<= 0 || rtPeriodTime
<= 0)
1162 return E_INVALIDARG
;
1164 if (!pdwAdviseCookie
)
1167 EnterCriticalSection(&This
->renderer
.filter
.csFilter
);
1168 if (!This
->threadid
&& This
->dsbuffer
) {
1169 This
->thread_wait
= CreateEventW(0, 0, 0, 0);
1170 This
->advisethread
= CreateThread(NULL
, 0, DSoundAdviseThread
, This
, 0, &This
->threadid
);
1171 WaitForSingleObject(This
->thread_wait
, INFINITE
);
1172 CloseHandle(This
->thread_wait
);
1174 LeaveCriticalSection(&This
->renderer
.filter
.csFilter
);
1176 t
= HeapAlloc(GetProcessHeap(), 0, sizeof(*t
));
1178 t
->start
= rtStartTime
;
1179 t
->periodicity
= rtPeriodTime
;
1180 t
->handle
= (HANDLE
)hSemaphore
;
1181 t
->cookie
= InterlockedIncrement(&cookie_counter
);
1182 PostThreadMessageW(This
->threadid
, WM_APP
+1, (WPARAM
)t
, 0);
1183 *pdwAdviseCookie
= t
->cookie
;
1188 static HRESULT WINAPI
ReferenceClock_Unadvise(IReferenceClock
*iface
,
1189 DWORD_PTR dwAdviseCookie
)
1191 DSoundRenderImpl
*This
= impl_from_IReferenceClock(iface
);
1193 TRACE("(%p/%p)->(%p)\n", This
, iface
, (void*)dwAdviseCookie
);
1194 if (!This
->advisethread
|| !dwAdviseCookie
)
1196 PostThreadMessageW(This
->threadid
, WM_APP
+3, dwAdviseCookie
, 0);
1200 static const IReferenceClockVtbl IReferenceClock_Vtbl
=
1202 ReferenceClock_QueryInterface
,
1203 ReferenceClock_AddRef
,
1204 ReferenceClock_Release
,
1205 ReferenceClock_GetTime
,
1206 ReferenceClock_AdviseTime
,
1207 ReferenceClock_AdvisePeriodic
,
1208 ReferenceClock_Unadvise
1211 /*** IUnknown methods ***/
1212 static HRESULT WINAPI
AMDirectSound_QueryInterface(IAMDirectSound
*iface
,
1216 DSoundRenderImpl
*This
= impl_from_IAMDirectSound(iface
);
1218 TRACE("(%p/%p)->(%s (%p), %p)\n", This
, iface
, debugstr_guid(riid
), riid
, ppvObj
);
1220 return DSoundRender_QueryInterface(&This
->renderer
.filter
.IBaseFilter_iface
, riid
, ppvObj
);
1223 static ULONG WINAPI
AMDirectSound_AddRef(IAMDirectSound
*iface
)
1225 DSoundRenderImpl
*This
= impl_from_IAMDirectSound(iface
);
1227 TRACE("(%p/%p)->()\n", This
, iface
);
1229 return BaseFilterImpl_AddRef(&This
->renderer
.filter
.IBaseFilter_iface
);
1232 static ULONG WINAPI
AMDirectSound_Release(IAMDirectSound
*iface
)
1234 DSoundRenderImpl
*This
= impl_from_IAMDirectSound(iface
);
1236 TRACE("(%p/%p)->()\n", This
, iface
);
1238 return DSoundRender_Release(&This
->renderer
.filter
.IBaseFilter_iface
);
1241 /*** IAMDirectSound methods ***/
1242 static HRESULT WINAPI
AMDirectSound_GetDirectSoundInterface(IAMDirectSound
*iface
, IDirectSound
**ds
)
1244 DSoundRenderImpl
*This
= impl_from_IAMDirectSound(iface
);
1246 FIXME("(%p/%p)->(%p): stub\n", This
, iface
, ds
);
1251 static HRESULT WINAPI
AMDirectSound_GetPrimaryBufferInterface(IAMDirectSound
*iface
, IDirectSoundBuffer
**buf
)
1253 DSoundRenderImpl
*This
= impl_from_IAMDirectSound(iface
);
1255 FIXME("(%p/%p)->(%p): stub\n", This
, iface
, buf
);
1260 static HRESULT WINAPI
AMDirectSound_GetSecondaryBufferInterface(IAMDirectSound
*iface
, IDirectSoundBuffer
**buf
)
1262 DSoundRenderImpl
*This
= impl_from_IAMDirectSound(iface
);
1264 FIXME("(%p/%p)->(%p): stub\n", This
, iface
, buf
);
1269 static HRESULT WINAPI
AMDirectSound_ReleaseDirectSoundInterface(IAMDirectSound
*iface
, IDirectSound
*ds
)
1271 DSoundRenderImpl
*This
= impl_from_IAMDirectSound(iface
);
1273 FIXME("(%p/%p)->(%p): stub\n", This
, iface
, ds
);
1278 static HRESULT WINAPI
AMDirectSound_ReleasePrimaryBufferInterface(IAMDirectSound
*iface
, IDirectSoundBuffer
*buf
)
1280 DSoundRenderImpl
*This
= impl_from_IAMDirectSound(iface
);
1282 FIXME("(%p/%p)->(%p): stub\n", This
, iface
, buf
);
1287 static HRESULT WINAPI
AMDirectSound_ReleaseSecondaryBufferInterface(IAMDirectSound
*iface
, IDirectSoundBuffer
*buf
)
1289 DSoundRenderImpl
*This
= impl_from_IAMDirectSound(iface
);
1291 FIXME("(%p/%p)->(%p): stub\n", This
, iface
, buf
);
1296 static HRESULT WINAPI
AMDirectSound_SetFocusWindow(IAMDirectSound
*iface
, HWND hwnd
, BOOL bgsilent
)
1298 DSoundRenderImpl
*This
= impl_from_IAMDirectSound(iface
);
1300 FIXME("(%p/%p)->(%p,%d): stub\n", This
, iface
, hwnd
, bgsilent
);
1305 static HRESULT WINAPI
AMDirectSound_GetFocusWindow(IAMDirectSound
*iface
, HWND hwnd
)
1307 DSoundRenderImpl
*This
= impl_from_IAMDirectSound(iface
);
1309 FIXME("(%p/%p)->(%p): stub\n", This
, iface
, hwnd
);
1314 static const IAMDirectSoundVtbl IAMDirectSound_Vtbl
=
1316 AMDirectSound_QueryInterface
,
1317 AMDirectSound_AddRef
,
1318 AMDirectSound_Release
,
1319 AMDirectSound_GetDirectSoundInterface
,
1320 AMDirectSound_GetPrimaryBufferInterface
,
1321 AMDirectSound_GetSecondaryBufferInterface
,
1322 AMDirectSound_ReleaseDirectSoundInterface
,
1323 AMDirectSound_ReleasePrimaryBufferInterface
,
1324 AMDirectSound_ReleaseSecondaryBufferInterface
,
1325 AMDirectSound_SetFocusWindow
,
1326 AMDirectSound_GetFocusWindow
1329 static HRESULT WINAPI
AMFilterMiscFlags_QueryInterface(IAMFilterMiscFlags
*iface
, REFIID riid
, void **ppv
) {
1330 DSoundRenderImpl
*This
= impl_from_IAMFilterMiscFlags(iface
);
1331 return IUnknown_QueryInterface((IUnknown
*)This
, riid
, ppv
);
1334 static ULONG WINAPI
AMFilterMiscFlags_AddRef(IAMFilterMiscFlags
*iface
) {
1335 DSoundRenderImpl
*This
= impl_from_IAMFilterMiscFlags(iface
);
1336 return IUnknown_AddRef((IUnknown
*)This
);
1339 static ULONG WINAPI
AMFilterMiscFlags_Release(IAMFilterMiscFlags
*iface
) {
1340 DSoundRenderImpl
*This
= impl_from_IAMFilterMiscFlags(iface
);
1341 return IUnknown_Release((IUnknown
*)This
);
1344 static ULONG WINAPI
AMFilterMiscFlags_GetMiscFlags(IAMFilterMiscFlags
*iface
) {
1345 return AM_FILTER_MISC_FLAGS_IS_RENDERER
;
1348 static const IAMFilterMiscFlagsVtbl IAMFilterMiscFlags_Vtbl
= {
1349 AMFilterMiscFlags_QueryInterface
,
1350 AMFilterMiscFlags_AddRef
,
1351 AMFilterMiscFlags_Release
,
1352 AMFilterMiscFlags_GetMiscFlags