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);
105 CoTaskMemFree(pPinImpl);
110 static inline HRESULT DSoundRender_GetPos(DSoundRenderImpl *This, DWORD *pPlayPos, DWORD *pWritePos, REFERENCE_TIME *pRefTime)
114 EnterCriticalSection(&This->csFilter);
116 hr = IDirectSoundBuffer_GetCurrentPosition(This->dsbuffer, pPlayPos, pWritePos);
119 DWORD play_pos = *pPlayPos;
121 if (play_pos < This->last_play_pos)
123 This->last_play_pos = play_pos;
125 /* If we're really falling behind, kick the play time back */
126 if ((This->play_loops*This->buf_size)+play_pos >=
127 (This->write_loops*This->buf_size)+This->write_pos)
132 REFERENCE_TIME play_time;
133 play_time = ((REFERENCE_TIME)This->play_loops*10000000) +
134 ((REFERENCE_TIME)play_pos*10000000/This->buf_size);
136 /* Don't let time run backwards */
137 if(play_time-This->play_time > 0)
138 This->play_time = play_time;
142 *pRefTime = This->play_time;
146 LeaveCriticalSection(&This->csFilter);
151 static HRESULT DSoundRender_SendSampleData(DSoundRenderImpl* This, const BYTE *data, DWORD size)
154 LPBYTE lpbuf1 = NULL;
155 LPBYTE lpbuf2 = NULL;
159 DWORD play_pos,buf_free;
162 hr = DSoundRender_GetPos(This, &play_pos, NULL, NULL);
165 ERR("GetPos returned error: %x\n", hr);
168 if (This->write_pos <= play_pos)
169 buf_free = play_pos-This->write_pos;
171 buf_free = This->buf_size - This->write_pos + play_pos;
173 /* Wait for enough of the buffer to empty before filling it */
174 if(buf_free < This->buf_size/4)
180 size2 = min(buf_free, size);
181 hr = IDirectSoundBuffer_Lock(This->dsbuffer, This->write_pos, size2, (LPVOID *)&lpbuf1, &dwsize1, (LPVOID *)&lpbuf2, &dwsize2, 0);
183 ERR("Unable to lock sound buffer! (%x)\n", hr);
186 /* TRACE("write_pos=%d, size=%d, sz1=%d, sz2=%d\n", This->write_pos, size2, dwsize1, dwsize2); */
188 memcpy(lpbuf1, data, dwsize1);
190 memcpy(lpbuf2, data + dwsize1, dwsize2);
192 hr = IDirectSoundBuffer_Unlock(This->dsbuffer, lpbuf1, dwsize1, lpbuf2, dwsize2);
194 ERR("Unable to unlock sound buffer! (%x)\n", hr);
196 size -= dwsize1 + dwsize2;
197 data += dwsize1 + dwsize2;
198 This->write_pos += dwsize1 + dwsize2;
199 if (This->write_pos >= This->buf_size)
201 This->write_pos -= This->buf_size;
204 } while (size && This->state == State_Running);
209 static HRESULT DSoundRender_Sample(LPVOID iface, IMediaSample * pSample)
211 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
212 LPBYTE pbSrcStream = NULL;
213 long cbSrcStream = 0;
214 REFERENCE_TIME tStart, tStop;
217 TRACE("%p %p\n", iface, pSample);
219 if (This->state != State_Running)
220 return VFW_E_WRONG_STATE;
222 hr = IMediaSample_GetPointer(pSample, &pbSrcStream);
225 ERR("Cannot get pointer to sample data (%x)\n", hr);
229 hr = IMediaSample_GetTime(pSample, &tStart, &tStop);
231 ERR("Cannot get sample time (%x)\n", hr);
233 cbSrcStream = IMediaSample_GetActualDataLength(pSample);
235 TRACE("Sample data ptr = %p, size = %ld\n", pbSrcStream, cbSrcStream);
237 #if 0 /* For debugging purpose */
240 for(i = 0; i < cbSrcStream; i++)
242 if ((i!=0) && !(i%16))
244 TRACE("%02x ", pbSrcStream[i]);
250 return DSoundRender_SendSampleData(This, pbSrcStream, cbSrcStream);
253 static HRESULT DSoundRender_QueryAccept(LPVOID iface, const AM_MEDIA_TYPE * pmt)
255 WAVEFORMATEX* format = (WAVEFORMATEX*)pmt->pbFormat;
256 TRACE("wFormatTag = %x %x\n", format->wFormatTag, WAVE_FORMAT_PCM);
257 TRACE("nChannels = %d\n", format->nChannels);
258 TRACE("nSamplesPerSec = %d\n", format->nAvgBytesPerSec);
259 TRACE("nAvgBytesPerSec = %d\n", format->nAvgBytesPerSec);
260 TRACE("nBlockAlign = %d\n", format->nBlockAlign);
261 TRACE("wBitsPerSample = %d\n", format->wBitsPerSample);
263 if (IsEqualIID(&pmt->majortype, &MEDIATYPE_Audio) && IsEqualIID(&pmt->subtype, &MEDIASUBTYPE_PCM))
268 HRESULT DSoundRender_create(IUnknown * pUnkOuter, LPVOID * ppv)
272 DSoundRenderImpl * pDSoundRender;
274 TRACE("(%p, %p)\n", pUnkOuter, ppv);
279 return CLASS_E_NOAGGREGATION;
281 pDSoundRender = CoTaskMemAlloc(sizeof(DSoundRenderImpl));
283 return E_OUTOFMEMORY;
284 ZeroMemory(pDSoundRender, sizeof(DSoundRenderImpl));
286 pDSoundRender->lpVtbl = &DSoundRender_Vtbl;
287 pDSoundRender->IBasicAudio_vtbl = &IBasicAudio_Vtbl;
288 pDSoundRender->IReferenceClock_vtbl = &IReferenceClock_Vtbl;
289 pDSoundRender->refCount = 1;
290 InitializeCriticalSection(&pDSoundRender->csFilter);
291 pDSoundRender->csFilter.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": DSoundRenderImpl.csFilter");
292 pDSoundRender->state = State_Stopped;
294 pDSoundRender->ppPins = CoTaskMemAlloc(1 * sizeof(IPin *));
295 if (!pDSoundRender->ppPins)
297 pDSoundRender->csFilter.DebugInfo->Spare[0] = 0;
298 DeleteCriticalSection(&pDSoundRender->csFilter);
299 CoTaskMemFree(pDSoundRender);
300 return E_OUTOFMEMORY;
303 /* construct input pin */
304 piInput.dir = PINDIR_INPUT;
305 piInput.pFilter = (IBaseFilter *)pDSoundRender;
306 lstrcpynW(piInput.achName, wcsInputPinName, sizeof(piInput.achName) / sizeof(piInput.achName[0]));
307 hr = DSoundRender_InputPin_Construct(&piInput, DSoundRender_Sample, (LPVOID)pDSoundRender, DSoundRender_QueryAccept, &pDSoundRender->csFilter, (IPin **)&pDSoundRender->pInputPin);
311 hr = DirectSoundCreate(NULL, &pDSoundRender->dsound, NULL);
313 ERR("Cannot create Direct Sound object (%x)\n", hr);
318 pDSoundRender->ppPins[0] = (IPin *)pDSoundRender->pInputPin;
319 *ppv = (LPVOID)pDSoundRender;
323 if (pDSoundRender->pInputPin)
324 IPin_Release((IPin*)pDSoundRender->pInputPin);
325 CoTaskMemFree(pDSoundRender->ppPins);
326 pDSoundRender->csFilter.DebugInfo->Spare[0] = 0;
327 DeleteCriticalSection(&pDSoundRender->csFilter);
328 CoTaskMemFree(pDSoundRender);
334 static HRESULT WINAPI DSoundRender_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv)
336 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
337 TRACE("(%p, %p)->(%s, %p)\n", This, iface, qzdebugstr_guid(riid), ppv);
341 if (IsEqualIID(riid, &IID_IUnknown))
343 else if (IsEqualIID(riid, &IID_IPersist))
345 else if (IsEqualIID(riid, &IID_IMediaFilter))
347 else if (IsEqualIID(riid, &IID_IBaseFilter))
349 else if (IsEqualIID(riid, &IID_IBasicAudio))
350 *ppv = (LPVOID)&(This->IBasicAudio_vtbl);
351 else if (IsEqualIID(riid, &IID_IReferenceClock))
352 *ppv = (LPVOID)&(This->IReferenceClock_vtbl);
356 IUnknown_AddRef((IUnknown *)(*ppv));
360 FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
362 return E_NOINTERFACE;
365 static ULONG WINAPI DSoundRender_AddRef(IBaseFilter * iface)
367 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
368 ULONG refCount = InterlockedIncrement(&This->refCount);
370 TRACE("(%p/%p)->() AddRef from %d\n", This, iface, refCount - 1);
375 static ULONG WINAPI DSoundRender_Release(IBaseFilter * iface)
377 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
378 ULONG refCount = InterlockedDecrement(&This->refCount);
380 TRACE("(%p)->() Release from %d\n", This, refCount + 1);
387 IReferenceClock_Release(This->pClock);
390 IDirectSoundBuffer_Release(This->dsbuffer);
391 This->dsbuffer = NULL;
393 IDirectSound_Release(This->dsound);
396 if (SUCCEEDED(IPin_ConnectedTo(This->ppPins[0], &pConnectedTo)))
398 IPin_Disconnect(pConnectedTo);
399 IPin_Release(pConnectedTo);
401 IPin_Disconnect(This->ppPins[0]);
403 IPin_Release(This->ppPins[0]);
405 CoTaskMemFree(This->ppPins);
407 This->IBasicAudio_vtbl = NULL;
409 This->csFilter.DebugInfo->Spare[0] = 0;
410 DeleteCriticalSection(&This->csFilter);
412 TRACE("Destroying Audio Renderer\n");
421 /** IPersist methods **/
423 static HRESULT WINAPI DSoundRender_GetClassID(IBaseFilter * iface, CLSID * pClsid)
425 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
426 TRACE("(%p/%p)->(%p)\n", This, iface, pClsid);
428 *pClsid = CLSID_DSoundRender;
433 /** IMediaFilter methods **/
435 static HRESULT WINAPI DSoundRender_Stop(IBaseFilter * iface)
438 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
440 TRACE("(%p/%p)->()\n", This, iface);
442 EnterCriticalSection(&This->csFilter);
447 hr = IDirectSoundBuffer_GetStatus(This->dsbuffer, &state);
450 if (state & DSBSTATUS_PLAYING)
451 hr = IDirectSoundBuffer_Stop(This->dsbuffer);
455 This->state = State_Stopped;
457 LeaveCriticalSection(&This->csFilter);
462 static HRESULT WINAPI DSoundRender_Pause(IBaseFilter * iface)
465 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
467 TRACE("(%p/%p)->()\n", This, iface);
469 EnterCriticalSection(&This->csFilter);
474 hr = IDirectSoundBuffer_GetStatus(This->dsbuffer, &state);
477 if (state & DSBSTATUS_PLAYING)
478 hr = IDirectSoundBuffer_Stop(This->dsbuffer);
482 This->state = State_Paused;
484 LeaveCriticalSection(&This->csFilter);
489 static HRESULT WINAPI DSoundRender_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
492 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
494 TRACE("(%p/%p)->(%s)\n", This, iface, wine_dbgstr_longlong(tStart));
496 EnterCriticalSection(&This->csFilter);
498 /* It's okay if there's no buffer yet. It'll start when it's created */
501 hr = IDirectSoundBuffer_Play(This->dsbuffer, 0, 0, DSBPLAY_LOOPING);
503 ERR("Can't start playing! (%x)\n", hr);
507 This->rtStreamStart = tStart;
508 This->state = State_Running;
511 LeaveCriticalSection(&This->csFilter);
516 static HRESULT WINAPI DSoundRender_GetState(IBaseFilter * iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState)
518 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
520 TRACE("(%p/%p)->(%d, %p)\n", This, iface, dwMilliSecsTimeout, pState);
522 EnterCriticalSection(&This->csFilter);
524 *pState = This->state;
526 LeaveCriticalSection(&This->csFilter);
531 static HRESULT WINAPI DSoundRender_SetSyncSource(IBaseFilter * iface, IReferenceClock *pClock)
533 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
535 TRACE("(%p/%p)->(%p)\n", This, iface, pClock);
537 EnterCriticalSection(&This->csFilter);
540 IReferenceClock_Release(This->pClock);
541 This->pClock = pClock;
543 IReferenceClock_AddRef(This->pClock);
545 LeaveCriticalSection(&This->csFilter);
550 static HRESULT WINAPI DSoundRender_GetSyncSource(IBaseFilter * iface, IReferenceClock **ppClock)
552 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
554 TRACE("(%p/%p)->(%p)\n", This, iface, ppClock);
556 EnterCriticalSection(&This->csFilter);
558 *ppClock = This->pClock;
559 IReferenceClock_AddRef(This->pClock);
561 LeaveCriticalSection(&This->csFilter);
566 /** IBaseFilter implementation **/
568 static HRESULT WINAPI DSoundRender_EnumPins(IBaseFilter * iface, IEnumPins **ppEnum)
571 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
573 TRACE("(%p/%p)->(%p)\n", This, iface, ppEnum);
575 epd.cPins = 1; /* input pin */
576 epd.ppPins = This->ppPins;
577 return IEnumPinsImpl_Construct(&epd, ppEnum);
580 static HRESULT WINAPI DSoundRender_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin)
582 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
584 TRACE("(%p/%p)->(%s,%p)\n", This, iface, debugstr_w(Id), ppPin);
586 FIXME("DSoundRender::FindPin(...)\n");
588 /* FIXME: critical section */
593 static HRESULT WINAPI DSoundRender_QueryFilterInfo(IBaseFilter * iface, FILTER_INFO *pInfo)
595 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
597 TRACE("(%p/%p)->(%p)\n", This, iface, pInfo);
599 strcpyW(pInfo->achName, This->filterInfo.achName);
600 pInfo->pGraph = This->filterInfo.pGraph;
603 IFilterGraph_AddRef(pInfo->pGraph);
608 static HRESULT WINAPI DSoundRender_JoinFilterGraph(IBaseFilter * iface, IFilterGraph *pGraph, LPCWSTR pName)
610 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
612 TRACE("(%p/%p)->(%p, %s)\n", This, iface, pGraph, debugstr_w(pName));
614 EnterCriticalSection(&This->csFilter);
617 strcpyW(This->filterInfo.achName, pName);
619 *This->filterInfo.achName = '\0';
620 This->filterInfo.pGraph = pGraph; /* NOTE: do NOT increase ref. count */
622 LeaveCriticalSection(&This->csFilter);
627 static HRESULT WINAPI DSoundRender_QueryVendorInfo(IBaseFilter * iface, LPWSTR *pVendorInfo)
629 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
630 TRACE("(%p/%p)->(%p)\n", This, iface, pVendorInfo);
634 static const IBaseFilterVtbl DSoundRender_Vtbl =
636 DSoundRender_QueryInterface,
638 DSoundRender_Release,
639 DSoundRender_GetClassID,
643 DSoundRender_GetState,
644 DSoundRender_SetSyncSource,
645 DSoundRender_GetSyncSource,
646 DSoundRender_EnumPins,
647 DSoundRender_FindPin,
648 DSoundRender_QueryFilterInfo,
649 DSoundRender_JoinFilterGraph,
650 DSoundRender_QueryVendorInfo
653 static HRESULT WINAPI DSoundRender_InputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
655 InputPin *This = (InputPin *)iface;
656 PIN_DIRECTION pindirReceive;
657 DSoundRenderImpl *DSImpl;
660 TRACE("(%p)->(%p, %p)\n", This, pReceivePin, pmt);
661 dump_AM_MEDIA_TYPE(pmt);
663 EnterCriticalSection(This->pin.pCritSec);
665 DSImpl = (DSoundRenderImpl*)This->pin.pinInfo.pFilter;
667 if (This->pin.pConnectedTo)
668 hr = VFW_E_ALREADY_CONNECTED;
670 if (SUCCEEDED(hr) && This->pin.fnQueryAccept(This->pin.pUserData, pmt) != S_OK)
671 hr = VFW_E_TYPE_NOT_ACCEPTED;
675 IPin_QueryDirection(pReceivePin, &pindirReceive);
677 if (pindirReceive != PINDIR_OUTPUT)
679 ERR("Can't connect from non-output pin\n");
680 hr = VFW_E_INVALID_DIRECTION;
686 WAVEFORMATEX *format;
687 DSBUFFERDESC buf_desc;
689 TRACE("MajorType %s\n", debugstr_guid(&pmt->majortype));
690 TRACE("SubType %s\n", debugstr_guid(&pmt->subtype));
691 TRACE("Format %s\n", debugstr_guid(&pmt->formattype));
692 TRACE("Size %d\n", pmt->cbFormat);
694 format = (WAVEFORMATEX*)pmt->pbFormat;
696 DSImpl->buf_size = format->nAvgBytesPerSec;
698 memset(&buf_desc,0,sizeof(DSBUFFERDESC));
699 buf_desc.dwSize = sizeof(DSBUFFERDESC);
700 buf_desc.dwFlags = DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLPAN |
701 DSBCAPS_CTRLFREQUENCY |
702 DSBCAPS_GETCURRENTPOSITION2;
703 buf_desc.dwBufferBytes = DSImpl->buf_size;
704 buf_desc.lpwfxFormat = format;
705 hr = IDirectSound_CreateSoundBuffer(DSImpl->dsound, &buf_desc, &DSImpl->dsbuffer, NULL);
707 ERR("Can't create sound buffer (%x)\n", hr);
712 hr = IDirectSoundBuffer_SetVolume(DSImpl->dsbuffer, DSImpl->volume);
714 ERR("Can't set volume to %ld (%x)\n", DSImpl->volume, hr);
716 hr = IDirectSoundBuffer_SetPan(DSImpl->dsbuffer, DSImpl->pan);
718 ERR("Can't set pan to %ld (%x)\n", DSImpl->pan, hr);
720 DSImpl->write_pos = 0;
722 if (DSImpl->state == State_Running)
723 hr = IDirectSoundBuffer_Play(DSImpl->dsbuffer, 0, 0, DSBPLAY_LOOPING);
725 ERR("Can't play sound buffer (%x)\n", hr);
730 CopyMediaType(&This->pin.mtCurrent, pmt);
731 This->pin.pConnectedTo = pReceivePin;
732 IPin_AddRef(pReceivePin);
736 if (DSImpl->dsbuffer)
737 IDirectSoundBuffer_Release(DSImpl->dsbuffer);
738 DSImpl->dsbuffer = NULL;
741 LeaveCriticalSection(This->pin.pCritSec);
746 static HRESULT WINAPI DSoundRender_InputPin_Disconnect(IPin * iface)
748 IPinImpl *This = (IPinImpl*)iface;
749 DSoundRenderImpl *DSImpl;
751 TRACE("(%p)->()\n", iface);
753 DSImpl = (DSoundRenderImpl*)This->pinInfo.pFilter;
754 if (DSImpl->dsbuffer)
755 IDirectSoundBuffer_Release(DSImpl->dsbuffer);
756 DSImpl->dsbuffer = NULL;
758 return IPinImpl_Disconnect(iface);
761 static HRESULT WINAPI DSoundRender_InputPin_EndOfStream(IPin * iface)
763 InputPin* This = (InputPin*)iface;
764 IMediaEventSink* pEventSink;
767 TRACE("(%p/%p)->()\n", This, iface);
769 hr = IFilterGraph_QueryInterface(((DSoundRenderImpl*)This->pin.pinInfo.pFilter)->filterInfo.pGraph, &IID_IMediaEventSink, (LPVOID*)&pEventSink);
772 /* FIXME: We should wait that all audio data has been played */
773 hr = IMediaEventSink_Notify(pEventSink, EC_COMPLETE, S_OK, 0);
774 IMediaEventSink_Release(pEventSink);
780 static const IPinVtbl DSoundRender_InputPin_Vtbl =
782 InputPin_QueryInterface,
786 DSoundRender_InputPin_ReceiveConnection,
787 DSoundRender_InputPin_Disconnect,
788 IPinImpl_ConnectedTo,
789 IPinImpl_ConnectionMediaType,
790 IPinImpl_QueryPinInfo,
791 IPinImpl_QueryDirection,
793 IPinImpl_QueryAccept,
794 IPinImpl_EnumMediaTypes,
795 IPinImpl_QueryInternalConnections,
796 DSoundRender_InputPin_EndOfStream,
802 static const IMemInputPinVtbl MemInputPin_Vtbl =
804 MemInputPin_QueryInterface,
807 MemInputPin_GetAllocator,
808 MemInputPin_NotifyAllocator,
809 MemInputPin_GetAllocatorRequirements,
811 MemInputPin_ReceiveMultiple,
812 MemInputPin_ReceiveCanBlock
815 /*** IUnknown methods ***/
816 static HRESULT WINAPI Basicaudio_QueryInterface(IBasicAudio *iface,
819 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
821 TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
823 return DSoundRender_QueryInterface((IBaseFilter*)This, riid, ppvObj);
826 static ULONG WINAPI Basicaudio_AddRef(IBasicAudio *iface) {
827 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
829 TRACE("(%p/%p)->()\n", This, iface);
831 return DSoundRender_AddRef((IBaseFilter*)This);
834 static ULONG WINAPI Basicaudio_Release(IBasicAudio *iface) {
835 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
837 TRACE("(%p/%p)->()\n", This, iface);
839 return DSoundRender_Release((IBaseFilter*)This);
842 /*** IDispatch methods ***/
843 static HRESULT WINAPI Basicaudio_GetTypeInfoCount(IBasicAudio *iface,
845 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
847 TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pctinfo);
852 static HRESULT WINAPI Basicaudio_GetTypeInfo(IBasicAudio *iface,
855 ITypeInfo**ppTInfo) {
856 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
858 TRACE("(%p/%p)->(%d, %d, %p): stub !!!\n", This, iface, iTInfo, lcid, ppTInfo);
863 static HRESULT WINAPI Basicaudio_GetIDsOfNames(IBasicAudio *iface,
869 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
871 TRACE("(%p/%p)->(%s (%p), %p, %d, %d, %p): stub !!!\n", This, iface, debugstr_guid(riid), riid, rgszNames, cNames, lcid, rgDispId);
876 static HRESULT WINAPI Basicaudio_Invoke(IBasicAudio *iface,
881 DISPPARAMS*pDispParams,
885 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
887 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);
892 /*** IBasicAudio methods ***/
893 static HRESULT WINAPI Basicaudio_put_Volume(IBasicAudio *iface,
895 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
897 TRACE("(%p/%p)->(%ld)\n", This, iface, lVolume);
899 if (lVolume > DSBVOLUME_MAX || lVolume < DSBVOLUME_MIN)
902 if (This->dsbuffer) {
903 if (FAILED(IDirectSoundBuffer_SetVolume(This->dsbuffer, lVolume)))
907 This->volume = lVolume;
911 static HRESULT WINAPI Basicaudio_get_Volume(IBasicAudio *iface,
913 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
915 TRACE("(%p/%p)->(%p)\n", This, iface, plVolume);
920 *plVolume = This->volume;
924 static HRESULT WINAPI Basicaudio_put_Balance(IBasicAudio *iface,
926 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
928 TRACE("(%p/%p)->(%ld)\n", This, iface, lBalance);
930 if (lBalance < DSBPAN_LEFT || lBalance > DSBPAN_RIGHT)
933 if (This->dsbuffer) {
934 if (FAILED(IDirectSoundBuffer_SetPan(This->dsbuffer, lBalance)))
938 This->pan = lBalance;
942 static HRESULT WINAPI Basicaudio_get_Balance(IBasicAudio *iface,
944 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
946 TRACE("(%p/%p)->(%p)\n", This, iface, plBalance);
951 *plBalance = This->pan;
955 static const IBasicAudioVtbl IBasicAudio_Vtbl =
957 Basicaudio_QueryInterface,
960 Basicaudio_GetTypeInfoCount,
961 Basicaudio_GetTypeInfo,
962 Basicaudio_GetIDsOfNames,
964 Basicaudio_put_Volume,
965 Basicaudio_get_Volume,
966 Basicaudio_put_Balance,
967 Basicaudio_get_Balance
971 /*** IUnknown methods ***/
972 static HRESULT WINAPI ReferenceClock_QueryInterface(IReferenceClock *iface,
976 ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
978 TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
980 return DSoundRender_QueryInterface((IBaseFilter*)This, riid, ppvObj);
983 static ULONG WINAPI ReferenceClock_AddRef(IReferenceClock *iface)
985 ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
987 TRACE("(%p/%p)->()\n", This, iface);
989 return DSoundRender_AddRef((IBaseFilter*)This);
992 static ULONG WINAPI ReferenceClock_Release(IReferenceClock *iface)
994 ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
996 TRACE("(%p/%p)->()\n", This, iface);
998 return DSoundRender_Release((IBaseFilter*)This);
1001 /*** IReferenceClock methods ***/
1002 static HRESULT WINAPI ReferenceClock_GetTime(IReferenceClock *iface,
1003 REFERENCE_TIME *pTime)
1005 ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1006 HRESULT hr = E_FAIL;
1009 TRACE("(%p/%p)->(%p)\n", This, iface, pTime);
1012 hr = DSoundRender_GetPos(This, &play_pos, NULL, pTime);
1014 ERR("Could not get refreence time (%x)!\n", hr);
1019 static HRESULT WINAPI ReferenceClock_AdviseTime(IReferenceClock *iface,
1020 REFERENCE_TIME rtBaseTime,
1021 REFERENCE_TIME rtStreamTime,
1023 DWORD_PTR *pdwAdviseCookie)
1025 ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1027 FIXME("(%p/%p)->(%s, %s, %p, %p): stub!\n", This, iface, wine_dbgstr_longlong(rtBaseTime), wine_dbgstr_longlong(rtStreamTime), (void*)hEvent, pdwAdviseCookie);
1032 static HRESULT WINAPI ReferenceClock_AdvisePeriodic(IReferenceClock *iface,
1033 REFERENCE_TIME rtBaseTime,
1034 REFERENCE_TIME rtStreamTime,
1035 HSEMAPHORE hSemaphore,
1036 DWORD_PTR *pdwAdviseCookie)
1038 ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1040 FIXME("(%p/%p)->(%s, %s, %p, %p): stub!\n", This, iface, wine_dbgstr_longlong(rtBaseTime), wine_dbgstr_longlong(rtStreamTime), (void*)hSemaphore, pdwAdviseCookie);
1045 static HRESULT WINAPI ReferenceClock_Unadvise(IReferenceClock *iface,
1046 DWORD_PTR dwAdviseCookie)
1048 ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1050 FIXME("(%p/%p)->(%p): stub!\n", This, iface, (void*)dwAdviseCookie);
1055 static const IReferenceClockVtbl IReferenceClock_Vtbl =
1057 ReferenceClock_QueryInterface,
1058 ReferenceClock_AddRef,
1059 ReferenceClock_Release,
1060 ReferenceClock_GetTime,
1061 ReferenceClock_AdviseTime,
1062 ReferenceClock_AdvisePeriodic,
1063 ReferenceClock_Unadvise