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
55 const IBasicAudioVtbl
*IBasicAudio_vtbl
;
56 const IReferenceClockVtbl
*IReferenceClock_vtbl
;
57 const IAMDirectSoundVtbl
*IAMDirectSound_vtbl
;
58 IUnknown
*seekthru_unk
;
60 REFERENCE_TIME rtLastStop
;
62 BaseInputPin
* pInputPin
;
64 IDirectSound8
*dsound
;
65 LPDIRECTSOUNDBUFFER dsbuffer
;
74 REFERENCE_TIME play_time
;
76 HANDLE state_change
, blocked
;
82 static inline HRESULT
DSoundRender_GetPos(DSoundRenderImpl
*This
, DWORD
*pPlayPos
, REFERENCE_TIME
*pRefTime
)
86 EnterCriticalSection(&This
->filter
.csFilter
);
91 hr
= IDirectSoundBuffer_GetStatus(This
->dsbuffer
, &state
);
92 if (SUCCEEDED(hr
) && !(state
& DSBSTATUS_PLAYING
) && This
->filter
.state
== State_Running
)
94 TRACE("Not playing, kickstarting the engine\n");
96 hr
= IDirectSoundBuffer_Play(This
->dsbuffer
, 0, 0, DSBPLAY_LOOPING
);
98 ERR("Can't play sound buffer (%x)\n", hr
);
102 hr
= IDirectSoundBuffer_GetCurrentPosition(This
->dsbuffer
, pPlayPos
, &write_pos
);
105 DWORD play_pos
= *pPlayPos
;
107 if (play_pos
< This
->last_play_pos
)
109 This
->last_play_pos
= play_pos
;
111 /* If we really fell behind, start at the next possible position
112 * Also happens when just starting playback for the first time,
115 if ((This
->play_loops
*This
->buf_size
)+play_pos
>=
116 (This
->write_loops
*This
->buf_size
)+This
->write_pos
)
117 This
->write_pos
= 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
->filter
.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
;
152 hr
= DSoundRender_GetPos(This
, &play_pos
, NULL
);
155 ERR("GetPos returned error: %x\n", hr
);
158 if (This
->write_pos
<= play_pos
)
159 buf_free
= play_pos
-This
->write_pos
;
161 buf_free
= This
->buf_size
- This
->write_pos
+ play_pos
;
163 /* Wait for enough of the buffer to empty before filling it */
164 if(buf_free
< This
->buf_size
/20)
168 LeaveCriticalSection(&This
->filter
.csFilter
);
169 ret
= WaitForSingleObject(This
->blocked
, 50);
170 if (ret
!= WAIT_TIMEOUT
)
172 EnterCriticalSection(&This
->filter
.csFilter
);
174 if (This
->pInputPin
->flushing
)
175 return VFW_E_WRONG_STATE
;
176 if (This
->filter
.state
== State_Stopped
)
177 return VFW_E_WRONG_STATE
;
181 size2
= min(buf_free
, size
);
182 hr
= IDirectSoundBuffer_Lock(This
->dsbuffer
, This
->write_pos
, size2
, (LPVOID
*)&lpbuf1
, &dwsize1
, (LPVOID
*)&lpbuf2
, &dwsize2
, 0);
184 ERR("Unable to lock sound buffer! (%x)\n", hr
);
187 /* TRACE("write_pos=%d, size=%d, sz1=%d, sz2=%d\n", This->write_pos, size2, dwsize1, dwsize2); */
189 memcpy(lpbuf1
, data
, dwsize1
);
191 memcpy(lpbuf2
, data
+ dwsize1
, dwsize2
);
193 hr
= IDirectSoundBuffer_Unlock(This
->dsbuffer
, lpbuf1
, dwsize1
, lpbuf2
, dwsize2
);
195 ERR("Unable to unlock sound buffer! (%x)\n", hr
);
197 size
-= dwsize1
+ dwsize2
;
198 data
+= dwsize1
+ dwsize2
;
199 This
->write_pos
+= dwsize1
+ dwsize2
;
200 if (This
->write_pos
>= This
->buf_size
)
202 This
->write_pos
-= This
->buf_size
;
205 } while (size
&& This
->filter
.state
== State_Running
);
210 static HRESULT WINAPI
DSoundRender_Receive(BaseInputPin
*pin
, IMediaSample
* pSample
)
212 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)pin
->pin
.pinInfo
.pFilter
;
213 LPBYTE pbSrcStream
= NULL
;
214 LONG cbSrcStream
= 0;
215 REFERENCE_TIME tStart
, tStop
;
219 TRACE("%p %p\n", pin
, pSample
);
221 /* Slightly incorrect, Pause completes when a frame is received so we should signal
222 * pause completion here, but for sound playing a single frame doesn't make sense
225 EnterCriticalSection(&This
->filter
.csFilter
);
227 if (This
->pInputPin
->end_of_stream
|| This
->pInputPin
->flushing
)
229 LeaveCriticalSection(&This
->filter
.csFilter
);
233 if (This
->filter
.state
== State_Stopped
)
235 LeaveCriticalSection(&This
->filter
.csFilter
);
236 return VFW_E_WRONG_STATE
;
239 if (IMediaSample_GetMediaType(pSample
, &amt
) == S_OK
)
241 AM_MEDIA_TYPE
*orig
= &This
->pInputPin
->pin
.mtCurrent
;
242 WAVEFORMATEX
*origfmt
= (WAVEFORMATEX
*)orig
->pbFormat
;
243 WAVEFORMATEX
*newfmt
= (WAVEFORMATEX
*)amt
->pbFormat
;
245 if (origfmt
->wFormatTag
== newfmt
->wFormatTag
&&
246 origfmt
->nChannels
== newfmt
->nChannels
&&
247 origfmt
->nBlockAlign
== newfmt
->nBlockAlign
&&
248 origfmt
->wBitsPerSample
== newfmt
->wBitsPerSample
&&
249 origfmt
->cbSize
== newfmt
->cbSize
)
251 if (origfmt
->nSamplesPerSec
!= newfmt
->nSamplesPerSec
)
253 hr
= IDirectSoundBuffer_SetFrequency(This
->dsbuffer
,
254 newfmt
->nSamplesPerSec
);
257 LeaveCriticalSection(&This
->filter
.csFilter
);
258 return VFW_E_TYPE_NOT_ACCEPTED
;
261 CopyMediaType(orig
, amt
);
262 IMediaSample_SetMediaType(pSample
, NULL
);
267 LeaveCriticalSection(&This
->filter
.csFilter
);
268 return VFW_E_TYPE_NOT_ACCEPTED
;
272 hr
= IMediaSample_GetPointer(pSample
, &pbSrcStream
);
275 ERR("Cannot get pointer to sample data (%x)\n", hr
);
276 LeaveCriticalSection(&This
->filter
.csFilter
);
280 hr
= IMediaSample_GetTime(pSample
, &tStart
, &tStop
);
282 ERR("Cannot get sample time (%x)\n", hr
);
284 MediaSeekingPassThru_RegisterMediaTime(This
->seekthru_unk
, tStart
);
286 if (This
->rtLastStop
!= tStart
&& (IMediaSample_IsDiscontinuity(pSample
) == S_FALSE
))
287 WARN("Unexpected discontinuity: Last: %u.%03u, tStart: %u.%03u\n",
288 (DWORD
)(This
->rtLastStop
/ 10000000), (DWORD
)((This
->rtLastStop
/ 10000)%1000),
289 (DWORD
)(tStart
/ 10000000), (DWORD
)((tStart
/ 10000)%1000));
290 This
->rtLastStop
= tStop
;
292 if (IMediaSample_IsPreroll(pSample
) == S_OK
)
295 LeaveCriticalSection(&This
->filter
.csFilter
);
299 if (This
->filter
.state
== State_Paused
)
301 SetEvent(This
->state_change
);
302 LeaveCriticalSection(&This
->filter
.csFilter
);
303 WaitForSingleObject(This
->blocked
, INFINITE
);
304 EnterCriticalSection(&This
->filter
.csFilter
);
305 if (This
->filter
.state
== State_Stopped
)
307 LeaveCriticalSection(&This
->filter
.csFilter
);
308 return VFW_E_WRONG_STATE
;
311 if (This
->filter
.state
== State_Paused
)
313 /* Assuming we return because of flushing */
315 LeaveCriticalSection(&This
->filter
.csFilter
);
318 SetEvent(This
->state_change
);
321 cbSrcStream
= IMediaSample_GetActualDataLength(pSample
);
322 TRACE("Sample data ptr = %p, size = %d\n", pbSrcStream
, cbSrcStream
);
324 #if 0 /* For debugging purpose */
327 for(i
= 0; i
< cbSrcStream
; i
++)
329 if ((i
!=0) && !(i
%16))
331 TRACE("%02x ", pbSrcStream
[i
]);
337 hr
= DSoundRender_SendSampleData(This
, pbSrcStream
, cbSrcStream
);
338 SetEvent(This
->state_change
);
339 LeaveCriticalSection(&This
->filter
.csFilter
);
343 static HRESULT WINAPI
DSoundRender_CheckMediaType(BasePin
*iface
, const AM_MEDIA_TYPE
* pmt
)
345 WAVEFORMATEX
* format
;
347 if (!IsEqualIID(&pmt
->majortype
, &MEDIATYPE_Audio
))
350 format
= (WAVEFORMATEX
*)pmt
->pbFormat
;
351 TRACE("Format = %p\n", format
);
352 TRACE("wFormatTag = %x %x\n", format
->wFormatTag
, WAVE_FORMAT_PCM
);
353 TRACE("nChannels = %d\n", format
->nChannels
);
354 TRACE("nSamplesPerSec = %d\n", format
->nAvgBytesPerSec
);
355 TRACE("nAvgBytesPerSec = %d\n", format
->nAvgBytesPerSec
);
356 TRACE("nBlockAlign = %d\n", format
->nBlockAlign
);
357 TRACE("wBitsPerSample = %d\n", format
->wBitsPerSample
);
359 if (!IsEqualIID(&pmt
->subtype
, &MEDIASUBTYPE_PCM
))
365 static IPin
* WINAPI
DSoundRender_GetPin(BaseFilter
*iface
, int pos
)
367 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
369 if (pos
>= 1 || pos
< 0)
372 IPin_AddRef((IPin
*)This
->pInputPin
);
373 return (IPin
*)This
->pInputPin
;
376 static LONG WINAPI
DSoundRender_GetPinCount(BaseFilter
*iface
)
378 /* Our pins are static */
382 static const BaseFilterFuncTable BaseFuncTable
= {
384 DSoundRender_GetPinCount
387 static const BasePinFuncTable input_BaseFuncTable
= {
388 DSoundRender_CheckMediaType
,
390 BasePinImpl_GetMediaTypeVersion
,
391 BasePinImpl_GetMediaType
394 static const BaseInputPinFuncTable input_BaseInputFuncTable
= {
399 HRESULT
DSoundRender_create(IUnknown
* pUnkOuter
, LPVOID
* ppv
)
403 DSoundRenderImpl
* pDSoundRender
;
405 TRACE("(%p, %p)\n", pUnkOuter
, ppv
);
410 return CLASS_E_NOAGGREGATION
;
412 pDSoundRender
= CoTaskMemAlloc(sizeof(DSoundRenderImpl
));
414 return E_OUTOFMEMORY
;
415 ZeroMemory(pDSoundRender
, sizeof(DSoundRenderImpl
));
417 BaseFilter_Init(&pDSoundRender
->filter
, &DSoundRender_Vtbl
, &CLSID_DSoundRender
, (DWORD_PTR
)(__FILE__
": DSoundRenderImpl.csFilter"), &BaseFuncTable
);
419 pDSoundRender
->IBasicAudio_vtbl
= &IBasicAudio_Vtbl
;
420 pDSoundRender
->IReferenceClock_vtbl
= &IReferenceClock_Vtbl
;
421 pDSoundRender
->IAMDirectSound_vtbl
= &IAMDirectSound_Vtbl
;
423 /* construct input pin */
424 piInput
.dir
= PINDIR_INPUT
;
425 piInput
.pFilter
= (IBaseFilter
*)pDSoundRender
;
426 lstrcpynW(piInput
.achName
, wcsInputPinName
, sizeof(piInput
.achName
) / sizeof(piInput
.achName
[0]));
427 hr
= BaseInputPin_Construct(&DSoundRender_InputPin_Vtbl
, &piInput
, &input_BaseFuncTable
, &input_BaseInputFuncTable
, &pDSoundRender
->filter
.csFilter
, NULL
, (IPin
**)&pDSoundRender
->pInputPin
);
431 hr
= DirectSoundCreate8(NULL
, &pDSoundRender
->dsound
, NULL
);
433 ERR("Cannot create Direct Sound object (%x)\n", hr
);
435 IDirectSound_SetCooperativeLevel(pDSoundRender
->dsound
, GetDesktopWindow(), DSSCL_PRIORITY
);
440 ISeekingPassThru
*passthru
;
441 pDSoundRender
->state_change
= CreateEventW(NULL
, TRUE
, TRUE
, NULL
);
442 pDSoundRender
->blocked
= CreateEventW(NULL
, TRUE
, TRUE
, NULL
);
443 hr
= CoCreateInstance(&CLSID_SeekingPassThru
, (IUnknown
*)pDSoundRender
, CLSCTX_INPROC_SERVER
, &IID_IUnknown
, (void**)&pDSoundRender
->seekthru_unk
);
444 if (!pDSoundRender
->state_change
|| !pDSoundRender
->blocked
|| FAILED(hr
))
446 IUnknown_Release((IUnknown
*)pDSoundRender
);
447 return HRESULT_FROM_WIN32(GetLastError());
450 IUnknown_QueryInterface(pDSoundRender
->seekthru_unk
, &IID_ISeekingPassThru
, (void**)&passthru
);
451 ISeekingPassThru_Init(passthru
, TRUE
, (IPin
*)pDSoundRender
->pInputPin
);
452 ISeekingPassThru_Release(passthru
);
453 *ppv
= pDSoundRender
;
457 if (pDSoundRender
->pInputPin
)
458 IPin_Release((IPin
*)pDSoundRender
->pInputPin
);
459 BaseFilterImpl_Release((IBaseFilter
*)pDSoundRender
);
460 CoTaskMemFree(pDSoundRender
);
466 static HRESULT WINAPI
DSoundRender_QueryInterface(IBaseFilter
* iface
, REFIID riid
, LPVOID
* ppv
)
468 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
469 TRACE("(%p, %p)->(%s, %p)\n", This
, iface
, qzdebugstr_guid(riid
), ppv
);
473 if (IsEqualIID(riid
, &IID_IUnknown
))
475 else if (IsEqualIID(riid
, &IID_IPersist
))
477 else if (IsEqualIID(riid
, &IID_IMediaFilter
))
479 else if (IsEqualIID(riid
, &IID_IBaseFilter
))
481 else if (IsEqualIID(riid
, &IID_IBasicAudio
))
482 *ppv
= &This
->IBasicAudio_vtbl
;
483 else if (IsEqualIID(riid
, &IID_IReferenceClock
))
484 *ppv
= &This
->IReferenceClock_vtbl
;
485 else if (IsEqualIID(riid
, &IID_IMediaSeeking
))
486 return IUnknown_QueryInterface(This
->seekthru_unk
, riid
, ppv
);
487 else if (IsEqualIID(riid
, &IID_IAMDirectSound
))
488 *ppv
= &This
->IAMDirectSound_vtbl
;
492 IUnknown_AddRef((IUnknown
*)(*ppv
));
496 if (!IsEqualIID(riid
, &IID_IPin
) && !IsEqualIID(riid
, &IID_IVideoWindow
))
497 FIXME("No interface for %s!\n", qzdebugstr_guid(riid
));
499 return E_NOINTERFACE
;
502 static ULONG WINAPI
DSoundRender_Release(IBaseFilter
* iface
)
504 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
505 ULONG refCount
= BaseFilterImpl_Release(iface
);
507 TRACE("(%p)->() Release from %d\n", This
, refCount
+ 1);
514 IDirectSoundBuffer_Release(This
->dsbuffer
);
515 This
->dsbuffer
= NULL
;
517 IDirectSound_Release(This
->dsound
);
520 if (SUCCEEDED(IPin_ConnectedTo((IPin
*)This
->pInputPin
, &pConnectedTo
)))
522 IPin_Disconnect(pConnectedTo
);
523 IPin_Release(pConnectedTo
);
525 IPin_Disconnect((IPin
*)This
->pInputPin
);
527 IPin_Release((IPin
*)This
->pInputPin
);
529 This
->IBasicAudio_vtbl
= NULL
;
530 if (This
->seekthru_unk
)
531 IUnknown_Release(This
->seekthru_unk
);
533 CloseHandle(This
->state_change
);
534 CloseHandle(This
->blocked
);
536 TRACE("Destroying Audio Renderer\n");
545 /** IMediaFilter methods **/
547 static HRESULT WINAPI
DSoundRender_Stop(IBaseFilter
* iface
)
550 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
552 TRACE("(%p/%p)->()\n", This
, iface
);
554 EnterCriticalSection(&This
->filter
.csFilter
);
559 hr
= IDirectSoundBuffer_GetStatus(This
->dsbuffer
, &state
);
562 if (state
& DSBSTATUS_PLAYING
)
563 hr
= IDirectSoundBuffer_Stop(This
->dsbuffer
);
567 This
->filter
.state
= State_Stopped
;
569 /* Complete our transition */
570 SetEvent(This
->state_change
);
571 SetEvent(This
->blocked
);
572 MediaSeekingPassThru_ResetMediaTime(This
->seekthru_unk
);
574 LeaveCriticalSection(&This
->filter
.csFilter
);
579 static HRESULT WINAPI
DSoundRender_Pause(IBaseFilter
* iface
)
582 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
584 TRACE("(%p/%p)->()\n", This
, iface
);
586 EnterCriticalSection(&This
->filter
.csFilter
);
587 if (This
->filter
.state
!= State_Paused
)
590 if (This
->filter
.state
== State_Stopped
)
592 This
->pInputPin
->end_of_stream
= 0;
597 hr
= IDirectSoundBuffer_GetStatus(This
->dsbuffer
, &state
);
600 if (state
& DSBSTATUS_PLAYING
)
601 hr
= IDirectSoundBuffer_Stop(This
->dsbuffer
);
605 This
->filter
.state
= State_Paused
;
607 ResetEvent(This
->blocked
);
608 ResetEvent(This
->state_change
);
610 LeaveCriticalSection(&This
->filter
.csFilter
);
615 static HRESULT WINAPI
DSoundRender_Run(IBaseFilter
* iface
, REFERENCE_TIME tStart
)
618 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
620 TRACE("(%p/%p)->(%s)\n", This
, iface
, wine_dbgstr_longlong(tStart
));
622 EnterCriticalSection(&This
->filter
.csFilter
);
623 if (This
->pInputPin
->pin
.pConnectedTo
)
625 This
->filter
.rtStreamStart
= tStart
;
626 if (This
->filter
.state
== State_Paused
)
628 /* Unblock our thread, state changing from paused to running doesn't need a reset for state change */
629 SetEvent(This
->blocked
);
631 else if (This
->filter
.state
== State_Stopped
)
633 ResetEvent(This
->state_change
);
634 This
->pInputPin
->end_of_stream
= 0;
636 ResetEvent(This
->blocked
);
637 } else if (This
->filter
.filterInfo
.pGraph
) {
638 IMediaEventSink
*pEventSink
;
639 hr
= IFilterGraph_QueryInterface(This
->filter
.filterInfo
.pGraph
, &IID_IMediaEventSink
, (LPVOID
*)&pEventSink
);
642 hr
= IMediaEventSink_Notify(pEventSink
, EC_COMPLETE
, S_OK
, (LONG_PTR
)This
);
643 IMediaEventSink_Release(pEventSink
);
648 This
->filter
.state
= State_Running
;
649 LeaveCriticalSection(&This
->filter
.csFilter
);
654 static HRESULT WINAPI
DSoundRender_GetState(IBaseFilter
* iface
, DWORD dwMilliSecsTimeout
, FILTER_STATE
*pState
)
657 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
659 TRACE("(%p/%p)->(%d, %p)\n", This
, iface
, dwMilliSecsTimeout
, pState
);
661 if (WaitForSingleObject(This
->state_change
, dwMilliSecsTimeout
) == WAIT_TIMEOUT
)
662 hr
= VFW_S_STATE_INTERMEDIATE
;
666 BaseFilterImpl_GetState(iface
, dwMilliSecsTimeout
, pState
);
671 /** IBaseFilter implementation **/
673 static HRESULT WINAPI
DSoundRender_FindPin(IBaseFilter
* iface
, LPCWSTR Id
, IPin
**ppPin
)
675 DSoundRenderImpl
*This
= (DSoundRenderImpl
*)iface
;
677 TRACE("(%p/%p)->(%s,%p)\n", This
, iface
, debugstr_w(Id
), ppPin
);
679 FIXME("DSoundRender::FindPin(...)\n");
681 /* FIXME: critical section */
686 static const IBaseFilterVtbl DSoundRender_Vtbl
=
688 DSoundRender_QueryInterface
,
689 BaseFilterImpl_AddRef
,
690 DSoundRender_Release
,
691 BaseFilterImpl_GetClassID
,
695 DSoundRender_GetState
,
696 BaseFilterImpl_SetSyncSource
,
697 BaseFilterImpl_GetSyncSource
,
698 BaseFilterImpl_EnumPins
,
699 DSoundRender_FindPin
,
700 BaseFilterImpl_QueryFilterInfo
,
701 BaseFilterImpl_JoinFilterGraph
,
702 BaseFilterImpl_QueryVendorInfo
705 static HRESULT WINAPI
DSoundRender_InputPin_ReceiveConnection(IPin
* iface
, IPin
* pReceivePin
, const AM_MEDIA_TYPE
* pmt
)
707 BaseInputPin
*This
= (BaseInputPin
*)iface
;
708 PIN_DIRECTION pindirReceive
;
709 DSoundRenderImpl
*DSImpl
;
712 TRACE("(%p)->(%p, %p)\n", This
, pReceivePin
, pmt
);
713 dump_AM_MEDIA_TYPE(pmt
);
715 EnterCriticalSection(This
->pin
.pCritSec
);
717 DSImpl
= (DSoundRenderImpl
*)This
->pin
.pinInfo
.pFilter
;
718 DSImpl
->rtLastStop
= -1;
720 if (This
->pin
.pConnectedTo
)
721 hr
= VFW_E_ALREADY_CONNECTED
;
723 if (SUCCEEDED(hr
) && This
->pin
.pFuncsTable
->pfnCheckMediaType((BasePin
*)This
, pmt
) != S_OK
)
724 hr
= VFW_E_TYPE_NOT_ACCEPTED
;
728 IPin_QueryDirection(pReceivePin
, &pindirReceive
);
730 if (pindirReceive
!= PINDIR_OUTPUT
)
732 ERR("Can't connect from non-output pin\n");
733 hr
= VFW_E_INVALID_DIRECTION
;
739 WAVEFORMATEX
*format
;
740 DSBUFFERDESC buf_desc
;
742 TRACE("MajorType %s\n", debugstr_guid(&pmt
->majortype
));
743 TRACE("SubType %s\n", debugstr_guid(&pmt
->subtype
));
744 TRACE("Format %s\n", debugstr_guid(&pmt
->formattype
));
745 TRACE("Size %d\n", pmt
->cbFormat
);
747 format
= (WAVEFORMATEX
*)pmt
->pbFormat
;
749 DSImpl
->buf_size
= format
->nAvgBytesPerSec
;
751 memset(&buf_desc
,0,sizeof(DSBUFFERDESC
));
752 buf_desc
.dwSize
= sizeof(DSBUFFERDESC
);
753 buf_desc
.dwFlags
= DSBCAPS_CTRLVOLUME
| DSBCAPS_CTRLPAN
|
754 DSBCAPS_CTRLFREQUENCY
|
755 DSBCAPS_GETCURRENTPOSITION2
;
756 buf_desc
.dwBufferBytes
= DSImpl
->buf_size
;
757 buf_desc
.lpwfxFormat
= format
;
758 hr
= IDirectSound_CreateSoundBuffer(DSImpl
->dsound
, &buf_desc
, &DSImpl
->dsbuffer
, NULL
);
760 ERR("Can't create sound buffer (%x)\n", hr
);
765 hr
= IDirectSoundBuffer_SetVolume(DSImpl
->dsbuffer
, DSImpl
->volume
);
767 ERR("Can't set volume to %d (%x)\n", DSImpl
->volume
, hr
);
769 hr
= IDirectSoundBuffer_SetPan(DSImpl
->dsbuffer
, DSImpl
->pan
);
771 ERR("Can't set pan to %d (%x)\n", DSImpl
->pan
, hr
);
773 DSImpl
->write_pos
= 0;
779 CopyMediaType(&This
->pin
.mtCurrent
, pmt
);
780 This
->pin
.pConnectedTo
= pReceivePin
;
781 IPin_AddRef(pReceivePin
);
783 else if (hr
!= VFW_E_ALREADY_CONNECTED
)
785 if (DSImpl
->dsbuffer
)
786 IDirectSoundBuffer_Release(DSImpl
->dsbuffer
);
787 DSImpl
->dsbuffer
= NULL
;
790 LeaveCriticalSection(This
->pin
.pCritSec
);
795 static HRESULT WINAPI
DSoundRender_InputPin_Disconnect(IPin
* iface
)
797 BasePin
*This
= (BasePin
*)iface
;
798 DSoundRenderImpl
*DSImpl
;
800 TRACE("(%p)->()\n", iface
);
802 DSImpl
= (DSoundRenderImpl
*)This
->pinInfo
.pFilter
;
803 if (DSImpl
->dsbuffer
)
804 IDirectSoundBuffer_Release(DSImpl
->dsbuffer
);
805 DSImpl
->dsbuffer
= NULL
;
807 return BasePinImpl_Disconnect(iface
);
810 static HRESULT WINAPI
DSoundRender_InputPin_EndOfStream(IPin
* iface
)
812 BaseInputPin
* This
= (BaseInputPin
*)iface
;
813 DSoundRenderImpl
*me
= (DSoundRenderImpl
*)This
->pin
.pinInfo
.pFilter
;
814 IMediaEventSink
* pEventSink
;
818 EnterCriticalSection(This
->pin
.pCritSec
);
820 TRACE("(%p/%p)->()\n", This
, iface
);
821 hr
= BaseInputPinImpl_EndOfStream(iface
);
825 LeaveCriticalSection(This
->pin
.pCritSec
);
829 silence
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, me
->buf_size
);
832 memset(silence
, 0, me
->buf_size
);
833 DSoundRender_SendSampleData(me
, silence
, me
->buf_size
);
834 HeapFree(GetProcessHeap(), 0, silence
);
837 if (me
->filter
.filterInfo
.pGraph
)
839 hr
= IFilterGraph_QueryInterface(me
->filter
.filterInfo
.pGraph
, &IID_IMediaEventSink
, (LPVOID
*)&pEventSink
);
842 hr
= IMediaEventSink_Notify(pEventSink
, EC_COMPLETE
, S_OK
, (LONG_PTR
)me
);
843 IMediaEventSink_Release(pEventSink
);
846 MediaSeekingPassThru_EOS(me
->seekthru_unk
);
847 LeaveCriticalSection(This
->pin
.pCritSec
);
852 static HRESULT WINAPI
DSoundRender_InputPin_BeginFlush(IPin
* iface
)
854 BaseInputPin
*This
= (BaseInputPin
*)iface
;
855 DSoundRenderImpl
*pFilter
= (DSoundRenderImpl
*)This
->pin
.pinInfo
.pFilter
;
860 EnterCriticalSection(This
->pin
.pCritSec
);
861 hr
= BaseInputPinImpl_BeginFlush(iface
);
862 SetEvent(pFilter
->blocked
);
863 LeaveCriticalSection(This
->pin
.pCritSec
);
868 static HRESULT WINAPI
DSoundRender_InputPin_EndFlush(IPin
* iface
)
870 BaseInputPin
*This
= (BaseInputPin
*)iface
;
871 DSoundRenderImpl
*pFilter
= (DSoundRenderImpl
*)This
->pin
.pinInfo
.pFilter
;
876 EnterCriticalSection(This
->pin
.pCritSec
);
877 if (pFilter
->in_loop
) {
878 ResetEvent(pFilter
->state_change
);
879 LeaveCriticalSection(This
->pin
.pCritSec
);
880 WaitForSingleObject(pFilter
->state_change
, -1);
881 EnterCriticalSection(This
->pin
.pCritSec
);
883 if (pFilter
->filter
.state
!= State_Stopped
)
884 ResetEvent(pFilter
->blocked
);
886 if (pFilter
->dsbuffer
)
890 IDirectSoundBuffer_Stop(pFilter
->dsbuffer
);
893 IDirectSoundBuffer_SetCurrentPosition(pFilter
->dsbuffer
, 0);
894 pFilter
->write_pos
= pFilter
->last_play_pos
= 0;
895 ++pFilter
->play_loops
;
896 pFilter
->write_loops
= pFilter
->play_loops
;
898 IDirectSoundBuffer_Lock(pFilter
->dsbuffer
, 0, 0, (LPVOID
*)&buffer
, &size
, NULL
, NULL
, DSBLOCK_ENTIREBUFFER
);
899 memset(buffer
, 0, size
);
900 IDirectSoundBuffer_Unlock(pFilter
->dsbuffer
, buffer
, size
, NULL
, 0);
902 hr
= BaseInputPinImpl_EndFlush(iface
);
903 LeaveCriticalSection(This
->pin
.pCritSec
);
904 MediaSeekingPassThru_ResetMediaTime(pFilter
->seekthru_unk
);
909 static const IPinVtbl DSoundRender_InputPin_Vtbl
=
911 BaseInputPinImpl_QueryInterface
,
913 BaseInputPinImpl_Release
,
914 BaseInputPinImpl_Connect
,
915 DSoundRender_InputPin_ReceiveConnection
,
916 DSoundRender_InputPin_Disconnect
,
917 BasePinImpl_ConnectedTo
,
918 BasePinImpl_ConnectionMediaType
,
919 BasePinImpl_QueryPinInfo
,
920 BasePinImpl_QueryDirection
,
922 BaseInputPinImpl_QueryAccept
,
923 BasePinImpl_EnumMediaTypes
,
924 BasePinImpl_QueryInternalConnections
,
925 DSoundRender_InputPin_EndOfStream
,
926 DSoundRender_InputPin_BeginFlush
,
927 DSoundRender_InputPin_EndFlush
,
928 BaseInputPinImpl_NewSegment
931 /*** IUnknown methods ***/
932 static HRESULT WINAPI
Basicaudio_QueryInterface(IBasicAudio
*iface
,
935 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
937 TRACE("(%p/%p)->(%s (%p), %p)\n", This
, iface
, debugstr_guid(riid
), riid
, ppvObj
);
939 return DSoundRender_QueryInterface((IBaseFilter
*)This
, riid
, ppvObj
);
942 static ULONG WINAPI
Basicaudio_AddRef(IBasicAudio
*iface
) {
943 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
945 TRACE("(%p/%p)->()\n", This
, iface
);
947 return BaseFilterImpl_AddRef((IBaseFilter
*)This
);
950 static ULONG WINAPI
Basicaudio_Release(IBasicAudio
*iface
) {
951 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
953 TRACE("(%p/%p)->()\n", This
, iface
);
955 return DSoundRender_Release((IBaseFilter
*)This
);
958 /*** IDispatch methods ***/
959 static HRESULT WINAPI
Basicaudio_GetTypeInfoCount(IBasicAudio
*iface
,
961 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
963 TRACE("(%p/%p)->(%p): stub !!!\n", This
, iface
, pctinfo
);
968 static HRESULT WINAPI
Basicaudio_GetTypeInfo(IBasicAudio
*iface
,
971 ITypeInfo
**ppTInfo
) {
972 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
974 TRACE("(%p/%p)->(%d, %d, %p): stub !!!\n", This
, iface
, iTInfo
, lcid
, ppTInfo
);
979 static HRESULT WINAPI
Basicaudio_GetIDsOfNames(IBasicAudio
*iface
,
985 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
987 TRACE("(%p/%p)->(%s (%p), %p, %d, %d, %p): stub !!!\n", This
, iface
, debugstr_guid(riid
), riid
, rgszNames
, cNames
, lcid
, rgDispId
);
992 static HRESULT WINAPI
Basicaudio_Invoke(IBasicAudio
*iface
,
997 DISPPARAMS
*pDispParams
,
1001 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
1003 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
);
1008 /*** IBasicAudio methods ***/
1009 static HRESULT WINAPI
Basicaudio_put_Volume(IBasicAudio
*iface
,
1011 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
1013 TRACE("(%p/%p)->(%d)\n", This
, iface
, lVolume
);
1015 if (lVolume
> DSBVOLUME_MAX
|| lVolume
< DSBVOLUME_MIN
)
1016 return E_INVALIDARG
;
1018 if (This
->dsbuffer
) {
1019 if (FAILED(IDirectSoundBuffer_SetVolume(This
->dsbuffer
, lVolume
)))
1023 This
->volume
= lVolume
;
1027 static HRESULT WINAPI
Basicaudio_get_Volume(IBasicAudio
*iface
,
1029 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
1031 TRACE("(%p/%p)->(%p)\n", This
, iface
, plVolume
);
1036 *plVolume
= This
->volume
;
1040 static HRESULT WINAPI
Basicaudio_put_Balance(IBasicAudio
*iface
,
1042 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
1044 TRACE("(%p/%p)->(%d)\n", This
, iface
, lBalance
);
1046 if (lBalance
< DSBPAN_LEFT
|| lBalance
> DSBPAN_RIGHT
)
1047 return E_INVALIDARG
;
1049 if (This
->dsbuffer
) {
1050 if (FAILED(IDirectSoundBuffer_SetPan(This
->dsbuffer
, lBalance
)))
1054 This
->pan
= lBalance
;
1058 static HRESULT WINAPI
Basicaudio_get_Balance(IBasicAudio
*iface
,
1060 ICOM_THIS_MULTI(DSoundRenderImpl
, IBasicAudio_vtbl
, iface
);
1062 TRACE("(%p/%p)->(%p)\n", This
, iface
, plBalance
);
1067 *plBalance
= This
->pan
;
1071 static const IBasicAudioVtbl IBasicAudio_Vtbl
=
1073 Basicaudio_QueryInterface
,
1076 Basicaudio_GetTypeInfoCount
,
1077 Basicaudio_GetTypeInfo
,
1078 Basicaudio_GetIDsOfNames
,
1080 Basicaudio_put_Volume
,
1081 Basicaudio_get_Volume
,
1082 Basicaudio_put_Balance
,
1083 Basicaudio_get_Balance
1087 /*** IUnknown methods ***/
1088 static HRESULT WINAPI
ReferenceClock_QueryInterface(IReferenceClock
*iface
,
1092 ICOM_THIS_MULTI(DSoundRenderImpl
, IReferenceClock_vtbl
, iface
);
1094 TRACE("(%p/%p)->(%s (%p), %p)\n", This
, iface
, debugstr_guid(riid
), riid
, ppvObj
);
1096 return DSoundRender_QueryInterface((IBaseFilter
*)This
, riid
, ppvObj
);
1099 static ULONG WINAPI
ReferenceClock_AddRef(IReferenceClock
*iface
)
1101 ICOM_THIS_MULTI(DSoundRenderImpl
, IReferenceClock_vtbl
, iface
);
1103 TRACE("(%p/%p)->()\n", This
, iface
);
1105 return BaseFilterImpl_AddRef((IBaseFilter
*)This
);
1108 static ULONG WINAPI
ReferenceClock_Release(IReferenceClock
*iface
)
1110 ICOM_THIS_MULTI(DSoundRenderImpl
, IReferenceClock_vtbl
, iface
);
1112 TRACE("(%p/%p)->()\n", This
, iface
);
1114 return DSoundRender_Release((IBaseFilter
*)This
);
1117 /*** IReferenceClock methods ***/
1118 static HRESULT WINAPI
ReferenceClock_GetTime(IReferenceClock
*iface
,
1119 REFERENCE_TIME
*pTime
)
1121 ICOM_THIS_MULTI(DSoundRenderImpl
, IReferenceClock_vtbl
, iface
);
1122 HRESULT hr
= E_FAIL
;
1125 TRACE("(%p/%p)->(%p)\n", This
, iface
, pTime
);
1128 hr
= DSoundRender_GetPos(This
, &play_pos
, pTime
);
1130 ERR("Could not get reference time (%x)!\n", hr
);
1135 static HRESULT WINAPI
ReferenceClock_AdviseTime(IReferenceClock
*iface
,
1136 REFERENCE_TIME rtBaseTime
,
1137 REFERENCE_TIME rtStreamTime
,
1139 DWORD_PTR
*pdwAdviseCookie
)
1141 ICOM_THIS_MULTI(DSoundRenderImpl
, IReferenceClock_vtbl
, iface
);
1143 FIXME("(%p/%p)->(%s, %s, %p, %p): stub!\n", This
, iface
, wine_dbgstr_longlong(rtBaseTime
), wine_dbgstr_longlong(rtStreamTime
), (void*)hEvent
, pdwAdviseCookie
);
1148 static HRESULT WINAPI
ReferenceClock_AdvisePeriodic(IReferenceClock
*iface
,
1149 REFERENCE_TIME rtBaseTime
,
1150 REFERENCE_TIME rtStreamTime
,
1151 HSEMAPHORE hSemaphore
,
1152 DWORD_PTR
*pdwAdviseCookie
)
1154 ICOM_THIS_MULTI(DSoundRenderImpl
, IReferenceClock_vtbl
, iface
);
1156 FIXME("(%p/%p)->(%s, %s, %p, %p): stub!\n", This
, iface
, wine_dbgstr_longlong(rtBaseTime
), wine_dbgstr_longlong(rtStreamTime
), (void*)hSemaphore
, pdwAdviseCookie
);
1161 static HRESULT WINAPI
ReferenceClock_Unadvise(IReferenceClock
*iface
,
1162 DWORD_PTR dwAdviseCookie
)
1164 ICOM_THIS_MULTI(DSoundRenderImpl
, IReferenceClock_vtbl
, iface
);
1166 FIXME("(%p/%p)->(%p): stub!\n", This
, iface
, (void*)dwAdviseCookie
);
1171 static const IReferenceClockVtbl IReferenceClock_Vtbl
=
1173 ReferenceClock_QueryInterface
,
1174 ReferenceClock_AddRef
,
1175 ReferenceClock_Release
,
1176 ReferenceClock_GetTime
,
1177 ReferenceClock_AdviseTime
,
1178 ReferenceClock_AdvisePeriodic
,
1179 ReferenceClock_Unadvise
1182 /*** IUnknown methods ***/
1183 static HRESULT WINAPI
AMDirectSound_QueryInterface(IAMDirectSound
*iface
,
1187 ICOM_THIS_MULTI(DSoundRenderImpl
, IAMDirectSound_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
AMDirectSound_AddRef(IAMDirectSound
*iface
)
1196 ICOM_THIS_MULTI(DSoundRenderImpl
, IAMDirectSound_vtbl
, iface
);
1198 TRACE("(%p/%p)->()\n", This
, iface
);
1200 return BaseFilterImpl_AddRef((IBaseFilter
*)This
);
1203 static ULONG WINAPI
AMDirectSound_Release(IAMDirectSound
*iface
)
1205 ICOM_THIS_MULTI(DSoundRenderImpl
, IAMDirectSound_vtbl
, iface
);
1207 TRACE("(%p/%p)->()\n", This
, iface
);
1209 return DSoundRender_Release((IBaseFilter
*)This
);
1212 /*** IAMDirectSound methods ***/
1213 static HRESULT WINAPI
AMDirectSound_GetDirectSoundInterface(IAMDirectSound
*iface
, IDirectSound
**ds
)
1215 ICOM_THIS_MULTI(DSoundRenderImpl
, IAMDirectSound_vtbl
, iface
);
1217 FIXME("(%p/%p)->(%p): stub\n", This
, iface
, ds
);
1222 static HRESULT WINAPI
AMDirectSound_GetPrimaryBufferInterface(IAMDirectSound
*iface
, IDirectSoundBuffer
**buf
)
1224 ICOM_THIS_MULTI(DSoundRenderImpl
, IAMDirectSound_vtbl
, iface
);
1226 FIXME("(%p/%p)->(%p): stub\n", This
, iface
, buf
);
1231 static HRESULT WINAPI
AMDirectSound_GetSecondaryBufferInterface(IAMDirectSound
*iface
, IDirectSoundBuffer
**buf
)
1233 ICOM_THIS_MULTI(DSoundRenderImpl
, IAMDirectSound_vtbl
, iface
);
1235 FIXME("(%p/%p)->(%p): stub\n", This
, iface
, buf
);
1240 static HRESULT WINAPI
AMDirectSound_ReleaseDirectSoundInterface(IAMDirectSound
*iface
, IDirectSound
*ds
)
1242 ICOM_THIS_MULTI(DSoundRenderImpl
, IAMDirectSound_vtbl
, iface
);
1244 FIXME("(%p/%p)->(%p): stub\n", This
, iface
, ds
);
1249 static HRESULT WINAPI
AMDirectSound_ReleasePrimaryBufferInterface(IAMDirectSound
*iface
, IDirectSoundBuffer
*buf
)
1251 ICOM_THIS_MULTI(DSoundRenderImpl
, IAMDirectSound_vtbl
, iface
);
1253 FIXME("(%p/%p)->(%p): stub\n", This
, iface
, buf
);
1258 static HRESULT WINAPI
AMDirectSound_ReleaseSecondaryBufferInterface(IAMDirectSound
*iface
, IDirectSoundBuffer
*buf
)
1260 ICOM_THIS_MULTI(DSoundRenderImpl
, IAMDirectSound_vtbl
, iface
);
1262 FIXME("(%p/%p)->(%p): stub\n", This
, iface
, buf
);
1267 static HRESULT WINAPI
AMDirectSound_SetFocusWindow(IAMDirectSound
*iface
, HWND hwnd
, BOOL bgsilent
)
1269 ICOM_THIS_MULTI(DSoundRenderImpl
, IAMDirectSound_vtbl
, iface
);
1271 FIXME("(%p/%p)->(%p,%d): stub\n", This
, iface
, hwnd
, bgsilent
);
1276 static HRESULT WINAPI
AMDirectSound_GetFocusWindow(IAMDirectSound
*iface
, HWND hwnd
)
1278 ICOM_THIS_MULTI(DSoundRenderImpl
, IAMDirectSound_vtbl
, iface
);
1280 FIXME("(%p/%p)->(%p): stub\n", This
, iface
, hwnd
);
1285 static const IAMDirectSoundVtbl IAMDirectSound_Vtbl
=
1287 AMDirectSound_QueryInterface
,
1288 AMDirectSound_AddRef
,
1289 AMDirectSound_Release
,
1290 AMDirectSound_GetDirectSoundInterface
,
1291 AMDirectSound_GetPrimaryBufferInterface
,
1292 AMDirectSound_GetSecondaryBufferInterface
,
1293 AMDirectSound_ReleaseDirectSoundInterface
,
1294 AMDirectSound_ReleasePrimaryBufferInterface
,
1295 AMDirectSound_ReleaseSecondaryBufferInterface
,
1296 AMDirectSound_SetFocusWindow
,
1297 AMDirectSound_GetFocusWindow