ntdll: move relocations from mapping into loader
[wine/kumbayo.git] / dlls / quartz / dsoundrender.c
blob947bb986da50be9d110c1be12538d56a8999bbd9
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;
105 CoTaskMemFree(pPinImpl);
106 return E_FAIL;
110 static inline HRESULT DSoundRender_GetPos(DSoundRenderImpl *This, DWORD *pPlayPos, DWORD *pWritePos, REFERENCE_TIME *pRefTime)
112 HRESULT hr;
114 EnterCriticalSection(&This->csFilter);
116 hr = IDirectSoundBuffer_GetCurrentPosition(This->dsbuffer, pPlayPos, pWritePos);
117 if (hr == DS_OK)
119 DWORD play_pos = *pPlayPos;
121 if (play_pos < This->last_play_pos)
122 This->play_loops++;
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)
128 This->play_loops--;
130 if (pRefTime)
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;
139 else
140 hr = S_FALSE;
142 *pRefTime = This->play_time;
146 LeaveCriticalSection(&This->csFilter);
148 return hr;
151 static HRESULT DSoundRender_SendSampleData(DSoundRenderImpl* This, const BYTE *data, DWORD size)
153 HRESULT hr;
154 LPBYTE lpbuf1 = NULL;
155 LPBYTE lpbuf2 = NULL;
156 DWORD dwsize1 = 0;
157 DWORD dwsize2 = 0;
158 DWORD size2;
159 DWORD play_pos,buf_free;
161 do {
162 hr = DSoundRender_GetPos(This, &play_pos, NULL, NULL);
163 if (hr != DS_OK)
165 ERR("GetPos returned error: %x\n", hr);
166 break;
168 if (This->write_pos <= play_pos)
169 buf_free = play_pos-This->write_pos;
170 else
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)
176 Sleep(10);
177 continue;
180 size2 = min(buf_free, size);
181 hr = IDirectSoundBuffer_Lock(This->dsbuffer, This->write_pos, size2, (LPVOID *)&lpbuf1, &dwsize1, (LPVOID *)&lpbuf2, &dwsize2, 0);
182 if (hr != DS_OK) {
183 ERR("Unable to lock sound buffer! (%x)\n", hr);
184 break;
186 /* TRACE("write_pos=%d, size=%d, sz1=%d, sz2=%d\n", This->write_pos, size2, dwsize1, dwsize2); */
188 memcpy(lpbuf1, data, dwsize1);
189 if (dwsize2)
190 memcpy(lpbuf2, data + dwsize1, dwsize2);
192 hr = IDirectSoundBuffer_Unlock(This->dsbuffer, lpbuf1, dwsize1, lpbuf2, dwsize2);
193 if (hr != DS_OK)
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;
202 This->write_loops++;
204 } while (size && This->state == State_Running);
206 return hr;
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;
215 HRESULT hr;
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);
223 if (FAILED(hr))
225 ERR("Cannot get pointer to sample data (%x)\n", hr);
226 return hr;
229 hr = IMediaSample_GetTime(pSample, &tStart, &tStop);
230 if (FAILED(hr))
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 */
239 int i;
240 for(i = 0; i < cbSrcStream; i++)
242 if ((i!=0) && !(i%16))
243 TRACE("\n");
244 TRACE("%02x ", pbSrcStream[i]);
246 TRACE("\n");
248 #endif
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))
264 return S_OK;
265 return S_FALSE;
268 HRESULT DSoundRender_create(IUnknown * pUnkOuter, LPVOID * ppv)
270 HRESULT hr;
271 PIN_INFO piInput;
272 DSoundRenderImpl * pDSoundRender;
274 TRACE("(%p, %p)\n", pUnkOuter, ppv);
276 *ppv = NULL;
278 if (pUnkOuter)
279 return CLASS_E_NOAGGREGATION;
281 pDSoundRender = CoTaskMemAlloc(sizeof(DSoundRenderImpl));
282 if (!pDSoundRender)
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);
309 if (SUCCEEDED(hr))
311 hr = DirectSoundCreate(NULL, &pDSoundRender->dsound, NULL);
312 if (FAILED(hr))
313 ERR("Cannot create Direct Sound object (%x)\n", hr);
316 if (SUCCEEDED(hr))
318 pDSoundRender->ppPins[0] = (IPin *)pDSoundRender->pInputPin;
319 *ppv = (LPVOID)pDSoundRender;
321 else
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);
331 return hr;
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);
339 *ppv = NULL;
341 if (IsEqualIID(riid, &IID_IUnknown))
342 *ppv = (LPVOID)This;
343 else if (IsEqualIID(riid, &IID_IPersist))
344 *ppv = (LPVOID)This;
345 else if (IsEqualIID(riid, &IID_IMediaFilter))
346 *ppv = (LPVOID)This;
347 else if (IsEqualIID(riid, &IID_IBaseFilter))
348 *ppv = (LPVOID)This;
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);
354 if (*ppv)
356 IUnknown_AddRef((IUnknown *)(*ppv));
357 return S_OK;
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);
372 return refCount;
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);
382 if (!refCount)
384 IPin *pConnectedTo;
386 if (This->pClock)
387 IReferenceClock_Release(This->pClock);
389 if (This->dsbuffer)
390 IDirectSoundBuffer_Release(This->dsbuffer);
391 This->dsbuffer = NULL;
392 if (This->dsound)
393 IDirectSound_Release(This->dsound);
394 This->dsound = NULL;
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);
406 This->lpVtbl = NULL;
407 This->IBasicAudio_vtbl = NULL;
409 This->csFilter.DebugInfo->Spare[0] = 0;
410 DeleteCriticalSection(&This->csFilter);
412 TRACE("Destroying Audio Renderer\n");
413 CoTaskMemFree(This);
415 return 0;
417 else
418 return refCount;
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;
430 return S_OK;
433 /** IMediaFilter methods **/
435 static HRESULT WINAPI DSoundRender_Stop(IBaseFilter * iface)
437 HRESULT hr = S_OK;
438 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
440 TRACE("(%p/%p)->()\n", This, iface);
442 EnterCriticalSection(&This->csFilter);
444 DWORD state = 0;
445 if (This->dsbuffer)
447 hr = IDirectSoundBuffer_GetStatus(This->dsbuffer, &state);
448 if (SUCCEEDED(hr))
450 if (state & DSBSTATUS_PLAYING)
451 hr = IDirectSoundBuffer_Stop(This->dsbuffer);
454 if (SUCCEEDED(hr))
455 This->state = State_Stopped;
457 LeaveCriticalSection(&This->csFilter);
459 return hr;
462 static HRESULT WINAPI DSoundRender_Pause(IBaseFilter * iface)
464 HRESULT hr = S_OK;
465 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
467 TRACE("(%p/%p)->()\n", This, iface);
469 EnterCriticalSection(&This->csFilter);
471 DWORD state = 0;
472 if (This->dsbuffer)
474 hr = IDirectSoundBuffer_GetStatus(This->dsbuffer, &state);
475 if (SUCCEEDED(hr))
477 if (state & DSBSTATUS_PLAYING)
478 hr = IDirectSoundBuffer_Stop(This->dsbuffer);
481 if (SUCCEEDED(hr))
482 This->state = State_Paused;
484 LeaveCriticalSection(&This->csFilter);
486 return hr;
489 static HRESULT WINAPI DSoundRender_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
491 HRESULT hr = S_OK;
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 */
499 if (This->dsbuffer)
501 hr = IDirectSoundBuffer_Play(This->dsbuffer, 0, 0, DSBPLAY_LOOPING);
502 if (FAILED(hr))
503 ERR("Can't start playing! (%x)\n", hr);
505 if (SUCCEEDED(hr))
507 This->rtStreamStart = tStart;
508 This->state = State_Running;
511 LeaveCriticalSection(&This->csFilter);
513 return hr;
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);
528 return S_OK;
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);
539 if (This->pClock)
540 IReferenceClock_Release(This->pClock);
541 This->pClock = pClock;
542 if (This->pClock)
543 IReferenceClock_AddRef(This->pClock);
545 LeaveCriticalSection(&This->csFilter);
547 return S_OK;
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);
563 return S_OK;
566 /** IBaseFilter implementation **/
568 static HRESULT WINAPI DSoundRender_EnumPins(IBaseFilter * iface, IEnumPins **ppEnum)
570 ENUMPINDETAILS epd;
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 */
590 return E_NOTIMPL;
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;
602 if (pInfo->pGraph)
603 IFilterGraph_AddRef(pInfo->pGraph);
605 return S_OK;
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);
616 if (pName)
617 strcpyW(This->filterInfo.achName, pName);
618 else
619 *This->filterInfo.achName = '\0';
620 This->filterInfo.pGraph = pGraph; /* NOTE: do NOT increase ref. count */
622 LeaveCriticalSection(&This->csFilter);
624 return S_OK;
627 static HRESULT WINAPI DSoundRender_QueryVendorInfo(IBaseFilter * iface, LPWSTR *pVendorInfo)
629 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
630 TRACE("(%p/%p)->(%p)\n", This, iface, pVendorInfo);
631 return E_NOTIMPL;
634 static const IBaseFilterVtbl DSoundRender_Vtbl =
636 DSoundRender_QueryInterface,
637 DSoundRender_AddRef,
638 DSoundRender_Release,
639 DSoundRender_GetClassID,
640 DSoundRender_Stop,
641 DSoundRender_Pause,
642 DSoundRender_Run,
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;
658 HRESULT hr = S_OK;
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;
673 if (SUCCEEDED(hr))
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;
684 if (SUCCEEDED(hr))
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);
706 if (FAILED(hr))
707 ERR("Can't create sound buffer (%x)\n", hr);
710 if (SUCCEEDED(hr))
712 hr = IDirectSoundBuffer_SetVolume(DSImpl->dsbuffer, DSImpl->volume);
713 if (FAILED(hr))
714 ERR("Can't set volume to %ld (%x)\n", DSImpl->volume, hr);
716 hr = IDirectSoundBuffer_SetPan(DSImpl->dsbuffer, DSImpl->pan);
717 if (FAILED(hr))
718 ERR("Can't set pan to %ld (%x)\n", DSImpl->pan, hr);
720 DSImpl->write_pos = 0;
721 hr = S_OK;
722 if (DSImpl->state == State_Running)
723 hr = IDirectSoundBuffer_Play(DSImpl->dsbuffer, 0, 0, DSBPLAY_LOOPING);
724 if (FAILED(hr))
725 ERR("Can't play sound buffer (%x)\n", hr);
728 if (SUCCEEDED(hr))
730 CopyMediaType(&This->pin.mtCurrent, pmt);
731 This->pin.pConnectedTo = pReceivePin;
732 IPin_AddRef(pReceivePin);
734 else
736 if (DSImpl->dsbuffer)
737 IDirectSoundBuffer_Release(DSImpl->dsbuffer);
738 DSImpl->dsbuffer = NULL;
741 LeaveCriticalSection(This->pin.pCritSec);
743 return hr;
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;
765 HRESULT hr;
767 TRACE("(%p/%p)->()\n", This, iface);
769 hr = IFilterGraph_QueryInterface(((DSoundRenderImpl*)This->pin.pinInfo.pFilter)->filterInfo.pGraph, &IID_IMediaEventSink, (LPVOID*)&pEventSink);
770 if (SUCCEEDED(hr))
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);
777 return hr;
780 static const IPinVtbl DSoundRender_InputPin_Vtbl =
782 InputPin_QueryInterface,
783 IPinImpl_AddRef,
784 InputPin_Release,
785 InputPin_Connect,
786 DSoundRender_InputPin_ReceiveConnection,
787 DSoundRender_InputPin_Disconnect,
788 IPinImpl_ConnectedTo,
789 IPinImpl_ConnectionMediaType,
790 IPinImpl_QueryPinInfo,
791 IPinImpl_QueryDirection,
792 IPinImpl_QueryId,
793 IPinImpl_QueryAccept,
794 IPinImpl_EnumMediaTypes,
795 IPinImpl_QueryInternalConnections,
796 DSoundRender_InputPin_EndOfStream,
797 InputPin_BeginFlush,
798 InputPin_EndFlush,
799 InputPin_NewSegment
802 static const IMemInputPinVtbl MemInputPin_Vtbl =
804 MemInputPin_QueryInterface,
805 MemInputPin_AddRef,
806 MemInputPin_Release,
807 MemInputPin_GetAllocator,
808 MemInputPin_NotifyAllocator,
809 MemInputPin_GetAllocatorRequirements,
810 MemInputPin_Receive,
811 MemInputPin_ReceiveMultiple,
812 MemInputPin_ReceiveCanBlock
815 /*** IUnknown methods ***/
816 static HRESULT WINAPI Basicaudio_QueryInterface(IBasicAudio *iface,
817 REFIID riid,
818 LPVOID*ppvObj) {
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,
844 UINT*pctinfo) {
845 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
847 TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pctinfo);
849 return S_OK;
852 static HRESULT WINAPI Basicaudio_GetTypeInfo(IBasicAudio *iface,
853 UINT iTInfo,
854 LCID lcid,
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);
860 return S_OK;
863 static HRESULT WINAPI Basicaudio_GetIDsOfNames(IBasicAudio *iface,
864 REFIID riid,
865 LPOLESTR*rgszNames,
866 UINT cNames,
867 LCID lcid,
868 DISPID*rgDispId) {
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);
873 return S_OK;
876 static HRESULT WINAPI Basicaudio_Invoke(IBasicAudio *iface,
877 DISPID dispIdMember,
878 REFIID riid,
879 LCID lcid,
880 WORD wFlags,
881 DISPPARAMS*pDispParams,
882 VARIANT*pVarResult,
883 EXCEPINFO*pExepInfo,
884 UINT*puArgErr) {
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);
889 return S_OK;
892 /*** IBasicAudio methods ***/
893 static HRESULT WINAPI Basicaudio_put_Volume(IBasicAudio *iface,
894 long lVolume) {
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)
900 return E_INVALIDARG;
902 if (This->dsbuffer) {
903 if (FAILED(IDirectSoundBuffer_SetVolume(This->dsbuffer, lVolume)))
904 return E_FAIL;
907 This->volume = lVolume;
908 return S_OK;
911 static HRESULT WINAPI Basicaudio_get_Volume(IBasicAudio *iface,
912 long *plVolume) {
913 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
915 TRACE("(%p/%p)->(%p)\n", This, iface, plVolume);
917 if (!plVolume)
918 return E_POINTER;
920 *plVolume = This->volume;
921 return S_OK;
924 static HRESULT WINAPI Basicaudio_put_Balance(IBasicAudio *iface,
925 long lBalance) {
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)
931 return E_INVALIDARG;
933 if (This->dsbuffer) {
934 if (FAILED(IDirectSoundBuffer_SetPan(This->dsbuffer, lBalance)))
935 return E_FAIL;
938 This->pan = lBalance;
939 return S_OK;
942 static HRESULT WINAPI Basicaudio_get_Balance(IBasicAudio *iface,
943 long *plBalance) {
944 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
946 TRACE("(%p/%p)->(%p)\n", This, iface, plBalance);
948 if (!plBalance)
949 return E_POINTER;
951 *plBalance = This->pan;
952 return S_OK;
955 static const IBasicAudioVtbl IBasicAudio_Vtbl =
957 Basicaudio_QueryInterface,
958 Basicaudio_AddRef,
959 Basicaudio_Release,
960 Basicaudio_GetTypeInfoCount,
961 Basicaudio_GetTypeInfo,
962 Basicaudio_GetIDsOfNames,
963 Basicaudio_Invoke,
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,
973 REFIID riid,
974 LPVOID*ppvObj)
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;
1007 DWORD play_pos;
1009 TRACE("(%p/%p)->(%p)\n", This, iface, pTime);
1011 if (This->dsbuffer)
1012 hr = DSoundRender_GetPos(This, &play_pos, NULL, pTime);
1013 if (FAILED(hr))
1014 ERR("Could not get refreence time (%x)!\n", hr);
1016 return hr;
1019 static HRESULT WINAPI ReferenceClock_AdviseTime(IReferenceClock *iface,
1020 REFERENCE_TIME rtBaseTime,
1021 REFERENCE_TIME rtStreamTime,
1022 HEVENT hEvent,
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);
1029 return E_NOTIMPL;
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);
1042 return E_NOTIMPL;
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);
1052 return S_FALSE;
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