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
);
464 ISeekingPassThru
*passthru
;
465 pDSoundRender
->state_change
= CreateEventW(NULL
, TRUE
, TRUE
, NULL
);
466 pDSoundRender
->blocked
= CreateEventW(NULL
, TRUE
, TRUE
, NULL
);
467 hr
= CoCreateInstance(&CLSID_SeekingPassThru
, (IUnknown
*)pDSoundRender
, CLSCTX_INPROC_SERVER
, &IID_IUnknown
, (void**)&pDSoundRender
->seekthru_unk
);
468 if (!pDSoundRender
->state_change
|| !pDSoundRender
->blocked
|| FAILED(hr
))
470 IUnknown_Release((IUnknown
*)pDSoundRender
);
471 return HRESULT_FROM_WIN32(GetLastError());
474 IUnknown_QueryInterface(pDSoundRender
->seekthru_unk
, &IID_ISeekingPassThru
, (void**)&passthru
);
475 ISeekingPassThru_Init(passthru
, TRUE
, (IPin
*)pDSoundRender
->pInputPin
);
476 ISeekingPassThru_Release(passthru
);
477 *ppv
= pDSoundRender
;
481 if (pDSoundRender
->pInputPin
)
482 IPin_Release((IPin
*)pDSoundRender
->pInputPin
);
483 BaseFilterImpl_Release((IBaseFilter
*)pDSoundRender
);
484 CoTaskMemFree(pDSoundRender
);
490 static HRESULT WINAPI
DSoundRender_QueryInterface(IBaseFilter
* iface
, REFIID riid
, LPVOID
* ppv
)
492 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
493 TRACE("(%p, %p)->(%s, %p)\n", This
, iface
, qzdebugstr_guid(riid
), ppv
);
497 if (IsEqualIID(riid
, &IID_IUnknown
))
499 else if (IsEqualIID(riid
, &IID_IPersist
))
501 else if (IsEqualIID(riid
, &IID_IMediaFilter
))
503 else if (IsEqualIID(riid
, &IID_IBaseFilter
))
505 else if (IsEqualIID(riid
, &IID_IBasicAudio
))
506 *ppv
= &This
->IBasicAudio_vtbl
;
507 else if (IsEqualIID(riid
, &IID_IReferenceClock
))
508 *ppv
= &This
->IReferenceClock_vtbl
;
509 else if (IsEqualIID(riid
, &IID_IMediaSeeking
))
510 return IUnknown_QueryInterface(This
->seekthru_unk
, riid
, ppv
);
511 else if (IsEqualIID(riid
, &IID_IAMDirectSound
))
512 *ppv
= &This
->IAMDirectSound_vtbl
;
513 else if (IsEqualIID(riid
, &IID_IAMFilterMiscFlags
))
514 *ppv
= &This
->IAMFilterMiscFlags_vtbl
;
518 IUnknown_AddRef((IUnknown
*)(*ppv
));
522 if (!IsEqualIID(riid
, &IID_IPin
) && !IsEqualIID(riid
, &IID_IVideoWindow
))
523 FIXME("No interface for %s!\n", qzdebugstr_guid(riid
));
525 return E_NOINTERFACE
;
528 static ULONG WINAPI
DSoundRender_Release(IBaseFilter
* iface
)
530 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
531 ULONG refCount
= BaseFilterImpl_Release(iface
);
533 TRACE("(%p)->() Release from %d\n", This
, refCount
+ 1);
540 IDirectSoundBuffer_Release(This
->dsbuffer
);
541 This
->dsbuffer
= NULL
;
543 IDirectSound_Release(This
->dsound
);
546 if (SUCCEEDED(IPin_ConnectedTo((IPin
*)This
->pInputPin
, &pConnectedTo
)))
548 IPin_Disconnect(pConnectedTo
);
549 IPin_Release(pConnectedTo
);
551 IPin_Disconnect((IPin
*)This
->pInputPin
);
553 IPin_Release((IPin
*)This
->pInputPin
);
555 This
->IBasicAudio_vtbl
= NULL
;
556 if (This
->seekthru_unk
)
557 IUnknown_Release(This
->seekthru_unk
);
559 CloseHandle(This
->state_change
);
560 CloseHandle(This
->blocked
);
562 TRACE("Destroying Audio Renderer\n");
571 /** IMediaFilter methods **/
573 static HRESULT WINAPI
DSoundRender_Stop(IBaseFilter
* iface
)
576 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
578 TRACE("(%p/%p)->()\n", This
, iface
);
580 EnterCriticalSection(&This
->filter
.csFilter
);
582 hr
= IDirectSoundBuffer_Stop(This
->dsbuffer
);
584 This
->filter
.state
= State_Stopped
;
586 /* Complete our transition */
587 This
->writepos
= This
->buf_size
;
588 SetEvent(This
->state_change
);
589 SetEvent(This
->blocked
);
590 MediaSeekingPassThru_ResetMediaTime(This
->seekthru_unk
);
592 LeaveCriticalSection(&This
->filter
.csFilter
);
597 static HRESULT WINAPI
DSoundRender_Pause(IBaseFilter
* iface
)
600 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
602 TRACE("(%p/%p)->()\n", This
, iface
);
604 EnterCriticalSection(&This
->filter
.csFilter
);
605 if (This
->filter
.state
!= State_Paused
)
607 if (This
->filter
.state
== State_Stopped
)
609 This
->pInputPin
->end_of_stream
= 0;
612 hr
= IDirectSoundBuffer_Stop(This
->dsbuffer
);
614 This
->filter
.state
= State_Paused
;
616 ResetEvent(This
->blocked
);
617 ResetEvent(This
->state_change
);
619 LeaveCriticalSection(&This
->filter
.csFilter
);
624 static HRESULT WINAPI
DSoundRender_Run(IBaseFilter
* iface
, REFERENCE_TIME tStart
)
627 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
629 TRACE("(%p/%p)->(%s)\n", This
, iface
, wine_dbgstr_longlong(tStart
));
631 EnterCriticalSection(&This
->filter
.csFilter
);
632 if (This
->pInputPin
->pin
.pConnectedTo
)
634 This
->filter
.rtStreamStart
= tStart
;
635 if (This
->filter
.state
== State_Paused
)
637 /* Unblock our thread, state changing from paused to running doesn't need a reset for state change */
638 SetEvent(This
->blocked
);
640 else if (This
->filter
.state
== State_Stopped
)
642 ResetEvent(This
->state_change
);
643 This
->pInputPin
->end_of_stream
= 0;
645 IDirectSoundBuffer_Play(This
->dsbuffer
, 0, 0, DSBPLAY_LOOPING
);
646 ResetEvent(This
->blocked
);
647 } else if (This
->filter
.filterInfo
.pGraph
) {
648 IMediaEventSink
*pEventSink
;
649 hr
= IFilterGraph_QueryInterface(This
->filter
.filterInfo
.pGraph
, &IID_IMediaEventSink
, (LPVOID
*)&pEventSink
);
652 hr
= IMediaEventSink_Notify(pEventSink
, EC_COMPLETE
, S_OK
, (LONG_PTR
)This
);
653 IMediaEventSink_Release(pEventSink
);
658 This
->filter
.state
= State_Running
;
659 LeaveCriticalSection(&This
->filter
.csFilter
);
664 static HRESULT WINAPI
DSoundRender_GetState(IBaseFilter
* iface
, DWORD dwMilliSecsTimeout
, FILTER_STATE
*pState
)
667 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
669 TRACE("(%p/%p)->(%d, %p)\n", This
, iface
, dwMilliSecsTimeout
, pState
);
671 if (WaitForSingleObject(This
->state_change
, dwMilliSecsTimeout
) == WAIT_TIMEOUT
)
672 hr
= VFW_S_STATE_INTERMEDIATE
;
676 BaseFilterImpl_GetState(iface
, dwMilliSecsTimeout
, pState
);
681 /** IBaseFilter implementation **/
683 static HRESULT WINAPI
DSoundRender_FindPin(IBaseFilter
* iface
, LPCWSTR Id
, IPin
**ppPin
)
685 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
687 TRACE("(%p/%p)->(%s,%p)\n", This
, iface
, debugstr_w(Id
), ppPin
);
689 FIXME("DSoundRender::FindPin(...)\n");
691 /* FIXME: critical section */
696 static const IBaseFilterVtbl DSoundRender_Vtbl
=
698 DSoundRender_QueryInterface
,
699 BaseFilterImpl_AddRef
,
700 DSoundRender_Release
,
701 BaseFilterImpl_GetClassID
,
705 DSoundRender_GetState
,
706 BaseFilterImpl_SetSyncSource
,
707 BaseFilterImpl_GetSyncSource
,
708 BaseFilterImpl_EnumPins
,
709 DSoundRender_FindPin
,
710 BaseFilterImpl_QueryFilterInfo
,
711 BaseFilterImpl_JoinFilterGraph
,
712 BaseFilterImpl_QueryVendorInfo
715 static HRESULT WINAPI
DSoundRender_InputPin_ReceiveConnection(IPin
* iface
, IPin
* pReceivePin
, const AM_MEDIA_TYPE
* pmt
)
717 BaseInputPin
*This
= (BaseInputPin
*)iface
;
718 PIN_DIRECTION pindirReceive
;
719 DSoundRenderImpl
*DSImpl
;
722 TRACE("(%p)->(%p, %p)\n", This
, pReceivePin
, pmt
);
723 dump_AM_MEDIA_TYPE(pmt
);
725 EnterCriticalSection(This
->pin
.pCritSec
);
727 DSImpl
= (DSoundRenderImpl
*)This
->pin
.pinInfo
.pFilter
;
729 if (This
->pin
.pConnectedTo
)
730 hr
= VFW_E_ALREADY_CONNECTED
;
732 if (SUCCEEDED(hr
) && This
->pin
.pFuncsTable
->pfnCheckMediaType((BasePin
*)This
, pmt
) != S_OK
)
733 hr
= VFW_E_TYPE_NOT_ACCEPTED
;
737 IPin_QueryDirection(pReceivePin
, &pindirReceive
);
739 if (pindirReceive
!= PINDIR_OUTPUT
)
741 ERR("Can't connect from non-output pin\n");
742 hr
= VFW_E_INVALID_DIRECTION
;
748 WAVEFORMATEX
*format
;
749 DSBUFFERDESC buf_desc
;
751 TRACE("MajorType %s\n", debugstr_guid(&pmt
->majortype
));
752 TRACE("SubType %s\n", debugstr_guid(&pmt
->subtype
));
753 TRACE("Format %s\n", debugstr_guid(&pmt
->formattype
));
754 TRACE("Size %d\n", pmt
->cbFormat
);
756 format
= (WAVEFORMATEX
*)pmt
->pbFormat
;
758 DSImpl
->buf_size
= format
->nAvgBytesPerSec
;
760 memset(&buf_desc
,0,sizeof(DSBUFFERDESC
));
761 buf_desc
.dwSize
= sizeof(DSBUFFERDESC
);
762 buf_desc
.dwFlags
= DSBCAPS_CTRLVOLUME
| DSBCAPS_CTRLPAN
|
763 DSBCAPS_CTRLFREQUENCY
| DSBCAPS_GLOBALFOCUS
|
764 DSBCAPS_GETCURRENTPOSITION2
;
765 buf_desc
.dwBufferBytes
= DSImpl
->buf_size
;
766 buf_desc
.lpwfxFormat
= format
;
767 hr
= IDirectSound_CreateSoundBuffer(DSImpl
->dsound
, &buf_desc
, &DSImpl
->dsbuffer
, NULL
);
768 DSImpl
->writepos
= DSImpl
->buf_size
;
770 ERR("Can't create sound buffer (%x)\n", hr
);
775 hr
= IDirectSoundBuffer_SetVolume(DSImpl
->dsbuffer
, DSImpl
->volume
);
777 ERR("Can't set volume to %d (%x)\n", DSImpl
->volume
, hr
);
779 hr
= IDirectSoundBuffer_SetPan(DSImpl
->dsbuffer
, DSImpl
->pan
);
781 ERR("Can't set pan to %d (%x)\n", DSImpl
->pan
, hr
);
787 CopyMediaType(&This
->pin
.mtCurrent
, pmt
);
788 This
->pin
.pConnectedTo
= pReceivePin
;
789 IPin_AddRef(pReceivePin
);
791 else if (hr
!= VFW_E_ALREADY_CONNECTED
)
793 if (DSImpl
->dsbuffer
)
794 IDirectSoundBuffer_Release(DSImpl
->dsbuffer
);
795 DSImpl
->dsbuffer
= NULL
;
798 LeaveCriticalSection(This
->pin
.pCritSec
);
803 static HRESULT WINAPI
DSoundRender_InputPin_Disconnect(IPin
* iface
)
805 BasePin
*This
= (BasePin
*)iface
;
806 DSoundRenderImpl
*DSImpl
;
808 TRACE("(%p)->()\n", iface
);
810 DSImpl
= (DSoundRenderImpl
*)This
->pinInfo
.pFilter
;
811 if (DSImpl
->dsbuffer
)
812 IDirectSoundBuffer_Release(DSImpl
->dsbuffer
);
813 DSImpl
->dsbuffer
= NULL
;
815 return BasePinImpl_Disconnect(iface
);
818 static HRESULT WINAPI
DSoundRender_InputPin_EndOfStream(IPin
* iface
)
820 BaseInputPin
* This
= (BaseInputPin
*)iface
;
821 DSoundRenderImpl
*me
= (DSoundRenderImpl
*)This
->pin
.pinInfo
.pFilter
;
822 IMediaEventSink
* pEventSink
;
825 EnterCriticalSection(This
->pin
.pCritSec
);
827 TRACE("(%p/%p)->()\n", This
, iface
);
828 hr
= BaseInputPinImpl_EndOfStream(iface
);
832 LeaveCriticalSection(This
->pin
.pCritSec
);
836 if (me
->filter
.filterInfo
.pGraph
)
838 hr
= IFilterGraph_QueryInterface(me
->filter
.filterInfo
.pGraph
, &IID_IMediaEventSink
, (LPVOID
*)&pEventSink
);
841 hr
= IMediaEventSink_Notify(pEventSink
, EC_COMPLETE
, S_OK
, (LONG_PTR
)me
);
842 IMediaEventSink_Release(pEventSink
);
845 MediaSeekingPassThru_EOS(me
->seekthru_unk
);
846 LeaveCriticalSection(This
->pin
.pCritSec
);
851 static HRESULT WINAPI
DSoundRender_InputPin_BeginFlush(IPin
* iface
)
853 BaseInputPin
*This
= (BaseInputPin
*)iface
;
854 DSoundRenderImpl
*pFilter
= (DSoundRenderImpl
*)This
->pin
.pinInfo
.pFilter
;
859 EnterCriticalSection(This
->pin
.pCritSec
);
860 hr
= BaseInputPinImpl_BeginFlush(iface
);
861 SetEvent(pFilter
->blocked
);
862 LeaveCriticalSection(This
->pin
.pCritSec
);
867 static HRESULT WINAPI
DSoundRender_InputPin_EndFlush(IPin
* iface
)
869 BaseInputPin
*This
= (BaseInputPin
*)iface
;
870 DSoundRenderImpl
*pFilter
= (DSoundRenderImpl
*)This
->pin
.pinInfo
.pFilter
;
875 EnterCriticalSection(This
->pin
.pCritSec
);
876 if (pFilter
->in_loop
) {
877 ResetEvent(pFilter
->state_change
);
878 LeaveCriticalSection(This
->pin
.pCritSec
);
879 WaitForSingleObject(pFilter
->state_change
, -1);
880 EnterCriticalSection(This
->pin
.pCritSec
);
882 if (pFilter
->filter
.state
!= State_Stopped
)
883 ResetEvent(pFilter
->blocked
);
885 if (pFilter
->dsbuffer
)
891 IDirectSoundBuffer_Lock(pFilter
->dsbuffer
, 0, 0, (LPVOID
*)&buffer
, &size
, NULL
, NULL
, DSBLOCK_ENTIREBUFFER
);
892 memset(buffer
, 0, size
);
893 IDirectSoundBuffer_Unlock(pFilter
->dsbuffer
, buffer
, size
, NULL
, 0);
894 pFilter
->writepos
= pFilter
->buf_size
;
896 hr
= BaseInputPinImpl_EndFlush(iface
);
897 LeaveCriticalSection(This
->pin
.pCritSec
);
898 MediaSeekingPassThru_ResetMediaTime(pFilter
->seekthru_unk
);
903 static const IPinVtbl DSoundRender_InputPin_Vtbl
=
905 BaseInputPinImpl_QueryInterface
,
907 BaseInputPinImpl_Release
,
908 BaseInputPinImpl_Connect
,
909 DSoundRender_InputPin_ReceiveConnection
,
910 DSoundRender_InputPin_Disconnect
,
911 BasePinImpl_ConnectedTo
,
912 BasePinImpl_ConnectionMediaType
,
913 BasePinImpl_QueryPinInfo
,
914 BasePinImpl_QueryDirection
,
916 BaseInputPinImpl_QueryAccept
,
917 BasePinImpl_EnumMediaTypes
,
918 BasePinImpl_QueryInternalConnections
,
919 DSoundRender_InputPin_EndOfStream
,
920 DSoundRender_InputPin_BeginFlush
,
921 DSoundRender_InputPin_EndFlush
,
922 BaseInputPinImpl_NewSegment
925 /*** IUnknown methods ***/
926 static HRESULT WINAPI
Basicaudio_QueryInterface(IBasicAudio
*iface
,
929 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
931 TRACE("(%p/%p)->(%s (%p), %p)\n", This
, iface
, debugstr_guid(riid
), riid
, ppvObj
);
933 return DSoundRender_QueryInterface((IBaseFilter
*)This
, riid
, ppvObj
);
936 static ULONG WINAPI
Basicaudio_AddRef(IBasicAudio
*iface
) {
937 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
939 TRACE("(%p/%p)->()\n", This
, iface
);
941 return BaseFilterImpl_AddRef((IBaseFilter
*)This
);
944 static ULONG WINAPI
Basicaudio_Release(IBasicAudio
*iface
) {
945 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
947 TRACE("(%p/%p)->()\n", This
, iface
);
949 return DSoundRender_Release((IBaseFilter
*)This
);
952 /*** IDispatch methods ***/
953 static HRESULT WINAPI
Basicaudio_GetTypeInfoCount(IBasicAudio
*iface
,
955 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
957 TRACE("(%p/%p)->(%p): stub !!!\n", This
, iface
, pctinfo
);
962 static HRESULT WINAPI
Basicaudio_GetTypeInfo(IBasicAudio
*iface
,
965 ITypeInfo
**ppTInfo
) {
966 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
968 TRACE("(%p/%p)->(%d, %d, %p): stub !!!\n", This
, iface
, iTInfo
, lcid
, ppTInfo
);
973 static HRESULT WINAPI
Basicaudio_GetIDsOfNames(IBasicAudio
*iface
,
979 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
981 TRACE("(%p/%p)->(%s (%p), %p, %d, %d, %p): stub !!!\n", This
, iface
, debugstr_guid(riid
), riid
, rgszNames
, cNames
, lcid
, rgDispId
);
986 static HRESULT WINAPI
Basicaudio_Invoke(IBasicAudio
*iface
,
991 DISPPARAMS
*pDispParams
,
995 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
997 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
);
1002 /*** IBasicAudio methods ***/
1003 static HRESULT WINAPI
Basicaudio_put_Volume(IBasicAudio
*iface
,
1005 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
1007 TRACE("(%p/%p)->(%d)\n", This
, iface
, lVolume
);
1009 if (lVolume
> DSBVOLUME_MAX
|| lVolume
< DSBVOLUME_MIN
)
1010 return E_INVALIDARG
;
1012 if (This
->dsbuffer
) {
1013 if (FAILED(IDirectSoundBuffer_SetVolume(This
->dsbuffer
, lVolume
)))
1017 This
->volume
= lVolume
;
1021 static HRESULT WINAPI
Basicaudio_get_Volume(IBasicAudio
*iface
,
1023 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
1025 TRACE("(%p/%p)->(%p)\n", This
, iface
, plVolume
);
1030 *plVolume
= This
->volume
;
1034 static HRESULT WINAPI
Basicaudio_put_Balance(IBasicAudio
*iface
,
1036 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
1038 TRACE("(%p/%p)->(%d)\n", This
, iface
, lBalance
);
1040 if (lBalance
< DSBPAN_LEFT
|| lBalance
> DSBPAN_RIGHT
)
1041 return E_INVALIDARG
;
1043 if (This
->dsbuffer
) {
1044 if (FAILED(IDirectSoundBuffer_SetPan(This
->dsbuffer
, lBalance
)))
1048 This
->pan
= lBalance
;
1052 static HRESULT WINAPI
Basicaudio_get_Balance(IBasicAudio
*iface
,
1054 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
1056 TRACE("(%p/%p)->(%p)\n", This
, iface
, plBalance
);
1061 *plBalance
= This
->pan
;
1065 static const IBasicAudioVtbl IBasicAudio_Vtbl
=
1067 Basicaudio_QueryInterface
,
1070 Basicaudio_GetTypeInfoCount
,
1071 Basicaudio_GetTypeInfo
,
1072 Basicaudio_GetIDsOfNames
,
1074 Basicaudio_put_Volume
,
1075 Basicaudio_get_Volume
,
1076 Basicaudio_put_Balance
,
1077 Basicaudio_get_Balance
1081 /*** IUnknown methods ***/
1082 static HRESULT WINAPI
ReferenceClock_QueryInterface(IReferenceClock
*iface
,
1086 ICOM_THIS_MULTI(DSoundRenderImpl
, IReferenceClock_vtbl
, iface
);
1088 TRACE("(%p/%p)->(%s (%p), %p)\n", This
, iface
, debugstr_guid(riid
), riid
, ppvObj
);
1090 return DSoundRender_QueryInterface((IBaseFilter
*)This
, riid
, ppvObj
);
1093 static ULONG WINAPI
ReferenceClock_AddRef(IReferenceClock
*iface
)
1095 ICOM_THIS_MULTI(DSoundRenderImpl
, IReferenceClock_vtbl
, iface
);
1097 TRACE("(%p/%p)->()\n", This
, iface
);
1099 return BaseFilterImpl_AddRef((IBaseFilter
*)This
);
1102 static ULONG WINAPI
ReferenceClock_Release(IReferenceClock
*iface
)
1104 ICOM_THIS_MULTI(DSoundRenderImpl
, IReferenceClock_vtbl
, iface
);
1106 TRACE("(%p/%p)->()\n", This
, iface
);
1108 return DSoundRender_Release((IBaseFilter
*)This
);
1111 /*** IReferenceClock methods ***/
1112 static HRESULT WINAPI
ReferenceClock_GetTime(IReferenceClock
*iface
,
1113 REFERENCE_TIME
*pTime
)
1115 ICOM_THIS_MULTI(DSoundRenderImpl
, IReferenceClock_vtbl
, iface
);
1116 HRESULT hr
= E_FAIL
;
1118 TRACE("(%p/%p)->(%p)\n", This
, iface
, pTime
);
1122 if (This
->dsbuffer
) {
1123 DWORD writepos1
, writepos2
;
1124 EnterCriticalSection(&This
->filter
.csFilter
);
1125 DSoundRender_UpdatePositions(This
, &writepos1
, &writepos2
);
1126 *pTime
= This
->play_time
+ time_from_pos(This
, This
->last_playpos
);
1127 LeaveCriticalSection(&This
->filter
.csFilter
);
1131 ERR("Could not get reference time (%x)!\n", hr
);
1136 static HRESULT WINAPI
ReferenceClock_AdviseTime(IReferenceClock
*iface
,
1137 REFERENCE_TIME rtBaseTime
,
1138 REFERENCE_TIME rtStreamTime
,
1140 DWORD_PTR
*pdwAdviseCookie
)
1142 ICOM_THIS_MULTI(DSoundRenderImpl
, IReferenceClock_vtbl
, iface
);
1144 FIXME("(%p/%p)->(%s, %s, %p, %p): stub!\n", This
, iface
, wine_dbgstr_longlong(rtBaseTime
), wine_dbgstr_longlong(rtStreamTime
), (void*)hEvent
, pdwAdviseCookie
);
1149 static HRESULT WINAPI
ReferenceClock_AdvisePeriodic(IReferenceClock
*iface
,
1150 REFERENCE_TIME rtBaseTime
,
1151 REFERENCE_TIME rtStreamTime
,
1152 HSEMAPHORE hSemaphore
,
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*)hSemaphore
, pdwAdviseCookie
);
1162 static HRESULT WINAPI
ReferenceClock_Unadvise(IReferenceClock
*iface
,
1163 DWORD_PTR dwAdviseCookie
)
1165 ICOM_THIS_MULTI(DSoundRenderImpl
, IReferenceClock_vtbl
, iface
);
1167 FIXME("(%p/%p)->(%p): stub!\n", This
, iface
, (void*)dwAdviseCookie
);
1172 static const IReferenceClockVtbl IReferenceClock_Vtbl
=
1174 ReferenceClock_QueryInterface
,
1175 ReferenceClock_AddRef
,
1176 ReferenceClock_Release
,
1177 ReferenceClock_GetTime
,
1178 ReferenceClock_AdviseTime
,
1179 ReferenceClock_AdvisePeriodic
,
1180 ReferenceClock_Unadvise
1183 /*** IUnknown methods ***/
1184 static HRESULT WINAPI
AMDirectSound_QueryInterface(IAMDirectSound
*iface
,
1188 ICOM_THIS_MULTI(DSoundRenderImpl
, IAMDirectSound_vtbl
, iface
);
1190 TRACE("(%p/%p)->(%s (%p), %p)\n", This
, iface
, debugstr_guid(riid
), riid
, ppvObj
);
1192 return DSoundRender_QueryInterface((IBaseFilter
*)This
, riid
, ppvObj
);
1195 static ULONG WINAPI
AMDirectSound_AddRef(IAMDirectSound
*iface
)
1197 ICOM_THIS_MULTI(DSoundRenderImpl
, IAMDirectSound_vtbl
, iface
);
1199 TRACE("(%p/%p)->()\n", This
, iface
);
1201 return BaseFilterImpl_AddRef((IBaseFilter
*)This
);
1204 static ULONG WINAPI
AMDirectSound_Release(IAMDirectSound
*iface
)
1206 ICOM_THIS_MULTI(DSoundRenderImpl
, IAMDirectSound_vtbl
, iface
);
1208 TRACE("(%p/%p)->()\n", This
, iface
);
1210 return DSoundRender_Release((IBaseFilter
*)This
);
1213 /*** IAMDirectSound methods ***/
1214 static HRESULT WINAPI
AMDirectSound_GetDirectSoundInterface(IAMDirectSound
*iface
, IDirectSound
**ds
)
1216 ICOM_THIS_MULTI(DSoundRenderImpl
, IAMDirectSound_vtbl
, iface
);
1218 FIXME("(%p/%p)->(%p): stub\n", This
, iface
, ds
);
1223 static HRESULT WINAPI
AMDirectSound_GetPrimaryBufferInterface(IAMDirectSound
*iface
, IDirectSoundBuffer
**buf
)
1225 ICOM_THIS_MULTI(DSoundRenderImpl
, IAMDirectSound_vtbl
, iface
);
1227 FIXME("(%p/%p)->(%p): stub\n", This
, iface
, buf
);
1232 static HRESULT WINAPI
AMDirectSound_GetSecondaryBufferInterface(IAMDirectSound
*iface
, IDirectSoundBuffer
**buf
)
1234 ICOM_THIS_MULTI(DSoundRenderImpl
, IAMDirectSound_vtbl
, iface
);
1236 FIXME("(%p/%p)->(%p): stub\n", This
, iface
, buf
);
1241 static HRESULT WINAPI
AMDirectSound_ReleaseDirectSoundInterface(IAMDirectSound
*iface
, IDirectSound
*ds
)
1243 ICOM_THIS_MULTI(DSoundRenderImpl
, IAMDirectSound_vtbl
, iface
);
1245 FIXME("(%p/%p)->(%p): stub\n", This
, iface
, ds
);
1250 static HRESULT WINAPI
AMDirectSound_ReleasePrimaryBufferInterface(IAMDirectSound
*iface
, IDirectSoundBuffer
*buf
)
1252 ICOM_THIS_MULTI(DSoundRenderImpl
, IAMDirectSound_vtbl
, iface
);
1254 FIXME("(%p/%p)->(%p): stub\n", This
, iface
, buf
);
1259 static HRESULT WINAPI
AMDirectSound_ReleaseSecondaryBufferInterface(IAMDirectSound
*iface
, IDirectSoundBuffer
*buf
)
1261 ICOM_THIS_MULTI(DSoundRenderImpl
, IAMDirectSound_vtbl
, iface
);
1263 FIXME("(%p/%p)->(%p): stub\n", This
, iface
, buf
);
1268 static HRESULT WINAPI
AMDirectSound_SetFocusWindow(IAMDirectSound
*iface
, HWND hwnd
, BOOL bgsilent
)
1270 ICOM_THIS_MULTI(DSoundRenderImpl
, IAMDirectSound_vtbl
, iface
);
1272 FIXME("(%p/%p)->(%p,%d): stub\n", This
, iface
, hwnd
, bgsilent
);
1277 static HRESULT WINAPI
AMDirectSound_GetFocusWindow(IAMDirectSound
*iface
, HWND hwnd
)
1279 ICOM_THIS_MULTI(DSoundRenderImpl
, IAMDirectSound_vtbl
, iface
);
1281 FIXME("(%p/%p)->(%p): stub\n", This
, iface
, hwnd
);
1286 static const IAMDirectSoundVtbl IAMDirectSound_Vtbl
=
1288 AMDirectSound_QueryInterface
,
1289 AMDirectSound_AddRef
,
1290 AMDirectSound_Release
,
1291 AMDirectSound_GetDirectSoundInterface
,
1292 AMDirectSound_GetPrimaryBufferInterface
,
1293 AMDirectSound_GetSecondaryBufferInterface
,
1294 AMDirectSound_ReleaseDirectSoundInterface
,
1295 AMDirectSound_ReleasePrimaryBufferInterface
,
1296 AMDirectSound_ReleaseSecondaryBufferInterface
,
1297 AMDirectSound_SetFocusWindow
,
1298 AMDirectSound_GetFocusWindow
1301 static DSoundRenderImpl
*from_IAMFilterMiscFlags(IAMFilterMiscFlags
*iface
) {
1302 return (DSoundRenderImpl
*)((char*)iface
- offsetof(DSoundRenderImpl
, IAMFilterMiscFlags_vtbl
));
1305 static HRESULT WINAPI
AMFilterMiscFlags_QueryInterface(IAMFilterMiscFlags
*iface
, const REFIID riid
, void **ppv
) {
1306 DSoundRenderImpl
*This
= from_IAMFilterMiscFlags(iface
);
1307 return IUnknown_QueryInterface((IUnknown
*)This
, riid
, ppv
);
1310 static ULONG WINAPI
AMFilterMiscFlags_AddRef(IAMFilterMiscFlags
*iface
) {
1311 DSoundRenderImpl
*This
= from_IAMFilterMiscFlags(iface
);
1312 return IUnknown_AddRef((IUnknown
*)This
);
1315 static ULONG WINAPI
AMFilterMiscFlags_Release(IAMFilterMiscFlags
*iface
) {
1316 DSoundRenderImpl
*This
= from_IAMFilterMiscFlags(iface
);
1317 return IUnknown_Release((IUnknown
*)This
);
1320 static ULONG WINAPI
AMFilterMiscFlags_GetMiscFlags(IAMFilterMiscFlags
*iface
) {
1321 return AM_FILTER_MISC_FLAGS_IS_RENDERER
;
1324 static const IAMFilterMiscFlagsVtbl IAMFilterMiscFlags_Vtbl
= {
1325 AMFilterMiscFlags_QueryInterface
,
1326 AMFilterMiscFlags_AddRef
,
1327 AMFilterMiscFlags_Release
,
1328 AMFilterMiscFlags_GetMiscFlags