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
;
57 typedef struct DSoundRenderImpl
61 const IBasicAudioVtbl
*IBasicAudio_vtbl
;
62 const IReferenceClockVtbl
*IReferenceClock_vtbl
;
63 const IAMDirectSoundVtbl
*IAMDirectSound_vtbl
;
64 const IAMFilterMiscFlagsVtbl
*IAMFilterMiscFlags_vtbl
;
65 IUnknown
*seekthru_unk
;
67 BaseInputPin
* pInputPin
;
69 IDirectSound8
*dsound
;
70 LPDIRECTSOUNDBUFFER dsbuffer
;
73 DWORD last_playpos
, writepos
;
75 REFERENCE_TIME play_time
;
77 HANDLE state_change
, blocked
;
83 static REFERENCE_TIME
time_from_pos(DSoundRenderImpl
*This
, DWORD pos
) {
84 WAVEFORMATEX
*wfx
= (WAVEFORMATEX
*)This
->pInputPin
->pin
.mtCurrent
.pbFormat
;
85 REFERENCE_TIME ret
= 10000000;
86 ret
= ret
* pos
/ wfx
->nAvgBytesPerSec
;
90 static DWORD
pos_from_time(DSoundRenderImpl
*This
, REFERENCE_TIME time
) {
91 WAVEFORMATEX
*wfx
= (WAVEFORMATEX
*)This
->pInputPin
->pin
.mtCurrent
.pbFormat
;
92 REFERENCE_TIME ret
= time
;
93 ret
*= wfx
->nSamplesPerSec
;
95 ret
*= wfx
->nBlockAlign
;
99 static void DSoundRender_UpdatePositions(DSoundRenderImpl
*This
, DWORD
*seqwritepos
, DWORD
*minwritepos
) {
100 WAVEFORMATEX
*wfx
= (WAVEFORMATEX
*)This
->pInputPin
->pin
.mtCurrent
.pbFormat
;
102 DWORD size1
, size2
, playpos
, writepos
, old_writepos
, old_playpos
, adv
;
103 BOOL writepos_set
= This
->writepos
< This
->buf_size
;
105 /* Update position and zero */
106 old_writepos
= This
->writepos
;
107 old_playpos
= This
->last_playpos
;
108 if (old_writepos
<= old_playpos
)
109 old_writepos
+= This
->buf_size
;
111 IDirectSoundBuffer_GetCurrentPosition(This
->dsbuffer
, &playpos
, &writepos
);
112 if (old_playpos
> playpos
) {
113 adv
= This
->buf_size
+ playpos
- old_playpos
;
114 This
->play_time
+= time_from_pos(This
, This
->buf_size
);
116 adv
= playpos
- old_playpos
;
117 This
->last_playpos
= playpos
;
119 TRACE("Moving from %u to %u: clearing %u bytes\n", old_playpos
, playpos
, adv
);
120 IDirectSoundBuffer_Lock(This
->dsbuffer
, old_playpos
, adv
, (void**)&buf1
, &size1
, (void**)&buf2
, &size2
, 0);
121 memset(buf1
, wfx
->wBitsPerSample
== 8 ? 128 : 0, size1
);
122 memset(buf2
, wfx
->wBitsPerSample
== 8 ? 128 : 0, size2
);
123 IDirectSoundBuffer_Unlock(This
->dsbuffer
, buf1
, size1
, buf2
, size2
);
125 *minwritepos
= writepos
;
126 if (!writepos_set
|| old_writepos
< writepos
) {
128 This
->writepos
= This
->buf_size
;
129 FIXME("Underrun of data occured!\n");
131 *seqwritepos
= writepos
;
133 *seqwritepos
= This
->writepos
;
136 static HRESULT
DSoundRender_GetWritePos(DSoundRenderImpl
*This
, DWORD
*ret_writepos
, REFERENCE_TIME write_at
, DWORD
*pfree
, DWORD
*skip
)
138 WAVEFORMATEX
*wfx
= (WAVEFORMATEX
*)This
->pInputPin
->pin
.mtCurrent
.pbFormat
;
139 DWORD writepos
, min_writepos
, playpos
;
140 REFERENCE_TIME max_lag
= 50 * 10000;
141 REFERENCE_TIME min_lag
= 1 * 10000;
142 REFERENCE_TIME cur
, writepos_t
, delta_t
;
144 DSoundRender_UpdatePositions(This
, &writepos
, &min_writepos
);
145 playpos
= This
->last_playpos
;
146 if (This
->filter
.pClock
== (IReferenceClock
*)&This
->IReferenceClock_vtbl
) {
148 cur
= This
->play_time
+ time_from_pos(This
, playpos
);
149 cur
-= This
->filter
.rtStreamStart
;
150 } else if (This
->filter
.pClock
) {
151 IReferenceClock_GetTime(This
->filter
.pClock
, &cur
);
152 cur
-= This
->filter
.rtStreamStart
;
156 if (writepos
== min_writepos
)
160 if (cur
< 0 || write_at
< 0) {
161 *ret_writepos
= writepos
;
165 if (writepos
>= playpos
)
166 writepos_t
= cur
+ time_from_pos(This
, writepos
- playpos
);
168 writepos_t
= cur
+ time_from_pos(This
, This
->buf_size
+ writepos
- playpos
);
170 /* write_at: Starting time of sample */
171 /* cur: current time of play position */
172 /* writepos_t: current time of our pointer play position */
173 delta_t
= write_at
- writepos_t
;
174 if (delta_t
>= -max_lag
&& delta_t
<= max_lag
) {
175 TRACE("Continuing from old position\n");
176 *ret_writepos
= writepos
;
177 } else if (delta_t
< 0) {
178 REFERENCE_TIME past
, min_writepos_t
;
179 FIXME("Delta too big %i/%i, overwriting old data or even skipping\n", (int)delta_t
/ 10000, (int)max_lag
/ 10000);
180 if (min_writepos
>= playpos
)
181 min_writepos_t
= cur
+ time_from_pos(This
, min_writepos
- playpos
);
183 min_writepos_t
= cur
+ time_from_pos(This
, This
->buf_size
- playpos
+ min_writepos
);
184 past
= min_writepos_t
- write_at
;
186 DWORD skipbytes
= pos_from_time(This
, past
);
187 FIXME("Skipping %u bytes\n", skipbytes
);
189 *ret_writepos
= min_writepos
;
191 DWORD aheadbytes
= pos_from_time(This
, -past
);
192 FIXME("Advancing %u bytes\n", aheadbytes
);
193 *ret_writepos
= (min_writepos
+ aheadbytes
) % This
->buf_size
;
195 } else /* delta_t > 0 */ {
197 FIXME("Delta too big %i/%i, too far ahead\n", (int)delta_t
/ 10000, (int)max_lag
/ 10000);
198 aheadbytes
= pos_from_time(This
, delta_t
);
199 FIXME("Advancing %u bytes\n", aheadbytes
);
200 if (delta_t
>= DSoundRenderer_Max_Fill
)
202 *ret_writepos
= (min_writepos
+ aheadbytes
) % This
->buf_size
;
205 if (playpos
> *ret_writepos
)
206 *pfree
= playpos
- *ret_writepos
;
207 else if (playpos
== *ret_writepos
)
208 *pfree
= This
->buf_size
- wfx
->nBlockAlign
;
210 *pfree
= This
->buf_size
+ playpos
- *ret_writepos
;
211 if (time_from_pos(This
, This
->buf_size
- *pfree
) >= DSoundRenderer_Max_Fill
) {
212 TRACE("Blocked: too full %i / %i\n", (int)(time_from_pos(This
, This
->buf_size
- *pfree
)/10000), (int)(DSoundRenderer_Max_Fill
/ 10000));
218 static HRESULT
DSoundRender_SendSampleData(DSoundRenderImpl
* This
, REFERENCE_TIME tStart
, REFERENCE_TIME tStop
, const BYTE
*data
, DWORD size
)
222 while (size
&& This
->filter
.state
!= State_Stopped
) {
223 DWORD writepos
, skip
= 0, free
, size1
, size2
, ret
;
226 if (This
->filter
.state
== State_Running
)
227 hr
= DSoundRender_GetWritePos(This
, &writepos
, tStart
, &free
, &skip
);
233 LeaveCriticalSection(&This
->filter
.csFilter
);
234 ret
= WaitForSingleObject(This
->blocked
, 10);
235 EnterCriticalSection(&This
->filter
.csFilter
);
237 if (This
->pInputPin
->flushing
||
238 This
->filter
.state
== State_Stopped
) {
239 SetEvent(This
->state_change
);
240 return This
->filter
.state
== State_Paused
? S_OK
: VFW_E_WRONG_STATE
;
242 if (ret
!= WAIT_TIMEOUT
)
249 FIXME("Sample dropped %u of %u bytes\n", skip
, size
);
255 hr
= IDirectSoundBuffer_Lock(This
->dsbuffer
, writepos
, min(free
, size
), (void**)&buf1
, &size1
, (void**)&buf2
, &size2
, 0);
257 ERR("Unable to lock sound buffer! (%x)\n", hr
);
260 memcpy(buf1
, data
, size1
);
262 memcpy(buf2
, data
+size1
, size2
);
263 IDirectSoundBuffer_Unlock(This
->dsbuffer
, buf1
, size1
, buf2
, size2
);
264 This
->writepos
= (writepos
+ size1
+ size2
) % This
->buf_size
;
265 TRACE("Wrote %u bytes at %u, next at %u - (%u/%u)\n", size1
+size2
, writepos
, This
->writepos
, free
, size
);
266 data
+= size1
+ size2
;
267 size
-= size1
+ size2
;
272 static HRESULT WINAPI
DSoundRender_Receive(BaseInputPin
*pin
, IMediaSample
* pSample
)
274 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)pin
->pin
.pinInfo
.pFilter
;
275 LPBYTE pbSrcStream
= NULL
;
276 LONG cbSrcStream
= 0;
277 REFERENCE_TIME tStart
, tStop
;
281 TRACE("%p %p\n", pin
, pSample
);
283 /* Slightly incorrect, Pause completes when a frame is received so we should signal
284 * pause completion here, but for sound playing a single frame doesn't make sense
287 EnterCriticalSection(&This
->filter
.csFilter
);
289 if (This
->pInputPin
->end_of_stream
|| This
->pInputPin
->flushing
)
291 LeaveCriticalSection(&This
->filter
.csFilter
);
295 if (This
->filter
.state
== State_Stopped
)
297 LeaveCriticalSection(&This
->filter
.csFilter
);
298 return VFW_E_WRONG_STATE
;
301 if (IMediaSample_GetMediaType(pSample
, &amt
) == S_OK
)
303 AM_MEDIA_TYPE
*orig
= &This
->pInputPin
->pin
.mtCurrent
;
304 WAVEFORMATEX
*origfmt
= (WAVEFORMATEX
*)orig
->pbFormat
;
305 WAVEFORMATEX
*newfmt
= (WAVEFORMATEX
*)amt
->pbFormat
;
307 if (origfmt
->wFormatTag
== newfmt
->wFormatTag
&&
308 origfmt
->nChannels
== newfmt
->nChannels
&&
309 origfmt
->nBlockAlign
== newfmt
->nBlockAlign
&&
310 origfmt
->wBitsPerSample
== newfmt
->wBitsPerSample
&&
311 origfmt
->cbSize
== newfmt
->cbSize
)
313 if (origfmt
->nSamplesPerSec
!= newfmt
->nSamplesPerSec
)
315 hr
= IDirectSoundBuffer_SetFrequency(This
->dsbuffer
,
316 newfmt
->nSamplesPerSec
);
319 LeaveCriticalSection(&This
->filter
.csFilter
);
320 return VFW_E_TYPE_NOT_ACCEPTED
;
323 CopyMediaType(orig
, amt
);
324 IMediaSample_SetMediaType(pSample
, NULL
);
329 LeaveCriticalSection(&This
->filter
.csFilter
);
330 return VFW_E_TYPE_NOT_ACCEPTED
;
334 hr
= IMediaSample_GetPointer(pSample
, &pbSrcStream
);
337 ERR("Cannot get pointer to sample data (%x)\n", hr
);
338 LeaveCriticalSection(&This
->filter
.csFilter
);
342 if (IMediaSample_GetMediaTime(pSample
, &tStart
, &tStop
) == S_OK
)
343 MediaSeekingPassThru_RegisterMediaTime(This
->seekthru_unk
, tStart
);
344 hr
= IMediaSample_GetTime(pSample
, &tStart
, &tStop
);
346 ERR("Cannot get sample time (%x)\n", hr
);
348 IMediaSample_IsDiscontinuity(pSample
);
350 if (IMediaSample_IsPreroll(pSample
) == S_OK
)
353 LeaveCriticalSection(&This
->filter
.csFilter
);
357 cbSrcStream
= IMediaSample_GetActualDataLength(pSample
);
358 TRACE("Sample data ptr = %p, size = %d\n", pbSrcStream
, cbSrcStream
);
360 SetEvent(This
->state_change
);
361 hr
= DSoundRender_SendSampleData(This
, tStart
, tStop
, pbSrcStream
, cbSrcStream
);
362 LeaveCriticalSection(&This
->filter
.csFilter
);
366 static HRESULT WINAPI
DSoundRender_CheckMediaType(BasePin
*iface
, const AM_MEDIA_TYPE
* pmt
)
368 WAVEFORMATEX
* format
;
370 if (!IsEqualIID(&pmt
->majortype
, &MEDIATYPE_Audio
))
373 format
= (WAVEFORMATEX
*)pmt
->pbFormat
;
374 TRACE("Format = %p\n", format
);
375 TRACE("wFormatTag = %x %x\n", format
->wFormatTag
, WAVE_FORMAT_PCM
);
376 TRACE("nChannels = %d\n", format
->nChannels
);
377 TRACE("nSamplesPerSec = %d\n", format
->nAvgBytesPerSec
);
378 TRACE("nAvgBytesPerSec = %d\n", format
->nAvgBytesPerSec
);
379 TRACE("nBlockAlign = %d\n", format
->nBlockAlign
);
380 TRACE("wBitsPerSample = %d\n", format
->wBitsPerSample
);
382 if (!IsEqualIID(&pmt
->subtype
, &MEDIASUBTYPE_PCM
))
388 static IPin
* WINAPI
DSoundRender_GetPin(BaseFilter
*iface
, int pos
)
390 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
392 if (pos
>= 1 || pos
< 0)
395 IPin_AddRef((IPin
*)This
->pInputPin
);
396 return (IPin
*)This
->pInputPin
;
399 static LONG WINAPI
DSoundRender_GetPinCount(BaseFilter
*iface
)
401 /* Our pins are static */
405 static const BaseFilterFuncTable BaseFuncTable
= {
407 DSoundRender_GetPinCount
410 static const BasePinFuncTable input_BaseFuncTable
= {
411 DSoundRender_CheckMediaType
,
413 BasePinImpl_GetMediaTypeVersion
,
414 BasePinImpl_GetMediaType
417 static const BaseInputPinFuncTable input_BaseInputFuncTable
= {
422 HRESULT
DSoundRender_create(IUnknown
* pUnkOuter
, LPVOID
* ppv
)
426 DSoundRenderImpl
* pDSoundRender
;
428 TRACE("(%p, %p)\n", pUnkOuter
, ppv
);
433 return CLASS_E_NOAGGREGATION
;
435 pDSoundRender
= CoTaskMemAlloc(sizeof(DSoundRenderImpl
));
437 return E_OUTOFMEMORY
;
438 ZeroMemory(pDSoundRender
, sizeof(DSoundRenderImpl
));
440 BaseFilter_Init(&pDSoundRender
->filter
, &DSoundRender_Vtbl
, &CLSID_DSoundRender
, (DWORD_PTR
)(__FILE__
": DSoundRenderImpl.csFilter"), &BaseFuncTable
);
442 pDSoundRender
->IBasicAudio_vtbl
= &IBasicAudio_Vtbl
;
443 pDSoundRender
->IReferenceClock_vtbl
= &IReferenceClock_Vtbl
;
444 pDSoundRender
->IAMDirectSound_vtbl
= &IAMDirectSound_Vtbl
;
445 pDSoundRender
->IAMFilterMiscFlags_vtbl
= &IAMFilterMiscFlags_Vtbl
;
447 /* construct input pin */
448 piInput
.dir
= PINDIR_INPUT
;
449 piInput
.pFilter
= (IBaseFilter
*)pDSoundRender
;
450 lstrcpynW(piInput
.achName
, wcsInputPinName
, sizeof(piInput
.achName
) / sizeof(piInput
.achName
[0]));
451 hr
= BaseInputPin_Construct(&DSoundRender_InputPin_Vtbl
, &piInput
, &input_BaseFuncTable
, &input_BaseInputFuncTable
, &pDSoundRender
->filter
.csFilter
, NULL
, (IPin
**)&pDSoundRender
->pInputPin
);
455 hr
= DirectSoundCreate8(NULL
, &pDSoundRender
->dsound
, NULL
);
457 ERR("Cannot create Direct Sound object (%x)\n", hr
);
459 hr
= IDirectSound_SetCooperativeLevel(pDSoundRender
->dsound
, GetDesktopWindow(), DSSCL_PRIORITY
);
461 IDirectSoundBuffer
*buf
;
462 DSBUFFERDESC buf_desc
;
463 memset(&buf_desc
,0,sizeof(DSBUFFERDESC
));
464 buf_desc
.dwSize
= sizeof(DSBUFFERDESC
);
465 buf_desc
.dwFlags
= DSBCAPS_PRIMARYBUFFER
;
466 hr
= IDirectSound_CreateSoundBuffer(pDSoundRender
->dsound
, &buf_desc
, &buf
, NULL
);
468 IDirectSoundBuffer_Play(buf
, 0, 0, DSBPLAY_LOOPING
);
469 IUnknown_Release(buf
);
477 ISeekingPassThru
*passthru
;
478 pDSoundRender
->state_change
= CreateEventW(NULL
, TRUE
, TRUE
, NULL
);
479 pDSoundRender
->blocked
= CreateEventW(NULL
, TRUE
, TRUE
, NULL
);
480 hr
= CoCreateInstance(&CLSID_SeekingPassThru
, (IUnknown
*)pDSoundRender
, CLSCTX_INPROC_SERVER
, &IID_IUnknown
, (void**)&pDSoundRender
->seekthru_unk
);
481 if (!pDSoundRender
->state_change
|| !pDSoundRender
->blocked
|| FAILED(hr
))
483 IUnknown_Release((IUnknown
*)pDSoundRender
);
484 return HRESULT_FROM_WIN32(GetLastError());
487 IUnknown_QueryInterface(pDSoundRender
->seekthru_unk
, &IID_ISeekingPassThru
, (void**)&passthru
);
488 ISeekingPassThru_Init(passthru
, TRUE
, (IPin
*)pDSoundRender
->pInputPin
);
489 ISeekingPassThru_Release(passthru
);
490 *ppv
= pDSoundRender
;
494 if (pDSoundRender
->pInputPin
)
495 IPin_Release((IPin
*)pDSoundRender
->pInputPin
);
496 BaseFilterImpl_Release((IBaseFilter
*)pDSoundRender
);
497 CoTaskMemFree(pDSoundRender
);
503 static HRESULT WINAPI
DSoundRender_QueryInterface(IBaseFilter
* iface
, REFIID riid
, LPVOID
* ppv
)
505 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
506 TRACE("(%p, %p)->(%s, %p)\n", This
, iface
, qzdebugstr_guid(riid
), ppv
);
510 if (IsEqualIID(riid
, &IID_IUnknown
))
512 else if (IsEqualIID(riid
, &IID_IPersist
))
514 else if (IsEqualIID(riid
, &IID_IMediaFilter
))
516 else if (IsEqualIID(riid
, &IID_IBaseFilter
))
518 else if (IsEqualIID(riid
, &IID_IBasicAudio
))
519 *ppv
= &This
->IBasicAudio_vtbl
;
520 else if (IsEqualIID(riid
, &IID_IReferenceClock
))
521 *ppv
= &This
->IReferenceClock_vtbl
;
522 else if (IsEqualIID(riid
, &IID_IMediaSeeking
))
523 return IUnknown_QueryInterface(This
->seekthru_unk
, riid
, ppv
);
524 else if (IsEqualIID(riid
, &IID_IAMDirectSound
))
525 *ppv
= &This
->IAMDirectSound_vtbl
;
526 else if (IsEqualIID(riid
, &IID_IAMFilterMiscFlags
))
527 *ppv
= &This
->IAMFilterMiscFlags_vtbl
;
531 IUnknown_AddRef((IUnknown
*)(*ppv
));
535 if (!IsEqualIID(riid
, &IID_IPin
) && !IsEqualIID(riid
, &IID_IVideoWindow
))
536 FIXME("No interface for %s!\n", qzdebugstr_guid(riid
));
538 return E_NOINTERFACE
;
541 static ULONG WINAPI
DSoundRender_Release(IBaseFilter
* iface
)
543 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
544 ULONG refCount
= BaseFilterImpl_Release(iface
);
546 TRACE("(%p)->() Release from %d\n", This
, refCount
+ 1);
553 IDirectSoundBuffer_Release(This
->dsbuffer
);
554 This
->dsbuffer
= NULL
;
556 IDirectSound_Release(This
->dsound
);
559 if (SUCCEEDED(IPin_ConnectedTo((IPin
*)This
->pInputPin
, &pConnectedTo
)))
561 IPin_Disconnect(pConnectedTo
);
562 IPin_Release(pConnectedTo
);
564 IPin_Disconnect((IPin
*)This
->pInputPin
);
566 IPin_Release((IPin
*)This
->pInputPin
);
568 This
->IBasicAudio_vtbl
= NULL
;
569 if (This
->seekthru_unk
)
570 IUnknown_Release(This
->seekthru_unk
);
572 CloseHandle(This
->state_change
);
573 CloseHandle(This
->blocked
);
575 TRACE("Destroying Audio Renderer\n");
584 /** IMediaFilter methods **/
586 static HRESULT WINAPI
DSoundRender_Stop(IBaseFilter
* iface
)
589 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
591 TRACE("(%p/%p)->()\n", This
, iface
);
593 EnterCriticalSection(&This
->filter
.csFilter
);
595 hr
= IDirectSoundBuffer_Stop(This
->dsbuffer
);
597 This
->filter
.state
= State_Stopped
;
599 /* Complete our transition */
600 This
->writepos
= This
->buf_size
;
601 SetEvent(This
->state_change
);
602 SetEvent(This
->blocked
);
603 MediaSeekingPassThru_ResetMediaTime(This
->seekthru_unk
);
605 LeaveCriticalSection(&This
->filter
.csFilter
);
610 static HRESULT WINAPI
DSoundRender_Pause(IBaseFilter
* iface
)
613 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
615 TRACE("(%p/%p)->()\n", This
, iface
);
617 EnterCriticalSection(&This
->filter
.csFilter
);
618 if (This
->filter
.state
!= State_Paused
)
620 if (This
->filter
.state
== State_Stopped
)
622 This
->pInputPin
->end_of_stream
= 0;
625 hr
= IDirectSoundBuffer_Stop(This
->dsbuffer
);
627 This
->filter
.state
= State_Paused
;
629 ResetEvent(This
->blocked
);
630 ResetEvent(This
->state_change
);
632 LeaveCriticalSection(&This
->filter
.csFilter
);
637 static HRESULT WINAPI
DSoundRender_Run(IBaseFilter
* iface
, REFERENCE_TIME tStart
)
640 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
642 TRACE("(%p/%p)->(%s)\n", This
, iface
, wine_dbgstr_longlong(tStart
));
644 EnterCriticalSection(&This
->filter
.csFilter
);
645 if (This
->pInputPin
->pin
.pConnectedTo
)
647 This
->filter
.rtStreamStart
= tStart
;
648 if (This
->filter
.state
== State_Paused
)
650 /* Unblock our thread, state changing from paused to running doesn't need a reset for state change */
651 SetEvent(This
->blocked
);
653 else if (This
->filter
.state
== State_Stopped
)
655 ResetEvent(This
->state_change
);
656 This
->pInputPin
->end_of_stream
= 0;
658 IDirectSoundBuffer_Play(This
->dsbuffer
, 0, 0, DSBPLAY_LOOPING
);
659 ResetEvent(This
->blocked
);
660 } else if (This
->filter
.filterInfo
.pGraph
) {
661 IMediaEventSink
*pEventSink
;
662 hr
= IFilterGraph_QueryInterface(This
->filter
.filterInfo
.pGraph
, &IID_IMediaEventSink
, (LPVOID
*)&pEventSink
);
665 hr
= IMediaEventSink_Notify(pEventSink
, EC_COMPLETE
, S_OK
, (LONG_PTR
)This
);
666 IMediaEventSink_Release(pEventSink
);
671 This
->filter
.state
= State_Running
;
672 LeaveCriticalSection(&This
->filter
.csFilter
);
677 static HRESULT WINAPI
DSoundRender_GetState(IBaseFilter
* iface
, DWORD dwMilliSecsTimeout
, FILTER_STATE
*pState
)
680 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
682 TRACE("(%p/%p)->(%d, %p)\n", This
, iface
, dwMilliSecsTimeout
, pState
);
684 if (WaitForSingleObject(This
->state_change
, dwMilliSecsTimeout
) == WAIT_TIMEOUT
)
685 hr
= VFW_S_STATE_INTERMEDIATE
;
689 BaseFilterImpl_GetState(iface
, dwMilliSecsTimeout
, pState
);
694 /** IBaseFilter implementation **/
696 static HRESULT WINAPI
DSoundRender_FindPin(IBaseFilter
* iface
, LPCWSTR Id
, IPin
**ppPin
)
698 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
700 TRACE("(%p/%p)->(%s,%p)\n", This
, iface
, debugstr_w(Id
), ppPin
);
702 FIXME("DSoundRender::FindPin(...)\n");
704 /* FIXME: critical section */
709 static const IBaseFilterVtbl DSoundRender_Vtbl
=
711 DSoundRender_QueryInterface
,
712 BaseFilterImpl_AddRef
,
713 DSoundRender_Release
,
714 BaseFilterImpl_GetClassID
,
718 DSoundRender_GetState
,
719 BaseFilterImpl_SetSyncSource
,
720 BaseFilterImpl_GetSyncSource
,
721 BaseFilterImpl_EnumPins
,
722 DSoundRender_FindPin
,
723 BaseFilterImpl_QueryFilterInfo
,
724 BaseFilterImpl_JoinFilterGraph
,
725 BaseFilterImpl_QueryVendorInfo
728 static HRESULT WINAPI
DSoundRender_InputPin_ReceiveConnection(IPin
* iface
, IPin
* pReceivePin
, const AM_MEDIA_TYPE
* pmt
)
730 BaseInputPin
*This
= (BaseInputPin
*)iface
;
731 PIN_DIRECTION pindirReceive
;
732 DSoundRenderImpl
*DSImpl
;
735 TRACE("(%p)->(%p, %p)\n", This
, pReceivePin
, pmt
);
736 dump_AM_MEDIA_TYPE(pmt
);
738 EnterCriticalSection(This
->pin
.pCritSec
);
740 DSImpl
= (DSoundRenderImpl
*)This
->pin
.pinInfo
.pFilter
;
742 if (This
->pin
.pConnectedTo
)
743 hr
= VFW_E_ALREADY_CONNECTED
;
745 if (SUCCEEDED(hr
) && This
->pin
.pFuncsTable
->pfnCheckMediaType((BasePin
*)This
, pmt
) != S_OK
)
746 hr
= VFW_E_TYPE_NOT_ACCEPTED
;
750 IPin_QueryDirection(pReceivePin
, &pindirReceive
);
752 if (pindirReceive
!= PINDIR_OUTPUT
)
754 ERR("Can't connect from non-output pin\n");
755 hr
= VFW_E_INVALID_DIRECTION
;
761 WAVEFORMATEX
*format
;
762 DSBUFFERDESC buf_desc
;
764 TRACE("MajorType %s\n", debugstr_guid(&pmt
->majortype
));
765 TRACE("SubType %s\n", debugstr_guid(&pmt
->subtype
));
766 TRACE("Format %s\n", debugstr_guid(&pmt
->formattype
));
767 TRACE("Size %d\n", pmt
->cbFormat
);
769 format
= (WAVEFORMATEX
*)pmt
->pbFormat
;
771 DSImpl
->buf_size
= format
->nAvgBytesPerSec
;
773 memset(&buf_desc
,0,sizeof(DSBUFFERDESC
));
774 buf_desc
.dwSize
= sizeof(DSBUFFERDESC
);
775 buf_desc
.dwFlags
= DSBCAPS_CTRLVOLUME
| DSBCAPS_CTRLPAN
|
776 DSBCAPS_CTRLFREQUENCY
| DSBCAPS_GLOBALFOCUS
|
777 DSBCAPS_GETCURRENTPOSITION2
;
778 buf_desc
.dwBufferBytes
= DSImpl
->buf_size
;
779 buf_desc
.lpwfxFormat
= format
;
780 hr
= IDirectSound_CreateSoundBuffer(DSImpl
->dsound
, &buf_desc
, &DSImpl
->dsbuffer
, NULL
);
781 DSImpl
->writepos
= DSImpl
->buf_size
;
783 ERR("Can't create sound buffer (%x)\n", hr
);
788 hr
= IDirectSoundBuffer_SetVolume(DSImpl
->dsbuffer
, DSImpl
->volume
);
790 ERR("Can't set volume to %d (%x)\n", DSImpl
->volume
, hr
);
792 hr
= IDirectSoundBuffer_SetPan(DSImpl
->dsbuffer
, DSImpl
->pan
);
794 ERR("Can't set pan to %d (%x)\n", DSImpl
->pan
, hr
);
800 CopyMediaType(&This
->pin
.mtCurrent
, pmt
);
801 This
->pin
.pConnectedTo
= pReceivePin
;
802 IPin_AddRef(pReceivePin
);
804 else if (hr
!= VFW_E_ALREADY_CONNECTED
)
806 if (DSImpl
->dsbuffer
)
807 IDirectSoundBuffer_Release(DSImpl
->dsbuffer
);
808 DSImpl
->dsbuffer
= NULL
;
811 LeaveCriticalSection(This
->pin
.pCritSec
);
816 static HRESULT WINAPI
DSoundRender_InputPin_Disconnect(IPin
* iface
)
818 BasePin
*This
= (BasePin
*)iface
;
819 DSoundRenderImpl
*DSImpl
;
821 TRACE("(%p)->()\n", iface
);
823 DSImpl
= (DSoundRenderImpl
*)This
->pinInfo
.pFilter
;
824 if (DSImpl
->dsbuffer
)
825 IDirectSoundBuffer_Release(DSImpl
->dsbuffer
);
826 DSImpl
->dsbuffer
= NULL
;
828 return BasePinImpl_Disconnect(iface
);
831 static HRESULT WINAPI
DSoundRender_InputPin_EndOfStream(IPin
* iface
)
833 BaseInputPin
* This
= (BaseInputPin
*)iface
;
834 DSoundRenderImpl
*me
= (DSoundRenderImpl
*)This
->pin
.pinInfo
.pFilter
;
835 IMediaEventSink
* pEventSink
;
838 EnterCriticalSection(This
->pin
.pCritSec
);
840 TRACE("(%p/%p)->()\n", This
, iface
);
841 hr
= BaseInputPinImpl_EndOfStream(iface
);
845 LeaveCriticalSection(This
->pin
.pCritSec
);
849 if (me
->filter
.filterInfo
.pGraph
)
851 hr
= IFilterGraph_QueryInterface(me
->filter
.filterInfo
.pGraph
, &IID_IMediaEventSink
, (LPVOID
*)&pEventSink
);
854 hr
= IMediaEventSink_Notify(pEventSink
, EC_COMPLETE
, S_OK
, (LONG_PTR
)me
);
855 IMediaEventSink_Release(pEventSink
);
858 MediaSeekingPassThru_EOS(me
->seekthru_unk
);
859 LeaveCriticalSection(This
->pin
.pCritSec
);
864 static HRESULT WINAPI
DSoundRender_InputPin_BeginFlush(IPin
* iface
)
866 BaseInputPin
*This
= (BaseInputPin
*)iface
;
867 DSoundRenderImpl
*pFilter
= (DSoundRenderImpl
*)This
->pin
.pinInfo
.pFilter
;
872 EnterCriticalSection(This
->pin
.pCritSec
);
873 hr
= BaseInputPinImpl_BeginFlush(iface
);
874 SetEvent(pFilter
->blocked
);
875 LeaveCriticalSection(This
->pin
.pCritSec
);
880 static HRESULT WINAPI
DSoundRender_InputPin_EndFlush(IPin
* iface
)
882 BaseInputPin
*This
= (BaseInputPin
*)iface
;
883 DSoundRenderImpl
*pFilter
= (DSoundRenderImpl
*)This
->pin
.pinInfo
.pFilter
;
888 EnterCriticalSection(This
->pin
.pCritSec
);
889 if (pFilter
->in_loop
) {
890 ResetEvent(pFilter
->state_change
);
891 LeaveCriticalSection(This
->pin
.pCritSec
);
892 WaitForSingleObject(pFilter
->state_change
, -1);
893 EnterCriticalSection(This
->pin
.pCritSec
);
895 if (pFilter
->filter
.state
!= State_Stopped
)
896 ResetEvent(pFilter
->blocked
);
898 if (pFilter
->dsbuffer
)
904 IDirectSoundBuffer_Lock(pFilter
->dsbuffer
, 0, 0, (LPVOID
*)&buffer
, &size
, NULL
, NULL
, DSBLOCK_ENTIREBUFFER
);
905 memset(buffer
, 0, size
);
906 IDirectSoundBuffer_Unlock(pFilter
->dsbuffer
, buffer
, size
, NULL
, 0);
907 pFilter
->writepos
= pFilter
->buf_size
;
909 hr
= BaseInputPinImpl_EndFlush(iface
);
910 LeaveCriticalSection(This
->pin
.pCritSec
);
911 MediaSeekingPassThru_ResetMediaTime(pFilter
->seekthru_unk
);
916 static const IPinVtbl DSoundRender_InputPin_Vtbl
=
918 BaseInputPinImpl_QueryInterface
,
920 BaseInputPinImpl_Release
,
921 BaseInputPinImpl_Connect
,
922 DSoundRender_InputPin_ReceiveConnection
,
923 DSoundRender_InputPin_Disconnect
,
924 BasePinImpl_ConnectedTo
,
925 BasePinImpl_ConnectionMediaType
,
926 BasePinImpl_QueryPinInfo
,
927 BasePinImpl_QueryDirection
,
929 BaseInputPinImpl_QueryAccept
,
930 BasePinImpl_EnumMediaTypes
,
931 BasePinImpl_QueryInternalConnections
,
932 DSoundRender_InputPin_EndOfStream
,
933 DSoundRender_InputPin_BeginFlush
,
934 DSoundRender_InputPin_EndFlush
,
935 BaseInputPinImpl_NewSegment
938 /*** IUnknown methods ***/
939 static HRESULT WINAPI
Basicaudio_QueryInterface(IBasicAudio
*iface
,
942 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
944 TRACE("(%p/%p)->(%s (%p), %p)\n", This
, iface
, debugstr_guid(riid
), riid
, ppvObj
);
946 return DSoundRender_QueryInterface((IBaseFilter
*)This
, riid
, ppvObj
);
949 static ULONG WINAPI
Basicaudio_AddRef(IBasicAudio
*iface
) {
950 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
952 TRACE("(%p/%p)->()\n", This
, iface
);
954 return BaseFilterImpl_AddRef((IBaseFilter
*)This
);
957 static ULONG WINAPI
Basicaudio_Release(IBasicAudio
*iface
) {
958 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
960 TRACE("(%p/%p)->()\n", This
, iface
);
962 return DSoundRender_Release((IBaseFilter
*)This
);
965 /*** IDispatch methods ***/
966 static HRESULT WINAPI
Basicaudio_GetTypeInfoCount(IBasicAudio
*iface
,
968 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
970 TRACE("(%p/%p)->(%p): stub !!!\n", This
, iface
, pctinfo
);
975 static HRESULT WINAPI
Basicaudio_GetTypeInfo(IBasicAudio
*iface
,
978 ITypeInfo
**ppTInfo
) {
979 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
981 TRACE("(%p/%p)->(%d, %d, %p): stub !!!\n", This
, iface
, iTInfo
, lcid
, ppTInfo
);
986 static HRESULT WINAPI
Basicaudio_GetIDsOfNames(IBasicAudio
*iface
,
992 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
994 TRACE("(%p/%p)->(%s (%p), %p, %d, %d, %p): stub !!!\n", This
, iface
, debugstr_guid(riid
), riid
, rgszNames
, cNames
, lcid
, rgDispId
);
999 static HRESULT WINAPI
Basicaudio_Invoke(IBasicAudio
*iface
,
1000 DISPID dispIdMember
,
1004 DISPPARAMS
*pDispParams
,
1006 EXCEPINFO
*pExepInfo
,
1008 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
1010 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
);
1015 /*** IBasicAudio methods ***/
1016 static HRESULT WINAPI
Basicaudio_put_Volume(IBasicAudio
*iface
,
1018 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
1020 TRACE("(%p/%p)->(%d)\n", This
, iface
, lVolume
);
1022 if (lVolume
> DSBVOLUME_MAX
|| lVolume
< DSBVOLUME_MIN
)
1023 return E_INVALIDARG
;
1025 if (This
->dsbuffer
) {
1026 if (FAILED(IDirectSoundBuffer_SetVolume(This
->dsbuffer
, lVolume
)))
1030 This
->volume
= lVolume
;
1034 static HRESULT WINAPI
Basicaudio_get_Volume(IBasicAudio
*iface
,
1036 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
1038 TRACE("(%p/%p)->(%p)\n", This
, iface
, plVolume
);
1043 *plVolume
= This
->volume
;
1047 static HRESULT WINAPI
Basicaudio_put_Balance(IBasicAudio
*iface
,
1049 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
1051 TRACE("(%p/%p)->(%d)\n", This
, iface
, lBalance
);
1053 if (lBalance
< DSBPAN_LEFT
|| lBalance
> DSBPAN_RIGHT
)
1054 return E_INVALIDARG
;
1056 if (This
->dsbuffer
) {
1057 if (FAILED(IDirectSoundBuffer_SetPan(This
->dsbuffer
, lBalance
)))
1061 This
->pan
= lBalance
;
1065 static HRESULT WINAPI
Basicaudio_get_Balance(IBasicAudio
*iface
,
1067 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
1069 TRACE("(%p/%p)->(%p)\n", This
, iface
, plBalance
);
1074 *plBalance
= This
->pan
;
1078 static const IBasicAudioVtbl IBasicAudio_Vtbl
=
1080 Basicaudio_QueryInterface
,
1083 Basicaudio_GetTypeInfoCount
,
1084 Basicaudio_GetTypeInfo
,
1085 Basicaudio_GetIDsOfNames
,
1087 Basicaudio_put_Volume
,
1088 Basicaudio_get_Volume
,
1089 Basicaudio_put_Balance
,
1090 Basicaudio_get_Balance
1094 /*** IUnknown methods ***/
1095 static HRESULT WINAPI
ReferenceClock_QueryInterface(IReferenceClock
*iface
,
1099 ICOM_THIS_MULTI(DSoundRenderImpl
, IReferenceClock_vtbl
, iface
);
1101 TRACE("(%p/%p)->(%s (%p), %p)\n", This
, iface
, debugstr_guid(riid
), riid
, ppvObj
);
1103 return DSoundRender_QueryInterface((IBaseFilter
*)This
, riid
, ppvObj
);
1106 static ULONG WINAPI
ReferenceClock_AddRef(IReferenceClock
*iface
)
1108 ICOM_THIS_MULTI(DSoundRenderImpl
, IReferenceClock_vtbl
, iface
);
1110 TRACE("(%p/%p)->()\n", This
, iface
);
1112 return BaseFilterImpl_AddRef((IBaseFilter
*)This
);
1115 static ULONG WINAPI
ReferenceClock_Release(IReferenceClock
*iface
)
1117 ICOM_THIS_MULTI(DSoundRenderImpl
, IReferenceClock_vtbl
, iface
);
1119 TRACE("(%p/%p)->()\n", This
, iface
);
1121 return DSoundRender_Release((IBaseFilter
*)This
);
1124 /*** IReferenceClock methods ***/
1125 static HRESULT WINAPI
ReferenceClock_GetTime(IReferenceClock
*iface
,
1126 REFERENCE_TIME
*pTime
)
1128 ICOM_THIS_MULTI(DSoundRenderImpl
, IReferenceClock_vtbl
, iface
);
1129 HRESULT hr
= E_FAIL
;
1131 TRACE("(%p/%p)->(%p)\n", This
, iface
, pTime
);
1135 if (This
->dsbuffer
) {
1136 DWORD writepos1
, writepos2
;
1137 EnterCriticalSection(&This
->filter
.csFilter
);
1138 DSoundRender_UpdatePositions(This
, &writepos1
, &writepos2
);
1139 *pTime
= This
->play_time
+ time_from_pos(This
, This
->last_playpos
);
1140 LeaveCriticalSection(&This
->filter
.csFilter
);
1144 ERR("Could not get reference time (%x)!\n", hr
);
1149 static HRESULT WINAPI
ReferenceClock_AdviseTime(IReferenceClock
*iface
,
1150 REFERENCE_TIME rtBaseTime
,
1151 REFERENCE_TIME rtStreamTime
,
1153 DWORD_PTR
*pdwAdviseCookie
)
1155 ICOM_THIS_MULTI(DSoundRenderImpl
, IReferenceClock_vtbl
, iface
);
1157 FIXME("(%p/%p)->(%s, %s, %p, %p): stub!\n", This
, iface
, wine_dbgstr_longlong(rtBaseTime
), wine_dbgstr_longlong(rtStreamTime
), (void*)hEvent
, pdwAdviseCookie
);
1162 static HRESULT WINAPI
ReferenceClock_AdvisePeriodic(IReferenceClock
*iface
,
1163 REFERENCE_TIME rtBaseTime
,
1164 REFERENCE_TIME rtStreamTime
,
1165 HSEMAPHORE hSemaphore
,
1166 DWORD_PTR
*pdwAdviseCookie
)
1168 ICOM_THIS_MULTI(DSoundRenderImpl
, IReferenceClock_vtbl
, iface
);
1170 FIXME("(%p/%p)->(%s, %s, %p, %p): stub!\n", This
, iface
, wine_dbgstr_longlong(rtBaseTime
), wine_dbgstr_longlong(rtStreamTime
), (void*)hSemaphore
, pdwAdviseCookie
);
1175 static HRESULT WINAPI
ReferenceClock_Unadvise(IReferenceClock
*iface
,
1176 DWORD_PTR dwAdviseCookie
)
1178 ICOM_THIS_MULTI(DSoundRenderImpl
, IReferenceClock_vtbl
, iface
);
1180 FIXME("(%p/%p)->(%p): stub!\n", This
, iface
, (void*)dwAdviseCookie
);
1185 static const IReferenceClockVtbl IReferenceClock_Vtbl
=
1187 ReferenceClock_QueryInterface
,
1188 ReferenceClock_AddRef
,
1189 ReferenceClock_Release
,
1190 ReferenceClock_GetTime
,
1191 ReferenceClock_AdviseTime
,
1192 ReferenceClock_AdvisePeriodic
,
1193 ReferenceClock_Unadvise
1196 /*** IUnknown methods ***/
1197 static HRESULT WINAPI
AMDirectSound_QueryInterface(IAMDirectSound
*iface
,
1201 ICOM_THIS_MULTI(DSoundRenderImpl
, IAMDirectSound_vtbl
, iface
);
1203 TRACE("(%p/%p)->(%s (%p), %p)\n", This
, iface
, debugstr_guid(riid
), riid
, ppvObj
);
1205 return DSoundRender_QueryInterface((IBaseFilter
*)This
, riid
, ppvObj
);
1208 static ULONG WINAPI
AMDirectSound_AddRef(IAMDirectSound
*iface
)
1210 ICOM_THIS_MULTI(DSoundRenderImpl
, IAMDirectSound_vtbl
, iface
);
1212 TRACE("(%p/%p)->()\n", This
, iface
);
1214 return BaseFilterImpl_AddRef((IBaseFilter
*)This
);
1217 static ULONG WINAPI
AMDirectSound_Release(IAMDirectSound
*iface
)
1219 ICOM_THIS_MULTI(DSoundRenderImpl
, IAMDirectSound_vtbl
, iface
);
1221 TRACE("(%p/%p)->()\n", This
, iface
);
1223 return DSoundRender_Release((IBaseFilter
*)This
);
1226 /*** IAMDirectSound methods ***/
1227 static HRESULT WINAPI
AMDirectSound_GetDirectSoundInterface(IAMDirectSound
*iface
, IDirectSound
**ds
)
1229 ICOM_THIS_MULTI(DSoundRenderImpl
, IAMDirectSound_vtbl
, iface
);
1231 FIXME("(%p/%p)->(%p): stub\n", This
, iface
, ds
);
1236 static HRESULT WINAPI
AMDirectSound_GetPrimaryBufferInterface(IAMDirectSound
*iface
, IDirectSoundBuffer
**buf
)
1238 ICOM_THIS_MULTI(DSoundRenderImpl
, IAMDirectSound_vtbl
, iface
);
1240 FIXME("(%p/%p)->(%p): stub\n", This
, iface
, buf
);
1245 static HRESULT WINAPI
AMDirectSound_GetSecondaryBufferInterface(IAMDirectSound
*iface
, IDirectSoundBuffer
**buf
)
1247 ICOM_THIS_MULTI(DSoundRenderImpl
, IAMDirectSound_vtbl
, iface
);
1249 FIXME("(%p/%p)->(%p): stub\n", This
, iface
, buf
);
1254 static HRESULT WINAPI
AMDirectSound_ReleaseDirectSoundInterface(IAMDirectSound
*iface
, IDirectSound
*ds
)
1256 ICOM_THIS_MULTI(DSoundRenderImpl
, IAMDirectSound_vtbl
, iface
);
1258 FIXME("(%p/%p)->(%p): stub\n", This
, iface
, ds
);
1263 static HRESULT WINAPI
AMDirectSound_ReleasePrimaryBufferInterface(IAMDirectSound
*iface
, IDirectSoundBuffer
*buf
)
1265 ICOM_THIS_MULTI(DSoundRenderImpl
, IAMDirectSound_vtbl
, iface
);
1267 FIXME("(%p/%p)->(%p): stub\n", This
, iface
, buf
);
1272 static HRESULT WINAPI
AMDirectSound_ReleaseSecondaryBufferInterface(IAMDirectSound
*iface
, IDirectSoundBuffer
*buf
)
1274 ICOM_THIS_MULTI(DSoundRenderImpl
, IAMDirectSound_vtbl
, iface
);
1276 FIXME("(%p/%p)->(%p): stub\n", This
, iface
, buf
);
1281 static HRESULT WINAPI
AMDirectSound_SetFocusWindow(IAMDirectSound
*iface
, HWND hwnd
, BOOL bgsilent
)
1283 ICOM_THIS_MULTI(DSoundRenderImpl
, IAMDirectSound_vtbl
, iface
);
1285 FIXME("(%p/%p)->(%p,%d): stub\n", This
, iface
, hwnd
, bgsilent
);
1290 static HRESULT WINAPI
AMDirectSound_GetFocusWindow(IAMDirectSound
*iface
, HWND hwnd
)
1292 ICOM_THIS_MULTI(DSoundRenderImpl
, IAMDirectSound_vtbl
, iface
);
1294 FIXME("(%p/%p)->(%p): stub\n", This
, iface
, hwnd
);
1299 static const IAMDirectSoundVtbl IAMDirectSound_Vtbl
=
1301 AMDirectSound_QueryInterface
,
1302 AMDirectSound_AddRef
,
1303 AMDirectSound_Release
,
1304 AMDirectSound_GetDirectSoundInterface
,
1305 AMDirectSound_GetPrimaryBufferInterface
,
1306 AMDirectSound_GetSecondaryBufferInterface
,
1307 AMDirectSound_ReleaseDirectSoundInterface
,
1308 AMDirectSound_ReleasePrimaryBufferInterface
,
1309 AMDirectSound_ReleaseSecondaryBufferInterface
,
1310 AMDirectSound_SetFocusWindow
,
1311 AMDirectSound_GetFocusWindow
1314 static DSoundRenderImpl
*from_IAMFilterMiscFlags(IAMFilterMiscFlags
*iface
) {
1315 return (DSoundRenderImpl
*)((char*)iface
- offsetof(DSoundRenderImpl
, IAMFilterMiscFlags_vtbl
));
1318 static HRESULT WINAPI
AMFilterMiscFlags_QueryInterface(IAMFilterMiscFlags
*iface
, const REFIID riid
, void **ppv
) {
1319 DSoundRenderImpl
*This
= from_IAMFilterMiscFlags(iface
);
1320 return IUnknown_QueryInterface((IUnknown
*)This
, riid
, ppv
);
1323 static ULONG WINAPI
AMFilterMiscFlags_AddRef(IAMFilterMiscFlags
*iface
) {
1324 DSoundRenderImpl
*This
= from_IAMFilterMiscFlags(iface
);
1325 return IUnknown_AddRef((IUnknown
*)This
);
1328 static ULONG WINAPI
AMFilterMiscFlags_Release(IAMFilterMiscFlags
*iface
) {
1329 DSoundRenderImpl
*This
= from_IAMFilterMiscFlags(iface
);
1330 return IUnknown_Release((IUnknown
*)This
);
1333 static ULONG WINAPI
AMFilterMiscFlags_GetMiscFlags(IAMFilterMiscFlags
*iface
) {
1334 return AM_FILTER_MISC_FLAGS_IS_RENDERER
;
1337 static const IAMFilterMiscFlagsVtbl IAMFilterMiscFlags_Vtbl
= {
1338 AMFilterMiscFlags_QueryInterface
,
1339 AMFilterMiscFlags_AddRef
,
1340 AMFilterMiscFlags_Release
,
1341 AMFilterMiscFlags_GetMiscFlags