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 static const WCHAR wcsInputPinName
[] = {'i','n','p','u','t',' ','p','i','n',0};
44 static const IBaseFilterVtbl DSoundRender_Vtbl
;
45 static const IPinVtbl DSoundRender_InputPin_Vtbl
;
46 static const IBasicAudioVtbl IBasicAudio_Vtbl
;
47 static const IReferenceClockVtbl IReferenceClock_Vtbl
;
48 static const IMediaSeekingVtbl IMediaSeeking_Vtbl
;
49 static const IAMDirectSoundVtbl IAMDirectSound_Vtbl
;
51 typedef struct DSoundRenderImpl
53 const IBaseFilterVtbl
* lpVtbl
;
54 const IBasicAudioVtbl
*IBasicAudio_vtbl
;
55 const IReferenceClockVtbl
*IReferenceClock_vtbl
;
56 const IAMDirectSoundVtbl
*IAMDirectSound_vtbl
;
57 IUnknown
*seekthru_unk
;
60 CRITICAL_SECTION csFilter
;
62 REFERENCE_TIME rtStreamStart
, rtLastStop
;
63 IReferenceClock
* pClock
;
64 FILTER_INFO filterInfo
;
68 IDirectSound8
*dsound
;
69 LPDIRECTSOUNDBUFFER dsbuffer
;
78 REFERENCE_TIME play_time
;
80 HANDLE state_change
, blocked
;
86 static inline HRESULT
DSoundRender_GetPos(DSoundRenderImpl
*This
, DWORD
*pPlayPos
, REFERENCE_TIME
*pRefTime
)
90 EnterCriticalSection(&This
->csFilter
);
95 hr
= IDirectSoundBuffer_GetStatus(This
->dsbuffer
, &state
);
96 if (SUCCEEDED(hr
) && !(state
& DSBSTATUS_PLAYING
) && This
->state
== State_Running
)
98 TRACE("Not playing, kickstarting the engine\n");
100 hr
= IDirectSoundBuffer_Play(This
->dsbuffer
, 0, 0, DSBPLAY_LOOPING
);
102 ERR("Can't play sound buffer (%x)\n", hr
);
106 hr
= IDirectSoundBuffer_GetCurrentPosition(This
->dsbuffer
, pPlayPos
, &write_pos
);
109 DWORD play_pos
= *pPlayPos
;
111 if (play_pos
< This
->last_play_pos
)
113 This
->last_play_pos
= play_pos
;
115 /* If we really fell behind, start at the next possible position
116 * Also happens when just starting playback for the first time,
119 if ((This
->play_loops
*This
->buf_size
)+play_pos
>=
120 (This
->write_loops
*This
->buf_size
)+This
->write_pos
)
121 This
->write_pos
= write_pos
;
125 REFERENCE_TIME play_time
;
126 play_time
= ((REFERENCE_TIME
)This
->play_loops
*10000000) +
127 ((REFERENCE_TIME
)play_pos
*10000000/This
->buf_size
);
129 /* Don't let time run backwards */
130 if(play_time
-This
->play_time
> 0)
131 This
->play_time
= play_time
;
135 *pRefTime
= This
->play_time
;
139 LeaveCriticalSection(&This
->csFilter
);
144 static HRESULT
DSoundRender_SendSampleData(DSoundRenderImpl
* This
, const BYTE
*data
, DWORD size
)
147 LPBYTE lpbuf1
= NULL
;
148 LPBYTE lpbuf2
= NULL
;
152 DWORD play_pos
,buf_free
;
156 hr
= DSoundRender_GetPos(This
, &play_pos
, NULL
);
159 ERR("GetPos returned error: %x\n", hr
);
162 if (This
->write_pos
<= play_pos
)
163 buf_free
= play_pos
-This
->write_pos
;
165 buf_free
= This
->buf_size
- This
->write_pos
+ play_pos
;
167 /* Wait for enough of the buffer to empty before filling it */
168 if(buf_free
< This
->buf_size
/20)
172 LeaveCriticalSection(&This
->csFilter
);
173 ret
= WaitForSingleObject(This
->blocked
, 50);
174 if (ret
!= WAIT_TIMEOUT
)
176 EnterCriticalSection(&This
->csFilter
);
178 if (This
->pInputPin
->flushing
)
179 return VFW_E_WRONG_STATE
;
180 if (This
->state
== State_Stopped
)
181 return VFW_E_WRONG_STATE
;
185 size2
= min(buf_free
, size
);
186 hr
= IDirectSoundBuffer_Lock(This
->dsbuffer
, This
->write_pos
, size2
, (LPVOID
*)&lpbuf1
, &dwsize1
, (LPVOID
*)&lpbuf2
, &dwsize2
, 0);
188 ERR("Unable to lock sound buffer! (%x)\n", hr
);
191 /* TRACE("write_pos=%d, size=%d, sz1=%d, sz2=%d\n", This->write_pos, size2, dwsize1, dwsize2); */
193 memcpy(lpbuf1
, data
, dwsize1
);
195 memcpy(lpbuf2
, data
+ dwsize1
, dwsize2
);
197 hr
= IDirectSoundBuffer_Unlock(This
->dsbuffer
, lpbuf1
, dwsize1
, lpbuf2
, dwsize2
);
199 ERR("Unable to unlock sound buffer! (%x)\n", hr
);
201 size
-= dwsize1
+ dwsize2
;
202 data
+= dwsize1
+ dwsize2
;
203 This
->write_pos
+= dwsize1
+ dwsize2
;
204 if (This
->write_pos
>= This
->buf_size
)
206 This
->write_pos
-= This
->buf_size
;
209 } while (size
&& This
->state
== State_Running
);
214 static HRESULT
DSoundRender_Sample(LPVOID iface
, IMediaSample
* pSample
)
216 DSoundRenderImpl
*This
= iface
;
217 LPBYTE pbSrcStream
= NULL
;
218 LONG cbSrcStream
= 0;
219 REFERENCE_TIME tStart
, tStop
;
223 TRACE("%p %p\n", iface
, pSample
);
225 /* Slightly incorrect, Pause completes when a frame is received so we should signal
226 * pause completion here, but for sound playing a single frame doesn't make sense
229 EnterCriticalSection(&This
->csFilter
);
231 if (This
->pInputPin
->end_of_stream
|| This
->pInputPin
->flushing
)
233 LeaveCriticalSection(&This
->csFilter
);
237 if (This
->state
== State_Stopped
)
239 LeaveCriticalSection(&This
->csFilter
);
240 return VFW_E_WRONG_STATE
;
243 if (IMediaSample_GetMediaType(pSample
, &amt
) == S_OK
)
245 AM_MEDIA_TYPE
*orig
= &This
->pInputPin
->pin
.mtCurrent
;
246 WAVEFORMATEX
*origfmt
= (WAVEFORMATEX
*)orig
->pbFormat
;
247 WAVEFORMATEX
*newfmt
= (WAVEFORMATEX
*)amt
->pbFormat
;
249 if (origfmt
->wFormatTag
== newfmt
->wFormatTag
&&
250 origfmt
->nChannels
== newfmt
->nChannels
&&
251 origfmt
->nBlockAlign
== newfmt
->nBlockAlign
&&
252 origfmt
->wBitsPerSample
== newfmt
->wBitsPerSample
&&
253 origfmt
->cbSize
== newfmt
->cbSize
)
255 if (origfmt
->nSamplesPerSec
!= newfmt
->nSamplesPerSec
)
257 hr
= IDirectSoundBuffer_SetFrequency(This
->dsbuffer
,
258 newfmt
->nSamplesPerSec
);
261 LeaveCriticalSection(&This
->csFilter
);
262 return VFW_E_TYPE_NOT_ACCEPTED
;
265 CopyMediaType(orig
, amt
);
266 IMediaSample_SetMediaType(pSample
, NULL
);
271 LeaveCriticalSection(&This
->csFilter
);
272 return VFW_E_TYPE_NOT_ACCEPTED
;
276 hr
= IMediaSample_GetPointer(pSample
, &pbSrcStream
);
279 ERR("Cannot get pointer to sample data (%x)\n", hr
);
280 LeaveCriticalSection(&This
->csFilter
);
284 hr
= IMediaSample_GetTime(pSample
, &tStart
, &tStop
);
286 ERR("Cannot get sample time (%x)\n", hr
);
288 MediaSeekingPassThru_RegisterMediaTime(This
->seekthru_unk
, tStart
);
290 if (This
->rtLastStop
!= tStart
&& (IMediaSample_IsDiscontinuity(pSample
) == S_FALSE
))
291 WARN("Unexpected discontinuity: Last: %u.%03u, tStart: %u.%03u\n",
292 (DWORD
)(This
->rtLastStop
/ 10000000), (DWORD
)((This
->rtLastStop
/ 10000)%1000),
293 (DWORD
)(tStart
/ 10000000), (DWORD
)((tStart
/ 10000)%1000));
294 This
->rtLastStop
= tStop
;
296 if (IMediaSample_IsPreroll(pSample
) == S_OK
)
299 LeaveCriticalSection(&This
->csFilter
);
303 if (This
->state
== State_Paused
)
305 SetEvent(This
->state_change
);
306 LeaveCriticalSection(&This
->csFilter
);
307 WaitForSingleObject(This
->blocked
, INFINITE
);
308 EnterCriticalSection(&This
->csFilter
);
309 if (This
->state
== State_Stopped
)
311 LeaveCriticalSection(&This
->csFilter
);
312 return VFW_E_WRONG_STATE
;
315 if (This
->state
== State_Paused
)
317 /* Assuming we return because of flushing */
319 LeaveCriticalSection(&This
->csFilter
);
322 SetEvent(This
->state_change
);
325 cbSrcStream
= IMediaSample_GetActualDataLength(pSample
);
326 TRACE("Sample data ptr = %p, size = %d\n", pbSrcStream
, cbSrcStream
);
328 #if 0 /* For debugging purpose */
331 for(i
= 0; i
< cbSrcStream
; i
++)
333 if ((i
!=0) && !(i
%16))
335 TRACE("%02x ", pbSrcStream
[i
]);
341 hr
= DSoundRender_SendSampleData(This
, pbSrcStream
, cbSrcStream
);
342 SetEvent(This
->state_change
);
343 LeaveCriticalSection(&This
->csFilter
);
347 static HRESULT
DSoundRender_QueryAccept(LPVOID iface
, const AM_MEDIA_TYPE
* pmt
)
349 WAVEFORMATEX
* format
;
351 if (!IsEqualIID(&pmt
->majortype
, &MEDIATYPE_Audio
))
354 format
= (WAVEFORMATEX
*)pmt
->pbFormat
;
355 TRACE("Format = %p\n", format
);
356 TRACE("wFormatTag = %x %x\n", format
->wFormatTag
, WAVE_FORMAT_PCM
);
357 TRACE("nChannels = %d\n", format
->nChannels
);
358 TRACE("nSamplesPerSec = %d\n", format
->nAvgBytesPerSec
);
359 TRACE("nAvgBytesPerSec = %d\n", format
->nAvgBytesPerSec
);
360 TRACE("nBlockAlign = %d\n", format
->nBlockAlign
);
361 TRACE("wBitsPerSample = %d\n", format
->wBitsPerSample
);
363 if (!IsEqualIID(&pmt
->subtype
, &MEDIASUBTYPE_PCM
))
369 HRESULT
DSoundRender_create(IUnknown
* pUnkOuter
, LPVOID
* ppv
)
373 DSoundRenderImpl
* pDSoundRender
;
375 TRACE("(%p, %p)\n", pUnkOuter
, ppv
);
380 return CLASS_E_NOAGGREGATION
;
382 pDSoundRender
= CoTaskMemAlloc(sizeof(DSoundRenderImpl
));
384 return E_OUTOFMEMORY
;
385 ZeroMemory(pDSoundRender
, sizeof(DSoundRenderImpl
));
387 pDSoundRender
->lpVtbl
= &DSoundRender_Vtbl
;
388 pDSoundRender
->IBasicAudio_vtbl
= &IBasicAudio_Vtbl
;
389 pDSoundRender
->IReferenceClock_vtbl
= &IReferenceClock_Vtbl
;
390 pDSoundRender
->IAMDirectSound_vtbl
= &IAMDirectSound_Vtbl
;
391 pDSoundRender
->refCount
= 1;
392 InitializeCriticalSection(&pDSoundRender
->csFilter
);
393 pDSoundRender
->csFilter
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": DSoundRenderImpl.csFilter");
394 pDSoundRender
->state
= State_Stopped
;
396 /* construct input pin */
397 piInput
.dir
= PINDIR_INPUT
;
398 piInput
.pFilter
= (IBaseFilter
*)pDSoundRender
;
399 lstrcpynW(piInput
.achName
, wcsInputPinName
, sizeof(piInput
.achName
) / sizeof(piInput
.achName
[0]));
400 hr
= InputPin_Construct(&DSoundRender_InputPin_Vtbl
, &piInput
, DSoundRender_Sample
, pDSoundRender
, DSoundRender_QueryAccept
, NULL
, &pDSoundRender
->csFilter
, NULL
, (IPin
**)&pDSoundRender
->pInputPin
);
404 hr
= DirectSoundCreate8(NULL
, &pDSoundRender
->dsound
, NULL
);
406 ERR("Cannot create Direct Sound object (%x)\n", hr
);
408 IDirectSound_SetCooperativeLevel(pDSoundRender
->dsound
, GetDesktopWindow(), DSSCL_PRIORITY
);
413 ISeekingPassThru
*passthru
;
414 pDSoundRender
->state_change
= CreateEventW(NULL
, TRUE
, TRUE
, NULL
);
415 pDSoundRender
->blocked
= CreateEventW(NULL
, TRUE
, TRUE
, NULL
);
416 hr
= CoCreateInstance(&CLSID_SeekingPassThru
, (IUnknown
*)pDSoundRender
, CLSCTX_INPROC_SERVER
, &IID_IUnknown
, (void**)&pDSoundRender
->seekthru_unk
);
417 if (!pDSoundRender
->state_change
|| !pDSoundRender
->blocked
|| FAILED(hr
))
419 IUnknown_Release((IUnknown
*)pDSoundRender
);
420 return HRESULT_FROM_WIN32(GetLastError());
423 IUnknown_QueryInterface(pDSoundRender
->seekthru_unk
, &IID_ISeekingPassThru
, (void**)&passthru
);
424 ISeekingPassThru_Init(passthru
, TRUE
, (IPin
*)pDSoundRender
->pInputPin
);
425 ISeekingPassThru_Release(passthru
);
426 *ppv
= pDSoundRender
;
430 if (pDSoundRender
->pInputPin
)
431 IPin_Release((IPin
*)pDSoundRender
->pInputPin
);
432 pDSoundRender
->csFilter
.DebugInfo
->Spare
[0] = 0;
433 DeleteCriticalSection(&pDSoundRender
->csFilter
);
434 CoTaskMemFree(pDSoundRender
);
440 static HRESULT WINAPI
DSoundRender_QueryInterface(IBaseFilter
* iface
, REFIID riid
, LPVOID
* ppv
)
442 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
443 TRACE("(%p, %p)->(%s, %p)\n", This
, iface
, qzdebugstr_guid(riid
), ppv
);
447 if (IsEqualIID(riid
, &IID_IUnknown
))
449 else if (IsEqualIID(riid
, &IID_IPersist
))
451 else if (IsEqualIID(riid
, &IID_IMediaFilter
))
453 else if (IsEqualIID(riid
, &IID_IBaseFilter
))
455 else if (IsEqualIID(riid
, &IID_IBasicAudio
))
456 *ppv
= &This
->IBasicAudio_vtbl
;
457 else if (IsEqualIID(riid
, &IID_IReferenceClock
))
458 *ppv
= &This
->IReferenceClock_vtbl
;
459 else if (IsEqualIID(riid
, &IID_IMediaSeeking
))
460 return IUnknown_QueryInterface(This
->seekthru_unk
, riid
, ppv
);
461 else if (IsEqualIID(riid
, &IID_IAMDirectSound
))
462 *ppv
= &This
->IAMDirectSound_vtbl
;
466 IUnknown_AddRef((IUnknown
*)(*ppv
));
470 if (!IsEqualIID(riid
, &IID_IPin
) && !IsEqualIID(riid
, &IID_IVideoWindow
))
471 FIXME("No interface for %s!\n", qzdebugstr_guid(riid
));
473 return E_NOINTERFACE
;
476 static ULONG WINAPI
DSoundRender_AddRef(IBaseFilter
* iface
)
478 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
479 ULONG refCount
= InterlockedIncrement(&This
->refCount
);
481 TRACE("(%p/%p)->() AddRef from %d\n", This
, iface
, refCount
- 1);
486 static ULONG WINAPI
DSoundRender_Release(IBaseFilter
* iface
)
488 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
489 ULONG refCount
= InterlockedDecrement(&This
->refCount
);
491 TRACE("(%p)->() Release from %d\n", This
, refCount
+ 1);
498 IReferenceClock_Release(This
->pClock
);
501 IDirectSoundBuffer_Release(This
->dsbuffer
);
502 This
->dsbuffer
= NULL
;
504 IDirectSound_Release(This
->dsound
);
507 if (SUCCEEDED(IPin_ConnectedTo((IPin
*)This
->pInputPin
, &pConnectedTo
)))
509 IPin_Disconnect(pConnectedTo
);
510 IPin_Release(pConnectedTo
);
512 IPin_Disconnect((IPin
*)This
->pInputPin
);
514 IPin_Release((IPin
*)This
->pInputPin
);
517 This
->IBasicAudio_vtbl
= NULL
;
518 if (This
->seekthru_unk
)
519 IUnknown_Release(This
->seekthru_unk
);
520 This
->csFilter
.DebugInfo
->Spare
[0] = 0;
521 DeleteCriticalSection(&This
->csFilter
);
523 CloseHandle(This
->state_change
);
524 CloseHandle(This
->blocked
);
526 TRACE("Destroying Audio Renderer\n");
535 /** IPersist methods **/
537 static HRESULT WINAPI
DSoundRender_GetClassID(IBaseFilter
* iface
, CLSID
* pClsid
)
539 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
540 TRACE("(%p/%p)->(%p)\n", This
, iface
, pClsid
);
542 *pClsid
= CLSID_DSoundRender
;
547 /** IMediaFilter methods **/
549 static HRESULT WINAPI
DSoundRender_Stop(IBaseFilter
* iface
)
552 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
554 TRACE("(%p/%p)->()\n", This
, iface
);
556 EnterCriticalSection(&This
->csFilter
);
561 hr
= IDirectSoundBuffer_GetStatus(This
->dsbuffer
, &state
);
564 if (state
& DSBSTATUS_PLAYING
)
565 hr
= IDirectSoundBuffer_Stop(This
->dsbuffer
);
569 This
->state
= State_Stopped
;
571 /* Complete our transition */
572 SetEvent(This
->state_change
);
573 SetEvent(This
->blocked
);
574 MediaSeekingPassThru_ResetMediaTime(This
->seekthru_unk
);
576 LeaveCriticalSection(&This
->csFilter
);
581 static HRESULT WINAPI
DSoundRender_Pause(IBaseFilter
* iface
)
584 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
586 TRACE("(%p/%p)->()\n", This
, iface
);
588 EnterCriticalSection(&This
->csFilter
);
589 if (This
->state
!= State_Paused
)
592 if (This
->state
== State_Stopped
)
594 This
->pInputPin
->end_of_stream
= 0;
599 hr
= IDirectSoundBuffer_GetStatus(This
->dsbuffer
, &state
);
602 if (state
& DSBSTATUS_PLAYING
)
603 hr
= IDirectSoundBuffer_Stop(This
->dsbuffer
);
607 This
->state
= State_Paused
;
609 ResetEvent(This
->blocked
);
610 ResetEvent(This
->state_change
);
612 LeaveCriticalSection(&This
->csFilter
);
617 static HRESULT WINAPI
DSoundRender_Run(IBaseFilter
* iface
, REFERENCE_TIME tStart
)
620 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
622 TRACE("(%p/%p)->(%s)\n", This
, iface
, wine_dbgstr_longlong(tStart
));
624 EnterCriticalSection(&This
->csFilter
);
626 This
->rtStreamStart
= tStart
;
627 if (This
->state
== State_Paused
)
629 /* Unblock our thread, state changing from paused to running doesn't need a reset for state change */
630 SetEvent(This
->blocked
);
632 else if (This
->state
== State_Stopped
)
634 ResetEvent(This
->state_change
);
635 This
->pInputPin
->end_of_stream
= 0;
637 ResetEvent(This
->blocked
);
639 This
->state
= State_Running
;
641 LeaveCriticalSection(&This
->csFilter
);
646 static HRESULT WINAPI
DSoundRender_GetState(IBaseFilter
* iface
, DWORD dwMilliSecsTimeout
, FILTER_STATE
*pState
)
649 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
651 TRACE("(%p/%p)->(%d, %p)\n", This
, iface
, dwMilliSecsTimeout
, pState
);
653 if (WaitForSingleObject(This
->state_change
, dwMilliSecsTimeout
) == WAIT_TIMEOUT
)
654 hr
= VFW_S_STATE_INTERMEDIATE
;
658 EnterCriticalSection(&This
->csFilter
);
660 *pState
= This
->state
;
662 LeaveCriticalSection(&This
->csFilter
);
667 static HRESULT WINAPI
DSoundRender_SetSyncSource(IBaseFilter
* iface
, IReferenceClock
*pClock
)
669 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
671 TRACE("(%p/%p)->(%p)\n", This
, iface
, pClock
);
673 EnterCriticalSection(&This
->csFilter
);
676 IReferenceClock_Release(This
->pClock
);
677 This
->pClock
= pClock
;
679 IReferenceClock_AddRef(This
->pClock
);
681 LeaveCriticalSection(&This
->csFilter
);
686 static HRESULT WINAPI
DSoundRender_GetSyncSource(IBaseFilter
* iface
, IReferenceClock
**ppClock
)
688 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
690 TRACE("(%p/%p)->(%p)\n", This
, iface
, ppClock
);
692 EnterCriticalSection(&This
->csFilter
);
694 *ppClock
= This
->pClock
;
696 IReferenceClock_AddRef(This
->pClock
);
698 LeaveCriticalSection(&This
->csFilter
);
703 /** IBaseFilter implementation **/
705 static HRESULT
DSoundRender_GetPin(IBaseFilter
*iface
, ULONG pos
, IPin
**pin
, DWORD
*lastsynctick
)
707 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
709 /* Our pins are static, not changing so setting static tick count is ok */
715 *pin
= (IPin
*)This
->pInputPin
;
720 static HRESULT WINAPI
DSoundRender_EnumPins(IBaseFilter
* iface
, IEnumPins
**ppEnum
)
722 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
724 TRACE("(%p/%p)->(%p)\n", This
, iface
, ppEnum
);
726 return IEnumPinsImpl_Construct(ppEnum
, DSoundRender_GetPin
, iface
);
729 static HRESULT WINAPI
DSoundRender_FindPin(IBaseFilter
* iface
, LPCWSTR Id
, IPin
**ppPin
)
731 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
733 TRACE("(%p/%p)->(%s,%p)\n", This
, iface
, debugstr_w(Id
), ppPin
);
735 FIXME("DSoundRender::FindPin(...)\n");
737 /* FIXME: critical section */
742 static HRESULT WINAPI
DSoundRender_QueryFilterInfo(IBaseFilter
* iface
, FILTER_INFO
*pInfo
)
744 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
746 TRACE("(%p/%p)->(%p)\n", This
, iface
, pInfo
);
748 strcpyW(pInfo
->achName
, This
->filterInfo
.achName
);
749 pInfo
->pGraph
= This
->filterInfo
.pGraph
;
752 IFilterGraph_AddRef(pInfo
->pGraph
);
757 static HRESULT WINAPI
DSoundRender_JoinFilterGraph(IBaseFilter
* iface
, IFilterGraph
*pGraph
, LPCWSTR pName
)
759 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
761 TRACE("(%p/%p)->(%p, %s)\n", This
, iface
, pGraph
, debugstr_w(pName
));
763 EnterCriticalSection(&This
->csFilter
);
766 strcpyW(This
->filterInfo
.achName
, pName
);
768 *This
->filterInfo
.achName
= '\0';
769 This
->filterInfo
.pGraph
= pGraph
; /* NOTE: do NOT increase ref. count */
771 LeaveCriticalSection(&This
->csFilter
);
776 static HRESULT WINAPI
DSoundRender_QueryVendorInfo(IBaseFilter
* iface
, LPWSTR
*pVendorInfo
)
778 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
779 TRACE("(%p/%p)->(%p)\n", This
, iface
, pVendorInfo
);
783 static const IBaseFilterVtbl DSoundRender_Vtbl
=
785 DSoundRender_QueryInterface
,
787 DSoundRender_Release
,
788 DSoundRender_GetClassID
,
792 DSoundRender_GetState
,
793 DSoundRender_SetSyncSource
,
794 DSoundRender_GetSyncSource
,
795 DSoundRender_EnumPins
,
796 DSoundRender_FindPin
,
797 DSoundRender_QueryFilterInfo
,
798 DSoundRender_JoinFilterGraph
,
799 DSoundRender_QueryVendorInfo
802 static HRESULT WINAPI
DSoundRender_InputPin_ReceiveConnection(IPin
* iface
, IPin
* pReceivePin
, const AM_MEDIA_TYPE
* pmt
)
804 InputPin
*This
= (InputPin
*)iface
;
805 PIN_DIRECTION pindirReceive
;
806 DSoundRenderImpl
*DSImpl
;
809 TRACE("(%p)->(%p, %p)\n", This
, pReceivePin
, pmt
);
810 dump_AM_MEDIA_TYPE(pmt
);
812 EnterCriticalSection(This
->pin
.pCritSec
);
814 DSImpl
= (DSoundRenderImpl
*)This
->pin
.pinInfo
.pFilter
;
815 DSImpl
->rtLastStop
= -1;
817 if (This
->pin
.pConnectedTo
)
818 hr
= VFW_E_ALREADY_CONNECTED
;
820 if (SUCCEEDED(hr
) && This
->pin
.fnQueryAccept(This
->pin
.pUserData
, pmt
) != S_OK
)
821 hr
= VFW_E_TYPE_NOT_ACCEPTED
;
825 IPin_QueryDirection(pReceivePin
, &pindirReceive
);
827 if (pindirReceive
!= PINDIR_OUTPUT
)
829 ERR("Can't connect from non-output pin\n");
830 hr
= VFW_E_INVALID_DIRECTION
;
836 WAVEFORMATEX
*format
;
837 DSBUFFERDESC buf_desc
;
839 TRACE("MajorType %s\n", debugstr_guid(&pmt
->majortype
));
840 TRACE("SubType %s\n", debugstr_guid(&pmt
->subtype
));
841 TRACE("Format %s\n", debugstr_guid(&pmt
->formattype
));
842 TRACE("Size %d\n", pmt
->cbFormat
);
844 format
= (WAVEFORMATEX
*)pmt
->pbFormat
;
846 DSImpl
->buf_size
= format
->nAvgBytesPerSec
;
848 memset(&buf_desc
,0,sizeof(DSBUFFERDESC
));
849 buf_desc
.dwSize
= sizeof(DSBUFFERDESC
);
850 buf_desc
.dwFlags
= DSBCAPS_CTRLVOLUME
| DSBCAPS_CTRLPAN
|
851 DSBCAPS_CTRLFREQUENCY
|
852 DSBCAPS_GETCURRENTPOSITION2
;
853 buf_desc
.dwBufferBytes
= DSImpl
->buf_size
;
854 buf_desc
.lpwfxFormat
= format
;
855 hr
= IDirectSound_CreateSoundBuffer(DSImpl
->dsound
, &buf_desc
, &DSImpl
->dsbuffer
, NULL
);
857 ERR("Can't create sound buffer (%x)\n", hr
);
862 hr
= IDirectSoundBuffer_SetVolume(DSImpl
->dsbuffer
, DSImpl
->volume
);
864 ERR("Can't set volume to %d (%x)\n", DSImpl
->volume
, hr
);
866 hr
= IDirectSoundBuffer_SetPan(DSImpl
->dsbuffer
, DSImpl
->pan
);
868 ERR("Can't set pan to %d (%x)\n", DSImpl
->pan
, hr
);
870 DSImpl
->write_pos
= 0;
876 CopyMediaType(&This
->pin
.mtCurrent
, pmt
);
877 This
->pin
.pConnectedTo
= pReceivePin
;
878 IPin_AddRef(pReceivePin
);
880 else if (hr
!= VFW_E_ALREADY_CONNECTED
)
882 if (DSImpl
->dsbuffer
)
883 IDirectSoundBuffer_Release(DSImpl
->dsbuffer
);
884 DSImpl
->dsbuffer
= NULL
;
887 LeaveCriticalSection(This
->pin
.pCritSec
);
892 static HRESULT WINAPI
DSoundRender_InputPin_Disconnect(IPin
* iface
)
894 IPinImpl
*This
= (IPinImpl
*)iface
;
895 DSoundRenderImpl
*DSImpl
;
897 TRACE("(%p)->()\n", iface
);
899 DSImpl
= (DSoundRenderImpl
*)This
->pinInfo
.pFilter
;
900 if (DSImpl
->dsbuffer
)
901 IDirectSoundBuffer_Release(DSImpl
->dsbuffer
);
902 DSImpl
->dsbuffer
= NULL
;
904 return IPinImpl_Disconnect(iface
);
907 static HRESULT WINAPI
DSoundRender_InputPin_EndOfStream(IPin
* iface
)
909 InputPin
* This
= (InputPin
*)iface
;
910 DSoundRenderImpl
*me
= (DSoundRenderImpl
*)This
->pin
.pinInfo
.pFilter
;
911 IMediaEventSink
* pEventSink
;
914 EnterCriticalSection(This
->pin
.pCritSec
);
916 TRACE("(%p/%p)->()\n", This
, iface
);
917 hr
= InputPin_EndOfStream(iface
);
921 LeaveCriticalSection(This
->pin
.pCritSec
);
925 hr
= IFilterGraph_QueryInterface(me
->filterInfo
.pGraph
, &IID_IMediaEventSink
, (LPVOID
*)&pEventSink
);
930 silence
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, me
->buf_size
);
933 memset(silence
, 0, me
->buf_size
);
934 DSoundRender_SendSampleData((DSoundRenderImpl
*)This
->pin
.pinInfo
.pFilter
, silence
, me
->buf_size
);
935 HeapFree(GetProcessHeap(), 0, silence
);
938 hr
= IMediaEventSink_Notify(pEventSink
, EC_COMPLETE
, S_OK
, 0);
939 IMediaEventSink_Release(pEventSink
);
941 MediaSeekingPassThru_EOS(me
->seekthru_unk
);
942 LeaveCriticalSection(This
->pin
.pCritSec
);
947 static HRESULT WINAPI
DSoundRender_InputPin_BeginFlush(IPin
* iface
)
949 InputPin
*This
= (InputPin
*)iface
;
950 DSoundRenderImpl
*pFilter
= (DSoundRenderImpl
*)This
->pin
.pinInfo
.pFilter
;
955 EnterCriticalSection(This
->pin
.pCritSec
);
956 hr
= InputPin_BeginFlush(iface
);
957 SetEvent(pFilter
->blocked
);
958 LeaveCriticalSection(This
->pin
.pCritSec
);
963 static HRESULT WINAPI
DSoundRender_InputPin_EndFlush(IPin
* iface
)
965 InputPin
*This
= (InputPin
*)iface
;
966 DSoundRenderImpl
*pFilter
= (DSoundRenderImpl
*)This
->pin
.pinInfo
.pFilter
;
971 EnterCriticalSection(This
->pin
.pCritSec
);
972 if (pFilter
->in_loop
) {
973 ResetEvent(pFilter
->state_change
);
974 LeaveCriticalSection(This
->pin
.pCritSec
);
975 WaitForSingleObject(pFilter
->state_change
, -1);
976 EnterCriticalSection(This
->pin
.pCritSec
);
978 if (pFilter
->state
!= State_Stopped
)
979 ResetEvent(pFilter
->blocked
);
981 if (pFilter
->dsbuffer
)
985 IDirectSoundBuffer_Stop(pFilter
->dsbuffer
);
988 IDirectSoundBuffer_SetCurrentPosition(pFilter
->dsbuffer
, 0);
989 pFilter
->write_pos
= pFilter
->last_play_pos
= 0;
990 ++pFilter
->play_loops
;
991 pFilter
->write_loops
= pFilter
->play_loops
;
993 IDirectSoundBuffer_Lock(pFilter
->dsbuffer
, 0, 0, (LPVOID
*)&buffer
, &size
, NULL
, NULL
, DSBLOCK_ENTIREBUFFER
);
994 memset(buffer
, 0, size
);
995 IDirectSoundBuffer_Unlock(pFilter
->dsbuffer
, buffer
, size
, NULL
, 0);
997 hr
= InputPin_EndFlush(iface
);
998 LeaveCriticalSection(This
->pin
.pCritSec
);
999 MediaSeekingPassThru_ResetMediaTime(pFilter
->seekthru_unk
);
1004 static const IPinVtbl DSoundRender_InputPin_Vtbl
=
1006 InputPin_QueryInterface
,
1010 DSoundRender_InputPin_ReceiveConnection
,
1011 DSoundRender_InputPin_Disconnect
,
1012 IPinImpl_ConnectedTo
,
1013 IPinImpl_ConnectionMediaType
,
1014 IPinImpl_QueryPinInfo
,
1015 IPinImpl_QueryDirection
,
1017 IPinImpl_QueryAccept
,
1018 IPinImpl_EnumMediaTypes
,
1019 IPinImpl_QueryInternalConnections
,
1020 DSoundRender_InputPin_EndOfStream
,
1021 DSoundRender_InputPin_BeginFlush
,
1022 DSoundRender_InputPin_EndFlush
,
1026 /*** IUnknown methods ***/
1027 static HRESULT WINAPI
Basicaudio_QueryInterface(IBasicAudio
*iface
,
1030 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
1032 TRACE("(%p/%p)->(%s (%p), %p)\n", This
, iface
, debugstr_guid(riid
), riid
, ppvObj
);
1034 return DSoundRender_QueryInterface((IBaseFilter
*)This
, riid
, ppvObj
);
1037 static ULONG WINAPI
Basicaudio_AddRef(IBasicAudio
*iface
) {
1038 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
1040 TRACE("(%p/%p)->()\n", This
, iface
);
1042 return DSoundRender_AddRef((IBaseFilter
*)This
);
1045 static ULONG WINAPI
Basicaudio_Release(IBasicAudio
*iface
) {
1046 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
1048 TRACE("(%p/%p)->()\n", This
, iface
);
1050 return DSoundRender_Release((IBaseFilter
*)This
);
1053 /*** IDispatch methods ***/
1054 static HRESULT WINAPI
Basicaudio_GetTypeInfoCount(IBasicAudio
*iface
,
1056 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
1058 TRACE("(%p/%p)->(%p): stub !!!\n", This
, iface
, pctinfo
);
1063 static HRESULT WINAPI
Basicaudio_GetTypeInfo(IBasicAudio
*iface
,
1066 ITypeInfo
**ppTInfo
) {
1067 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
1069 TRACE("(%p/%p)->(%d, %d, %p): stub !!!\n", This
, iface
, iTInfo
, lcid
, ppTInfo
);
1074 static HRESULT WINAPI
Basicaudio_GetIDsOfNames(IBasicAudio
*iface
,
1080 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
1082 TRACE("(%p/%p)->(%s (%p), %p, %d, %d, %p): stub !!!\n", This
, iface
, debugstr_guid(riid
), riid
, rgszNames
, cNames
, lcid
, rgDispId
);
1087 static HRESULT WINAPI
Basicaudio_Invoke(IBasicAudio
*iface
,
1088 DISPID dispIdMember
,
1092 DISPPARAMS
*pDispParams
,
1094 EXCEPINFO
*pExepInfo
,
1096 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
1098 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
);
1103 /*** IBasicAudio methods ***/
1104 static HRESULT WINAPI
Basicaudio_put_Volume(IBasicAudio
*iface
,
1106 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
1108 TRACE("(%p/%p)->(%d)\n", This
, iface
, lVolume
);
1110 if (lVolume
> DSBVOLUME_MAX
|| lVolume
< DSBVOLUME_MIN
)
1111 return E_INVALIDARG
;
1113 if (This
->dsbuffer
) {
1114 if (FAILED(IDirectSoundBuffer_SetVolume(This
->dsbuffer
, lVolume
)))
1118 This
->volume
= lVolume
;
1122 static HRESULT WINAPI
Basicaudio_get_Volume(IBasicAudio
*iface
,
1124 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
1126 TRACE("(%p/%p)->(%p)\n", This
, iface
, plVolume
);
1131 *plVolume
= This
->volume
;
1135 static HRESULT WINAPI
Basicaudio_put_Balance(IBasicAudio
*iface
,
1137 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
1139 TRACE("(%p/%p)->(%d)\n", This
, iface
, lBalance
);
1141 if (lBalance
< DSBPAN_LEFT
|| lBalance
> DSBPAN_RIGHT
)
1142 return E_INVALIDARG
;
1144 if (This
->dsbuffer
) {
1145 if (FAILED(IDirectSoundBuffer_SetPan(This
->dsbuffer
, lBalance
)))
1149 This
->pan
= lBalance
;
1153 static HRESULT WINAPI
Basicaudio_get_Balance(IBasicAudio
*iface
,
1155 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
1157 TRACE("(%p/%p)->(%p)\n", This
, iface
, plBalance
);
1162 *plBalance
= This
->pan
;
1166 static const IBasicAudioVtbl IBasicAudio_Vtbl
=
1168 Basicaudio_QueryInterface
,
1171 Basicaudio_GetTypeInfoCount
,
1172 Basicaudio_GetTypeInfo
,
1173 Basicaudio_GetIDsOfNames
,
1175 Basicaudio_put_Volume
,
1176 Basicaudio_get_Volume
,
1177 Basicaudio_put_Balance
,
1178 Basicaudio_get_Balance
1182 /*** IUnknown methods ***/
1183 static HRESULT WINAPI
ReferenceClock_QueryInterface(IReferenceClock
*iface
,
1187 ICOM_THIS_MULTI(DSoundRenderImpl
, IReferenceClock_vtbl
, iface
);
1189 TRACE("(%p/%p)->(%s (%p), %p)\n", This
, iface
, debugstr_guid(riid
), riid
, ppvObj
);
1191 return DSoundRender_QueryInterface((IBaseFilter
*)This
, riid
, ppvObj
);
1194 static ULONG WINAPI
ReferenceClock_AddRef(IReferenceClock
*iface
)
1196 ICOM_THIS_MULTI(DSoundRenderImpl
, IReferenceClock_vtbl
, iface
);
1198 TRACE("(%p/%p)->()\n", This
, iface
);
1200 return DSoundRender_AddRef((IBaseFilter
*)This
);
1203 static ULONG WINAPI
ReferenceClock_Release(IReferenceClock
*iface
)
1205 ICOM_THIS_MULTI(DSoundRenderImpl
, IReferenceClock_vtbl
, iface
);
1207 TRACE("(%p/%p)->()\n", This
, iface
);
1209 return DSoundRender_Release((IBaseFilter
*)This
);
1212 /*** IReferenceClock methods ***/
1213 static HRESULT WINAPI
ReferenceClock_GetTime(IReferenceClock
*iface
,
1214 REFERENCE_TIME
*pTime
)
1216 ICOM_THIS_MULTI(DSoundRenderImpl
, IReferenceClock_vtbl
, iface
);
1217 HRESULT hr
= E_FAIL
;
1220 TRACE("(%p/%p)->(%p)\n", This
, iface
, pTime
);
1223 hr
= DSoundRender_GetPos(This
, &play_pos
, pTime
);
1225 ERR("Could not get reference time (%x)!\n", hr
);
1230 static HRESULT WINAPI
ReferenceClock_AdviseTime(IReferenceClock
*iface
,
1231 REFERENCE_TIME rtBaseTime
,
1232 REFERENCE_TIME rtStreamTime
,
1234 DWORD_PTR
*pdwAdviseCookie
)
1236 ICOM_THIS_MULTI(DSoundRenderImpl
, IReferenceClock_vtbl
, iface
);
1238 FIXME("(%p/%p)->(%s, %s, %p, %p): stub!\n", This
, iface
, wine_dbgstr_longlong(rtBaseTime
), wine_dbgstr_longlong(rtStreamTime
), (void*)hEvent
, pdwAdviseCookie
);
1243 static HRESULT WINAPI
ReferenceClock_AdvisePeriodic(IReferenceClock
*iface
,
1244 REFERENCE_TIME rtBaseTime
,
1245 REFERENCE_TIME rtStreamTime
,
1246 HSEMAPHORE hSemaphore
,
1247 DWORD_PTR
*pdwAdviseCookie
)
1249 ICOM_THIS_MULTI(DSoundRenderImpl
, IReferenceClock_vtbl
, iface
);
1251 FIXME("(%p/%p)->(%s, %s, %p, %p): stub!\n", This
, iface
, wine_dbgstr_longlong(rtBaseTime
), wine_dbgstr_longlong(rtStreamTime
), (void*)hSemaphore
, pdwAdviseCookie
);
1256 static HRESULT WINAPI
ReferenceClock_Unadvise(IReferenceClock
*iface
,
1257 DWORD_PTR dwAdviseCookie
)
1259 ICOM_THIS_MULTI(DSoundRenderImpl
, IReferenceClock_vtbl
, iface
);
1261 FIXME("(%p/%p)->(%p): stub!\n", This
, iface
, (void*)dwAdviseCookie
);
1266 static const IReferenceClockVtbl IReferenceClock_Vtbl
=
1268 ReferenceClock_QueryInterface
,
1269 ReferenceClock_AddRef
,
1270 ReferenceClock_Release
,
1271 ReferenceClock_GetTime
,
1272 ReferenceClock_AdviseTime
,
1273 ReferenceClock_AdvisePeriodic
,
1274 ReferenceClock_Unadvise
1277 /*** IUnknown methods ***/
1278 static HRESULT WINAPI
AMDirectSound_QueryInterface(IAMDirectSound
*iface
,
1282 ICOM_THIS_MULTI(DSoundRenderImpl
, IAMDirectSound_vtbl
, iface
);
1284 TRACE("(%p/%p)->(%s (%p), %p)\n", This
, iface
, debugstr_guid(riid
), riid
, ppvObj
);
1286 return DSoundRender_QueryInterface((IBaseFilter
*)This
, riid
, ppvObj
);
1289 static ULONG WINAPI
AMDirectSound_AddRef(IAMDirectSound
*iface
)
1291 ICOM_THIS_MULTI(DSoundRenderImpl
, IAMDirectSound_vtbl
, iface
);
1293 TRACE("(%p/%p)->()\n", This
, iface
);
1295 return DSoundRender_AddRef((IBaseFilter
*)This
);
1298 static ULONG WINAPI
AMDirectSound_Release(IAMDirectSound
*iface
)
1300 ICOM_THIS_MULTI(DSoundRenderImpl
, IAMDirectSound_vtbl
, iface
);
1302 TRACE("(%p/%p)->()\n", This
, iface
);
1304 return DSoundRender_Release((IBaseFilter
*)This
);
1307 /*** IAMDirectSound methods ***/
1308 static HRESULT WINAPI
AMDirectSound_GetDirectSoundInterface(IAMDirectSound
*iface
, IDirectSound
**ds
)
1310 ICOM_THIS_MULTI(DSoundRenderImpl
, IAMDirectSound_vtbl
, iface
);
1312 FIXME("(%p/%p)->(%p): stub\n", This
, iface
, ds
);
1317 static HRESULT WINAPI
AMDirectSound_GetPrimaryBufferInterface(IAMDirectSound
*iface
, IDirectSoundBuffer
**buf
)
1319 ICOM_THIS_MULTI(DSoundRenderImpl
, IAMDirectSound_vtbl
, iface
);
1321 FIXME("(%p/%p)->(%p): stub\n", This
, iface
, buf
);
1326 static HRESULT WINAPI
AMDirectSound_GetSecondaryBufferInterface(IAMDirectSound
*iface
, IDirectSoundBuffer
**buf
)
1328 ICOM_THIS_MULTI(DSoundRenderImpl
, IAMDirectSound_vtbl
, iface
);
1330 FIXME("(%p/%p)->(%p): stub\n", This
, iface
, buf
);
1335 static HRESULT WINAPI
AMDirectSound_ReleaseDirectSoundInterface(IAMDirectSound
*iface
, IDirectSound
*ds
)
1337 ICOM_THIS_MULTI(DSoundRenderImpl
, IAMDirectSound_vtbl
, iface
);
1339 FIXME("(%p/%p)->(%p): stub\n", This
, iface
, ds
);
1344 static HRESULT WINAPI
AMDirectSound_ReleasePrimaryBufferInterface(IAMDirectSound
*iface
, IDirectSoundBuffer
*buf
)
1346 ICOM_THIS_MULTI(DSoundRenderImpl
, IAMDirectSound_vtbl
, iface
);
1348 FIXME("(%p/%p)->(%p): stub\n", This
, iface
, buf
);
1353 static HRESULT WINAPI
AMDirectSound_ReleaseSecondaryBufferInterface(IAMDirectSound
*iface
, IDirectSoundBuffer
*buf
)
1355 ICOM_THIS_MULTI(DSoundRenderImpl
, IAMDirectSound_vtbl
, iface
);
1357 FIXME("(%p/%p)->(%p): stub\n", This
, iface
, buf
);
1362 static HRESULT WINAPI
AMDirectSound_SetFocusWindow(IAMDirectSound
*iface
, HWND hwnd
, BOOL bgsilent
)
1364 ICOM_THIS_MULTI(DSoundRenderImpl
, IAMDirectSound_vtbl
, iface
);
1366 FIXME("(%p/%p)->(%p,%d): stub\n", This
, iface
, hwnd
, bgsilent
);
1371 static HRESULT WINAPI
AMDirectSound_GetFocusWindow(IAMDirectSound
*iface
, HWND hwnd
)
1373 ICOM_THIS_MULTI(DSoundRenderImpl
, IAMDirectSound_vtbl
, iface
);
1375 FIXME("(%p/%p)->(%p): stub\n", This
, iface
, hwnd
);
1380 static const IAMDirectSoundVtbl IAMDirectSound_Vtbl
=
1382 AMDirectSound_QueryInterface
,
1383 AMDirectSound_AddRef
,
1384 AMDirectSound_Release
,
1385 AMDirectSound_GetDirectSoundInterface
,
1386 AMDirectSound_GetPrimaryBufferInterface
,
1387 AMDirectSound_GetSecondaryBufferInterface
,
1388 AMDirectSound_ReleaseDirectSoundInterface
,
1389 AMDirectSound_ReleasePrimaryBufferInterface
,
1390 AMDirectSound_ReleaseSecondaryBufferInterface
,
1391 AMDirectSound_SetFocusWindow
,
1392 AMDirectSound_GetFocusWindow