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;
75 REFERENCE_TIME play_time;
76 MediaSeekingImpl mediaSeeking;
82 static HRESULT sound_mod_stop(IBaseFilter *iface)
84 FIXME("(%p) stub\n", iface);
88 static HRESULT sound_mod_start(IBaseFilter *iface)
90 FIXME("(%p) stub\n", iface);
94 static HRESULT sound_mod_rate(IBaseFilter *iface)
96 FIXME("(%p) stub\n", iface);
100 static inline HRESULT DSoundRender_GetPos(DSoundRenderImpl *This, DWORD *pPlayPos, REFERENCE_TIME *pRefTime)
104 EnterCriticalSection(&This->csFilter);
109 hr = IDirectSoundBuffer_GetStatus(This->dsbuffer, &state);
110 if (SUCCEEDED(hr) && !(state & DSBSTATUS_PLAYING) && This->state == State_Running)
112 TRACE("Not playing, kickstarting the engine\n");
114 hr = IDirectSoundBuffer_Play(This->dsbuffer, 0, 0, DSBPLAY_LOOPING);
116 ERR("Can't play sound buffer (%x)\n", hr);
120 hr = IDirectSoundBuffer_GetCurrentPosition(This->dsbuffer, pPlayPos, &write_pos);
123 DWORD play_pos = *pPlayPos;
125 if (play_pos < This->last_play_pos)
127 This->last_play_pos = play_pos;
129 /* If we really fell behind, start at the next possible position
130 * Also happens when just starting playback for the first time,
133 if ((This->play_loops*This->buf_size)+play_pos >=
134 (This->write_loops*This->buf_size)+This->write_pos)
135 This->write_pos = write_pos;
139 REFERENCE_TIME play_time;
140 play_time = ((REFERENCE_TIME)This->play_loops*10000000) +
141 ((REFERENCE_TIME)play_pos*10000000/This->buf_size);
143 /* Don't let time run backwards */
144 if(play_time-This->play_time > 0)
145 This->play_time = play_time;
149 *pRefTime = This->play_time;
153 LeaveCriticalSection(&This->csFilter);
158 static HRESULT DSoundRender_SendSampleData(DSoundRenderImpl* This, const BYTE *data, DWORD size)
161 LPBYTE lpbuf1 = NULL;
162 LPBYTE lpbuf2 = NULL;
166 DWORD play_pos,buf_free;
170 hr = DSoundRender_GetPos(This, &play_pos, NULL);
173 ERR("GetPos returned error: %x\n", hr);
176 if (This->write_pos <= play_pos)
177 buf_free = play_pos-This->write_pos;
179 buf_free = This->buf_size - This->write_pos + play_pos;
181 /* Wait for enough of the buffer to empty before filling it */
182 if(buf_free < This->buf_size/4)
188 size2 = min(buf_free, size);
189 hr = IDirectSoundBuffer_Lock(This->dsbuffer, This->write_pos, size2, (LPVOID *)&lpbuf1, &dwsize1, (LPVOID *)&lpbuf2, &dwsize2, 0);
191 ERR("Unable to lock sound buffer! (%x)\n", hr);
194 /* TRACE("write_pos=%d, size=%d, sz1=%d, sz2=%d\n", This->write_pos, size2, dwsize1, dwsize2); */
196 memcpy(lpbuf1, data, dwsize1);
198 memcpy(lpbuf2, data + dwsize1, dwsize2);
200 hr = IDirectSoundBuffer_Unlock(This->dsbuffer, lpbuf1, dwsize1, lpbuf2, dwsize2);
202 ERR("Unable to unlock sound buffer! (%x)\n", hr);
204 size -= dwsize1 + dwsize2;
205 data += dwsize1 + dwsize2;
206 This->write_pos += dwsize1 + dwsize2;
207 if (This->write_pos >= This->buf_size)
209 This->write_pos -= This->buf_size;
212 } while (size && This->state == State_Running);
217 static HRESULT DSoundRender_Sample(LPVOID iface, IMediaSample * pSample)
219 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
220 LPBYTE pbSrcStream = NULL;
221 long cbSrcStream = 0;
222 REFERENCE_TIME tStart, tStop;
225 TRACE("%p %p\n", iface, pSample);
227 if (This->state == State_Paused)
230 if (This->state == State_Stopped)
231 return VFW_E_WRONG_STATE;
233 hr = IMediaSample_GetPointer(pSample, &pbSrcStream);
236 ERR("Cannot get pointer to sample data (%x)\n", hr);
240 hr = IMediaSample_GetTime(pSample, &tStart, &tStop);
242 ERR("Cannot get sample time (%x)\n", hr);
244 cbSrcStream = IMediaSample_GetActualDataLength(pSample);
245 TRACE("Sample data ptr = %p, size = %ld\n", pbSrcStream, cbSrcStream);
247 #if 0 /* For debugging purpose */
250 for(i = 0; i < cbSrcStream; i++)
252 if ((i!=0) && !(i%16))
254 TRACE("%02x ", pbSrcStream[i]);
260 return DSoundRender_SendSampleData(This, pbSrcStream, cbSrcStream);
263 static HRESULT DSoundRender_QueryAccept(LPVOID iface, const AM_MEDIA_TYPE * pmt)
265 WAVEFORMATEX* format = (WAVEFORMATEX*)pmt->pbFormat;
266 TRACE("wFormatTag = %x %x\n", format->wFormatTag, WAVE_FORMAT_PCM);
267 TRACE("nChannels = %d\n", format->nChannels);
268 TRACE("nSamplesPerSec = %d\n", format->nAvgBytesPerSec);
269 TRACE("nAvgBytesPerSec = %d\n", format->nAvgBytesPerSec);
270 TRACE("nBlockAlign = %d\n", format->nBlockAlign);
271 TRACE("wBitsPerSample = %d\n", format->wBitsPerSample);
273 if (IsEqualIID(&pmt->majortype, &MEDIATYPE_Audio) && IsEqualIID(&pmt->subtype, &MEDIASUBTYPE_PCM))
278 HRESULT DSoundRender_create(IUnknown * pUnkOuter, LPVOID * ppv)
282 DSoundRenderImpl * pDSoundRender;
284 TRACE("(%p, %p)\n", pUnkOuter, ppv);
289 return CLASS_E_NOAGGREGATION;
291 pDSoundRender = CoTaskMemAlloc(sizeof(DSoundRenderImpl));
293 return E_OUTOFMEMORY;
294 ZeroMemory(pDSoundRender, sizeof(DSoundRenderImpl));
296 pDSoundRender->lpVtbl = &DSoundRender_Vtbl;
297 pDSoundRender->IBasicAudio_vtbl = &IBasicAudio_Vtbl;
298 pDSoundRender->IReferenceClock_vtbl = &IReferenceClock_Vtbl;
299 pDSoundRender->refCount = 1;
300 InitializeCriticalSection(&pDSoundRender->csFilter);
301 pDSoundRender->csFilter.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": DSoundRenderImpl.csFilter");
302 pDSoundRender->state = State_Stopped;
304 pDSoundRender->ppPins = CoTaskMemAlloc(1 * sizeof(IPin *));
305 if (!pDSoundRender->ppPins)
307 pDSoundRender->csFilter.DebugInfo->Spare[0] = 0;
308 DeleteCriticalSection(&pDSoundRender->csFilter);
309 CoTaskMemFree(pDSoundRender);
310 return E_OUTOFMEMORY;
313 /* construct input pin */
314 piInput.dir = PINDIR_INPUT;
315 piInput.pFilter = (IBaseFilter *)pDSoundRender;
316 lstrcpynW(piInput.achName, wcsInputPinName, sizeof(piInput.achName) / sizeof(piInput.achName[0]));
317 hr = InputPin_Construct(&DSoundRender_InputPin_Vtbl, &piInput, DSoundRender_Sample, pDSoundRender, DSoundRender_QueryAccept, NULL, &pDSoundRender->csFilter, (IPin **)&pDSoundRender->pInputPin);
321 hr = DirectSoundCreate(NULL, &pDSoundRender->dsound, NULL);
323 ERR("Cannot create Direct Sound object (%x)\n", hr);
328 MediaSeekingImpl_Init((IBaseFilter*)pDSoundRender, sound_mod_stop, sound_mod_start, sound_mod_rate, &pDSoundRender->mediaSeeking, &pDSoundRender->csFilter);
329 pDSoundRender->mediaSeeking.lpVtbl = &IMediaSeeking_Vtbl;
331 pDSoundRender->ppPins[0] = (IPin *)pDSoundRender->pInputPin;
332 *ppv = (LPVOID)pDSoundRender;
336 if (pDSoundRender->pInputPin)
337 IPin_Release((IPin*)pDSoundRender->pInputPin);
338 CoTaskMemFree(pDSoundRender->ppPins);
339 pDSoundRender->csFilter.DebugInfo->Spare[0] = 0;
340 DeleteCriticalSection(&pDSoundRender->csFilter);
341 CoTaskMemFree(pDSoundRender);
347 static HRESULT WINAPI DSoundRender_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv)
349 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
350 TRACE("(%p, %p)->(%s, %p)\n", This, iface, qzdebugstr_guid(riid), ppv);
354 if (IsEqualIID(riid, &IID_IUnknown))
356 else if (IsEqualIID(riid, &IID_IPersist))
358 else if (IsEqualIID(riid, &IID_IMediaFilter))
360 else if (IsEqualIID(riid, &IID_IBaseFilter))
362 else if (IsEqualIID(riid, &IID_IBasicAudio))
363 *ppv = (LPVOID)&(This->IBasicAudio_vtbl);
364 else if (IsEqualIID(riid, &IID_IReferenceClock))
365 *ppv = (LPVOID)&(This->IReferenceClock_vtbl);
366 else if (IsEqualIID(riid, &IID_IMediaSeeking))
367 *ppv = &This->mediaSeeking.lpVtbl;
371 IUnknown_AddRef((IUnknown *)(*ppv));
375 if (!IsEqualIID(riid, &IID_IPin))
376 FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
378 return E_NOINTERFACE;
381 static ULONG WINAPI DSoundRender_AddRef(IBaseFilter * iface)
383 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
384 ULONG refCount = InterlockedIncrement(&This->refCount);
386 TRACE("(%p/%p)->() AddRef from %d\n", This, iface, refCount - 1);
391 static ULONG WINAPI DSoundRender_Release(IBaseFilter * iface)
393 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
394 ULONG refCount = InterlockedDecrement(&This->refCount);
396 TRACE("(%p)->() Release from %d\n", This, refCount + 1);
403 IReferenceClock_Release(This->pClock);
406 IDirectSoundBuffer_Release(This->dsbuffer);
407 This->dsbuffer = NULL;
409 IDirectSound_Release(This->dsound);
412 if (SUCCEEDED(IPin_ConnectedTo(This->ppPins[0], &pConnectedTo)))
414 IPin_Disconnect(pConnectedTo);
415 IPin_Release(pConnectedTo);
417 IPin_Disconnect(This->ppPins[0]);
419 IPin_Release(This->ppPins[0]);
421 CoTaskMemFree(This->ppPins);
423 This->IBasicAudio_vtbl = NULL;
425 This->csFilter.DebugInfo->Spare[0] = 0;
426 DeleteCriticalSection(&This->csFilter);
428 TRACE("Destroying Audio Renderer\n");
437 /** IPersist methods **/
439 static HRESULT WINAPI DSoundRender_GetClassID(IBaseFilter * iface, CLSID * pClsid)
441 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
442 TRACE("(%p/%p)->(%p)\n", This, iface, pClsid);
444 *pClsid = CLSID_DSoundRender;
449 /** IMediaFilter methods **/
451 static HRESULT WINAPI DSoundRender_Stop(IBaseFilter * iface)
454 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
456 TRACE("(%p/%p)->()\n", This, iface);
458 EnterCriticalSection(&This->csFilter);
463 hr = IDirectSoundBuffer_GetStatus(This->dsbuffer, &state);
466 if (state & DSBSTATUS_PLAYING)
467 hr = IDirectSoundBuffer_Stop(This->dsbuffer);
471 This->state = State_Stopped;
473 LeaveCriticalSection(&This->csFilter);
478 static HRESULT WINAPI DSoundRender_Pause(IBaseFilter * iface)
481 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
483 TRACE("(%p/%p)->()\n", This, iface);
485 EnterCriticalSection(&This->csFilter);
488 if (This->state == State_Stopped)
489 This->pInputPin->end_of_stream = 0;
493 hr = IDirectSoundBuffer_GetStatus(This->dsbuffer, &state);
496 if (state & DSBSTATUS_PLAYING)
497 hr = IDirectSoundBuffer_Stop(This->dsbuffer);
501 This->state = State_Paused;
503 LeaveCriticalSection(&This->csFilter);
508 static HRESULT WINAPI DSoundRender_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
511 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
513 TRACE("(%p/%p)->(%s)\n", This, iface, wine_dbgstr_longlong(tStart));
515 EnterCriticalSection(&This->csFilter);
517 This->rtStreamStart = tStart;
518 This->state = State_Running;
519 This->pInputPin->end_of_stream = 0;
521 LeaveCriticalSection(&This->csFilter);
526 static HRESULT WINAPI DSoundRender_GetState(IBaseFilter * iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState)
528 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
530 TRACE("(%p/%p)->(%d, %p)\n", This, iface, dwMilliSecsTimeout, pState);
532 EnterCriticalSection(&This->csFilter);
534 *pState = This->state;
536 LeaveCriticalSection(&This->csFilter);
541 static HRESULT WINAPI DSoundRender_SetSyncSource(IBaseFilter * iface, IReferenceClock *pClock)
543 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
545 TRACE("(%p/%p)->(%p)\n", This, iface, pClock);
547 EnterCriticalSection(&This->csFilter);
550 IReferenceClock_Release(This->pClock);
551 This->pClock = pClock;
553 IReferenceClock_AddRef(This->pClock);
555 LeaveCriticalSection(&This->csFilter);
560 static HRESULT WINAPI DSoundRender_GetSyncSource(IBaseFilter * iface, IReferenceClock **ppClock)
562 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
564 TRACE("(%p/%p)->(%p)\n", This, iface, ppClock);
566 EnterCriticalSection(&This->csFilter);
568 *ppClock = This->pClock;
569 IReferenceClock_AddRef(This->pClock);
571 LeaveCriticalSection(&This->csFilter);
576 /** IBaseFilter implementation **/
578 static HRESULT WINAPI DSoundRender_EnumPins(IBaseFilter * iface, IEnumPins **ppEnum)
581 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
583 TRACE("(%p/%p)->(%p)\n", This, iface, ppEnum);
585 epd.cPins = 1; /* input pin */
586 epd.ppPins = This->ppPins;
587 return IEnumPinsImpl_Construct(&epd, ppEnum);
590 static HRESULT WINAPI DSoundRender_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin)
592 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
594 TRACE("(%p/%p)->(%s,%p)\n", This, iface, debugstr_w(Id), ppPin);
596 FIXME("DSoundRender::FindPin(...)\n");
598 /* FIXME: critical section */
603 static HRESULT WINAPI DSoundRender_QueryFilterInfo(IBaseFilter * iface, FILTER_INFO *pInfo)
605 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
607 TRACE("(%p/%p)->(%p)\n", This, iface, pInfo);
609 strcpyW(pInfo->achName, This->filterInfo.achName);
610 pInfo->pGraph = This->filterInfo.pGraph;
613 IFilterGraph_AddRef(pInfo->pGraph);
618 static HRESULT WINAPI DSoundRender_JoinFilterGraph(IBaseFilter * iface, IFilterGraph *pGraph, LPCWSTR pName)
620 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
622 TRACE("(%p/%p)->(%p, %s)\n", This, iface, pGraph, debugstr_w(pName));
624 EnterCriticalSection(&This->csFilter);
627 strcpyW(This->filterInfo.achName, pName);
629 *This->filterInfo.achName = '\0';
630 This->filterInfo.pGraph = pGraph; /* NOTE: do NOT increase ref. count */
632 LeaveCriticalSection(&This->csFilter);
637 static HRESULT WINAPI DSoundRender_QueryVendorInfo(IBaseFilter * iface, LPWSTR *pVendorInfo)
639 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
640 TRACE("(%p/%p)->(%p)\n", This, iface, pVendorInfo);
644 static const IBaseFilterVtbl DSoundRender_Vtbl =
646 DSoundRender_QueryInterface,
648 DSoundRender_Release,
649 DSoundRender_GetClassID,
653 DSoundRender_GetState,
654 DSoundRender_SetSyncSource,
655 DSoundRender_GetSyncSource,
656 DSoundRender_EnumPins,
657 DSoundRender_FindPin,
658 DSoundRender_QueryFilterInfo,
659 DSoundRender_JoinFilterGraph,
660 DSoundRender_QueryVendorInfo
663 static HRESULT WINAPI DSoundRender_InputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
665 InputPin *This = (InputPin *)iface;
666 PIN_DIRECTION pindirReceive;
667 DSoundRenderImpl *DSImpl;
670 TRACE("(%p)->(%p, %p)\n", This, pReceivePin, pmt);
671 dump_AM_MEDIA_TYPE(pmt);
673 EnterCriticalSection(This->pin.pCritSec);
675 DSImpl = (DSoundRenderImpl*)This->pin.pinInfo.pFilter;
677 if (This->pin.pConnectedTo)
678 hr = VFW_E_ALREADY_CONNECTED;
680 if (SUCCEEDED(hr) && This->pin.fnQueryAccept(This->pin.pUserData, pmt) != S_OK)
681 hr = VFW_E_TYPE_NOT_ACCEPTED;
685 IPin_QueryDirection(pReceivePin, &pindirReceive);
687 if (pindirReceive != PINDIR_OUTPUT)
689 ERR("Can't connect from non-output pin\n");
690 hr = VFW_E_INVALID_DIRECTION;
696 WAVEFORMATEX *format;
697 DSBUFFERDESC buf_desc;
699 TRACE("MajorType %s\n", debugstr_guid(&pmt->majortype));
700 TRACE("SubType %s\n", debugstr_guid(&pmt->subtype));
701 TRACE("Format %s\n", debugstr_guid(&pmt->formattype));
702 TRACE("Size %d\n", pmt->cbFormat);
704 format = (WAVEFORMATEX*)pmt->pbFormat;
706 DSImpl->buf_size = format->nAvgBytesPerSec;
708 memset(&buf_desc,0,sizeof(DSBUFFERDESC));
709 buf_desc.dwSize = sizeof(DSBUFFERDESC);
710 buf_desc.dwFlags = DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLPAN |
711 DSBCAPS_CTRLFREQUENCY |
712 DSBCAPS_GETCURRENTPOSITION2;
713 buf_desc.dwBufferBytes = DSImpl->buf_size;
714 buf_desc.lpwfxFormat = format;
715 hr = IDirectSound_CreateSoundBuffer(DSImpl->dsound, &buf_desc, &DSImpl->dsbuffer, NULL);
717 ERR("Can't create sound buffer (%x)\n", hr);
722 hr = IDirectSoundBuffer_SetVolume(DSImpl->dsbuffer, DSImpl->volume);
724 ERR("Can't set volume to %ld (%x)\n", DSImpl->volume, hr);
726 hr = IDirectSoundBuffer_SetPan(DSImpl->dsbuffer, DSImpl->pan);
728 ERR("Can't set pan to %ld (%x)\n", DSImpl->pan, hr);
730 DSImpl->write_pos = 0;
736 CopyMediaType(&This->pin.mtCurrent, pmt);
737 This->pin.pConnectedTo = pReceivePin;
738 IPin_AddRef(pReceivePin);
742 if (DSImpl->dsbuffer)
743 IDirectSoundBuffer_Release(DSImpl->dsbuffer);
744 DSImpl->dsbuffer = NULL;
747 LeaveCriticalSection(This->pin.pCritSec);
752 static HRESULT WINAPI DSoundRender_InputPin_Disconnect(IPin * iface)
754 IPinImpl *This = (IPinImpl*)iface;
755 DSoundRenderImpl *DSImpl;
757 TRACE("(%p)->()\n", iface);
759 DSImpl = (DSoundRenderImpl*)This->pinInfo.pFilter;
760 if (DSImpl->dsbuffer)
761 IDirectSoundBuffer_Release(DSImpl->dsbuffer);
762 DSImpl->dsbuffer = NULL;
764 return IPinImpl_Disconnect(iface);
767 static HRESULT WINAPI DSoundRender_InputPin_EndOfStream(IPin * iface)
769 InputPin* This = (InputPin*)iface;
770 DSoundRenderImpl *me = (DSoundRenderImpl*)This->pin.pinInfo.pFilter;
771 IMediaEventSink* pEventSink;
774 EnterCriticalSection(This->pin.pCritSec);
776 TRACE("(%p/%p)->()\n", This, iface);
777 InputPin_EndOfStream(iface);
779 hr = IFilterGraph_QueryInterface(me->filterInfo.pGraph, &IID_IMediaEventSink, (LPVOID*)&pEventSink);
784 silence = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, me->buf_size);
787 memset(silence, 0, me->buf_size);
788 DSoundRender_SendSampleData((DSoundRenderImpl*)This->pin.pinInfo.pFilter, silence, me->buf_size);
789 HeapFree(GetProcessHeap(), 0, silence);
792 hr = IMediaEventSink_Notify(pEventSink, EC_COMPLETE, S_OK, 0);
793 IMediaEventSink_Release(pEventSink);
795 LeaveCriticalSection(This->pin.pCritSec);
800 static HRESULT WINAPI DSoundRender_InputPin_BeginFlush(IPin * iface)
802 InputPin *This = (InputPin *)iface;
803 DSoundRenderImpl *pFilter = (DSoundRenderImpl *)This->pin.pinInfo.pFilter;
810 EnterCriticalSection(This->pin.pCritSec);
811 hr = InputPin_BeginFlush(iface);
813 if (pFilter->dsbuffer)
815 IDirectSoundBuffer_Stop(pFilter->dsbuffer);
818 IDirectSoundBuffer_SetCurrentPosition(pFilter->dsbuffer, 0);
819 pFilter->write_pos = pFilter->last_play_pos = 0;
820 ++pFilter->play_loops;
821 pFilter->write_loops = pFilter->play_loops;
823 IDirectSoundBuffer_Lock(pFilter->dsbuffer, 0, 0, (LPVOID *)&buffer, &size, NULL, NULL, DSBLOCK_ENTIREBUFFER);
824 memset(buffer, 0, size);
825 IDirectSoundBuffer_Unlock(pFilter->dsbuffer, buffer, size, NULL, 0);
827 LeaveCriticalSection(This->pin.pCritSec);
832 static const IPinVtbl DSoundRender_InputPin_Vtbl =
834 InputPin_QueryInterface,
838 DSoundRender_InputPin_ReceiveConnection,
839 DSoundRender_InputPin_Disconnect,
840 IPinImpl_ConnectedTo,
841 IPinImpl_ConnectionMediaType,
842 IPinImpl_QueryPinInfo,
843 IPinImpl_QueryDirection,
845 IPinImpl_QueryAccept,
846 IPinImpl_EnumMediaTypes,
847 IPinImpl_QueryInternalConnections,
848 DSoundRender_InputPin_EndOfStream,
849 DSoundRender_InputPin_BeginFlush,
854 static const IMemInputPinVtbl MemInputPin_Vtbl =
856 MemInputPin_QueryInterface,
859 MemInputPin_GetAllocator,
860 MemInputPin_NotifyAllocator,
861 MemInputPin_GetAllocatorRequirements,
863 MemInputPin_ReceiveMultiple,
864 MemInputPin_ReceiveCanBlock
867 /*** IUnknown methods ***/
868 static HRESULT WINAPI Basicaudio_QueryInterface(IBasicAudio *iface,
871 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
873 TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
875 return DSoundRender_QueryInterface((IBaseFilter*)This, riid, ppvObj);
878 static ULONG WINAPI Basicaudio_AddRef(IBasicAudio *iface) {
879 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
881 TRACE("(%p/%p)->()\n", This, iface);
883 return DSoundRender_AddRef((IBaseFilter*)This);
886 static ULONG WINAPI Basicaudio_Release(IBasicAudio *iface) {
887 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
889 TRACE("(%p/%p)->()\n", This, iface);
891 return DSoundRender_Release((IBaseFilter*)This);
894 /*** IDispatch methods ***/
895 static HRESULT WINAPI Basicaudio_GetTypeInfoCount(IBasicAudio *iface,
897 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
899 TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pctinfo);
904 static HRESULT WINAPI Basicaudio_GetTypeInfo(IBasicAudio *iface,
907 ITypeInfo**ppTInfo) {
908 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
910 TRACE("(%p/%p)->(%d, %d, %p): stub !!!\n", This, iface, iTInfo, lcid, ppTInfo);
915 static HRESULT WINAPI Basicaudio_GetIDsOfNames(IBasicAudio *iface,
921 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
923 TRACE("(%p/%p)->(%s (%p), %p, %d, %d, %p): stub !!!\n", This, iface, debugstr_guid(riid), riid, rgszNames, cNames, lcid, rgDispId);
928 static HRESULT WINAPI Basicaudio_Invoke(IBasicAudio *iface,
933 DISPPARAMS*pDispParams,
937 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
939 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);
944 /*** IBasicAudio methods ***/
945 static HRESULT WINAPI Basicaudio_put_Volume(IBasicAudio *iface,
947 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
949 TRACE("(%p/%p)->(%ld)\n", This, iface, lVolume);
951 if (lVolume > DSBVOLUME_MAX || lVolume < DSBVOLUME_MIN)
954 if (This->dsbuffer) {
955 if (FAILED(IDirectSoundBuffer_SetVolume(This->dsbuffer, lVolume)))
959 This->volume = lVolume;
963 static HRESULT WINAPI Basicaudio_get_Volume(IBasicAudio *iface,
965 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
967 TRACE("(%p/%p)->(%p)\n", This, iface, plVolume);
972 *plVolume = This->volume;
976 static HRESULT WINAPI Basicaudio_put_Balance(IBasicAudio *iface,
978 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
980 TRACE("(%p/%p)->(%ld)\n", This, iface, lBalance);
982 if (lBalance < DSBPAN_LEFT || lBalance > DSBPAN_RIGHT)
985 if (This->dsbuffer) {
986 if (FAILED(IDirectSoundBuffer_SetPan(This->dsbuffer, lBalance)))
990 This->pan = lBalance;
994 static HRESULT WINAPI Basicaudio_get_Balance(IBasicAudio *iface,
996 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
998 TRACE("(%p/%p)->(%p)\n", This, iface, plBalance);
1003 *plBalance = This->pan;
1007 static const IBasicAudioVtbl IBasicAudio_Vtbl =
1009 Basicaudio_QueryInterface,
1012 Basicaudio_GetTypeInfoCount,
1013 Basicaudio_GetTypeInfo,
1014 Basicaudio_GetIDsOfNames,
1016 Basicaudio_put_Volume,
1017 Basicaudio_get_Volume,
1018 Basicaudio_put_Balance,
1019 Basicaudio_get_Balance
1023 /*** IUnknown methods ***/
1024 static HRESULT WINAPI ReferenceClock_QueryInterface(IReferenceClock *iface,
1028 ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1030 TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
1032 return DSoundRender_QueryInterface((IBaseFilter*)This, riid, ppvObj);
1035 static ULONG WINAPI ReferenceClock_AddRef(IReferenceClock *iface)
1037 ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1039 TRACE("(%p/%p)->()\n", This, iface);
1041 return DSoundRender_AddRef((IBaseFilter*)This);
1044 static ULONG WINAPI ReferenceClock_Release(IReferenceClock *iface)
1046 ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1048 TRACE("(%p/%p)->()\n", This, iface);
1050 return DSoundRender_Release((IBaseFilter*)This);
1053 /*** IReferenceClock methods ***/
1054 static HRESULT WINAPI ReferenceClock_GetTime(IReferenceClock *iface,
1055 REFERENCE_TIME *pTime)
1057 ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1058 HRESULT hr = E_FAIL;
1061 TRACE("(%p/%p)->(%p)\n", This, iface, pTime);
1064 hr = DSoundRender_GetPos(This, &play_pos, pTime);
1066 ERR("Could not get reference time (%x)!\n", hr);
1071 static HRESULT WINAPI ReferenceClock_AdviseTime(IReferenceClock *iface,
1072 REFERENCE_TIME rtBaseTime,
1073 REFERENCE_TIME rtStreamTime,
1075 DWORD_PTR *pdwAdviseCookie)
1077 ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1079 FIXME("(%p/%p)->(%s, %s, %p, %p): stub!\n", This, iface, wine_dbgstr_longlong(rtBaseTime), wine_dbgstr_longlong(rtStreamTime), (void*)hEvent, pdwAdviseCookie);
1084 static HRESULT WINAPI ReferenceClock_AdvisePeriodic(IReferenceClock *iface,
1085 REFERENCE_TIME rtBaseTime,
1086 REFERENCE_TIME rtStreamTime,
1087 HSEMAPHORE hSemaphore,
1088 DWORD_PTR *pdwAdviseCookie)
1090 ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1092 FIXME("(%p/%p)->(%s, %s, %p, %p): stub!\n", This, iface, wine_dbgstr_longlong(rtBaseTime), wine_dbgstr_longlong(rtStreamTime), (void*)hSemaphore, pdwAdviseCookie);
1097 static HRESULT WINAPI ReferenceClock_Unadvise(IReferenceClock *iface,
1098 DWORD_PTR dwAdviseCookie)
1100 ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1102 FIXME("(%p/%p)->(%p): stub!\n", This, iface, (void*)dwAdviseCookie);
1107 static const IReferenceClockVtbl IReferenceClock_Vtbl =
1109 ReferenceClock_QueryInterface,
1110 ReferenceClock_AddRef,
1111 ReferenceClock_Release,
1112 ReferenceClock_GetTime,
1113 ReferenceClock_AdviseTime,
1114 ReferenceClock_AdvisePeriodic,
1115 ReferenceClock_Unadvise
1118 static inline DSoundRenderImpl *impl_from_IMediaSeeking( IMediaSeeking *iface )
1120 return (DSoundRenderImpl *)((char*)iface - FIELD_OFFSET(DSoundRenderImpl, mediaSeeking.lpVtbl));
1123 static HRESULT WINAPI sound_seek_QueryInterface(IMediaSeeking * iface, REFIID riid, LPVOID * ppv)
1125 DSoundRenderImpl *This = impl_from_IMediaSeeking(iface);
1127 return IUnknown_QueryInterface((IUnknown *)This, riid, ppv);
1130 static ULONG WINAPI sound_seek_AddRef(IMediaSeeking * iface)
1132 DSoundRenderImpl *This = impl_from_IMediaSeeking(iface);
1134 return IUnknown_AddRef((IUnknown *)This);
1137 static ULONG WINAPI sound_seek_Release(IMediaSeeking * iface)
1139 DSoundRenderImpl *This = impl_from_IMediaSeeking(iface);
1141 return IUnknown_Release((IUnknown *)This);
1144 static const IMediaSeekingVtbl IMediaSeeking_Vtbl =
1146 sound_seek_QueryInterface,
1149 MediaSeekingImpl_GetCapabilities,
1150 MediaSeekingImpl_CheckCapabilities,
1151 MediaSeekingImpl_IsFormatSupported,
1152 MediaSeekingImpl_QueryPreferredFormat,
1153 MediaSeekingImpl_GetTimeFormat,
1154 MediaSeekingImpl_IsUsingTimeFormat,
1155 MediaSeekingImpl_SetTimeFormat,
1156 MediaSeekingImpl_GetDuration,
1157 MediaSeekingImpl_GetStopPosition,
1158 MediaSeekingImpl_GetCurrentPosition,
1159 MediaSeekingImpl_ConvertTimeFormat,
1160 MediaSeekingImpl_SetPositions,
1161 MediaSeekingImpl_GetPositions,
1162 MediaSeekingImpl_GetAvailable,
1163 MediaSeekingImpl_SetRate,
1164 MediaSeekingImpl_GetRate,
1165 MediaSeekingImpl_GetPreroll