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;
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;
59 IReferenceClock * pClock;
60 FILTER_INFO filterInfo;
66 LPDIRECTSOUNDBUFFER dsbuffer;
73 REFERENCE_TIME play_time;
79 static HRESULT DSoundRender_InputPin_Construct(const PIN_INFO * pPinInfo, SAMPLEPROC pSampleProc, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, LPCRITICAL_SECTION pCritSec, IPin ** ppPin)
85 if (pPinInfo->dir != PINDIR_INPUT)
87 ERR("Pin direction(%x) != PINDIR_INPUT\n", pPinInfo->dir);
91 pPinImpl = CoTaskMemAlloc(sizeof(*pPinImpl));
96 if (SUCCEEDED(InputPin_Init(pPinInfo, pSampleProc, pUserData, pQueryAccept, pCritSec, pPinImpl)))
98 pPinImpl->pin.lpVtbl = &DSoundRender_InputPin_Vtbl;
99 pPinImpl->lpVtblMemInput = &MemInputPin_Vtbl;
101 *ppPin = (IPin *)(&pPinImpl->pin.lpVtbl);
108 static inline HRESULT DSoundRender_GetPos(DSoundRenderImpl *This, DWORD *pPlayPos, DWORD *pWritePos, REFERENCE_TIME *pRefTime)
112 EnterCriticalSection(&This->csFilter);
114 hr = IDirectSoundBuffer_GetCurrentPosition(This->dsbuffer, pPlayPos, pWritePos);
117 DWORD play_pos = *pPlayPos;
119 if (play_pos < This->last_play_pos)
121 This->last_play_pos = play_pos;
123 /* If we're really falling behind, kick the play time back */
124 if ((This->play_loops*This->buf_size)+play_pos >=
125 (This->write_loops*This->buf_size)+This->write_pos)
130 REFERENCE_TIME play_time;
131 play_time = ((REFERENCE_TIME)This->play_loops*10000000) +
132 ((REFERENCE_TIME)play_pos*10000000/This->buf_size);
134 /* Don't let time run backwards */
135 if(play_time-This->play_time > 0)
136 This->play_time = play_time;
140 *pRefTime = This->play_time;
144 LeaveCriticalSection(&This->csFilter);
149 static HRESULT DSoundRender_SendSampleData(DSoundRenderImpl* This, const BYTE *data, DWORD size)
152 LPBYTE lpbuf1 = NULL;
153 LPBYTE lpbuf2 = NULL;
157 DWORD play_pos,buf_free;
160 hr = DSoundRender_GetPos(This, &play_pos, NULL, NULL);
163 ERR("GetPos returned error: %x\n", hr);
166 if (This->write_pos <= play_pos)
167 buf_free = play_pos-This->write_pos;
169 buf_free = This->buf_size - This->write_pos + play_pos;
171 /* Wait for enough of the buffer to empty before filling it */
172 if(buf_free < This->buf_size/4)
178 size2 = min(buf_free, size);
179 hr = IDirectSoundBuffer_Lock(This->dsbuffer, This->write_pos, size2, (LPVOID *)&lpbuf1, &dwsize1, (LPVOID *)&lpbuf2, &dwsize2, 0);
181 ERR("Unable to lock sound buffer! (%x)\n", hr);
184 /* TRACE("write_pos=%d, size=%d, sz1=%d, sz2=%d\n", This->write_pos, size2, dwsize1, dwsize2); */
186 memcpy(lpbuf1, data, dwsize1);
188 memcpy(lpbuf2, data + dwsize1, dwsize2);
190 hr = IDirectSoundBuffer_Unlock(This->dsbuffer, lpbuf1, dwsize1, lpbuf2, dwsize2);
192 ERR("Unable to unlock sound buffer! (%x)\n", hr);
194 size -= dwsize1 + dwsize2;
195 data += dwsize1 + dwsize2;
196 This->write_pos += dwsize1 + dwsize2;
197 if (This->write_pos >= This->buf_size)
199 This->write_pos -= This->buf_size;
202 } while (size && This->state == State_Running);
207 static HRESULT DSoundRender_Sample(LPVOID iface, IMediaSample * pSample)
209 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
210 LPBYTE pbSrcStream = NULL;
211 long cbSrcStream = 0;
212 REFERENCE_TIME tStart, tStop;
215 TRACE("%p %p\n", iface, pSample);
217 if (This->state != State_Running)
218 return VFW_E_WRONG_STATE;
220 hr = IMediaSample_GetPointer(pSample, &pbSrcStream);
223 ERR("Cannot get pointer to sample data (%x)\n", hr);
227 hr = IMediaSample_GetTime(pSample, &tStart, &tStop);
229 ERR("Cannot get sample time (%x)\n", hr);
231 cbSrcStream = IMediaSample_GetActualDataLength(pSample);
233 TRACE("Sample data ptr = %p, size = %ld\n", pbSrcStream, cbSrcStream);
235 #if 0 /* For debugging purpose */
238 for(i = 0; i < cbSrcStream; i++)
240 if ((i!=0) && !(i%16))
242 TRACE("%02x ", pbSrcStream[i]);
248 return DSoundRender_SendSampleData(This, pbSrcStream, cbSrcStream);
251 static HRESULT DSoundRender_QueryAccept(LPVOID iface, const AM_MEDIA_TYPE * pmt)
253 WAVEFORMATEX* format = (WAVEFORMATEX*)pmt->pbFormat;
254 TRACE("wFormatTag = %x %x\n", format->wFormatTag, WAVE_FORMAT_PCM);
255 TRACE("nChannels = %d\n", format->nChannels);
256 TRACE("nSamplesPerSec = %d\n", format->nAvgBytesPerSec);
257 TRACE("nAvgBytesPerSec = %d\n", format->nAvgBytesPerSec);
258 TRACE("nBlockAlign = %d\n", format->nBlockAlign);
259 TRACE("wBitsPerSample = %d\n", format->wBitsPerSample);
261 if (IsEqualIID(&pmt->majortype, &MEDIATYPE_Audio) && IsEqualIID(&pmt->subtype, &MEDIASUBTYPE_PCM))
266 HRESULT DSoundRender_create(IUnknown * pUnkOuter, LPVOID * ppv)
270 DSoundRenderImpl * pDSoundRender;
272 TRACE("(%p, %p)\n", pUnkOuter, ppv);
277 return CLASS_E_NOAGGREGATION;
279 pDSoundRender = CoTaskMemAlloc(sizeof(DSoundRenderImpl));
281 return E_OUTOFMEMORY;
282 ZeroMemory(pDSoundRender, sizeof(DSoundRenderImpl));
284 pDSoundRender->lpVtbl = &DSoundRender_Vtbl;
285 pDSoundRender->IBasicAudio_vtbl = &IBasicAudio_Vtbl;
286 pDSoundRender->IReferenceClock_vtbl = &IReferenceClock_Vtbl;
287 pDSoundRender->refCount = 1;
288 InitializeCriticalSection(&pDSoundRender->csFilter);
289 pDSoundRender->csFilter.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": DSoundRenderImpl.csFilter");
290 pDSoundRender->state = State_Stopped;
292 pDSoundRender->ppPins = CoTaskMemAlloc(1 * sizeof(IPin *));
293 if (!pDSoundRender->ppPins)
295 pDSoundRender->csFilter.DebugInfo->Spare[0] = 0;
296 DeleteCriticalSection(&pDSoundRender->csFilter);
297 CoTaskMemFree(pDSoundRender);
298 return E_OUTOFMEMORY;
301 /* construct input pin */
302 piInput.dir = PINDIR_INPUT;
303 piInput.pFilter = (IBaseFilter *)pDSoundRender;
304 lstrcpynW(piInput.achName, wcsInputPinName, sizeof(piInput.achName) / sizeof(piInput.achName[0]));
305 hr = DSoundRender_InputPin_Construct(&piInput, DSoundRender_Sample, (LPVOID)pDSoundRender, DSoundRender_QueryAccept, &pDSoundRender->csFilter, (IPin **)&pDSoundRender->pInputPin);
309 hr = DirectSoundCreate(NULL, &pDSoundRender->dsound, NULL);
311 ERR("Cannot create Direct Sound object (%x)\n", hr);
316 pDSoundRender->ppPins[0] = (IPin *)pDSoundRender->pInputPin;
317 *ppv = (LPVOID)pDSoundRender;
321 if (pDSoundRender->pInputPin)
322 IPin_Release((IPin*)pDSoundRender->pInputPin);
323 CoTaskMemFree(pDSoundRender->ppPins);
324 pDSoundRender->csFilter.DebugInfo->Spare[0] = 0;
325 DeleteCriticalSection(&pDSoundRender->csFilter);
326 CoTaskMemFree(pDSoundRender);
332 static HRESULT WINAPI DSoundRender_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv)
334 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
335 TRACE("(%p, %p)->(%s, %p)\n", This, iface, qzdebugstr_guid(riid), ppv);
339 if (IsEqualIID(riid, &IID_IUnknown))
341 else if (IsEqualIID(riid, &IID_IPersist))
343 else if (IsEqualIID(riid, &IID_IMediaFilter))
345 else if (IsEqualIID(riid, &IID_IBaseFilter))
347 else if (IsEqualIID(riid, &IID_IBasicAudio))
348 *ppv = (LPVOID)&(This->IBasicAudio_vtbl);
349 else if (IsEqualIID(riid, &IID_IReferenceClock))
350 *ppv = (LPVOID)&(This->IReferenceClock_vtbl);
354 IUnknown_AddRef((IUnknown *)(*ppv));
358 FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
360 return E_NOINTERFACE;
363 static ULONG WINAPI DSoundRender_AddRef(IBaseFilter * iface)
365 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
366 ULONG refCount = InterlockedIncrement(&This->refCount);
368 TRACE("(%p/%p)->() AddRef from %d\n", This, iface, refCount - 1);
373 static ULONG WINAPI DSoundRender_Release(IBaseFilter * iface)
375 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
376 ULONG refCount = InterlockedDecrement(&This->refCount);
378 TRACE("(%p)->() Release from %d\n", This, refCount + 1);
385 IReferenceClock_Release(This->pClock);
388 IDirectSoundBuffer_Release(This->dsbuffer);
389 This->dsbuffer = NULL;
391 IDirectSound_Release(This->dsound);
394 if (SUCCEEDED(IPin_ConnectedTo(This->ppPins[0], &pConnectedTo)))
396 IPin_Disconnect(pConnectedTo);
397 IPin_Release(pConnectedTo);
399 IPin_Disconnect(This->ppPins[0]);
401 IPin_Release(This->ppPins[0]);
403 CoTaskMemFree(This->ppPins);
405 This->IBasicAudio_vtbl = NULL;
407 This->csFilter.DebugInfo->Spare[0] = 0;
408 DeleteCriticalSection(&This->csFilter);
410 TRACE("Destroying Audio Renderer\n");
419 /** IPersist methods **/
421 static HRESULT WINAPI DSoundRender_GetClassID(IBaseFilter * iface, CLSID * pClsid)
423 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
424 TRACE("(%p/%p)->(%p)\n", This, iface, pClsid);
426 *pClsid = CLSID_DSoundRender;
431 /** IMediaFilter methods **/
433 static HRESULT WINAPI DSoundRender_Stop(IBaseFilter * iface)
436 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
438 TRACE("(%p/%p)->()\n", This, iface);
440 EnterCriticalSection(&This->csFilter);
445 hr = IDirectSoundBuffer_GetStatus(This->dsbuffer, &state);
448 if (state & DSBSTATUS_PLAYING)
449 hr = IDirectSoundBuffer_Stop(This->dsbuffer);
453 This->state = State_Stopped;
455 LeaveCriticalSection(&This->csFilter);
460 static HRESULT WINAPI DSoundRender_Pause(IBaseFilter * iface)
463 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
465 TRACE("(%p/%p)->()\n", This, iface);
467 EnterCriticalSection(&This->csFilter);
472 hr = IDirectSoundBuffer_GetStatus(This->dsbuffer, &state);
475 if (state & DSBSTATUS_PLAYING)
476 hr = IDirectSoundBuffer_Stop(This->dsbuffer);
480 This->state = State_Paused;
482 LeaveCriticalSection(&This->csFilter);
487 static HRESULT WINAPI DSoundRender_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
490 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
492 TRACE("(%p/%p)->(%s)\n", This, iface, wine_dbgstr_longlong(tStart));
494 EnterCriticalSection(&This->csFilter);
496 /* It's okay if there's no buffer yet. It'll start when it's created */
499 hr = IDirectSoundBuffer_Play(This->dsbuffer, 0, 0, DSBPLAY_LOOPING);
501 ERR("Can't start playing! (%x)\n", hr);
505 This->rtStreamStart = tStart;
506 This->state = State_Running;
509 LeaveCriticalSection(&This->csFilter);
514 static HRESULT WINAPI DSoundRender_GetState(IBaseFilter * iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState)
516 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
518 TRACE("(%p/%p)->(%d, %p)\n", This, iface, dwMilliSecsTimeout, pState);
520 EnterCriticalSection(&This->csFilter);
522 *pState = This->state;
524 LeaveCriticalSection(&This->csFilter);
529 static HRESULT WINAPI DSoundRender_SetSyncSource(IBaseFilter * iface, IReferenceClock *pClock)
531 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
533 TRACE("(%p/%p)->(%p)\n", This, iface, pClock);
535 EnterCriticalSection(&This->csFilter);
538 IReferenceClock_Release(This->pClock);
539 This->pClock = pClock;
541 IReferenceClock_AddRef(This->pClock);
543 LeaveCriticalSection(&This->csFilter);
548 static HRESULT WINAPI DSoundRender_GetSyncSource(IBaseFilter * iface, IReferenceClock **ppClock)
550 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
552 TRACE("(%p/%p)->(%p)\n", This, iface, ppClock);
554 EnterCriticalSection(&This->csFilter);
556 *ppClock = This->pClock;
557 IReferenceClock_AddRef(This->pClock);
559 LeaveCriticalSection(&This->csFilter);
564 /** IBaseFilter implementation **/
566 static HRESULT WINAPI DSoundRender_EnumPins(IBaseFilter * iface, IEnumPins **ppEnum)
569 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
571 TRACE("(%p/%p)->(%p)\n", This, iface, ppEnum);
573 epd.cPins = 1; /* input pin */
574 epd.ppPins = This->ppPins;
575 return IEnumPinsImpl_Construct(&epd, ppEnum);
578 static HRESULT WINAPI DSoundRender_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin)
580 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
582 TRACE("(%p/%p)->(%s,%p)\n", This, iface, debugstr_w(Id), ppPin);
584 FIXME("DSoundRender::FindPin(...)\n");
586 /* FIXME: critical section */
591 static HRESULT WINAPI DSoundRender_QueryFilterInfo(IBaseFilter * iface, FILTER_INFO *pInfo)
593 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
595 TRACE("(%p/%p)->(%p)\n", This, iface, pInfo);
597 strcpyW(pInfo->achName, This->filterInfo.achName);
598 pInfo->pGraph = This->filterInfo.pGraph;
601 IFilterGraph_AddRef(pInfo->pGraph);
606 static HRESULT WINAPI DSoundRender_JoinFilterGraph(IBaseFilter * iface, IFilterGraph *pGraph, LPCWSTR pName)
608 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
610 TRACE("(%p/%p)->(%p, %s)\n", This, iface, pGraph, debugstr_w(pName));
612 EnterCriticalSection(&This->csFilter);
615 strcpyW(This->filterInfo.achName, pName);
617 *This->filterInfo.achName = '\0';
618 This->filterInfo.pGraph = pGraph; /* NOTE: do NOT increase ref. count */
620 LeaveCriticalSection(&This->csFilter);
625 static HRESULT WINAPI DSoundRender_QueryVendorInfo(IBaseFilter * iface, LPWSTR *pVendorInfo)
627 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
628 TRACE("(%p/%p)->(%p)\n", This, iface, pVendorInfo);
632 static const IBaseFilterVtbl DSoundRender_Vtbl =
634 DSoundRender_QueryInterface,
636 DSoundRender_Release,
637 DSoundRender_GetClassID,
641 DSoundRender_GetState,
642 DSoundRender_SetSyncSource,
643 DSoundRender_GetSyncSource,
644 DSoundRender_EnumPins,
645 DSoundRender_FindPin,
646 DSoundRender_QueryFilterInfo,
647 DSoundRender_JoinFilterGraph,
648 DSoundRender_QueryVendorInfo
651 static HRESULT WINAPI DSoundRender_InputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
653 InputPin *This = (InputPin *)iface;
654 PIN_DIRECTION pindirReceive;
655 DSoundRenderImpl *DSImpl;
658 TRACE("(%p)->(%p, %p)\n", This, pReceivePin, pmt);
659 dump_AM_MEDIA_TYPE(pmt);
661 EnterCriticalSection(This->pin.pCritSec);
663 DSImpl = (DSoundRenderImpl*)This->pin.pinInfo.pFilter;
665 if (This->pin.pConnectedTo)
666 hr = VFW_E_ALREADY_CONNECTED;
668 if (SUCCEEDED(hr) && This->pin.fnQueryAccept(This->pin.pUserData, pmt) != S_OK)
669 hr = VFW_E_TYPE_NOT_ACCEPTED;
673 IPin_QueryDirection(pReceivePin, &pindirReceive);
675 if (pindirReceive != PINDIR_OUTPUT)
677 ERR("Can't connect from non-output pin\n");
678 hr = VFW_E_INVALID_DIRECTION;
684 WAVEFORMATEX *format;
685 DSBUFFERDESC buf_desc;
687 TRACE("MajorType %s\n", debugstr_guid(&pmt->majortype));
688 TRACE("SubType %s\n", debugstr_guid(&pmt->subtype));
689 TRACE("Format %s\n", debugstr_guid(&pmt->formattype));
690 TRACE("Size %d\n", pmt->cbFormat);
692 format = (WAVEFORMATEX*)pmt->pbFormat;
694 DSImpl->buf_size = format->nAvgBytesPerSec;
696 memset(&buf_desc,0,sizeof(DSBUFFERDESC));
697 buf_desc.dwSize = sizeof(DSBUFFERDESC);
698 buf_desc.dwFlags = DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLPAN |
699 DSBCAPS_CTRLFREQUENCY |
700 DSBCAPS_GETCURRENTPOSITION2;
701 buf_desc.dwBufferBytes = DSImpl->buf_size;
702 buf_desc.lpwfxFormat = format;
703 hr = IDirectSound_CreateSoundBuffer(DSImpl->dsound, &buf_desc, &DSImpl->dsbuffer, NULL);
705 ERR("Can't create sound buffer (%x)\n", hr);
710 hr = IDirectSoundBuffer_SetVolume(DSImpl->dsbuffer, DSImpl->volume);
712 ERR("Can't set volume to %ld (%x)\n", DSImpl->volume, hr);
714 hr = IDirectSoundBuffer_SetPan(DSImpl->dsbuffer, DSImpl->pan);
716 ERR("Can't set pan to %ld (%x)\n", DSImpl->pan, hr);
718 DSImpl->write_pos = 0;
720 if (DSImpl->state == State_Running)
721 hr = IDirectSoundBuffer_Play(DSImpl->dsbuffer, 0, 0, DSBPLAY_LOOPING);
723 ERR("Can't play sound buffer (%x)\n", hr);
728 CopyMediaType(&This->pin.mtCurrent, pmt);
729 This->pin.pConnectedTo = pReceivePin;
730 IPin_AddRef(pReceivePin);
734 if (DSImpl->dsbuffer)
735 IDirectSoundBuffer_Release(DSImpl->dsbuffer);
736 DSImpl->dsbuffer = NULL;
739 LeaveCriticalSection(This->pin.pCritSec);
744 static HRESULT WINAPI DSoundRender_InputPin_Disconnect(IPin * iface)
746 IPinImpl *This = (IPinImpl*)iface;
747 DSoundRenderImpl *DSImpl;
749 TRACE("(%p)->()\n", iface);
751 DSImpl = (DSoundRenderImpl*)This->pinInfo.pFilter;
752 if (DSImpl->dsbuffer)
753 IDirectSoundBuffer_Release(DSImpl->dsbuffer);
754 DSImpl->dsbuffer = NULL;
756 return IPinImpl_Disconnect(iface);
759 static HRESULT WINAPI DSoundRender_InputPin_EndOfStream(IPin * iface)
761 InputPin* This = (InputPin*)iface;
762 IMediaEventSink* pEventSink;
765 TRACE("(%p/%p)->()\n", This, iface);
767 hr = IFilterGraph_QueryInterface(((DSoundRenderImpl*)This->pin.pinInfo.pFilter)->filterInfo.pGraph, &IID_IMediaEventSink, (LPVOID*)&pEventSink);
770 /* FIXME: We should wait that all audio data has been played */
771 hr = IMediaEventSink_Notify(pEventSink, EC_COMPLETE, S_OK, 0);
772 IMediaEventSink_Release(pEventSink);
778 static const IPinVtbl DSoundRender_InputPin_Vtbl =
780 InputPin_QueryInterface,
784 DSoundRender_InputPin_ReceiveConnection,
785 DSoundRender_InputPin_Disconnect,
786 IPinImpl_ConnectedTo,
787 IPinImpl_ConnectionMediaType,
788 IPinImpl_QueryPinInfo,
789 IPinImpl_QueryDirection,
791 IPinImpl_QueryAccept,
792 IPinImpl_EnumMediaTypes,
793 IPinImpl_QueryInternalConnections,
794 DSoundRender_InputPin_EndOfStream,
800 static const IMemInputPinVtbl MemInputPin_Vtbl =
802 MemInputPin_QueryInterface,
805 MemInputPin_GetAllocator,
806 MemInputPin_NotifyAllocator,
807 MemInputPin_GetAllocatorRequirements,
809 MemInputPin_ReceiveMultiple,
810 MemInputPin_ReceiveCanBlock
813 /*** IUnknown methods ***/
814 static HRESULT WINAPI Basicaudio_QueryInterface(IBasicAudio *iface,
817 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
819 TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
821 return DSoundRender_QueryInterface((IBaseFilter*)This, riid, ppvObj);
824 static ULONG WINAPI Basicaudio_AddRef(IBasicAudio *iface) {
825 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
827 TRACE("(%p/%p)->()\n", This, iface);
829 return DSoundRender_AddRef((IBaseFilter*)This);
832 static ULONG WINAPI Basicaudio_Release(IBasicAudio *iface) {
833 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
835 TRACE("(%p/%p)->()\n", This, iface);
837 return DSoundRender_Release((IBaseFilter*)This);
840 /*** IDispatch methods ***/
841 static HRESULT WINAPI Basicaudio_GetTypeInfoCount(IBasicAudio *iface,
843 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
845 TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pctinfo);
850 static HRESULT WINAPI Basicaudio_GetTypeInfo(IBasicAudio *iface,
853 ITypeInfo**ppTInfo) {
854 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
856 TRACE("(%p/%p)->(%d, %d, %p): stub !!!\n", This, iface, iTInfo, lcid, ppTInfo);
861 static HRESULT WINAPI Basicaudio_GetIDsOfNames(IBasicAudio *iface,
867 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
869 TRACE("(%p/%p)->(%s (%p), %p, %d, %d, %p): stub !!!\n", This, iface, debugstr_guid(riid), riid, rgszNames, cNames, lcid, rgDispId);
874 static HRESULT WINAPI Basicaudio_Invoke(IBasicAudio *iface,
879 DISPPARAMS*pDispParams,
883 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
885 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);
890 /*** IBasicAudio methods ***/
891 static HRESULT WINAPI Basicaudio_put_Volume(IBasicAudio *iface,
893 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
895 TRACE("(%p/%p)->(%ld)\n", This, iface, lVolume);
897 if (lVolume > DSBVOLUME_MAX || lVolume < DSBVOLUME_MIN)
900 if (This->dsbuffer) {
901 if (FAILED(IDirectSoundBuffer_SetVolume(This->dsbuffer, lVolume)))
905 This->volume = lVolume;
909 static HRESULT WINAPI Basicaudio_get_Volume(IBasicAudio *iface,
911 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
913 TRACE("(%p/%p)->(%p)\n", This, iface, plVolume);
918 *plVolume = This->volume;
922 static HRESULT WINAPI Basicaudio_put_Balance(IBasicAudio *iface,
924 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
926 TRACE("(%p/%p)->(%ld)\n", This, iface, lBalance);
928 if (lBalance < DSBPAN_LEFT || lBalance > DSBPAN_RIGHT)
931 if (This->dsbuffer) {
932 if (FAILED(IDirectSoundBuffer_SetPan(This->dsbuffer, lBalance)))
936 This->pan = lBalance;
940 static HRESULT WINAPI Basicaudio_get_Balance(IBasicAudio *iface,
942 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
944 TRACE("(%p/%p)->(%p)\n", This, iface, plBalance);
949 *plBalance = This->pan;
953 static const IBasicAudioVtbl IBasicAudio_Vtbl =
955 Basicaudio_QueryInterface,
958 Basicaudio_GetTypeInfoCount,
959 Basicaudio_GetTypeInfo,
960 Basicaudio_GetIDsOfNames,
962 Basicaudio_put_Volume,
963 Basicaudio_get_Volume,
964 Basicaudio_put_Balance,
965 Basicaudio_get_Balance
969 /*** IUnknown methods ***/
970 static HRESULT WINAPI ReferenceClock_QueryInterface(IReferenceClock *iface,
974 ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
976 TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
978 return DSoundRender_QueryInterface((IBaseFilter*)This, riid, ppvObj);
981 static ULONG WINAPI ReferenceClock_AddRef(IReferenceClock *iface)
983 ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
985 TRACE("(%p/%p)->()\n", This, iface);
987 return DSoundRender_AddRef((IBaseFilter*)This);
990 static ULONG WINAPI ReferenceClock_Release(IReferenceClock *iface)
992 ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
994 TRACE("(%p/%p)->()\n", This, iface);
996 return DSoundRender_Release((IBaseFilter*)This);
999 /*** IReferenceClock methods ***/
1000 static HRESULT WINAPI ReferenceClock_GetTime(IReferenceClock *iface,
1001 REFERENCE_TIME *pTime)
1003 ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1004 HRESULT hr = E_FAIL;
1007 TRACE("(%p/%p)->(%p)\n", This, iface, pTime);
1010 hr = DSoundRender_GetPos(This, &play_pos, NULL, pTime);
1012 ERR("Could not get refreence time (%x)!\n", hr);
1017 static HRESULT WINAPI ReferenceClock_AdviseTime(IReferenceClock *iface,
1018 REFERENCE_TIME rtBaseTime,
1019 REFERENCE_TIME rtStreamTime,
1021 DWORD_PTR *pdwAdviseCookie)
1023 ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1025 FIXME("(%p/%p)->(%s, %s, %p, %p): stub!\n", This, iface, wine_dbgstr_longlong(rtBaseTime), wine_dbgstr_longlong(rtStreamTime), (void*)hEvent, pdwAdviseCookie);
1030 static HRESULT WINAPI ReferenceClock_AdvisePeriodic(IReferenceClock *iface,
1031 REFERENCE_TIME rtBaseTime,
1032 REFERENCE_TIME rtStreamTime,
1033 HSEMAPHORE hSemaphore,
1034 DWORD_PTR *pdwAdviseCookie)
1036 ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1038 FIXME("(%p/%p)->(%s, %s, %p, %p): stub!\n", This, iface, wine_dbgstr_longlong(rtBaseTime), wine_dbgstr_longlong(rtStreamTime), (void*)hSemaphore, pdwAdviseCookie);
1043 static HRESULT WINAPI ReferenceClock_Unadvise(IReferenceClock *iface,
1044 DWORD_PTR dwAdviseCookie)
1046 ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1048 FIXME("(%p/%p)->(%p): stub!\n", This, iface, (void*)dwAdviseCookie);
1053 static const IReferenceClockVtbl IReferenceClock_Vtbl =
1055 ReferenceClock_QueryInterface,
1056 ReferenceClock_AddRef,
1057 ReferenceClock_Release,
1058 ReferenceClock_GetTime,
1059 ReferenceClock_AdviseTime,
1060 ReferenceClock_AdvisePeriodic,
1061 ReferenceClock_Unadvise