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 IBasicAudioVtbl IBasicAudio_Vtbl
;
46 static const IReferenceClockVtbl IReferenceClock_Vtbl
;
47 static const IMediaSeekingVtbl IMediaSeeking_Vtbl
;
49 typedef struct DSoundRenderImpl
51 const IBaseFilterVtbl
* lpVtbl
;
52 const IBasicAudioVtbl
*IBasicAudio_vtbl
;
53 const IReferenceClockVtbl
*IReferenceClock_vtbl
;
56 CRITICAL_SECTION csFilter
;
58 REFERENCE_TIME rtStreamStart
, rtLastStop
;
59 IReferenceClock
* pClock
;
60 FILTER_INFO filterInfo
;
64 IDirectSound8
*dsound
;
65 LPDIRECTSOUNDBUFFER dsbuffer
;
73 REFERENCE_TIME play_time
;
74 MediaSeekingImpl mediaSeeking
;
76 HANDLE state_change
, blocked
;
82 /* Seeking is not needed for a renderer, rely on newsegment for the appropriate changes */
83 static HRESULT
sound_mod_stop(IBaseFilter
*iface
)
85 TRACE("(%p)\n", iface
);
89 static HRESULT
sound_mod_start(IBaseFilter
*iface
)
91 TRACE("(%p)\n", iface
);
96 static HRESULT
sound_mod_rate(IBaseFilter
*iface
)
98 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
100 WAVEFORMATEX
*format
= (WAVEFORMATEX
*)This
->pInputPin
->pin
.mtCurrent
.pbFormat
;
101 DWORD freq
= format
->nSamplesPerSec
;
102 double rate
= This
->mediaSeeking
.dRate
;
104 freq
= (DWORD
)((double)freq
* rate
);
106 TRACE("(%p)\n", iface
);
108 if (freq
> DSBFREQUENCY_MAX
)
109 return VFW_E_UNSUPPORTED_AUDIO
;
111 if (freq
< DSBFREQUENCY_MIN
)
112 return VFW_E_UNSUPPORTED_AUDIO
;
117 static inline HRESULT
DSoundRender_GetPos(DSoundRenderImpl
*This
, DWORD
*pPlayPos
, REFERENCE_TIME
*pRefTime
)
121 EnterCriticalSection(&This
->csFilter
);
126 hr
= IDirectSoundBuffer_GetStatus(This
->dsbuffer
, &state
);
127 if (SUCCEEDED(hr
) && !(state
& DSBSTATUS_PLAYING
) && This
->state
== State_Running
)
129 TRACE("Not playing, kickstarting the engine\n");
131 hr
= IDirectSoundBuffer_Play(This
->dsbuffer
, 0, 0, DSBPLAY_LOOPING
);
133 ERR("Can't play sound buffer (%x)\n", hr
);
137 hr
= IDirectSoundBuffer_GetCurrentPosition(This
->dsbuffer
, pPlayPos
, &write_pos
);
140 DWORD play_pos
= *pPlayPos
;
142 if (play_pos
< This
->last_play_pos
)
144 This
->last_play_pos
= play_pos
;
146 /* If we really fell behind, start at the next possible position
147 * Also happens when just starting playback for the first time,
150 if ((This
->play_loops
*This
->buf_size
)+play_pos
>=
151 (This
->write_loops
*This
->buf_size
)+This
->write_pos
)
152 This
->write_pos
= write_pos
;
156 REFERENCE_TIME play_time
;
157 play_time
= ((REFERENCE_TIME
)This
->play_loops
*10000000) +
158 ((REFERENCE_TIME
)play_pos
*10000000/This
->buf_size
);
160 /* Don't let time run backwards */
161 if(play_time
-This
->play_time
> 0)
162 This
->play_time
= play_time
;
166 *pRefTime
= This
->play_time
;
170 LeaveCriticalSection(&This
->csFilter
);
175 static HRESULT
DSoundRender_SendSampleData(DSoundRenderImpl
* This
, const BYTE
*data
, DWORD size
)
178 LPBYTE lpbuf1
= NULL
;
179 LPBYTE lpbuf2
= NULL
;
183 DWORD play_pos
,buf_free
;
187 hr
= DSoundRender_GetPos(This
, &play_pos
, NULL
);
190 ERR("GetPos returned error: %x\n", hr
);
193 if (This
->write_pos
<= play_pos
)
194 buf_free
= play_pos
-This
->write_pos
;
196 buf_free
= This
->buf_size
- This
->write_pos
+ play_pos
;
198 /* Wait for enough of the buffer to empty before filling it */
199 if(buf_free
< This
->buf_size
/4)
205 size2
= min(buf_free
, size
);
206 hr
= IDirectSoundBuffer_Lock(This
->dsbuffer
, This
->write_pos
, size2
, (LPVOID
*)&lpbuf1
, &dwsize1
, (LPVOID
*)&lpbuf2
, &dwsize2
, 0);
208 ERR("Unable to lock sound buffer! (%x)\n", hr
);
211 /* TRACE("write_pos=%d, size=%d, sz1=%d, sz2=%d\n", This->write_pos, size2, dwsize1, dwsize2); */
213 memcpy(lpbuf1
, data
, dwsize1
);
215 memcpy(lpbuf2
, data
+ dwsize1
, dwsize2
);
217 hr
= IDirectSoundBuffer_Unlock(This
->dsbuffer
, lpbuf1
, dwsize1
, lpbuf2
, dwsize2
);
219 ERR("Unable to unlock sound buffer! (%x)\n", hr
);
221 size
-= dwsize1
+ dwsize2
;
222 data
+= dwsize1
+ dwsize2
;
223 This
->write_pos
+= dwsize1
+ dwsize2
;
224 if (This
->write_pos
>= This
->buf_size
)
226 This
->write_pos
-= This
->buf_size
;
229 } while (size
&& This
->state
== State_Running
);
234 static HRESULT
DSoundRender_Sample(LPVOID iface
, IMediaSample
* pSample
)
236 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
237 LPBYTE pbSrcStream
= NULL
;
238 long cbSrcStream
= 0;
239 REFERENCE_TIME tStart
, tStop
;
242 TRACE("%p %p\n", iface
, pSample
);
244 /* Slightly incorrect, Pause completes when a frame is received so we should signal
245 * pause completion here, but for sound playing a single frame doesn't make sense
248 EnterCriticalSection(&This
->csFilter
);
250 if (This
->pInputPin
->end_of_stream
|| This
->pInputPin
->flushing
)
252 LeaveCriticalSection(&This
->csFilter
);
256 if (This
->state
== State_Stopped
)
258 LeaveCriticalSection(&This
->csFilter
);
259 return VFW_E_WRONG_STATE
;
262 SetEvent(This
->state_change
);
264 hr
= IMediaSample_GetPointer(pSample
, &pbSrcStream
);
267 ERR("Cannot get pointer to sample data (%x)\n", hr
);
268 LeaveCriticalSection(&This
->csFilter
);
272 hr
= IMediaSample_GetTime(pSample
, &tStart
, &tStop
);
274 ERR("Cannot get sample time (%x)\n", hr
);
276 if (This
->rtLastStop
!= tStart
&& (IMediaSample_IsDiscontinuity(pSample
) == S_FALSE
))
277 WARN("Unexpected discontinuity: Last: %u.%03u, tStart: %u.%03u\n",
278 (DWORD
)(This
->rtLastStop
/ 10000000), (DWORD
)((This
->rtLastStop
/ 10000)%1000),
279 (DWORD
)(tStart
/ 10000000), (DWORD
)((tStart
/ 10000)%1000));
280 This
->rtLastStop
= tStop
;
282 if (IMediaSample_IsPreroll(pSample
) == S_OK
)
285 LeaveCriticalSection(&This
->csFilter
);
289 if (This
->state
== State_Paused
)
291 LeaveCriticalSection(&This
->csFilter
);
292 WaitForSingleObject(This
->blocked
, INFINITE
);
293 EnterCriticalSection(&This
->csFilter
);
294 if (This
->state
== State_Stopped
)
296 LeaveCriticalSection(&This
->csFilter
);
297 return VFW_E_WRONG_STATE
;
300 if (This
->state
== State_Paused
)
302 /* Assuming we return because of flushing */
304 LeaveCriticalSection(&This
->csFilter
);
309 cbSrcStream
= IMediaSample_GetActualDataLength(pSample
);
310 TRACE("Sample data ptr = %p, size = %ld\n", pbSrcStream
, cbSrcStream
);
312 #if 0 /* For debugging purpose */
315 for(i
= 0; i
< cbSrcStream
; i
++)
317 if ((i
!=0) && !(i
%16))
319 TRACE("%02x ", pbSrcStream
[i
]);
325 hr
= DSoundRender_SendSampleData(This
, pbSrcStream
, cbSrcStream
);
326 LeaveCriticalSection(&This
->csFilter
);
330 static HRESULT
DSoundRender_QueryAccept(LPVOID iface
, const AM_MEDIA_TYPE
* pmt
)
332 WAVEFORMATEX
* format
;
334 if (!IsEqualIID(&pmt
->majortype
, &MEDIATYPE_Audio
))
337 format
= (WAVEFORMATEX
*)pmt
->pbFormat
;
338 TRACE("Format = %p\n", format
);
339 TRACE("wFormatTag = %x %x\n", format
->wFormatTag
, WAVE_FORMAT_PCM
);
340 TRACE("nChannels = %d\n", format
->nChannels
);
341 TRACE("nSamplesPerSec = %d\n", format
->nAvgBytesPerSec
);
342 TRACE("nAvgBytesPerSec = %d\n", format
->nAvgBytesPerSec
);
343 TRACE("nBlockAlign = %d\n", format
->nBlockAlign
);
344 TRACE("wBitsPerSample = %d\n", format
->wBitsPerSample
);
346 if (!IsEqualIID(&pmt
->subtype
, &MEDIASUBTYPE_PCM
))
352 HRESULT
DSoundRender_create(IUnknown
* pUnkOuter
, LPVOID
* ppv
)
356 DSoundRenderImpl
* pDSoundRender
;
358 TRACE("(%p, %p)\n", pUnkOuter
, ppv
);
363 return CLASS_E_NOAGGREGATION
;
365 pDSoundRender
= CoTaskMemAlloc(sizeof(DSoundRenderImpl
));
367 return E_OUTOFMEMORY
;
368 ZeroMemory(pDSoundRender
, sizeof(DSoundRenderImpl
));
370 pDSoundRender
->lpVtbl
= &DSoundRender_Vtbl
;
371 pDSoundRender
->IBasicAudio_vtbl
= &IBasicAudio_Vtbl
;
372 pDSoundRender
->IReferenceClock_vtbl
= &IReferenceClock_Vtbl
;
373 pDSoundRender
->refCount
= 1;
374 InitializeCriticalSection(&pDSoundRender
->csFilter
);
375 pDSoundRender
->csFilter
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": DSoundRenderImpl.csFilter");
376 pDSoundRender
->state
= State_Stopped
;
378 /* construct input pin */
379 piInput
.dir
= PINDIR_INPUT
;
380 piInput
.pFilter
= (IBaseFilter
*)pDSoundRender
;
381 lstrcpynW(piInput
.achName
, wcsInputPinName
, sizeof(piInput
.achName
) / sizeof(piInput
.achName
[0]));
382 hr
= InputPin_Construct(&DSoundRender_InputPin_Vtbl
, &piInput
, DSoundRender_Sample
, pDSoundRender
, DSoundRender_QueryAccept
, NULL
, &pDSoundRender
->csFilter
, NULL
, (IPin
**)&pDSoundRender
->pInputPin
);
386 hr
= DirectSoundCreate8(NULL
, &pDSoundRender
->dsound
, NULL
);
388 ERR("Cannot create Direct Sound object (%x)\n", hr
);
390 IDirectSound_SetCooperativeLevel(pDSoundRender
->dsound
, GetDesktopWindow(), DSSCL_PRIORITY
);
395 MediaSeekingImpl_Init((IBaseFilter
*)pDSoundRender
, sound_mod_stop
, sound_mod_start
, sound_mod_rate
, &pDSoundRender
->mediaSeeking
, &pDSoundRender
->csFilter
);
396 pDSoundRender
->mediaSeeking
.lpVtbl
= &IMediaSeeking_Vtbl
;
398 pDSoundRender
->state_change
= CreateEventW(NULL
, TRUE
, TRUE
, NULL
);
399 pDSoundRender
->blocked
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
401 if (!pDSoundRender
->state_change
|| !pDSoundRender
->blocked
)
403 IUnknown_Release((IUnknown
*)pDSoundRender
);
404 return HRESULT_FROM_WIN32(GetLastError());
407 *ppv
= (LPVOID
)pDSoundRender
;
411 if (pDSoundRender
->pInputPin
)
412 IPin_Release((IPin
*)pDSoundRender
->pInputPin
);
413 pDSoundRender
->csFilter
.DebugInfo
->Spare
[0] = 0;
414 DeleteCriticalSection(&pDSoundRender
->csFilter
);
415 CoTaskMemFree(pDSoundRender
);
421 static HRESULT WINAPI
DSoundRender_QueryInterface(IBaseFilter
* iface
, REFIID riid
, LPVOID
* ppv
)
423 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
424 TRACE("(%p, %p)->(%s, %p)\n", This
, iface
, qzdebugstr_guid(riid
), ppv
);
428 if (IsEqualIID(riid
, &IID_IUnknown
))
430 else if (IsEqualIID(riid
, &IID_IPersist
))
432 else if (IsEqualIID(riid
, &IID_IMediaFilter
))
434 else if (IsEqualIID(riid
, &IID_IBaseFilter
))
436 else if (IsEqualIID(riid
, &IID_IBasicAudio
))
437 *ppv
= (LPVOID
)&(This
->IBasicAudio_vtbl
);
438 else if (IsEqualIID(riid
, &IID_IReferenceClock
))
439 *ppv
= (LPVOID
)&(This
->IReferenceClock_vtbl
);
440 else if (IsEqualIID(riid
, &IID_IMediaSeeking
))
441 *ppv
= &This
->mediaSeeking
.lpVtbl
;
445 IUnknown_AddRef((IUnknown
*)(*ppv
));
449 if (!IsEqualIID(riid
, &IID_IPin
) && !IsEqualIID(riid
, &IID_IVideoWindow
))
450 FIXME("No interface for %s!\n", qzdebugstr_guid(riid
));
452 return E_NOINTERFACE
;
455 static ULONG WINAPI
DSoundRender_AddRef(IBaseFilter
* iface
)
457 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
458 ULONG refCount
= InterlockedIncrement(&This
->refCount
);
460 TRACE("(%p/%p)->() AddRef from %d\n", This
, iface
, refCount
- 1);
465 static ULONG WINAPI
DSoundRender_Release(IBaseFilter
* iface
)
467 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
468 ULONG refCount
= InterlockedDecrement(&This
->refCount
);
470 TRACE("(%p)->() Release from %d\n", This
, refCount
+ 1);
477 IReferenceClock_Release(This
->pClock
);
480 IDirectSoundBuffer_Release(This
->dsbuffer
);
481 This
->dsbuffer
= NULL
;
483 IDirectSound_Release(This
->dsound
);
486 if (SUCCEEDED(IPin_ConnectedTo((IPin
*)This
->pInputPin
, &pConnectedTo
)))
488 IPin_Disconnect(pConnectedTo
);
489 IPin_Release(pConnectedTo
);
491 IPin_Disconnect((IPin
*)This
->pInputPin
);
493 IPin_Release((IPin
*)This
->pInputPin
);
496 This
->IBasicAudio_vtbl
= NULL
;
498 This
->csFilter
.DebugInfo
->Spare
[0] = 0;
499 DeleteCriticalSection(&This
->csFilter
);
501 CloseHandle(This
->state_change
);
502 CloseHandle(This
->blocked
);
504 TRACE("Destroying Audio Renderer\n");
513 /** IPersist methods **/
515 static HRESULT WINAPI
DSoundRender_GetClassID(IBaseFilter
* iface
, CLSID
* pClsid
)
517 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
518 TRACE("(%p/%p)->(%p)\n", This
, iface
, pClsid
);
520 *pClsid
= CLSID_DSoundRender
;
525 /** IMediaFilter methods **/
527 static HRESULT WINAPI
DSoundRender_Stop(IBaseFilter
* iface
)
530 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
532 TRACE("(%p/%p)->()\n", This
, iface
);
534 EnterCriticalSection(&This
->csFilter
);
539 hr
= IDirectSoundBuffer_GetStatus(This
->dsbuffer
, &state
);
542 if (state
& DSBSTATUS_PLAYING
)
543 hr
= IDirectSoundBuffer_Stop(This
->dsbuffer
);
547 This
->state
= State_Stopped
;
549 /* Complete our transition */
550 SetEvent(This
->state_change
);
551 SetEvent(This
->blocked
);
553 LeaveCriticalSection(&This
->csFilter
);
558 static HRESULT WINAPI
DSoundRender_Pause(IBaseFilter
* iface
)
561 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
563 TRACE("(%p/%p)->()\n", This
, iface
);
565 EnterCriticalSection(&This
->csFilter
);
566 if (This
->state
!= State_Paused
)
569 if (This
->state
== State_Stopped
)
571 This
->pInputPin
->end_of_stream
= 0;
576 hr
= IDirectSoundBuffer_GetStatus(This
->dsbuffer
, &state
);
579 if (state
& DSBSTATUS_PLAYING
)
580 hr
= IDirectSoundBuffer_Stop(This
->dsbuffer
);
584 This
->state
= State_Paused
;
586 ResetEvent(This
->blocked
);
587 ResetEvent(This
->state_change
);
589 LeaveCriticalSection(&This
->csFilter
);
594 static HRESULT WINAPI
DSoundRender_Run(IBaseFilter
* iface
, REFERENCE_TIME tStart
)
597 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
599 TRACE("(%p/%p)->(%s)\n", This
, iface
, wine_dbgstr_longlong(tStart
));
601 EnterCriticalSection(&This
->csFilter
);
603 This
->rtStreamStart
= tStart
;
604 if (This
->state
== State_Paused
)
606 /* Unblock our thread, state changing from paused to running doesn't need a reset for state change */
607 SetEvent(This
->blocked
);
609 else if (This
->state
== State_Stopped
)
611 ResetEvent(This
->state_change
);
612 This
->pInputPin
->end_of_stream
= 0;
615 This
->state
= State_Running
;
617 LeaveCriticalSection(&This
->csFilter
);
622 static HRESULT WINAPI
DSoundRender_GetState(IBaseFilter
* iface
, DWORD dwMilliSecsTimeout
, FILTER_STATE
*pState
)
625 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
627 TRACE("(%p/%p)->(%d, %p)\n", This
, iface
, dwMilliSecsTimeout
, pState
);
629 if (WaitForSingleObject(This
->state_change
, dwMilliSecsTimeout
) == WAIT_TIMEOUT
)
630 hr
= VFW_S_STATE_INTERMEDIATE
;
634 EnterCriticalSection(&This
->csFilter
);
636 *pState
= This
->state
;
638 LeaveCriticalSection(&This
->csFilter
);
643 static HRESULT WINAPI
DSoundRender_SetSyncSource(IBaseFilter
* iface
, IReferenceClock
*pClock
)
645 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
647 TRACE("(%p/%p)->(%p)\n", This
, iface
, pClock
);
649 EnterCriticalSection(&This
->csFilter
);
652 IReferenceClock_Release(This
->pClock
);
653 This
->pClock
= pClock
;
655 IReferenceClock_AddRef(This
->pClock
);
657 LeaveCriticalSection(&This
->csFilter
);
662 static HRESULT WINAPI
DSoundRender_GetSyncSource(IBaseFilter
* iface
, IReferenceClock
**ppClock
)
664 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
666 TRACE("(%p/%p)->(%p)\n", This
, iface
, ppClock
);
668 EnterCriticalSection(&This
->csFilter
);
670 *ppClock
= This
->pClock
;
672 IReferenceClock_AddRef(This
->pClock
);
674 LeaveCriticalSection(&This
->csFilter
);
679 /** IBaseFilter implementation **/
681 static HRESULT
DSoundRender_GetPin(IBaseFilter
*iface
, ULONG pos
, IPin
**pin
, DWORD
*lastsynctick
)
683 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
685 /* Our pins are static, not changing so setting static tick count is ok */
691 *pin
= (IPin
*)This
->pInputPin
;
696 static HRESULT WINAPI
DSoundRender_EnumPins(IBaseFilter
* iface
, IEnumPins
**ppEnum
)
698 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
700 TRACE("(%p/%p)->(%p)\n", This
, iface
, ppEnum
);
702 return IEnumPinsImpl_Construct(ppEnum
, DSoundRender_GetPin
, iface
);
705 static HRESULT WINAPI
DSoundRender_FindPin(IBaseFilter
* iface
, LPCWSTR Id
, IPin
**ppPin
)
707 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
709 TRACE("(%p/%p)->(%s,%p)\n", This
, iface
, debugstr_w(Id
), ppPin
);
711 FIXME("DSoundRender::FindPin(...)\n");
713 /* FIXME: critical section */
718 static HRESULT WINAPI
DSoundRender_QueryFilterInfo(IBaseFilter
* iface
, FILTER_INFO
*pInfo
)
720 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
722 TRACE("(%p/%p)->(%p)\n", This
, iface
, pInfo
);
724 strcpyW(pInfo
->achName
, This
->filterInfo
.achName
);
725 pInfo
->pGraph
= This
->filterInfo
.pGraph
;
728 IFilterGraph_AddRef(pInfo
->pGraph
);
733 static HRESULT WINAPI
DSoundRender_JoinFilterGraph(IBaseFilter
* iface
, IFilterGraph
*pGraph
, LPCWSTR pName
)
735 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
737 TRACE("(%p/%p)->(%p, %s)\n", This
, iface
, pGraph
, debugstr_w(pName
));
739 EnterCriticalSection(&This
->csFilter
);
742 strcpyW(This
->filterInfo
.achName
, pName
);
744 *This
->filterInfo
.achName
= '\0';
745 This
->filterInfo
.pGraph
= pGraph
; /* NOTE: do NOT increase ref. count */
747 LeaveCriticalSection(&This
->csFilter
);
752 static HRESULT WINAPI
DSoundRender_QueryVendorInfo(IBaseFilter
* iface
, LPWSTR
*pVendorInfo
)
754 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
755 TRACE("(%p/%p)->(%p)\n", This
, iface
, pVendorInfo
);
759 static const IBaseFilterVtbl DSoundRender_Vtbl
=
761 DSoundRender_QueryInterface
,
763 DSoundRender_Release
,
764 DSoundRender_GetClassID
,
768 DSoundRender_GetState
,
769 DSoundRender_SetSyncSource
,
770 DSoundRender_GetSyncSource
,
771 DSoundRender_EnumPins
,
772 DSoundRender_FindPin
,
773 DSoundRender_QueryFilterInfo
,
774 DSoundRender_JoinFilterGraph
,
775 DSoundRender_QueryVendorInfo
778 static HRESULT WINAPI
DSoundRender_InputPin_ReceiveConnection(IPin
* iface
, IPin
* pReceivePin
, const AM_MEDIA_TYPE
* pmt
)
780 InputPin
*This
= (InputPin
*)iface
;
781 PIN_DIRECTION pindirReceive
;
782 DSoundRenderImpl
*DSImpl
;
785 TRACE("(%p)->(%p, %p)\n", This
, pReceivePin
, pmt
);
786 dump_AM_MEDIA_TYPE(pmt
);
788 EnterCriticalSection(This
->pin
.pCritSec
);
790 DSImpl
= (DSoundRenderImpl
*)This
->pin
.pinInfo
.pFilter
;
791 DSImpl
->rtLastStop
= -1;
793 if (This
->pin
.pConnectedTo
)
794 hr
= VFW_E_ALREADY_CONNECTED
;
796 if (SUCCEEDED(hr
) && This
->pin
.fnQueryAccept(This
->pin
.pUserData
, pmt
) != S_OK
)
797 hr
= VFW_E_TYPE_NOT_ACCEPTED
;
801 IPin_QueryDirection(pReceivePin
, &pindirReceive
);
803 if (pindirReceive
!= PINDIR_OUTPUT
)
805 ERR("Can't connect from non-output pin\n");
806 hr
= VFW_E_INVALID_DIRECTION
;
812 WAVEFORMATEX
*format
;
813 DSBUFFERDESC buf_desc
;
815 TRACE("MajorType %s\n", debugstr_guid(&pmt
->majortype
));
816 TRACE("SubType %s\n", debugstr_guid(&pmt
->subtype
));
817 TRACE("Format %s\n", debugstr_guid(&pmt
->formattype
));
818 TRACE("Size %d\n", pmt
->cbFormat
);
820 format
= (WAVEFORMATEX
*)pmt
->pbFormat
;
822 DSImpl
->buf_size
= format
->nAvgBytesPerSec
;
824 memset(&buf_desc
,0,sizeof(DSBUFFERDESC
));
825 buf_desc
.dwSize
= sizeof(DSBUFFERDESC
);
826 buf_desc
.dwFlags
= DSBCAPS_CTRLVOLUME
| DSBCAPS_CTRLPAN
|
827 DSBCAPS_CTRLFREQUENCY
|
828 DSBCAPS_GETCURRENTPOSITION2
;
829 buf_desc
.dwBufferBytes
= DSImpl
->buf_size
;
830 buf_desc
.lpwfxFormat
= format
;
831 hr
= IDirectSound_CreateSoundBuffer(DSImpl
->dsound
, &buf_desc
, &DSImpl
->dsbuffer
, NULL
);
833 ERR("Can't create sound buffer (%x)\n", hr
);
838 hr
= IDirectSoundBuffer_SetVolume(DSImpl
->dsbuffer
, DSImpl
->volume
);
840 ERR("Can't set volume to %ld (%x)\n", DSImpl
->volume
, hr
);
842 hr
= IDirectSoundBuffer_SetPan(DSImpl
->dsbuffer
, DSImpl
->pan
);
844 ERR("Can't set pan to %ld (%x)\n", DSImpl
->pan
, hr
);
846 DSImpl
->write_pos
= 0;
852 CopyMediaType(&This
->pin
.mtCurrent
, pmt
);
853 This
->pin
.pConnectedTo
= pReceivePin
;
854 IPin_AddRef(pReceivePin
);
856 else if (hr
!= VFW_E_ALREADY_CONNECTED
)
858 if (DSImpl
->dsbuffer
)
859 IDirectSoundBuffer_Release(DSImpl
->dsbuffer
);
860 DSImpl
->dsbuffer
= NULL
;
863 LeaveCriticalSection(This
->pin
.pCritSec
);
868 static HRESULT WINAPI
DSoundRender_InputPin_Disconnect(IPin
* iface
)
870 IPinImpl
*This
= (IPinImpl
*)iface
;
871 DSoundRenderImpl
*DSImpl
;
873 TRACE("(%p)->()\n", iface
);
875 DSImpl
= (DSoundRenderImpl
*)This
->pinInfo
.pFilter
;
876 if (DSImpl
->dsbuffer
)
877 IDirectSoundBuffer_Release(DSImpl
->dsbuffer
);
878 DSImpl
->dsbuffer
= NULL
;
880 return IPinImpl_Disconnect(iface
);
883 static HRESULT WINAPI
DSoundRender_InputPin_EndOfStream(IPin
* iface
)
885 InputPin
* This
= (InputPin
*)iface
;
886 DSoundRenderImpl
*me
= (DSoundRenderImpl
*)This
->pin
.pinInfo
.pFilter
;
887 IMediaEventSink
* pEventSink
;
890 EnterCriticalSection(This
->pin
.pCritSec
);
892 TRACE("(%p/%p)->()\n", This
, iface
);
893 hr
= InputPin_EndOfStream(iface
);
897 LeaveCriticalSection(This
->pin
.pCritSec
);
901 hr
= IFilterGraph_QueryInterface(me
->filterInfo
.pGraph
, &IID_IMediaEventSink
, (LPVOID
*)&pEventSink
);
906 silence
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, me
->buf_size
);
909 memset(silence
, 0, me
->buf_size
);
910 DSoundRender_SendSampleData((DSoundRenderImpl
*)This
->pin
.pinInfo
.pFilter
, silence
, me
->buf_size
);
911 HeapFree(GetProcessHeap(), 0, silence
);
914 hr
= IMediaEventSink_Notify(pEventSink
, EC_COMPLETE
, S_OK
, 0);
915 IMediaEventSink_Release(pEventSink
);
917 LeaveCriticalSection(This
->pin
.pCritSec
);
922 static HRESULT WINAPI
DSoundRender_InputPin_BeginFlush(IPin
* iface
)
924 InputPin
*This
= (InputPin
*)iface
;
925 DSoundRenderImpl
*pFilter
= (DSoundRenderImpl
*)This
->pin
.pinInfo
.pFilter
;
932 EnterCriticalSection(This
->pin
.pCritSec
);
933 hr
= InputPin_BeginFlush(iface
);
935 if (pFilter
->dsbuffer
)
937 IDirectSoundBuffer_Stop(pFilter
->dsbuffer
);
940 IDirectSoundBuffer_SetCurrentPosition(pFilter
->dsbuffer
, 0);
941 pFilter
->write_pos
= pFilter
->last_play_pos
= 0;
942 ++pFilter
->play_loops
;
943 pFilter
->write_loops
= pFilter
->play_loops
;
945 IDirectSoundBuffer_Lock(pFilter
->dsbuffer
, 0, 0, (LPVOID
*)&buffer
, &size
, NULL
, NULL
, DSBLOCK_ENTIREBUFFER
);
946 memset(buffer
, 0, size
);
947 IDirectSoundBuffer_Unlock(pFilter
->dsbuffer
, buffer
, size
, NULL
, 0);
950 if (pFilter
->state
== State_Paused
)
951 SetEvent(pFilter
->blocked
);
952 LeaveCriticalSection(This
->pin
.pCritSec
);
957 static HRESULT WINAPI
DSoundRender_InputPin_EndFlush(IPin
* iface
)
959 InputPin
*This
= (InputPin
*)iface
;
960 DSoundRenderImpl
*pFilter
= (DSoundRenderImpl
*)This
->pin
.pinInfo
.pFilter
;
965 EnterCriticalSection(This
->pin
.pCritSec
);
966 hr
= InputPin_EndFlush(iface
);
968 if (pFilter
->state
== State_Paused
)
969 SetEvent(pFilter
->blocked
);
970 LeaveCriticalSection(This
->pin
.pCritSec
);
975 static const IPinVtbl DSoundRender_InputPin_Vtbl
=
977 InputPin_QueryInterface
,
981 DSoundRender_InputPin_ReceiveConnection
,
982 DSoundRender_InputPin_Disconnect
,
983 IPinImpl_ConnectedTo
,
984 IPinImpl_ConnectionMediaType
,
985 IPinImpl_QueryPinInfo
,
986 IPinImpl_QueryDirection
,
988 IPinImpl_QueryAccept
,
989 IPinImpl_EnumMediaTypes
,
990 IPinImpl_QueryInternalConnections
,
991 DSoundRender_InputPin_EndOfStream
,
992 DSoundRender_InputPin_BeginFlush
,
993 DSoundRender_InputPin_EndFlush
,
997 /*** IUnknown methods ***/
998 static HRESULT WINAPI
Basicaudio_QueryInterface(IBasicAudio
*iface
,
1001 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
1003 TRACE("(%p/%p)->(%s (%p), %p)\n", This
, iface
, debugstr_guid(riid
), riid
, ppvObj
);
1005 return DSoundRender_QueryInterface((IBaseFilter
*)This
, riid
, ppvObj
);
1008 static ULONG WINAPI
Basicaudio_AddRef(IBasicAudio
*iface
) {
1009 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
1011 TRACE("(%p/%p)->()\n", This
, iface
);
1013 return DSoundRender_AddRef((IBaseFilter
*)This
);
1016 static ULONG WINAPI
Basicaudio_Release(IBasicAudio
*iface
) {
1017 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
1019 TRACE("(%p/%p)->()\n", This
, iface
);
1021 return DSoundRender_Release((IBaseFilter
*)This
);
1024 /*** IDispatch methods ***/
1025 static HRESULT WINAPI
Basicaudio_GetTypeInfoCount(IBasicAudio
*iface
,
1027 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
1029 TRACE("(%p/%p)->(%p): stub !!!\n", This
, iface
, pctinfo
);
1034 static HRESULT WINAPI
Basicaudio_GetTypeInfo(IBasicAudio
*iface
,
1037 ITypeInfo
**ppTInfo
) {
1038 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
1040 TRACE("(%p/%p)->(%d, %d, %p): stub !!!\n", This
, iface
, iTInfo
, lcid
, ppTInfo
);
1045 static HRESULT WINAPI
Basicaudio_GetIDsOfNames(IBasicAudio
*iface
,
1051 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
1053 TRACE("(%p/%p)->(%s (%p), %p, %d, %d, %p): stub !!!\n", This
, iface
, debugstr_guid(riid
), riid
, rgszNames
, cNames
, lcid
, rgDispId
);
1058 static HRESULT WINAPI
Basicaudio_Invoke(IBasicAudio
*iface
,
1059 DISPID dispIdMember
,
1063 DISPPARAMS
*pDispParams
,
1065 EXCEPINFO
*pExepInfo
,
1067 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
1069 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
);
1074 /*** IBasicAudio methods ***/
1075 static HRESULT WINAPI
Basicaudio_put_Volume(IBasicAudio
*iface
,
1077 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
1079 TRACE("(%p/%p)->(%ld)\n", This
, iface
, lVolume
);
1081 if (lVolume
> DSBVOLUME_MAX
|| lVolume
< DSBVOLUME_MIN
)
1082 return E_INVALIDARG
;
1084 if (This
->dsbuffer
) {
1085 if (FAILED(IDirectSoundBuffer_SetVolume(This
->dsbuffer
, lVolume
)))
1089 This
->volume
= lVolume
;
1093 static HRESULT WINAPI
Basicaudio_get_Volume(IBasicAudio
*iface
,
1095 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
1097 TRACE("(%p/%p)->(%p)\n", This
, iface
, plVolume
);
1102 *plVolume
= This
->volume
;
1106 static HRESULT WINAPI
Basicaudio_put_Balance(IBasicAudio
*iface
,
1108 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
1110 TRACE("(%p/%p)->(%ld)\n", This
, iface
, lBalance
);
1112 if (lBalance
< DSBPAN_LEFT
|| lBalance
> DSBPAN_RIGHT
)
1113 return E_INVALIDARG
;
1115 if (This
->dsbuffer
) {
1116 if (FAILED(IDirectSoundBuffer_SetPan(This
->dsbuffer
, lBalance
)))
1120 This
->pan
= lBalance
;
1124 static HRESULT WINAPI
Basicaudio_get_Balance(IBasicAudio
*iface
,
1126 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
1128 TRACE("(%p/%p)->(%p)\n", This
, iface
, plBalance
);
1133 *plBalance
= This
->pan
;
1137 static const IBasicAudioVtbl IBasicAudio_Vtbl
=
1139 Basicaudio_QueryInterface
,
1142 Basicaudio_GetTypeInfoCount
,
1143 Basicaudio_GetTypeInfo
,
1144 Basicaudio_GetIDsOfNames
,
1146 Basicaudio_put_Volume
,
1147 Basicaudio_get_Volume
,
1148 Basicaudio_put_Balance
,
1149 Basicaudio_get_Balance
1153 /*** IUnknown methods ***/
1154 static HRESULT WINAPI
ReferenceClock_QueryInterface(IReferenceClock
*iface
,
1158 ICOM_THIS_MULTI(DSoundRenderImpl
, IReferenceClock_vtbl
, iface
);
1160 TRACE("(%p/%p)->(%s (%p), %p)\n", This
, iface
, debugstr_guid(riid
), riid
, ppvObj
);
1162 return DSoundRender_QueryInterface((IBaseFilter
*)This
, riid
, ppvObj
);
1165 static ULONG WINAPI
ReferenceClock_AddRef(IReferenceClock
*iface
)
1167 ICOM_THIS_MULTI(DSoundRenderImpl
, IReferenceClock_vtbl
, iface
);
1169 TRACE("(%p/%p)->()\n", This
, iface
);
1171 return DSoundRender_AddRef((IBaseFilter
*)This
);
1174 static ULONG WINAPI
ReferenceClock_Release(IReferenceClock
*iface
)
1176 ICOM_THIS_MULTI(DSoundRenderImpl
, IReferenceClock_vtbl
, iface
);
1178 TRACE("(%p/%p)->()\n", This
, iface
);
1180 return DSoundRender_Release((IBaseFilter
*)This
);
1183 /*** IReferenceClock methods ***/
1184 static HRESULT WINAPI
ReferenceClock_GetTime(IReferenceClock
*iface
,
1185 REFERENCE_TIME
*pTime
)
1187 ICOM_THIS_MULTI(DSoundRenderImpl
, IReferenceClock_vtbl
, iface
);
1188 HRESULT hr
= E_FAIL
;
1191 TRACE("(%p/%p)->(%p)\n", This
, iface
, pTime
);
1194 hr
= DSoundRender_GetPos(This
, &play_pos
, pTime
);
1196 ERR("Could not get reference time (%x)!\n", hr
);
1201 static HRESULT WINAPI
ReferenceClock_AdviseTime(IReferenceClock
*iface
,
1202 REFERENCE_TIME rtBaseTime
,
1203 REFERENCE_TIME rtStreamTime
,
1205 DWORD_PTR
*pdwAdviseCookie
)
1207 ICOM_THIS_MULTI(DSoundRenderImpl
, IReferenceClock_vtbl
, iface
);
1209 FIXME("(%p/%p)->(%s, %s, %p, %p): stub!\n", This
, iface
, wine_dbgstr_longlong(rtBaseTime
), wine_dbgstr_longlong(rtStreamTime
), (void*)hEvent
, pdwAdviseCookie
);
1214 static HRESULT WINAPI
ReferenceClock_AdvisePeriodic(IReferenceClock
*iface
,
1215 REFERENCE_TIME rtBaseTime
,
1216 REFERENCE_TIME rtStreamTime
,
1217 HSEMAPHORE hSemaphore
,
1218 DWORD_PTR
*pdwAdviseCookie
)
1220 ICOM_THIS_MULTI(DSoundRenderImpl
, IReferenceClock_vtbl
, iface
);
1222 FIXME("(%p/%p)->(%s, %s, %p, %p): stub!\n", This
, iface
, wine_dbgstr_longlong(rtBaseTime
), wine_dbgstr_longlong(rtStreamTime
), (void*)hSemaphore
, pdwAdviseCookie
);
1227 static HRESULT WINAPI
ReferenceClock_Unadvise(IReferenceClock
*iface
,
1228 DWORD_PTR dwAdviseCookie
)
1230 ICOM_THIS_MULTI(DSoundRenderImpl
, IReferenceClock_vtbl
, iface
);
1232 FIXME("(%p/%p)->(%p): stub!\n", This
, iface
, (void*)dwAdviseCookie
);
1237 static const IReferenceClockVtbl IReferenceClock_Vtbl
=
1239 ReferenceClock_QueryInterface
,
1240 ReferenceClock_AddRef
,
1241 ReferenceClock_Release
,
1242 ReferenceClock_GetTime
,
1243 ReferenceClock_AdviseTime
,
1244 ReferenceClock_AdvisePeriodic
,
1245 ReferenceClock_Unadvise
1248 static inline DSoundRenderImpl
*impl_from_IMediaSeeking( IMediaSeeking
*iface
)
1250 return (DSoundRenderImpl
*)((char*)iface
- FIELD_OFFSET(DSoundRenderImpl
, mediaSeeking
.lpVtbl
));
1253 static HRESULT WINAPI
sound_seek_QueryInterface(IMediaSeeking
* iface
, REFIID riid
, LPVOID
* ppv
)
1255 DSoundRenderImpl
*This
= impl_from_IMediaSeeking(iface
);
1257 return IUnknown_QueryInterface((IUnknown
*)This
, riid
, ppv
);
1260 static ULONG WINAPI
sound_seek_AddRef(IMediaSeeking
* iface
)
1262 DSoundRenderImpl
*This
= impl_from_IMediaSeeking(iface
);
1264 return IUnknown_AddRef((IUnknown
*)This
);
1267 static ULONG WINAPI
sound_seek_Release(IMediaSeeking
* iface
)
1269 DSoundRenderImpl
*This
= impl_from_IMediaSeeking(iface
);
1271 return IUnknown_Release((IUnknown
*)This
);
1274 static const IMediaSeekingVtbl IMediaSeeking_Vtbl
=
1276 sound_seek_QueryInterface
,
1279 MediaSeekingImpl_GetCapabilities
,
1280 MediaSeekingImpl_CheckCapabilities
,
1281 MediaSeekingImpl_IsFormatSupported
,
1282 MediaSeekingImpl_QueryPreferredFormat
,
1283 MediaSeekingImpl_GetTimeFormat
,
1284 MediaSeekingImpl_IsUsingTimeFormat
,
1285 MediaSeekingImpl_SetTimeFormat
,
1286 MediaSeekingImpl_GetDuration
,
1287 MediaSeekingImpl_GetStopPosition
,
1288 MediaSeekingImpl_GetCurrentPosition
,
1289 MediaSeekingImpl_ConvertTimeFormat
,
1290 MediaSeekingImpl_SetPositions
,
1291 MediaSeekingImpl_GetPositions
,
1292 MediaSeekingImpl_GetAvailable
,
1293 MediaSeekingImpl_SetRate
,
1294 MediaSeekingImpl_GetRate
,
1295 MediaSeekingImpl_GetPreroll