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"
36 #include "wine/unicode.h"
37 #include "wine/debug.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(quartz
);
41 static const WCHAR wcsInputPinName
[] = {'i','n','p','u','t',' ','p','i','n',0};
43 static const IBaseFilterVtbl DSoundRender_Vtbl
;
44 static const IPinVtbl DSoundRender_InputPin_Vtbl
;
45 static const IMemInputPinVtbl MemInputPin_Vtbl
;
46 static const IBasicAudioVtbl IBasicAudio_Vtbl
;
47 static const IReferenceClockVtbl IReferenceClock_Vtbl
;
48 static const IMediaSeekingVtbl IMediaSeeking_Vtbl
;
50 typedef struct DSoundRenderImpl
52 const IBaseFilterVtbl
* lpVtbl
;
53 const IBasicAudioVtbl
*IBasicAudio_vtbl
;
54 const IReferenceClockVtbl
*IReferenceClock_vtbl
;
57 CRITICAL_SECTION csFilter
;
59 REFERENCE_TIME rtStreamStart
;
60 IReferenceClock
* pClock
;
61 FILTER_INFO filterInfo
;
67 LPDIRECTSOUNDBUFFER dsbuffer
;
74 REFERENCE_TIME play_time
;
75 MediaSeekingImpl mediaSeeking
;
81 static HRESULT
sound_mod_stop(IBaseFilter
*iface
)
83 FIXME("(%p) stub\n", iface
);
87 static HRESULT
sound_mod_start(IBaseFilter
*iface
)
89 FIXME("(%p) stub\n", iface
);
93 static HRESULT
sound_mod_rate(IBaseFilter
*iface
)
95 FIXME("(%p) stub\n", iface
);
99 static inline HRESULT
DSoundRender_GetPos(DSoundRenderImpl
*This
, DWORD
*pPlayPos
, DWORD
*pWritePos
, REFERENCE_TIME
*pRefTime
)
103 EnterCriticalSection(&This
->csFilter
);
105 hr
= IDirectSoundBuffer_GetCurrentPosition(This
->dsbuffer
, pPlayPos
, pWritePos
);
108 DWORD play_pos
= *pPlayPos
;
110 if (play_pos
< This
->last_play_pos
)
112 This
->last_play_pos
= play_pos
;
114 /* If we're really falling behind, kick the play time back */
115 if ((This
->play_loops
*This
->buf_size
)+play_pos
>=
116 (This
->write_loops
*This
->buf_size
)+This
->write_pos
)
121 REFERENCE_TIME play_time
;
122 play_time
= ((REFERENCE_TIME
)This
->play_loops
*10000000) +
123 ((REFERENCE_TIME
)play_pos
*10000000/This
->buf_size
);
125 /* Don't let time run backwards */
126 if(play_time
-This
->play_time
> 0)
127 This
->play_time
= play_time
;
131 *pRefTime
= This
->play_time
;
135 LeaveCriticalSection(&This
->csFilter
);
140 static HRESULT
DSoundRender_SendSampleData(DSoundRenderImpl
* This
, const BYTE
*data
, DWORD size
)
143 LPBYTE lpbuf1
= NULL
;
144 LPBYTE lpbuf2
= NULL
;
148 DWORD play_pos
,buf_free
;
151 hr
= DSoundRender_GetPos(This
, &play_pos
, NULL
, NULL
);
154 ERR("GetPos returned error: %x\n", hr
);
157 if (This
->write_pos
<= play_pos
)
158 buf_free
= play_pos
-This
->write_pos
;
160 buf_free
= This
->buf_size
- This
->write_pos
+ play_pos
;
162 /* Wait for enough of the buffer to empty before filling it */
163 if(buf_free
< This
->buf_size
/4)
169 size2
= min(buf_free
, size
);
170 hr
= IDirectSoundBuffer_Lock(This
->dsbuffer
, This
->write_pos
, size2
, (LPVOID
*)&lpbuf1
, &dwsize1
, (LPVOID
*)&lpbuf2
, &dwsize2
, 0);
172 ERR("Unable to lock sound buffer! (%x)\n", hr
);
175 /* TRACE("write_pos=%d, size=%d, sz1=%d, sz2=%d\n", This->write_pos, size2, dwsize1, dwsize2); */
177 memcpy(lpbuf1
, data
, dwsize1
);
179 memcpy(lpbuf2
, data
+ dwsize1
, dwsize2
);
181 hr
= IDirectSoundBuffer_Unlock(This
->dsbuffer
, lpbuf1
, dwsize1
, lpbuf2
, dwsize2
);
183 ERR("Unable to unlock sound buffer! (%x)\n", hr
);
185 size
-= dwsize1
+ dwsize2
;
186 data
+= dwsize1
+ dwsize2
;
187 This
->write_pos
+= dwsize1
+ dwsize2
;
188 if (This
->write_pos
>= This
->buf_size
)
190 This
->write_pos
-= This
->buf_size
;
193 } while (size
&& This
->state
== State_Running
);
198 static HRESULT
DSoundRender_Sample(LPVOID iface
, IMediaSample
* pSample
)
200 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
201 LPBYTE pbSrcStream
= NULL
;
202 long cbSrcStream
= 0;
203 REFERENCE_TIME tStart
, tStop
;
206 TRACE("%p %p\n", iface
, pSample
);
208 if (This
->state
!= State_Running
)
209 return VFW_E_WRONG_STATE
;
211 hr
= IMediaSample_GetPointer(pSample
, &pbSrcStream
);
214 ERR("Cannot get pointer to sample data (%x)\n", hr
);
218 hr
= IMediaSample_GetTime(pSample
, &tStart
, &tStop
);
220 ERR("Cannot get sample time (%x)\n", hr
);
222 cbSrcStream
= IMediaSample_GetActualDataLength(pSample
);
223 TRACE("Sample data ptr = %p, size = %ld\n", pbSrcStream
, cbSrcStream
);
225 #if 0 /* For debugging purpose */
228 for(i
= 0; i
< cbSrcStream
; i
++)
230 if ((i
!=0) && !(i
%16))
232 TRACE("%02x ", pbSrcStream
[i
]);
238 return DSoundRender_SendSampleData(This
, pbSrcStream
, cbSrcStream
);
241 static HRESULT
DSoundRender_QueryAccept(LPVOID iface
, const AM_MEDIA_TYPE
* pmt
)
243 WAVEFORMATEX
* format
= (WAVEFORMATEX
*)pmt
->pbFormat
;
244 TRACE("wFormatTag = %x %x\n", format
->wFormatTag
, WAVE_FORMAT_PCM
);
245 TRACE("nChannels = %d\n", format
->nChannels
);
246 TRACE("nSamplesPerSec = %d\n", format
->nAvgBytesPerSec
);
247 TRACE("nAvgBytesPerSec = %d\n", format
->nAvgBytesPerSec
);
248 TRACE("nBlockAlign = %d\n", format
->nBlockAlign
);
249 TRACE("wBitsPerSample = %d\n", format
->wBitsPerSample
);
251 if (IsEqualIID(&pmt
->majortype
, &MEDIATYPE_Audio
) && IsEqualIID(&pmt
->subtype
, &MEDIASUBTYPE_PCM
))
256 HRESULT
DSoundRender_create(IUnknown
* pUnkOuter
, LPVOID
* ppv
)
260 DSoundRenderImpl
* pDSoundRender
;
262 TRACE("(%p, %p)\n", pUnkOuter
, ppv
);
267 return CLASS_E_NOAGGREGATION
;
269 pDSoundRender
= CoTaskMemAlloc(sizeof(DSoundRenderImpl
));
271 return E_OUTOFMEMORY
;
272 ZeroMemory(pDSoundRender
, sizeof(DSoundRenderImpl
));
274 pDSoundRender
->lpVtbl
= &DSoundRender_Vtbl
;
275 pDSoundRender
->IBasicAudio_vtbl
= &IBasicAudio_Vtbl
;
276 pDSoundRender
->IReferenceClock_vtbl
= &IReferenceClock_Vtbl
;
277 pDSoundRender
->refCount
= 1;
278 InitializeCriticalSection(&pDSoundRender
->csFilter
);
279 pDSoundRender
->csFilter
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": DSoundRenderImpl.csFilter");
280 pDSoundRender
->state
= State_Stopped
;
282 pDSoundRender
->ppPins
= CoTaskMemAlloc(1 * sizeof(IPin
*));
283 if (!pDSoundRender
->ppPins
)
285 pDSoundRender
->csFilter
.DebugInfo
->Spare
[0] = 0;
286 DeleteCriticalSection(&pDSoundRender
->csFilter
);
287 CoTaskMemFree(pDSoundRender
);
288 return E_OUTOFMEMORY
;
291 /* construct input pin */
292 piInput
.dir
= PINDIR_INPUT
;
293 piInput
.pFilter
= (IBaseFilter
*)pDSoundRender
;
294 lstrcpynW(piInput
.achName
, wcsInputPinName
, sizeof(piInput
.achName
) / sizeof(piInput
.achName
[0]));
295 hr
= InputPin_Construct(&DSoundRender_InputPin_Vtbl
, &piInput
, DSoundRender_Sample
, pDSoundRender
, DSoundRender_QueryAccept
, NULL
, &pDSoundRender
->csFilter
, (IPin
**)&pDSoundRender
->pInputPin
);
299 hr
= DirectSoundCreate(NULL
, &pDSoundRender
->dsound
, NULL
);
301 ERR("Cannot create Direct Sound object (%x)\n", hr
);
306 MediaSeekingImpl_Init((IBaseFilter
*)pDSoundRender
, sound_mod_stop
, sound_mod_start
, sound_mod_rate
, &pDSoundRender
->mediaSeeking
, &pDSoundRender
->csFilter
);
307 pDSoundRender
->mediaSeeking
.lpVtbl
= &IMediaSeeking_Vtbl
;
309 pDSoundRender
->ppPins
[0] = (IPin
*)pDSoundRender
->pInputPin
;
310 *ppv
= (LPVOID
)pDSoundRender
;
314 if (pDSoundRender
->pInputPin
)
315 IPin_Release((IPin
*)pDSoundRender
->pInputPin
);
316 CoTaskMemFree(pDSoundRender
->ppPins
);
317 pDSoundRender
->csFilter
.DebugInfo
->Spare
[0] = 0;
318 DeleteCriticalSection(&pDSoundRender
->csFilter
);
319 CoTaskMemFree(pDSoundRender
);
325 static HRESULT WINAPI
DSoundRender_QueryInterface(IBaseFilter
* iface
, REFIID riid
, LPVOID
* ppv
)
327 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
328 TRACE("(%p, %p)->(%s, %p)\n", This
, iface
, qzdebugstr_guid(riid
), ppv
);
332 if (IsEqualIID(riid
, &IID_IUnknown
))
334 else if (IsEqualIID(riid
, &IID_IPersist
))
336 else if (IsEqualIID(riid
, &IID_IMediaFilter
))
338 else if (IsEqualIID(riid
, &IID_IBaseFilter
))
340 else if (IsEqualIID(riid
, &IID_IBasicAudio
))
341 *ppv
= (LPVOID
)&(This
->IBasicAudio_vtbl
);
342 else if (IsEqualIID(riid
, &IID_IReferenceClock
))
343 *ppv
= (LPVOID
)&(This
->IReferenceClock_vtbl
);
344 else if (IsEqualIID(riid
, &IID_IMediaSeeking
))
345 *ppv
= &This
->mediaSeeking
.lpVtbl
;
349 IUnknown_AddRef((IUnknown
*)(*ppv
));
353 if (!IsEqualIID(riid
, &IID_IPin
))
354 FIXME("No interface for %s!\n", qzdebugstr_guid(riid
));
356 return E_NOINTERFACE
;
359 static ULONG WINAPI
DSoundRender_AddRef(IBaseFilter
* iface
)
361 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
362 ULONG refCount
= InterlockedIncrement(&This
->refCount
);
364 TRACE("(%p/%p)->() AddRef from %d\n", This
, iface
, refCount
- 1);
369 static ULONG WINAPI
DSoundRender_Release(IBaseFilter
* iface
)
371 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
372 ULONG refCount
= InterlockedDecrement(&This
->refCount
);
374 TRACE("(%p)->() Release from %d\n", This
, refCount
+ 1);
381 IReferenceClock_Release(This
->pClock
);
384 IDirectSoundBuffer_Release(This
->dsbuffer
);
385 This
->dsbuffer
= NULL
;
387 IDirectSound_Release(This
->dsound
);
390 if (SUCCEEDED(IPin_ConnectedTo(This
->ppPins
[0], &pConnectedTo
)))
392 IPin_Disconnect(pConnectedTo
);
393 IPin_Release(pConnectedTo
);
395 IPin_Disconnect(This
->ppPins
[0]);
397 IPin_Release(This
->ppPins
[0]);
399 CoTaskMemFree(This
->ppPins
);
401 This
->IBasicAudio_vtbl
= NULL
;
403 This
->csFilter
.DebugInfo
->Spare
[0] = 0;
404 DeleteCriticalSection(&This
->csFilter
);
406 TRACE("Destroying Audio Renderer\n");
415 /** IPersist methods **/
417 static HRESULT WINAPI
DSoundRender_GetClassID(IBaseFilter
* iface
, CLSID
* pClsid
)
419 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
420 TRACE("(%p/%p)->(%p)\n", This
, iface
, pClsid
);
422 *pClsid
= CLSID_DSoundRender
;
427 /** IMediaFilter methods **/
429 static HRESULT WINAPI
DSoundRender_Stop(IBaseFilter
* iface
)
432 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
434 TRACE("(%p/%p)->()\n", This
, iface
);
436 EnterCriticalSection(&This
->csFilter
);
441 hr
= IDirectSoundBuffer_GetStatus(This
->dsbuffer
, &state
);
444 if (state
& DSBSTATUS_PLAYING
)
445 hr
= IDirectSoundBuffer_Stop(This
->dsbuffer
);
449 This
->state
= State_Stopped
;
451 LeaveCriticalSection(&This
->csFilter
);
456 static HRESULT WINAPI
DSoundRender_Pause(IBaseFilter
* iface
)
459 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
461 TRACE("(%p/%p)->()\n", This
, iface
);
463 EnterCriticalSection(&This
->csFilter
);
468 hr
= IDirectSoundBuffer_GetStatus(This
->dsbuffer
, &state
);
471 if (state
& DSBSTATUS_PLAYING
)
472 hr
= IDirectSoundBuffer_Stop(This
->dsbuffer
);
476 This
->state
= State_Paused
;
478 LeaveCriticalSection(&This
->csFilter
);
483 static HRESULT WINAPI
DSoundRender_Run(IBaseFilter
* iface
, REFERENCE_TIME tStart
)
486 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
488 TRACE("(%p/%p)->(%s)\n", This
, iface
, wine_dbgstr_longlong(tStart
));
490 EnterCriticalSection(&This
->csFilter
);
492 /* It's okay if there's no buffer yet. It'll start when it's created */
495 if (This
->state
== State_Stopped
)
500 IDirectSoundBuffer_Lock(This
->dsbuffer
, 0, 0, (void**)&buf1
, &size1
, NULL
, NULL
, DSBLOCK_ENTIREBUFFER
);
501 memset(buf1
, 0, size1
);
502 IDirectSoundBuffer_Unlock(This
->dsbuffer
, buf1
, size1
, NULL
, 0);
504 hr
= IDirectSoundBuffer_Play(This
->dsbuffer
, 0, 0, DSBPLAY_LOOPING
);
506 ERR("Can't start playing! (%x)\n", hr
);
510 This
->rtStreamStart
= tStart
;
511 This
->state
= State_Running
;
514 LeaveCriticalSection(&This
->csFilter
);
519 static HRESULT WINAPI
DSoundRender_GetState(IBaseFilter
* iface
, DWORD dwMilliSecsTimeout
, FILTER_STATE
*pState
)
521 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
523 TRACE("(%p/%p)->(%d, %p)\n", This
, iface
, dwMilliSecsTimeout
, pState
);
525 EnterCriticalSection(&This
->csFilter
);
527 *pState
= This
->state
;
529 LeaveCriticalSection(&This
->csFilter
);
534 static HRESULT WINAPI
DSoundRender_SetSyncSource(IBaseFilter
* iface
, IReferenceClock
*pClock
)
536 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
538 TRACE("(%p/%p)->(%p)\n", This
, iface
, pClock
);
540 EnterCriticalSection(&This
->csFilter
);
543 IReferenceClock_Release(This
->pClock
);
544 This
->pClock
= pClock
;
546 IReferenceClock_AddRef(This
->pClock
);
548 LeaveCriticalSection(&This
->csFilter
);
553 static HRESULT WINAPI
DSoundRender_GetSyncSource(IBaseFilter
* iface
, IReferenceClock
**ppClock
)
555 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
557 TRACE("(%p/%p)->(%p)\n", This
, iface
, ppClock
);
559 EnterCriticalSection(&This
->csFilter
);
561 *ppClock
= This
->pClock
;
562 IReferenceClock_AddRef(This
->pClock
);
564 LeaveCriticalSection(&This
->csFilter
);
569 /** IBaseFilter implementation **/
571 static HRESULT WINAPI
DSoundRender_EnumPins(IBaseFilter
* iface
, IEnumPins
**ppEnum
)
574 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
576 TRACE("(%p/%p)->(%p)\n", This
, iface
, ppEnum
);
578 epd
.cPins
= 1; /* input pin */
579 epd
.ppPins
= This
->ppPins
;
580 return IEnumPinsImpl_Construct(&epd
, ppEnum
);
583 static HRESULT WINAPI
DSoundRender_FindPin(IBaseFilter
* iface
, LPCWSTR Id
, IPin
**ppPin
)
585 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
587 TRACE("(%p/%p)->(%s,%p)\n", This
, iface
, debugstr_w(Id
), ppPin
);
589 FIXME("DSoundRender::FindPin(...)\n");
591 /* FIXME: critical section */
596 static HRESULT WINAPI
DSoundRender_QueryFilterInfo(IBaseFilter
* iface
, FILTER_INFO
*pInfo
)
598 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
600 TRACE("(%p/%p)->(%p)\n", This
, iface
, pInfo
);
602 strcpyW(pInfo
->achName
, This
->filterInfo
.achName
);
603 pInfo
->pGraph
= This
->filterInfo
.pGraph
;
606 IFilterGraph_AddRef(pInfo
->pGraph
);
611 static HRESULT WINAPI
DSoundRender_JoinFilterGraph(IBaseFilter
* iface
, IFilterGraph
*pGraph
, LPCWSTR pName
)
613 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
615 TRACE("(%p/%p)->(%p, %s)\n", This
, iface
, pGraph
, debugstr_w(pName
));
617 EnterCriticalSection(&This
->csFilter
);
620 strcpyW(This
->filterInfo
.achName
, pName
);
622 *This
->filterInfo
.achName
= '\0';
623 This
->filterInfo
.pGraph
= pGraph
; /* NOTE: do NOT increase ref. count */
625 LeaveCriticalSection(&This
->csFilter
);
630 static HRESULT WINAPI
DSoundRender_QueryVendorInfo(IBaseFilter
* iface
, LPWSTR
*pVendorInfo
)
632 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
633 TRACE("(%p/%p)->(%p)\n", This
, iface
, pVendorInfo
);
637 static const IBaseFilterVtbl DSoundRender_Vtbl
=
639 DSoundRender_QueryInterface
,
641 DSoundRender_Release
,
642 DSoundRender_GetClassID
,
646 DSoundRender_GetState
,
647 DSoundRender_SetSyncSource
,
648 DSoundRender_GetSyncSource
,
649 DSoundRender_EnumPins
,
650 DSoundRender_FindPin
,
651 DSoundRender_QueryFilterInfo
,
652 DSoundRender_JoinFilterGraph
,
653 DSoundRender_QueryVendorInfo
656 static HRESULT WINAPI
DSoundRender_InputPin_ReceiveConnection(IPin
* iface
, IPin
* pReceivePin
, const AM_MEDIA_TYPE
* pmt
)
658 InputPin
*This
= (InputPin
*)iface
;
659 PIN_DIRECTION pindirReceive
;
660 DSoundRenderImpl
*DSImpl
;
663 TRACE("(%p)->(%p, %p)\n", This
, pReceivePin
, pmt
);
664 dump_AM_MEDIA_TYPE(pmt
);
666 EnterCriticalSection(This
->pin
.pCritSec
);
668 DSImpl
= (DSoundRenderImpl
*)This
->pin
.pinInfo
.pFilter
;
670 if (This
->pin
.pConnectedTo
)
671 hr
= VFW_E_ALREADY_CONNECTED
;
673 if (SUCCEEDED(hr
) && This
->pin
.fnQueryAccept(This
->pin
.pUserData
, pmt
) != S_OK
)
674 hr
= VFW_E_TYPE_NOT_ACCEPTED
;
678 IPin_QueryDirection(pReceivePin
, &pindirReceive
);
680 if (pindirReceive
!= PINDIR_OUTPUT
)
682 ERR("Can't connect from non-output pin\n");
683 hr
= VFW_E_INVALID_DIRECTION
;
689 WAVEFORMATEX
*format
;
690 DSBUFFERDESC buf_desc
;
692 TRACE("MajorType %s\n", debugstr_guid(&pmt
->majortype
));
693 TRACE("SubType %s\n", debugstr_guid(&pmt
->subtype
));
694 TRACE("Format %s\n", debugstr_guid(&pmt
->formattype
));
695 TRACE("Size %d\n", pmt
->cbFormat
);
697 format
= (WAVEFORMATEX
*)pmt
->pbFormat
;
699 DSImpl
->buf_size
= format
->nAvgBytesPerSec
;
701 memset(&buf_desc
,0,sizeof(DSBUFFERDESC
));
702 buf_desc
.dwSize
= sizeof(DSBUFFERDESC
);
703 buf_desc
.dwFlags
= DSBCAPS_CTRLVOLUME
| DSBCAPS_CTRLPAN
|
704 DSBCAPS_CTRLFREQUENCY
|
705 DSBCAPS_GETCURRENTPOSITION2
;
706 buf_desc
.dwBufferBytes
= DSImpl
->buf_size
;
707 buf_desc
.lpwfxFormat
= format
;
708 hr
= IDirectSound_CreateSoundBuffer(DSImpl
->dsound
, &buf_desc
, &DSImpl
->dsbuffer
, NULL
);
710 ERR("Can't create sound buffer (%x)\n", hr
);
715 hr
= IDirectSoundBuffer_SetVolume(DSImpl
->dsbuffer
, DSImpl
->volume
);
717 ERR("Can't set volume to %ld (%x)\n", DSImpl
->volume
, hr
);
719 hr
= IDirectSoundBuffer_SetPan(DSImpl
->dsbuffer
, DSImpl
->pan
);
721 ERR("Can't set pan to %ld (%x)\n", DSImpl
->pan
, hr
);
723 DSImpl
->write_pos
= 0;
725 if (DSImpl
->state
== State_Running
)
726 hr
= IDirectSoundBuffer_Play(DSImpl
->dsbuffer
, 0, 0, DSBPLAY_LOOPING
);
728 ERR("Can't play sound buffer (%x)\n", hr
);
733 CopyMediaType(&This
->pin
.mtCurrent
, pmt
);
734 This
->pin
.pConnectedTo
= pReceivePin
;
735 IPin_AddRef(pReceivePin
);
739 if (DSImpl
->dsbuffer
)
740 IDirectSoundBuffer_Release(DSImpl
->dsbuffer
);
741 DSImpl
->dsbuffer
= NULL
;
744 LeaveCriticalSection(This
->pin
.pCritSec
);
749 static HRESULT WINAPI
DSoundRender_InputPin_Disconnect(IPin
* iface
)
751 IPinImpl
*This
= (IPinImpl
*)iface
;
752 DSoundRenderImpl
*DSImpl
;
754 TRACE("(%p)->()\n", iface
);
756 DSImpl
= (DSoundRenderImpl
*)This
->pinInfo
.pFilter
;
757 if (DSImpl
->dsbuffer
)
758 IDirectSoundBuffer_Release(DSImpl
->dsbuffer
);
759 DSImpl
->dsbuffer
= NULL
;
761 return IPinImpl_Disconnect(iface
);
764 static HRESULT WINAPI
DSoundRender_InputPin_EndOfStream(IPin
* iface
)
766 InputPin
* This
= (InputPin
*)iface
;
767 DSoundRenderImpl
*me
= (DSoundRenderImpl
*)This
->pin
.pinInfo
.pFilter
;
768 IMediaEventSink
* pEventSink
;
771 TRACE("(%p/%p)->()\n", This
, iface
);
772 InputPin_EndOfStream(iface
);
774 hr
= IFilterGraph_QueryInterface(me
->filterInfo
.pGraph
, &IID_IMediaEventSink
, (LPVOID
*)&pEventSink
);
779 silence
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, me
->buf_size
);
782 memset(silence
, 0, me
->buf_size
);
783 DSoundRender_SendSampleData((DSoundRenderImpl
*)This
->pin
.pinInfo
.pFilter
, silence
, me
->buf_size
);
784 HeapFree(GetProcessHeap(), 0, silence
);
787 hr
= IMediaEventSink_Notify(pEventSink
, EC_COMPLETE
, S_OK
, 0);
788 IMediaEventSink_Release(pEventSink
);
794 static const IPinVtbl DSoundRender_InputPin_Vtbl
=
796 InputPin_QueryInterface
,
800 DSoundRender_InputPin_ReceiveConnection
,
801 DSoundRender_InputPin_Disconnect
,
802 IPinImpl_ConnectedTo
,
803 IPinImpl_ConnectionMediaType
,
804 IPinImpl_QueryPinInfo
,
805 IPinImpl_QueryDirection
,
807 IPinImpl_QueryAccept
,
808 IPinImpl_EnumMediaTypes
,
809 IPinImpl_QueryInternalConnections
,
810 DSoundRender_InputPin_EndOfStream
,
816 static const IMemInputPinVtbl MemInputPin_Vtbl
=
818 MemInputPin_QueryInterface
,
821 MemInputPin_GetAllocator
,
822 MemInputPin_NotifyAllocator
,
823 MemInputPin_GetAllocatorRequirements
,
825 MemInputPin_ReceiveMultiple
,
826 MemInputPin_ReceiveCanBlock
829 /*** IUnknown methods ***/
830 static HRESULT WINAPI
Basicaudio_QueryInterface(IBasicAudio
*iface
,
833 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
835 TRACE("(%p/%p)->(%s (%p), %p)\n", This
, iface
, debugstr_guid(riid
), riid
, ppvObj
);
837 return DSoundRender_QueryInterface((IBaseFilter
*)This
, riid
, ppvObj
);
840 static ULONG WINAPI
Basicaudio_AddRef(IBasicAudio
*iface
) {
841 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
843 TRACE("(%p/%p)->()\n", This
, iface
);
845 return DSoundRender_AddRef((IBaseFilter
*)This
);
848 static ULONG WINAPI
Basicaudio_Release(IBasicAudio
*iface
) {
849 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
851 TRACE("(%p/%p)->()\n", This
, iface
);
853 return DSoundRender_Release((IBaseFilter
*)This
);
856 /*** IDispatch methods ***/
857 static HRESULT WINAPI
Basicaudio_GetTypeInfoCount(IBasicAudio
*iface
,
859 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
861 TRACE("(%p/%p)->(%p): stub !!!\n", This
, iface
, pctinfo
);
866 static HRESULT WINAPI
Basicaudio_GetTypeInfo(IBasicAudio
*iface
,
869 ITypeInfo
**ppTInfo
) {
870 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
872 TRACE("(%p/%p)->(%d, %d, %p): stub !!!\n", This
, iface
, iTInfo
, lcid
, ppTInfo
);
877 static HRESULT WINAPI
Basicaudio_GetIDsOfNames(IBasicAudio
*iface
,
883 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
885 TRACE("(%p/%p)->(%s (%p), %p, %d, %d, %p): stub !!!\n", This
, iface
, debugstr_guid(riid
), riid
, rgszNames
, cNames
, lcid
, rgDispId
);
890 static HRESULT WINAPI
Basicaudio_Invoke(IBasicAudio
*iface
,
895 DISPPARAMS
*pDispParams
,
899 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
901 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
);
906 /*** IBasicAudio methods ***/
907 static HRESULT WINAPI
Basicaudio_put_Volume(IBasicAudio
*iface
,
909 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
911 TRACE("(%p/%p)->(%ld)\n", This
, iface
, lVolume
);
913 if (lVolume
> DSBVOLUME_MAX
|| lVolume
< DSBVOLUME_MIN
)
916 if (This
->dsbuffer
) {
917 if (FAILED(IDirectSoundBuffer_SetVolume(This
->dsbuffer
, lVolume
)))
921 This
->volume
= lVolume
;
925 static HRESULT WINAPI
Basicaudio_get_Volume(IBasicAudio
*iface
,
927 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
929 TRACE("(%p/%p)->(%p)\n", This
, iface
, plVolume
);
934 *plVolume
= This
->volume
;
938 static HRESULT WINAPI
Basicaudio_put_Balance(IBasicAudio
*iface
,
940 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
942 TRACE("(%p/%p)->(%ld)\n", This
, iface
, lBalance
);
944 if (lBalance
< DSBPAN_LEFT
|| lBalance
> DSBPAN_RIGHT
)
947 if (This
->dsbuffer
) {
948 if (FAILED(IDirectSoundBuffer_SetPan(This
->dsbuffer
, lBalance
)))
952 This
->pan
= lBalance
;
956 static HRESULT WINAPI
Basicaudio_get_Balance(IBasicAudio
*iface
,
958 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
960 TRACE("(%p/%p)->(%p)\n", This
, iface
, plBalance
);
965 *plBalance
= This
->pan
;
969 static const IBasicAudioVtbl IBasicAudio_Vtbl
=
971 Basicaudio_QueryInterface
,
974 Basicaudio_GetTypeInfoCount
,
975 Basicaudio_GetTypeInfo
,
976 Basicaudio_GetIDsOfNames
,
978 Basicaudio_put_Volume
,
979 Basicaudio_get_Volume
,
980 Basicaudio_put_Balance
,
981 Basicaudio_get_Balance
985 /*** IUnknown methods ***/
986 static HRESULT WINAPI
ReferenceClock_QueryInterface(IReferenceClock
*iface
,
990 ICOM_THIS_MULTI(DSoundRenderImpl
, IReferenceClock_vtbl
, iface
);
992 TRACE("(%p/%p)->(%s (%p), %p)\n", This
, iface
, debugstr_guid(riid
), riid
, ppvObj
);
994 return DSoundRender_QueryInterface((IBaseFilter
*)This
, riid
, ppvObj
);
997 static ULONG WINAPI
ReferenceClock_AddRef(IReferenceClock
*iface
)
999 ICOM_THIS_MULTI(DSoundRenderImpl
, IReferenceClock_vtbl
, iface
);
1001 TRACE("(%p/%p)->()\n", This
, iface
);
1003 return DSoundRender_AddRef((IBaseFilter
*)This
);
1006 static ULONG WINAPI
ReferenceClock_Release(IReferenceClock
*iface
)
1008 ICOM_THIS_MULTI(DSoundRenderImpl
, IReferenceClock_vtbl
, iface
);
1010 TRACE("(%p/%p)->()\n", This
, iface
);
1012 return DSoundRender_Release((IBaseFilter
*)This
);
1015 /*** IReferenceClock methods ***/
1016 static HRESULT WINAPI
ReferenceClock_GetTime(IReferenceClock
*iface
,
1017 REFERENCE_TIME
*pTime
)
1019 ICOM_THIS_MULTI(DSoundRenderImpl
, IReferenceClock_vtbl
, iface
);
1020 HRESULT hr
= E_FAIL
;
1023 TRACE("(%p/%p)->(%p)\n", This
, iface
, pTime
);
1026 hr
= DSoundRender_GetPos(This
, &play_pos
, NULL
, pTime
);
1028 ERR("Could not get reference time (%x)!\n", hr
);
1033 static HRESULT WINAPI
ReferenceClock_AdviseTime(IReferenceClock
*iface
,
1034 REFERENCE_TIME rtBaseTime
,
1035 REFERENCE_TIME rtStreamTime
,
1037 DWORD_PTR
*pdwAdviseCookie
)
1039 ICOM_THIS_MULTI(DSoundRenderImpl
, IReferenceClock_vtbl
, iface
);
1041 FIXME("(%p/%p)->(%s, %s, %p, %p): stub!\n", This
, iface
, wine_dbgstr_longlong(rtBaseTime
), wine_dbgstr_longlong(rtStreamTime
), (void*)hEvent
, pdwAdviseCookie
);
1046 static HRESULT WINAPI
ReferenceClock_AdvisePeriodic(IReferenceClock
*iface
,
1047 REFERENCE_TIME rtBaseTime
,
1048 REFERENCE_TIME rtStreamTime
,
1049 HSEMAPHORE hSemaphore
,
1050 DWORD_PTR
*pdwAdviseCookie
)
1052 ICOM_THIS_MULTI(DSoundRenderImpl
, IReferenceClock_vtbl
, iface
);
1054 FIXME("(%p/%p)->(%s, %s, %p, %p): stub!\n", This
, iface
, wine_dbgstr_longlong(rtBaseTime
), wine_dbgstr_longlong(rtStreamTime
), (void*)hSemaphore
, pdwAdviseCookie
);
1059 static HRESULT WINAPI
ReferenceClock_Unadvise(IReferenceClock
*iface
,
1060 DWORD_PTR dwAdviseCookie
)
1062 ICOM_THIS_MULTI(DSoundRenderImpl
, IReferenceClock_vtbl
, iface
);
1064 FIXME("(%p/%p)->(%p): stub!\n", This
, iface
, (void*)dwAdviseCookie
);
1069 static const IReferenceClockVtbl IReferenceClock_Vtbl
=
1071 ReferenceClock_QueryInterface
,
1072 ReferenceClock_AddRef
,
1073 ReferenceClock_Release
,
1074 ReferenceClock_GetTime
,
1075 ReferenceClock_AdviseTime
,
1076 ReferenceClock_AdvisePeriodic
,
1077 ReferenceClock_Unadvise
1080 static inline DSoundRenderImpl
*impl_from_IMediaSeeking( IMediaSeeking
*iface
)
1082 return (DSoundRenderImpl
*)((char*)iface
- FIELD_OFFSET(DSoundRenderImpl
, mediaSeeking
.lpVtbl
));
1085 static HRESULT WINAPI
sound_seek_QueryInterface(IMediaSeeking
* iface
, REFIID riid
, LPVOID
* ppv
)
1087 DSoundRenderImpl
*This
= impl_from_IMediaSeeking(iface
);
1089 return IUnknown_QueryInterface((IUnknown
*)This
, riid
, ppv
);
1092 static ULONG WINAPI
sound_seek_AddRef(IMediaSeeking
* iface
)
1094 DSoundRenderImpl
*This
= impl_from_IMediaSeeking(iface
);
1096 return IUnknown_AddRef((IUnknown
*)This
);
1099 static ULONG WINAPI
sound_seek_Release(IMediaSeeking
* iface
)
1101 DSoundRenderImpl
*This
= impl_from_IMediaSeeking(iface
);
1103 return IUnknown_Release((IUnknown
*)This
);
1106 static const IMediaSeekingVtbl IMediaSeeking_Vtbl
=
1108 sound_seek_QueryInterface
,
1111 MediaSeekingImpl_GetCapabilities
,
1112 MediaSeekingImpl_CheckCapabilities
,
1113 MediaSeekingImpl_IsFormatSupported
,
1114 MediaSeekingImpl_QueryPreferredFormat
,
1115 MediaSeekingImpl_GetTimeFormat
,
1116 MediaSeekingImpl_IsUsingTimeFormat
,
1117 MediaSeekingImpl_SetTimeFormat
,
1118 MediaSeekingImpl_GetDuration
,
1119 MediaSeekingImpl_GetStopPosition
,
1120 MediaSeekingImpl_GetCurrentPosition
,
1121 MediaSeekingImpl_ConvertTimeFormat
,
1122 MediaSeekingImpl_SetPositions
,
1123 MediaSeekingImpl_GetPositions
,
1124 MediaSeekingImpl_GetAvailable
,
1125 MediaSeekingImpl_SetRate
,
1126 MediaSeekingImpl_GetRate
,
1127 MediaSeekingImpl_GetPreroll