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
53 const IBaseFilterVtbl * lpVtbl;
54 const IBasicAudioVtbl *IBasicAudio_vtbl;
55 const IReferenceClockVtbl *IReferenceClock_vtbl;
56 const IAMDirectSoundVtbl *IAMDirectSound_vtbl;
59 CRITICAL_SECTION csFilter;
61 REFERENCE_TIME rtStreamStart, rtLastStop;
62 IReferenceClock * pClock;
63 FILTER_INFO filterInfo;
67 IDirectSound8 *dsound;
68 LPDIRECTSOUNDBUFFER dsbuffer;
76 REFERENCE_TIME play_time;
77 MediaSeekingImpl mediaSeeking;
79 HANDLE state_change, blocked;
85 /* Seeking is not needed for a renderer, rely on newsegment for the appropriate changes */
86 static HRESULT sound_mod_stop(IBaseFilter *iface)
88 TRACE("(%p)\n", iface);
92 static HRESULT sound_mod_start(IBaseFilter *iface)
94 TRACE("(%p)\n", iface);
99 static HRESULT sound_mod_rate(IBaseFilter *iface)
101 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
103 WAVEFORMATEX *format = (WAVEFORMATEX*)This->pInputPin->pin.mtCurrent.pbFormat;
104 DWORD freq = format->nSamplesPerSec;
105 double rate = This->mediaSeeking.dRate;
107 freq = (DWORD)((double)freq * rate);
109 TRACE("(%p)\n", iface);
111 if (freq > DSBFREQUENCY_MAX)
112 return VFW_E_UNSUPPORTED_AUDIO;
114 if (freq < DSBFREQUENCY_MIN)
115 return VFW_E_UNSUPPORTED_AUDIO;
120 static inline HRESULT DSoundRender_GetPos(DSoundRenderImpl *This, DWORD *pPlayPos, REFERENCE_TIME *pRefTime)
124 EnterCriticalSection(&This->csFilter);
129 hr = IDirectSoundBuffer_GetStatus(This->dsbuffer, &state);
130 if (SUCCEEDED(hr) && !(state & DSBSTATUS_PLAYING) && This->state == State_Running)
132 TRACE("Not playing, kickstarting the engine\n");
134 hr = IDirectSoundBuffer_Play(This->dsbuffer, 0, 0, DSBPLAY_LOOPING);
136 ERR("Can't play sound buffer (%x)\n", hr);
140 hr = IDirectSoundBuffer_GetCurrentPosition(This->dsbuffer, pPlayPos, &write_pos);
143 DWORD play_pos = *pPlayPos;
145 if (play_pos < This->last_play_pos)
147 This->last_play_pos = play_pos;
149 /* If we really fell behind, start at the next possible position
150 * Also happens when just starting playback for the first time,
153 if ((This->play_loops*This->buf_size)+play_pos >=
154 (This->write_loops*This->buf_size)+This->write_pos)
155 This->write_pos = write_pos;
159 REFERENCE_TIME play_time;
160 play_time = ((REFERENCE_TIME)This->play_loops*10000000) +
161 ((REFERENCE_TIME)play_pos*10000000/This->buf_size);
163 /* Don't let time run backwards */
164 if(play_time-This->play_time > 0)
165 This->play_time = play_time;
169 *pRefTime = This->play_time;
173 LeaveCriticalSection(&This->csFilter);
178 static HRESULT DSoundRender_SendSampleData(DSoundRenderImpl* This, const BYTE *data, DWORD size)
181 LPBYTE lpbuf1 = NULL;
182 LPBYTE lpbuf2 = NULL;
186 DWORD play_pos,buf_free;
190 hr = DSoundRender_GetPos(This, &play_pos, NULL);
193 ERR("GetPos returned error: %x\n", hr);
196 if (This->write_pos <= play_pos)
197 buf_free = play_pos-This->write_pos;
199 buf_free = This->buf_size - This->write_pos + play_pos;
201 /* Wait for enough of the buffer to empty before filling it */
202 if(buf_free < This->buf_size/4)
208 size2 = min(buf_free, size);
209 hr = IDirectSoundBuffer_Lock(This->dsbuffer, This->write_pos, size2, (LPVOID *)&lpbuf1, &dwsize1, (LPVOID *)&lpbuf2, &dwsize2, 0);
211 ERR("Unable to lock sound buffer! (%x)\n", hr);
214 /* TRACE("write_pos=%d, size=%d, sz1=%d, sz2=%d\n", This->write_pos, size2, dwsize1, dwsize2); */
216 memcpy(lpbuf1, data, dwsize1);
218 memcpy(lpbuf2, data + dwsize1, dwsize2);
220 hr = IDirectSoundBuffer_Unlock(This->dsbuffer, lpbuf1, dwsize1, lpbuf2, dwsize2);
222 ERR("Unable to unlock sound buffer! (%x)\n", hr);
224 size -= dwsize1 + dwsize2;
225 data += dwsize1 + dwsize2;
226 This->write_pos += dwsize1 + dwsize2;
227 if (This->write_pos >= This->buf_size)
229 This->write_pos -= This->buf_size;
232 } while (size && This->state == State_Running);
237 static HRESULT DSoundRender_Sample(LPVOID iface, IMediaSample * pSample)
239 DSoundRenderImpl *This = iface;
240 LPBYTE pbSrcStream = NULL;
241 long cbSrcStream = 0;
242 REFERENCE_TIME tStart, tStop;
246 TRACE("%p %p\n", iface, pSample);
248 /* Slightly incorrect, Pause completes when a frame is received so we should signal
249 * pause completion here, but for sound playing a single frame doesn't make sense
252 EnterCriticalSection(&This->csFilter);
254 if (This->pInputPin->end_of_stream || This->pInputPin->flushing)
256 LeaveCriticalSection(&This->csFilter);
260 if (This->state == State_Stopped)
262 LeaveCriticalSection(&This->csFilter);
263 return VFW_E_WRONG_STATE;
266 if (IMediaSample_GetMediaType(pSample, &amt) == S_OK)
268 AM_MEDIA_TYPE *orig = &This->pInputPin->pin.mtCurrent;
269 WAVEFORMATEX *origfmt = (WAVEFORMATEX *)orig->pbFormat;
270 WAVEFORMATEX *newfmt = (WAVEFORMATEX *)amt->pbFormat;
272 if (origfmt->wFormatTag == newfmt->wFormatTag &&
273 origfmt->nChannels == newfmt->nChannels &&
274 origfmt->nBlockAlign == newfmt->nBlockAlign &&
275 origfmt->wBitsPerSample == newfmt->wBitsPerSample &&
276 origfmt->cbSize == newfmt->cbSize)
278 if (origfmt->nSamplesPerSec != newfmt->nSamplesPerSec)
280 hr = IDirectSoundBuffer_SetFrequency(This->dsbuffer,
281 newfmt->nSamplesPerSec);
284 LeaveCriticalSection(&This->csFilter);
285 return VFW_E_TYPE_NOT_ACCEPTED;
288 CopyMediaType(orig, amt);
289 IMediaSample_SetMediaType(pSample, NULL);
294 LeaveCriticalSection(&This->csFilter);
295 return VFW_E_TYPE_NOT_ACCEPTED;
299 SetEvent(This->state_change);
301 hr = IMediaSample_GetPointer(pSample, &pbSrcStream);
304 ERR("Cannot get pointer to sample data (%x)\n", hr);
305 LeaveCriticalSection(&This->csFilter);
309 hr = IMediaSample_GetTime(pSample, &tStart, &tStop);
311 ERR("Cannot get sample time (%x)\n", hr);
313 if (This->rtLastStop != tStart && (IMediaSample_IsDiscontinuity(pSample) == S_FALSE))
314 WARN("Unexpected discontinuity: Last: %u.%03u, tStart: %u.%03u\n",
315 (DWORD)(This->rtLastStop / 10000000), (DWORD)((This->rtLastStop / 10000)%1000),
316 (DWORD)(tStart / 10000000), (DWORD)((tStart / 10000)%1000));
317 This->rtLastStop = tStop;
319 if (IMediaSample_IsPreroll(pSample) == S_OK)
322 LeaveCriticalSection(&This->csFilter);
326 if (This->state == State_Paused)
328 LeaveCriticalSection(&This->csFilter);
329 WaitForSingleObject(This->blocked, INFINITE);
330 EnterCriticalSection(&This->csFilter);
331 if (This->state == State_Stopped)
333 LeaveCriticalSection(&This->csFilter);
334 return VFW_E_WRONG_STATE;
337 if (This->state == State_Paused)
339 /* Assuming we return because of flushing */
341 LeaveCriticalSection(&This->csFilter);
346 cbSrcStream = IMediaSample_GetActualDataLength(pSample);
347 TRACE("Sample data ptr = %p, size = %ld\n", pbSrcStream, cbSrcStream);
349 #if 0 /* For debugging purpose */
352 for(i = 0; i < cbSrcStream; i++)
354 if ((i!=0) && !(i%16))
356 TRACE("%02x ", pbSrcStream[i]);
362 hr = DSoundRender_SendSampleData(This, pbSrcStream, cbSrcStream);
363 LeaveCriticalSection(&This->csFilter);
367 static HRESULT DSoundRender_QueryAccept(LPVOID iface, const AM_MEDIA_TYPE * pmt)
369 WAVEFORMATEX* format;
371 if (!IsEqualIID(&pmt->majortype, &MEDIATYPE_Audio))
374 format = (WAVEFORMATEX*)pmt->pbFormat;
375 TRACE("Format = %p\n", format);
376 TRACE("wFormatTag = %x %x\n", format->wFormatTag, WAVE_FORMAT_PCM);
377 TRACE("nChannels = %d\n", format->nChannels);
378 TRACE("nSamplesPerSec = %d\n", format->nAvgBytesPerSec);
379 TRACE("nAvgBytesPerSec = %d\n", format->nAvgBytesPerSec);
380 TRACE("nBlockAlign = %d\n", format->nBlockAlign);
381 TRACE("wBitsPerSample = %d\n", format->wBitsPerSample);
383 if (!IsEqualIID(&pmt->subtype, &MEDIASUBTYPE_PCM))
389 HRESULT DSoundRender_create(IUnknown * pUnkOuter, LPVOID * ppv)
393 DSoundRenderImpl * pDSoundRender;
395 TRACE("(%p, %p)\n", pUnkOuter, ppv);
400 return CLASS_E_NOAGGREGATION;
402 pDSoundRender = CoTaskMemAlloc(sizeof(DSoundRenderImpl));
404 return E_OUTOFMEMORY;
405 ZeroMemory(pDSoundRender, sizeof(DSoundRenderImpl));
407 pDSoundRender->lpVtbl = &DSoundRender_Vtbl;
408 pDSoundRender->IBasicAudio_vtbl = &IBasicAudio_Vtbl;
409 pDSoundRender->IReferenceClock_vtbl = &IReferenceClock_Vtbl;
410 pDSoundRender->IAMDirectSound_vtbl = &IAMDirectSound_Vtbl;
411 pDSoundRender->refCount = 1;
412 InitializeCriticalSection(&pDSoundRender->csFilter);
413 pDSoundRender->csFilter.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": DSoundRenderImpl.csFilter");
414 pDSoundRender->state = State_Stopped;
416 /* construct input pin */
417 piInput.dir = PINDIR_INPUT;
418 piInput.pFilter = (IBaseFilter *)pDSoundRender;
419 lstrcpynW(piInput.achName, wcsInputPinName, sizeof(piInput.achName) / sizeof(piInput.achName[0]));
420 hr = InputPin_Construct(&DSoundRender_InputPin_Vtbl, &piInput, DSoundRender_Sample, pDSoundRender, DSoundRender_QueryAccept, NULL, &pDSoundRender->csFilter, NULL, (IPin **)&pDSoundRender->pInputPin);
424 hr = DirectSoundCreate8(NULL, &pDSoundRender->dsound, NULL);
426 ERR("Cannot create Direct Sound object (%x)\n", hr);
428 IDirectSound_SetCooperativeLevel(pDSoundRender->dsound, GetDesktopWindow(), DSSCL_PRIORITY);
433 MediaSeekingImpl_Init((IBaseFilter*)pDSoundRender, sound_mod_stop, sound_mod_start, sound_mod_rate, &pDSoundRender->mediaSeeking, &pDSoundRender->csFilter);
434 pDSoundRender->mediaSeeking.lpVtbl = &IMediaSeeking_Vtbl;
436 pDSoundRender->state_change = CreateEventW(NULL, TRUE, TRUE, NULL);
437 pDSoundRender->blocked = CreateEventW(NULL, FALSE, FALSE, NULL);
439 if (!pDSoundRender->state_change || !pDSoundRender->blocked)
441 IUnknown_Release((IUnknown *)pDSoundRender);
442 return HRESULT_FROM_WIN32(GetLastError());
445 *ppv = pDSoundRender;
449 if (pDSoundRender->pInputPin)
450 IPin_Release((IPin*)pDSoundRender->pInputPin);
451 pDSoundRender->csFilter.DebugInfo->Spare[0] = 0;
452 DeleteCriticalSection(&pDSoundRender->csFilter);
453 CoTaskMemFree(pDSoundRender);
459 static HRESULT WINAPI DSoundRender_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv)
461 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
462 TRACE("(%p, %p)->(%s, %p)\n", This, iface, qzdebugstr_guid(riid), ppv);
466 if (IsEqualIID(riid, &IID_IUnknown))
468 else if (IsEqualIID(riid, &IID_IPersist))
470 else if (IsEqualIID(riid, &IID_IMediaFilter))
472 else if (IsEqualIID(riid, &IID_IBaseFilter))
474 else if (IsEqualIID(riid, &IID_IBasicAudio))
475 *ppv = &This->IBasicAudio_vtbl;
476 else if (IsEqualIID(riid, &IID_IReferenceClock))
477 *ppv = &This->IReferenceClock_vtbl;
478 else if (IsEqualIID(riid, &IID_IMediaSeeking))
479 *ppv = &This->mediaSeeking.lpVtbl;
480 else if (IsEqualIID(riid, &IID_IAMDirectSound))
481 *ppv = &This->IAMDirectSound_vtbl;
485 IUnknown_AddRef((IUnknown *)(*ppv));
489 if (!IsEqualIID(riid, &IID_IPin) && !IsEqualIID(riid, &IID_IVideoWindow))
490 FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
492 return E_NOINTERFACE;
495 static ULONG WINAPI DSoundRender_AddRef(IBaseFilter * iface)
497 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
498 ULONG refCount = InterlockedIncrement(&This->refCount);
500 TRACE("(%p/%p)->() AddRef from %d\n", This, iface, refCount - 1);
505 static ULONG WINAPI DSoundRender_Release(IBaseFilter * iface)
507 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
508 ULONG refCount = InterlockedDecrement(&This->refCount);
510 TRACE("(%p)->() Release from %d\n", This, refCount + 1);
517 IReferenceClock_Release(This->pClock);
520 IDirectSoundBuffer_Release(This->dsbuffer);
521 This->dsbuffer = NULL;
523 IDirectSound_Release(This->dsound);
526 if (SUCCEEDED(IPin_ConnectedTo((IPin *)This->pInputPin, &pConnectedTo)))
528 IPin_Disconnect(pConnectedTo);
529 IPin_Release(pConnectedTo);
531 IPin_Disconnect((IPin *)This->pInputPin);
533 IPin_Release((IPin *)This->pInputPin);
536 This->IBasicAudio_vtbl = NULL;
538 This->csFilter.DebugInfo->Spare[0] = 0;
539 DeleteCriticalSection(&This->csFilter);
541 CloseHandle(This->state_change);
542 CloseHandle(This->blocked);
544 TRACE("Destroying Audio Renderer\n");
553 /** IPersist methods **/
555 static HRESULT WINAPI DSoundRender_GetClassID(IBaseFilter * iface, CLSID * pClsid)
557 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
558 TRACE("(%p/%p)->(%p)\n", This, iface, pClsid);
560 *pClsid = CLSID_DSoundRender;
565 /** IMediaFilter methods **/
567 static HRESULT WINAPI DSoundRender_Stop(IBaseFilter * iface)
570 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
572 TRACE("(%p/%p)->()\n", This, iface);
574 EnterCriticalSection(&This->csFilter);
579 hr = IDirectSoundBuffer_GetStatus(This->dsbuffer, &state);
582 if (state & DSBSTATUS_PLAYING)
583 hr = IDirectSoundBuffer_Stop(This->dsbuffer);
587 This->state = State_Stopped;
589 /* Complete our transition */
590 SetEvent(This->state_change);
591 SetEvent(This->blocked);
593 LeaveCriticalSection(&This->csFilter);
598 static HRESULT WINAPI DSoundRender_Pause(IBaseFilter * iface)
601 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
603 TRACE("(%p/%p)->()\n", This, iface);
605 EnterCriticalSection(&This->csFilter);
606 if (This->state != State_Paused)
609 if (This->state == State_Stopped)
611 This->pInputPin->end_of_stream = 0;
616 hr = IDirectSoundBuffer_GetStatus(This->dsbuffer, &state);
619 if (state & DSBSTATUS_PLAYING)
620 hr = IDirectSoundBuffer_Stop(This->dsbuffer);
624 This->state = State_Paused;
626 ResetEvent(This->blocked);
627 ResetEvent(This->state_change);
629 LeaveCriticalSection(&This->csFilter);
634 static HRESULT WINAPI DSoundRender_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
637 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
639 TRACE("(%p/%p)->(%s)\n", This, iface, wine_dbgstr_longlong(tStart));
641 EnterCriticalSection(&This->csFilter);
643 This->rtStreamStart = tStart;
644 if (This->state == State_Paused)
646 /* Unblock our thread, state changing from paused to running doesn't need a reset for state change */
647 SetEvent(This->blocked);
649 else if (This->state == State_Stopped)
651 ResetEvent(This->state_change);
652 This->pInputPin->end_of_stream = 0;
655 This->state = State_Running;
657 LeaveCriticalSection(&This->csFilter);
662 static HRESULT WINAPI DSoundRender_GetState(IBaseFilter * iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState)
665 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
667 TRACE("(%p/%p)->(%d, %p)\n", This, iface, dwMilliSecsTimeout, pState);
669 if (WaitForSingleObject(This->state_change, dwMilliSecsTimeout) == WAIT_TIMEOUT)
670 hr = VFW_S_STATE_INTERMEDIATE;
674 EnterCriticalSection(&This->csFilter);
676 *pState = This->state;
678 LeaveCriticalSection(&This->csFilter);
683 static HRESULT WINAPI DSoundRender_SetSyncSource(IBaseFilter * iface, IReferenceClock *pClock)
685 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
687 TRACE("(%p/%p)->(%p)\n", This, iface, pClock);
689 EnterCriticalSection(&This->csFilter);
692 IReferenceClock_Release(This->pClock);
693 This->pClock = pClock;
695 IReferenceClock_AddRef(This->pClock);
697 LeaveCriticalSection(&This->csFilter);
702 static HRESULT WINAPI DSoundRender_GetSyncSource(IBaseFilter * iface, IReferenceClock **ppClock)
704 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
706 TRACE("(%p/%p)->(%p)\n", This, iface, ppClock);
708 EnterCriticalSection(&This->csFilter);
710 *ppClock = This->pClock;
712 IReferenceClock_AddRef(This->pClock);
714 LeaveCriticalSection(&This->csFilter);
719 /** IBaseFilter implementation **/
721 static HRESULT DSoundRender_GetPin(IBaseFilter *iface, ULONG pos, IPin **pin, DWORD *lastsynctick)
723 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
725 /* Our pins are static, not changing so setting static tick count is ok */
731 *pin = (IPin *)This->pInputPin;
736 static HRESULT WINAPI DSoundRender_EnumPins(IBaseFilter * iface, IEnumPins **ppEnum)
738 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
740 TRACE("(%p/%p)->(%p)\n", This, iface, ppEnum);
742 return IEnumPinsImpl_Construct(ppEnum, DSoundRender_GetPin, iface);
745 static HRESULT WINAPI DSoundRender_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin)
747 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
749 TRACE("(%p/%p)->(%s,%p)\n", This, iface, debugstr_w(Id), ppPin);
751 FIXME("DSoundRender::FindPin(...)\n");
753 /* FIXME: critical section */
758 static HRESULT WINAPI DSoundRender_QueryFilterInfo(IBaseFilter * iface, FILTER_INFO *pInfo)
760 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
762 TRACE("(%p/%p)->(%p)\n", This, iface, pInfo);
764 strcpyW(pInfo->achName, This->filterInfo.achName);
765 pInfo->pGraph = This->filterInfo.pGraph;
768 IFilterGraph_AddRef(pInfo->pGraph);
773 static HRESULT WINAPI DSoundRender_JoinFilterGraph(IBaseFilter * iface, IFilterGraph *pGraph, LPCWSTR pName)
775 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
777 TRACE("(%p/%p)->(%p, %s)\n", This, iface, pGraph, debugstr_w(pName));
779 EnterCriticalSection(&This->csFilter);
782 strcpyW(This->filterInfo.achName, pName);
784 *This->filterInfo.achName = '\0';
785 This->filterInfo.pGraph = pGraph; /* NOTE: do NOT increase ref. count */
787 LeaveCriticalSection(&This->csFilter);
792 static HRESULT WINAPI DSoundRender_QueryVendorInfo(IBaseFilter * iface, LPWSTR *pVendorInfo)
794 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
795 TRACE("(%p/%p)->(%p)\n", This, iface, pVendorInfo);
799 static const IBaseFilterVtbl DSoundRender_Vtbl =
801 DSoundRender_QueryInterface,
803 DSoundRender_Release,
804 DSoundRender_GetClassID,
808 DSoundRender_GetState,
809 DSoundRender_SetSyncSource,
810 DSoundRender_GetSyncSource,
811 DSoundRender_EnumPins,
812 DSoundRender_FindPin,
813 DSoundRender_QueryFilterInfo,
814 DSoundRender_JoinFilterGraph,
815 DSoundRender_QueryVendorInfo
818 static HRESULT WINAPI DSoundRender_InputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
820 InputPin *This = (InputPin *)iface;
821 PIN_DIRECTION pindirReceive;
822 DSoundRenderImpl *DSImpl;
825 TRACE("(%p)->(%p, %p)\n", This, pReceivePin, pmt);
826 dump_AM_MEDIA_TYPE(pmt);
828 EnterCriticalSection(This->pin.pCritSec);
830 DSImpl = (DSoundRenderImpl*)This->pin.pinInfo.pFilter;
831 DSImpl->rtLastStop = -1;
833 if (This->pin.pConnectedTo)
834 hr = VFW_E_ALREADY_CONNECTED;
836 if (SUCCEEDED(hr) && This->pin.fnQueryAccept(This->pin.pUserData, pmt) != S_OK)
837 hr = VFW_E_TYPE_NOT_ACCEPTED;
841 IPin_QueryDirection(pReceivePin, &pindirReceive);
843 if (pindirReceive != PINDIR_OUTPUT)
845 ERR("Can't connect from non-output pin\n");
846 hr = VFW_E_INVALID_DIRECTION;
852 WAVEFORMATEX *format;
853 DSBUFFERDESC buf_desc;
855 TRACE("MajorType %s\n", debugstr_guid(&pmt->majortype));
856 TRACE("SubType %s\n", debugstr_guid(&pmt->subtype));
857 TRACE("Format %s\n", debugstr_guid(&pmt->formattype));
858 TRACE("Size %d\n", pmt->cbFormat);
860 format = (WAVEFORMATEX*)pmt->pbFormat;
862 DSImpl->buf_size = format->nAvgBytesPerSec;
864 memset(&buf_desc,0,sizeof(DSBUFFERDESC));
865 buf_desc.dwSize = sizeof(DSBUFFERDESC);
866 buf_desc.dwFlags = DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLPAN |
867 DSBCAPS_CTRLFREQUENCY |
868 DSBCAPS_GETCURRENTPOSITION2;
869 buf_desc.dwBufferBytes = DSImpl->buf_size;
870 buf_desc.lpwfxFormat = format;
871 hr = IDirectSound_CreateSoundBuffer(DSImpl->dsound, &buf_desc, &DSImpl->dsbuffer, NULL);
873 ERR("Can't create sound buffer (%x)\n", hr);
878 hr = IDirectSoundBuffer_SetVolume(DSImpl->dsbuffer, DSImpl->volume);
880 ERR("Can't set volume to %ld (%x)\n", DSImpl->volume, hr);
882 hr = IDirectSoundBuffer_SetPan(DSImpl->dsbuffer, DSImpl->pan);
884 ERR("Can't set pan to %ld (%x)\n", DSImpl->pan, hr);
886 DSImpl->write_pos = 0;
892 CopyMediaType(&This->pin.mtCurrent, pmt);
893 This->pin.pConnectedTo = pReceivePin;
894 IPin_AddRef(pReceivePin);
896 else if (hr != VFW_E_ALREADY_CONNECTED)
898 if (DSImpl->dsbuffer)
899 IDirectSoundBuffer_Release(DSImpl->dsbuffer);
900 DSImpl->dsbuffer = NULL;
903 LeaveCriticalSection(This->pin.pCritSec);
908 static HRESULT WINAPI DSoundRender_InputPin_Disconnect(IPin * iface)
910 IPinImpl *This = (IPinImpl*)iface;
911 DSoundRenderImpl *DSImpl;
913 TRACE("(%p)->()\n", iface);
915 DSImpl = (DSoundRenderImpl*)This->pinInfo.pFilter;
916 if (DSImpl->dsbuffer)
917 IDirectSoundBuffer_Release(DSImpl->dsbuffer);
918 DSImpl->dsbuffer = NULL;
920 return IPinImpl_Disconnect(iface);
923 static HRESULT WINAPI DSoundRender_InputPin_EndOfStream(IPin * iface)
925 InputPin* This = (InputPin*)iface;
926 DSoundRenderImpl *me = (DSoundRenderImpl*)This->pin.pinInfo.pFilter;
927 IMediaEventSink* pEventSink;
930 EnterCriticalSection(This->pin.pCritSec);
932 TRACE("(%p/%p)->()\n", This, iface);
933 hr = InputPin_EndOfStream(iface);
937 LeaveCriticalSection(This->pin.pCritSec);
941 hr = IFilterGraph_QueryInterface(me->filterInfo.pGraph, &IID_IMediaEventSink, (LPVOID*)&pEventSink);
946 silence = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, me->buf_size);
949 memset(silence, 0, me->buf_size);
950 DSoundRender_SendSampleData((DSoundRenderImpl*)This->pin.pinInfo.pFilter, silence, me->buf_size);
951 HeapFree(GetProcessHeap(), 0, silence);
954 hr = IMediaEventSink_Notify(pEventSink, EC_COMPLETE, S_OK, 0);
955 IMediaEventSink_Release(pEventSink);
957 LeaveCriticalSection(This->pin.pCritSec);
962 static HRESULT WINAPI DSoundRender_InputPin_BeginFlush(IPin * iface)
964 InputPin *This = (InputPin *)iface;
965 DSoundRenderImpl *pFilter = (DSoundRenderImpl *)This->pin.pinInfo.pFilter;
972 EnterCriticalSection(This->pin.pCritSec);
973 hr = InputPin_BeginFlush(iface);
975 if (pFilter->dsbuffer)
977 IDirectSoundBuffer_Stop(pFilter->dsbuffer);
980 IDirectSoundBuffer_SetCurrentPosition(pFilter->dsbuffer, 0);
981 pFilter->write_pos = pFilter->last_play_pos = 0;
982 ++pFilter->play_loops;
983 pFilter->write_loops = pFilter->play_loops;
985 IDirectSoundBuffer_Lock(pFilter->dsbuffer, 0, 0, (LPVOID *)&buffer, &size, NULL, NULL, DSBLOCK_ENTIREBUFFER);
986 memset(buffer, 0, size);
987 IDirectSoundBuffer_Unlock(pFilter->dsbuffer, buffer, size, NULL, 0);
990 if (pFilter->state == State_Paused)
991 SetEvent(pFilter->blocked);
992 LeaveCriticalSection(This->pin.pCritSec);
997 static HRESULT WINAPI DSoundRender_InputPin_EndFlush(IPin * iface)
999 InputPin *This = (InputPin *)iface;
1000 DSoundRenderImpl *pFilter = (DSoundRenderImpl *)This->pin.pinInfo.pFilter;
1005 EnterCriticalSection(This->pin.pCritSec);
1006 hr = InputPin_EndFlush(iface);
1008 if (pFilter->state == State_Paused)
1009 SetEvent(pFilter->blocked);
1010 LeaveCriticalSection(This->pin.pCritSec);
1015 static const IPinVtbl DSoundRender_InputPin_Vtbl =
1017 InputPin_QueryInterface,
1021 DSoundRender_InputPin_ReceiveConnection,
1022 DSoundRender_InputPin_Disconnect,
1023 IPinImpl_ConnectedTo,
1024 IPinImpl_ConnectionMediaType,
1025 IPinImpl_QueryPinInfo,
1026 IPinImpl_QueryDirection,
1028 IPinImpl_QueryAccept,
1029 IPinImpl_EnumMediaTypes,
1030 IPinImpl_QueryInternalConnections,
1031 DSoundRender_InputPin_EndOfStream,
1032 DSoundRender_InputPin_BeginFlush,
1033 DSoundRender_InputPin_EndFlush,
1037 /*** IUnknown methods ***/
1038 static HRESULT WINAPI Basicaudio_QueryInterface(IBasicAudio *iface,
1041 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1043 TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
1045 return DSoundRender_QueryInterface((IBaseFilter*)This, riid, ppvObj);
1048 static ULONG WINAPI Basicaudio_AddRef(IBasicAudio *iface) {
1049 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1051 TRACE("(%p/%p)->()\n", This, iface);
1053 return DSoundRender_AddRef((IBaseFilter*)This);
1056 static ULONG WINAPI Basicaudio_Release(IBasicAudio *iface) {
1057 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1059 TRACE("(%p/%p)->()\n", This, iface);
1061 return DSoundRender_Release((IBaseFilter*)This);
1064 /*** IDispatch methods ***/
1065 static HRESULT WINAPI Basicaudio_GetTypeInfoCount(IBasicAudio *iface,
1067 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1069 TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pctinfo);
1074 static HRESULT WINAPI Basicaudio_GetTypeInfo(IBasicAudio *iface,
1077 ITypeInfo**ppTInfo) {
1078 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1080 TRACE("(%p/%p)->(%d, %d, %p): stub !!!\n", This, iface, iTInfo, lcid, ppTInfo);
1085 static HRESULT WINAPI Basicaudio_GetIDsOfNames(IBasicAudio *iface,
1091 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1093 TRACE("(%p/%p)->(%s (%p), %p, %d, %d, %p): stub !!!\n", This, iface, debugstr_guid(riid), riid, rgszNames, cNames, lcid, rgDispId);
1098 static HRESULT WINAPI Basicaudio_Invoke(IBasicAudio *iface,
1099 DISPID dispIdMember,
1103 DISPPARAMS*pDispParams,
1105 EXCEPINFO*pExepInfo,
1107 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1109 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);
1114 /*** IBasicAudio methods ***/
1115 static HRESULT WINAPI Basicaudio_put_Volume(IBasicAudio *iface,
1117 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1119 TRACE("(%p/%p)->(%d)\n", This, iface, lVolume);
1121 if (lVolume > DSBVOLUME_MAX || lVolume < DSBVOLUME_MIN)
1122 return E_INVALIDARG;
1124 if (This->dsbuffer) {
1125 if (FAILED(IDirectSoundBuffer_SetVolume(This->dsbuffer, lVolume)))
1129 This->volume = lVolume;
1133 static HRESULT WINAPI Basicaudio_get_Volume(IBasicAudio *iface,
1135 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1137 TRACE("(%p/%p)->(%p)\n", This, iface, plVolume);
1142 *plVolume = This->volume;
1146 static HRESULT WINAPI Basicaudio_put_Balance(IBasicAudio *iface,
1148 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1150 TRACE("(%p/%p)->(%d)\n", This, iface, lBalance);
1152 if (lBalance < DSBPAN_LEFT || lBalance > DSBPAN_RIGHT)
1153 return E_INVALIDARG;
1155 if (This->dsbuffer) {
1156 if (FAILED(IDirectSoundBuffer_SetPan(This->dsbuffer, lBalance)))
1160 This->pan = lBalance;
1164 static HRESULT WINAPI Basicaudio_get_Balance(IBasicAudio *iface,
1166 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1168 TRACE("(%p/%p)->(%p)\n", This, iface, plBalance);
1173 *plBalance = This->pan;
1177 static const IBasicAudioVtbl IBasicAudio_Vtbl =
1179 Basicaudio_QueryInterface,
1182 Basicaudio_GetTypeInfoCount,
1183 Basicaudio_GetTypeInfo,
1184 Basicaudio_GetIDsOfNames,
1186 Basicaudio_put_Volume,
1187 Basicaudio_get_Volume,
1188 Basicaudio_put_Balance,
1189 Basicaudio_get_Balance
1193 /*** IUnknown methods ***/
1194 static HRESULT WINAPI ReferenceClock_QueryInterface(IReferenceClock *iface,
1198 ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1200 TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
1202 return DSoundRender_QueryInterface((IBaseFilter*)This, riid, ppvObj);
1205 static ULONG WINAPI ReferenceClock_AddRef(IReferenceClock *iface)
1207 ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1209 TRACE("(%p/%p)->()\n", This, iface);
1211 return DSoundRender_AddRef((IBaseFilter*)This);
1214 static ULONG WINAPI ReferenceClock_Release(IReferenceClock *iface)
1216 ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1218 TRACE("(%p/%p)->()\n", This, iface);
1220 return DSoundRender_Release((IBaseFilter*)This);
1223 /*** IReferenceClock methods ***/
1224 static HRESULT WINAPI ReferenceClock_GetTime(IReferenceClock *iface,
1225 REFERENCE_TIME *pTime)
1227 ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1228 HRESULT hr = E_FAIL;
1231 TRACE("(%p/%p)->(%p)\n", This, iface, pTime);
1234 hr = DSoundRender_GetPos(This, &play_pos, pTime);
1236 ERR("Could not get reference time (%x)!\n", hr);
1241 static HRESULT WINAPI ReferenceClock_AdviseTime(IReferenceClock *iface,
1242 REFERENCE_TIME rtBaseTime,
1243 REFERENCE_TIME rtStreamTime,
1245 DWORD_PTR *pdwAdviseCookie)
1247 ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1249 FIXME("(%p/%p)->(%s, %s, %p, %p): stub!\n", This, iface, wine_dbgstr_longlong(rtBaseTime), wine_dbgstr_longlong(rtStreamTime), (void*)hEvent, pdwAdviseCookie);
1254 static HRESULT WINAPI ReferenceClock_AdvisePeriodic(IReferenceClock *iface,
1255 REFERENCE_TIME rtBaseTime,
1256 REFERENCE_TIME rtStreamTime,
1257 HSEMAPHORE hSemaphore,
1258 DWORD_PTR *pdwAdviseCookie)
1260 ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1262 FIXME("(%p/%p)->(%s, %s, %p, %p): stub!\n", This, iface, wine_dbgstr_longlong(rtBaseTime), wine_dbgstr_longlong(rtStreamTime), (void*)hSemaphore, pdwAdviseCookie);
1267 static HRESULT WINAPI ReferenceClock_Unadvise(IReferenceClock *iface,
1268 DWORD_PTR dwAdviseCookie)
1270 ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1272 FIXME("(%p/%p)->(%p): stub!\n", This, iface, (void*)dwAdviseCookie);
1277 static const IReferenceClockVtbl IReferenceClock_Vtbl =
1279 ReferenceClock_QueryInterface,
1280 ReferenceClock_AddRef,
1281 ReferenceClock_Release,
1282 ReferenceClock_GetTime,
1283 ReferenceClock_AdviseTime,
1284 ReferenceClock_AdvisePeriodic,
1285 ReferenceClock_Unadvise
1288 static inline DSoundRenderImpl *impl_from_IMediaSeeking( IMediaSeeking *iface )
1290 return (DSoundRenderImpl *)((char*)iface - FIELD_OFFSET(DSoundRenderImpl, mediaSeeking.lpVtbl));
1293 static HRESULT WINAPI sound_seek_QueryInterface(IMediaSeeking * iface, REFIID riid, LPVOID * ppv)
1295 DSoundRenderImpl *This = impl_from_IMediaSeeking(iface);
1297 return IUnknown_QueryInterface((IUnknown *)This, riid, ppv);
1300 static ULONG WINAPI sound_seek_AddRef(IMediaSeeking * iface)
1302 DSoundRenderImpl *This = impl_from_IMediaSeeking(iface);
1304 return IUnknown_AddRef((IUnknown *)This);
1307 static ULONG WINAPI sound_seek_Release(IMediaSeeking * iface)
1309 DSoundRenderImpl *This = impl_from_IMediaSeeking(iface);
1311 return IUnknown_Release((IUnknown *)This);
1314 static const IMediaSeekingVtbl IMediaSeeking_Vtbl =
1316 sound_seek_QueryInterface,
1319 MediaSeekingImpl_GetCapabilities,
1320 MediaSeekingImpl_CheckCapabilities,
1321 MediaSeekingImpl_IsFormatSupported,
1322 MediaSeekingImpl_QueryPreferredFormat,
1323 MediaSeekingImpl_GetTimeFormat,
1324 MediaSeekingImpl_IsUsingTimeFormat,
1325 MediaSeekingImpl_SetTimeFormat,
1326 MediaSeekingImpl_GetDuration,
1327 MediaSeekingImpl_GetStopPosition,
1328 MediaSeekingImpl_GetCurrentPosition,
1329 MediaSeekingImpl_ConvertTimeFormat,
1330 MediaSeekingImpl_SetPositions,
1331 MediaSeekingImpl_GetPositions,
1332 MediaSeekingImpl_GetAvailable,
1333 MediaSeekingImpl_SetRate,
1334 MediaSeekingImpl_GetRate,
1335 MediaSeekingImpl_GetPreroll
1338 /*** IUnknown methods ***/
1339 static HRESULT WINAPI AMDirectSound_QueryInterface(IAMDirectSound *iface,
1343 ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1345 TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
1347 return DSoundRender_QueryInterface((IBaseFilter*)This, riid, ppvObj);
1350 static ULONG WINAPI AMDirectSound_AddRef(IAMDirectSound *iface)
1352 ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1354 TRACE("(%p/%p)->()\n", This, iface);
1356 return DSoundRender_AddRef((IBaseFilter*)This);
1359 static ULONG WINAPI AMDirectSound_Release(IAMDirectSound *iface)
1361 ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1363 TRACE("(%p/%p)->()\n", This, iface);
1365 return DSoundRender_Release((IBaseFilter*)This);
1368 /*** IAMDirectSound methods ***/
1369 static HRESULT WINAPI AMDirectSound_GetDirectSoundInterface(IAMDirectSound *iface, IDirectSound **ds)
1371 ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1373 FIXME("(%p/%p)->(%p): stub\n", This, iface, ds);
1378 static HRESULT WINAPI AMDirectSound_GetPrimaryBufferInterface(IAMDirectSound *iface, IDirectSoundBuffer **buf)
1380 ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1382 FIXME("(%p/%p)->(%p): stub\n", This, iface, buf);
1387 static HRESULT WINAPI AMDirectSound_GetSecondaryBufferInterface(IAMDirectSound *iface, IDirectSoundBuffer **buf)
1389 ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1391 FIXME("(%p/%p)->(%p): stub\n", This, iface, buf);
1396 static HRESULT WINAPI AMDirectSound_ReleaseDirectSoundInterface(IAMDirectSound *iface, IDirectSound *ds)
1398 ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1400 FIXME("(%p/%p)->(%p): stub\n", This, iface, ds);
1405 static HRESULT WINAPI AMDirectSound_ReleasePrimaryBufferInterface(IAMDirectSound *iface, IDirectSoundBuffer *buf)
1407 ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1409 FIXME("(%p/%p)->(%p): stub\n", This, iface, buf);
1414 static HRESULT WINAPI AMDirectSound_ReleaseSecondaryBufferInterface(IAMDirectSound *iface, IDirectSoundBuffer *buf)
1416 ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1418 FIXME("(%p/%p)->(%p): stub\n", This, iface, buf);
1423 static HRESULT WINAPI AMDirectSound_SetFocusWindow(IAMDirectSound *iface, HWND hwnd, BOOL bgsilent)
1425 ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1427 FIXME("(%p/%p)->(%p,%d): stub\n", This, iface, hwnd, bgsilent);
1432 static HRESULT WINAPI AMDirectSound_GetFocusWindow(IAMDirectSound *iface, HWND hwnd)
1434 ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1436 FIXME("(%p/%p)->(%p): stub\n", This, iface, hwnd);
1441 static const IAMDirectSoundVtbl IAMDirectSound_Vtbl =
1443 AMDirectSound_QueryInterface,
1444 AMDirectSound_AddRef,
1445 AMDirectSound_Release,
1446 AMDirectSound_GetDirectSoundInterface,
1447 AMDirectSound_GetPrimaryBufferInterface,
1448 AMDirectSound_GetSecondaryBufferInterface,
1449 AMDirectSound_ReleaseDirectSoundInterface,
1450 AMDirectSound_ReleasePrimaryBufferInterface,
1451 AMDirectSound_ReleaseSecondaryBufferInterface,
1452 AMDirectSound_SetFocusWindow,
1453 AMDirectSound_GetFocusWindow