msi: Avoid accessing a freed object.
[wine.git] / dlls / quartz / dsoundrender.c
bloba7ebd9f9c93ef1eaa60324ac01e4114eb24ef236
1 /*
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
21 #include "config.h"
23 #include "quartz_private.h"
24 #include "control_private.h"
25 #include "pin.h"
27 #include "uuids.h"
28 #include "vfwmsgs.h"
29 #include "windef.h"
30 #include "winbase.h"
31 #include "dshow.h"
32 #include "evcode.h"
33 #include "strmif.h"
34 #include "dsound.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;
55 LONG refCount;
56 CRITICAL_SECTION csFilter;
57 FILTER_STATE state;
58 REFERENCE_TIME rtStreamStart;
59 IReferenceClock * pClock;
60 FILTER_INFO filterInfo;
62 InputPin * pInputPin;
63 IPin ** ppPins;
65 LPDIRECTSOUND dsound;
66 LPDIRECTSOUNDBUFFER dsbuffer;
67 DWORD buf_size;
68 DWORD write_pos;
69 DWORD write_loops;
71 DWORD last_play_pos;
72 DWORD play_loops;
73 REFERENCE_TIME play_time;
75 long volume;
76 long pan;
77 } DSoundRenderImpl;
79 static HRESULT DSoundRender_InputPin_Construct(const PIN_INFO * pPinInfo, SAMPLEPROC pSampleProc, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, LPCRITICAL_SECTION pCritSec, IPin ** ppPin)
81 InputPin * pPinImpl;
83 *ppPin = NULL;
85 if (pPinInfo->dir != PINDIR_INPUT)
87 ERR("Pin direction(%x) != PINDIR_INPUT\n", pPinInfo->dir);
88 return E_INVALIDARG;
91 pPinImpl = CoTaskMemAlloc(sizeof(*pPinImpl));
93 if (!pPinImpl)
94 return E_OUTOFMEMORY;
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);
102 return S_OK;
104 return E_FAIL;
108 static inline HRESULT DSoundRender_GetPos(DSoundRenderImpl *This, DWORD *pPlayPos, DWORD *pWritePos, REFERENCE_TIME *pRefTime)
110 HRESULT hr;
112 EnterCriticalSection(&This->csFilter);
114 hr = IDirectSoundBuffer_GetCurrentPosition(This->dsbuffer, pPlayPos, pWritePos);
115 if (hr == DS_OK)
117 DWORD play_pos = *pPlayPos;
119 if (play_pos < This->last_play_pos)
120 This->play_loops++;
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)
126 This->play_loops--;
128 if (pRefTime)
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;
137 else
138 hr = S_FALSE;
140 *pRefTime = This->play_time;
144 LeaveCriticalSection(&This->csFilter);
146 return hr;
149 static HRESULT DSoundRender_SendSampleData(DSoundRenderImpl* This, const BYTE *data, DWORD size)
151 HRESULT hr;
152 LPBYTE lpbuf1 = NULL;
153 LPBYTE lpbuf2 = NULL;
154 DWORD dwsize1 = 0;
155 DWORD dwsize2 = 0;
156 DWORD size2;
157 DWORD play_pos,buf_free;
159 do {
160 hr = DSoundRender_GetPos(This, &play_pos, NULL, NULL);
161 if (hr != DS_OK)
163 ERR("GetPos returned error: %x\n", hr);
164 break;
166 if (This->write_pos <= play_pos)
167 buf_free = play_pos-This->write_pos;
168 else
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)
174 Sleep(10);
175 continue;
178 size2 = min(buf_free, size);
179 hr = IDirectSoundBuffer_Lock(This->dsbuffer, This->write_pos, size2, (LPVOID *)&lpbuf1, &dwsize1, (LPVOID *)&lpbuf2, &dwsize2, 0);
180 if (hr != DS_OK) {
181 ERR("Unable to lock sound buffer! (%x)\n", hr);
182 break;
184 /* TRACE("write_pos=%d, size=%d, sz1=%d, sz2=%d\n", This->write_pos, size2, dwsize1, dwsize2); */
186 memcpy(lpbuf1, data, dwsize1);
187 if (dwsize2)
188 memcpy(lpbuf2, data + dwsize1, dwsize2);
190 hr = IDirectSoundBuffer_Unlock(This->dsbuffer, lpbuf1, dwsize1, lpbuf2, dwsize2);
191 if (hr != DS_OK)
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;
200 This->write_loops++;
202 } while (size && This->state == State_Running);
204 return hr;
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;
213 HRESULT hr;
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);
221 if (FAILED(hr))
223 ERR("Cannot get pointer to sample data (%x)\n", hr);
224 return hr;
227 hr = IMediaSample_GetTime(pSample, &tStart, &tStop);
228 if (FAILED(hr))
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 */
237 int i;
238 for(i = 0; i < cbSrcStream; i++)
240 if ((i!=0) && !(i%16))
241 TRACE("\n");
242 TRACE("%02x ", pbSrcStream[i]);
244 TRACE("\n");
246 #endif
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))
262 return S_OK;
263 return S_FALSE;
266 HRESULT DSoundRender_create(IUnknown * pUnkOuter, LPVOID * ppv)
268 HRESULT hr;
269 PIN_INFO piInput;
270 DSoundRenderImpl * pDSoundRender;
272 TRACE("(%p, %p)\n", pUnkOuter, ppv);
274 *ppv = NULL;
276 if (pUnkOuter)
277 return CLASS_E_NOAGGREGATION;
279 pDSoundRender = CoTaskMemAlloc(sizeof(DSoundRenderImpl));
280 if (!pDSoundRender)
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);
307 if (SUCCEEDED(hr))
309 hr = DirectSoundCreate(NULL, &pDSoundRender->dsound, NULL);
310 if (FAILED(hr))
311 ERR("Cannot create Direct Sound object (%x)\n", hr);
314 if (SUCCEEDED(hr))
316 pDSoundRender->ppPins[0] = (IPin *)pDSoundRender->pInputPin;
317 *ppv = (LPVOID)pDSoundRender;
319 else
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);
329 return hr;
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);
337 *ppv = NULL;
339 if (IsEqualIID(riid, &IID_IUnknown))
340 *ppv = (LPVOID)This;
341 else if (IsEqualIID(riid, &IID_IPersist))
342 *ppv = (LPVOID)This;
343 else if (IsEqualIID(riid, &IID_IMediaFilter))
344 *ppv = (LPVOID)This;
345 else if (IsEqualIID(riid, &IID_IBaseFilter))
346 *ppv = (LPVOID)This;
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);
352 if (*ppv)
354 IUnknown_AddRef((IUnknown *)(*ppv));
355 return S_OK;
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);
370 return refCount;
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);
380 if (!refCount)
382 IPin *pConnectedTo;
384 if (This->pClock)
385 IReferenceClock_Release(This->pClock);
387 if (This->dsbuffer)
388 IDirectSoundBuffer_Release(This->dsbuffer);
389 This->dsbuffer = NULL;
390 if (This->dsound)
391 IDirectSound_Release(This->dsound);
392 This->dsound = NULL;
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);
404 This->lpVtbl = NULL;
405 This->IBasicAudio_vtbl = NULL;
407 This->csFilter.DebugInfo->Spare[0] = 0;
408 DeleteCriticalSection(&This->csFilter);
410 TRACE("Destroying Audio Renderer\n");
411 CoTaskMemFree(This);
413 return 0;
415 else
416 return refCount;
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;
428 return S_OK;
431 /** IMediaFilter methods **/
433 static HRESULT WINAPI DSoundRender_Stop(IBaseFilter * iface)
435 HRESULT hr = S_OK;
436 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
438 TRACE("(%p/%p)->()\n", This, iface);
440 EnterCriticalSection(&This->csFilter);
442 DWORD state = 0;
443 if (This->dsbuffer)
445 hr = IDirectSoundBuffer_GetStatus(This->dsbuffer, &state);
446 if (SUCCEEDED(hr))
448 if (state & DSBSTATUS_PLAYING)
449 hr = IDirectSoundBuffer_Stop(This->dsbuffer);
452 if (SUCCEEDED(hr))
453 This->state = State_Stopped;
455 LeaveCriticalSection(&This->csFilter);
457 return hr;
460 static HRESULT WINAPI DSoundRender_Pause(IBaseFilter * iface)
462 HRESULT hr = S_OK;
463 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
465 TRACE("(%p/%p)->()\n", This, iface);
467 EnterCriticalSection(&This->csFilter);
469 DWORD state = 0;
470 if (This->dsbuffer)
472 hr = IDirectSoundBuffer_GetStatus(This->dsbuffer, &state);
473 if (SUCCEEDED(hr))
475 if (state & DSBSTATUS_PLAYING)
476 hr = IDirectSoundBuffer_Stop(This->dsbuffer);
479 if (SUCCEEDED(hr))
480 This->state = State_Paused;
482 LeaveCriticalSection(&This->csFilter);
484 return hr;
487 static HRESULT WINAPI DSoundRender_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
489 HRESULT hr = S_OK;
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 */
497 if (This->dsbuffer)
499 hr = IDirectSoundBuffer_Play(This->dsbuffer, 0, 0, DSBPLAY_LOOPING);
500 if (FAILED(hr))
501 ERR("Can't start playing! (%x)\n", hr);
503 if (SUCCEEDED(hr))
505 This->rtStreamStart = tStart;
506 This->state = State_Running;
509 LeaveCriticalSection(&This->csFilter);
511 return hr;
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);
526 return S_OK;
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);
537 if (This->pClock)
538 IReferenceClock_Release(This->pClock);
539 This->pClock = pClock;
540 if (This->pClock)
541 IReferenceClock_AddRef(This->pClock);
543 LeaveCriticalSection(&This->csFilter);
545 return S_OK;
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);
561 return S_OK;
564 /** IBaseFilter implementation **/
566 static HRESULT WINAPI DSoundRender_EnumPins(IBaseFilter * iface, IEnumPins **ppEnum)
568 ENUMPINDETAILS epd;
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 */
588 return E_NOTIMPL;
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;
600 if (pInfo->pGraph)
601 IFilterGraph_AddRef(pInfo->pGraph);
603 return S_OK;
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);
614 if (pName)
615 strcpyW(This->filterInfo.achName, pName);
616 else
617 *This->filterInfo.achName = '\0';
618 This->filterInfo.pGraph = pGraph; /* NOTE: do NOT increase ref. count */
620 LeaveCriticalSection(&This->csFilter);
622 return S_OK;
625 static HRESULT WINAPI DSoundRender_QueryVendorInfo(IBaseFilter * iface, LPWSTR *pVendorInfo)
627 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
628 TRACE("(%p/%p)->(%p)\n", This, iface, pVendorInfo);
629 return E_NOTIMPL;
632 static const IBaseFilterVtbl DSoundRender_Vtbl =
634 DSoundRender_QueryInterface,
635 DSoundRender_AddRef,
636 DSoundRender_Release,
637 DSoundRender_GetClassID,
638 DSoundRender_Stop,
639 DSoundRender_Pause,
640 DSoundRender_Run,
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;
656 HRESULT hr = S_OK;
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;
671 if (SUCCEEDED(hr))
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;
682 if (SUCCEEDED(hr))
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);
704 if (FAILED(hr))
705 ERR("Can't create sound buffer (%x)\n", hr);
708 if (SUCCEEDED(hr))
710 hr = IDirectSoundBuffer_SetVolume(DSImpl->dsbuffer, DSImpl->volume);
711 if (FAILED(hr))
712 ERR("Can't set volume to %ld (%x)\n", DSImpl->volume, hr);
714 hr = IDirectSoundBuffer_SetPan(DSImpl->dsbuffer, DSImpl->pan);
715 if (FAILED(hr))
716 ERR("Can't set pan to %ld (%x)\n", DSImpl->pan, hr);
718 DSImpl->write_pos = 0;
719 hr = S_OK;
720 if (DSImpl->state == State_Running)
721 hr = IDirectSoundBuffer_Play(DSImpl->dsbuffer, 0, 0, DSBPLAY_LOOPING);
722 if (FAILED(hr))
723 ERR("Can't play sound buffer (%x)\n", hr);
726 if (SUCCEEDED(hr))
728 CopyMediaType(&This->pin.mtCurrent, pmt);
729 This->pin.pConnectedTo = pReceivePin;
730 IPin_AddRef(pReceivePin);
732 else
734 if (DSImpl->dsbuffer)
735 IDirectSoundBuffer_Release(DSImpl->dsbuffer);
736 DSImpl->dsbuffer = NULL;
739 LeaveCriticalSection(This->pin.pCritSec);
741 return hr;
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;
763 HRESULT hr;
765 TRACE("(%p/%p)->()\n", This, iface);
767 hr = IFilterGraph_QueryInterface(((DSoundRenderImpl*)This->pin.pinInfo.pFilter)->filterInfo.pGraph, &IID_IMediaEventSink, (LPVOID*)&pEventSink);
768 if (SUCCEEDED(hr))
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);
775 return hr;
778 static const IPinVtbl DSoundRender_InputPin_Vtbl =
780 InputPin_QueryInterface,
781 IPinImpl_AddRef,
782 InputPin_Release,
783 InputPin_Connect,
784 DSoundRender_InputPin_ReceiveConnection,
785 DSoundRender_InputPin_Disconnect,
786 IPinImpl_ConnectedTo,
787 IPinImpl_ConnectionMediaType,
788 IPinImpl_QueryPinInfo,
789 IPinImpl_QueryDirection,
790 IPinImpl_QueryId,
791 IPinImpl_QueryAccept,
792 IPinImpl_EnumMediaTypes,
793 IPinImpl_QueryInternalConnections,
794 DSoundRender_InputPin_EndOfStream,
795 InputPin_BeginFlush,
796 InputPin_EndFlush,
797 InputPin_NewSegment
800 static const IMemInputPinVtbl MemInputPin_Vtbl =
802 MemInputPin_QueryInterface,
803 MemInputPin_AddRef,
804 MemInputPin_Release,
805 MemInputPin_GetAllocator,
806 MemInputPin_NotifyAllocator,
807 MemInputPin_GetAllocatorRequirements,
808 MemInputPin_Receive,
809 MemInputPin_ReceiveMultiple,
810 MemInputPin_ReceiveCanBlock
813 /*** IUnknown methods ***/
814 static HRESULT WINAPI Basicaudio_QueryInterface(IBasicAudio *iface,
815 REFIID riid,
816 LPVOID*ppvObj) {
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,
842 UINT*pctinfo) {
843 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
845 TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pctinfo);
847 return S_OK;
850 static HRESULT WINAPI Basicaudio_GetTypeInfo(IBasicAudio *iface,
851 UINT iTInfo,
852 LCID lcid,
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);
858 return S_OK;
861 static HRESULT WINAPI Basicaudio_GetIDsOfNames(IBasicAudio *iface,
862 REFIID riid,
863 LPOLESTR*rgszNames,
864 UINT cNames,
865 LCID lcid,
866 DISPID*rgDispId) {
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);
871 return S_OK;
874 static HRESULT WINAPI Basicaudio_Invoke(IBasicAudio *iface,
875 DISPID dispIdMember,
876 REFIID riid,
877 LCID lcid,
878 WORD wFlags,
879 DISPPARAMS*pDispParams,
880 VARIANT*pVarResult,
881 EXCEPINFO*pExepInfo,
882 UINT*puArgErr) {
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);
887 return S_OK;
890 /*** IBasicAudio methods ***/
891 static HRESULT WINAPI Basicaudio_put_Volume(IBasicAudio *iface,
892 long lVolume) {
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)
898 return E_INVALIDARG;
900 if (This->dsbuffer) {
901 if (FAILED(IDirectSoundBuffer_SetVolume(This->dsbuffer, lVolume)))
902 return E_FAIL;
905 This->volume = lVolume;
906 return S_OK;
909 static HRESULT WINAPI Basicaudio_get_Volume(IBasicAudio *iface,
910 long *plVolume) {
911 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
913 TRACE("(%p/%p)->(%p)\n", This, iface, plVolume);
915 if (!plVolume)
916 return E_POINTER;
918 *plVolume = This->volume;
919 return S_OK;
922 static HRESULT WINAPI Basicaudio_put_Balance(IBasicAudio *iface,
923 long lBalance) {
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)
929 return E_INVALIDARG;
931 if (This->dsbuffer) {
932 if (FAILED(IDirectSoundBuffer_SetPan(This->dsbuffer, lBalance)))
933 return E_FAIL;
936 This->pan = lBalance;
937 return S_OK;
940 static HRESULT WINAPI Basicaudio_get_Balance(IBasicAudio *iface,
941 long *plBalance) {
942 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
944 TRACE("(%p/%p)->(%p)\n", This, iface, plBalance);
946 if (!plBalance)
947 return E_POINTER;
949 *plBalance = This->pan;
950 return S_OK;
953 static const IBasicAudioVtbl IBasicAudio_Vtbl =
955 Basicaudio_QueryInterface,
956 Basicaudio_AddRef,
957 Basicaudio_Release,
958 Basicaudio_GetTypeInfoCount,
959 Basicaudio_GetTypeInfo,
960 Basicaudio_GetIDsOfNames,
961 Basicaudio_Invoke,
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,
971 REFIID riid,
972 LPVOID*ppvObj)
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;
1005 DWORD play_pos;
1007 TRACE("(%p/%p)->(%p)\n", This, iface, pTime);
1009 if (This->dsbuffer)
1010 hr = DSoundRender_GetPos(This, &play_pos, NULL, pTime);
1011 if (FAILED(hr))
1012 ERR("Could not get refreence time (%x)!\n", hr);
1014 return hr;
1017 static HRESULT WINAPI ReferenceClock_AdviseTime(IReferenceClock *iface,
1018 REFERENCE_TIME rtBaseTime,
1019 REFERENCE_TIME rtStreamTime,
1020 HEVENT hEvent,
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);
1027 return E_NOTIMPL;
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);
1040 return E_NOTIMPL;
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);
1050 return S_FALSE;
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