strmbase: Move BasePin implementation to strmbase.
[wine/multimedia.git] / dlls / quartz / dsoundrender.c
blob63846ce3b25bc7a91078568149da145d88c734db
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"
35 #include "amaudio.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;
57 IUnknown *seekthru_unk;
59 LONG refCount;
60 CRITICAL_SECTION csFilter;
61 FILTER_STATE state;
62 REFERENCE_TIME rtStreamStart, rtLastStop;
63 IReferenceClock * pClock;
64 FILTER_INFO filterInfo;
66 InputPin * pInputPin;
68 IDirectSound8 *dsound;
69 LPDIRECTSOUNDBUFFER dsbuffer;
70 DWORD buf_size;
71 DWORD write_pos;
72 DWORD write_loops;
74 DWORD last_play_pos;
75 DWORD play_loops;
76 DWORD in_loop;
78 REFERENCE_TIME play_time;
80 HANDLE state_change, blocked;
82 LONG volume;
83 LONG pan;
84 } DSoundRenderImpl;
86 static inline HRESULT DSoundRender_GetPos(DSoundRenderImpl *This, DWORD *pPlayPos, REFERENCE_TIME *pRefTime)
88 HRESULT hr;
90 EnterCriticalSection(&This->csFilter);
92 DWORD state;
93 DWORD write_pos;
95 hr = IDirectSoundBuffer_GetStatus(This->dsbuffer, &state);
96 if (SUCCEEDED(hr) && !(state & DSBSTATUS_PLAYING) && This->state == State_Running)
98 TRACE("Not playing, kickstarting the engine\n");
100 hr = IDirectSoundBuffer_Play(This->dsbuffer, 0, 0, DSBPLAY_LOOPING);
101 if (FAILED(hr))
102 ERR("Can't play sound buffer (%x)\n", hr);
105 if (SUCCEEDED(hr))
106 hr = IDirectSoundBuffer_GetCurrentPosition(This->dsbuffer, pPlayPos, &write_pos);
107 if (hr == S_OK)
109 DWORD play_pos = *pPlayPos;
111 if (play_pos < This->last_play_pos)
112 This->play_loops++;
113 This->last_play_pos = play_pos;
115 /* If we really fell behind, start at the next possible position
116 * Also happens when just starting playback for the first time,
117 * or when flushing
119 if ((This->play_loops*This->buf_size)+play_pos >=
120 (This->write_loops*This->buf_size)+This->write_pos)
121 This->write_pos = write_pos;
123 if (pRefTime)
125 REFERENCE_TIME play_time;
126 play_time = ((REFERENCE_TIME)This->play_loops*10000000) +
127 ((REFERENCE_TIME)play_pos*10000000/This->buf_size);
129 /* Don't let time run backwards */
130 if(play_time-This->play_time > 0)
131 This->play_time = play_time;
132 else
133 hr = S_FALSE;
135 *pRefTime = This->play_time;
139 LeaveCriticalSection(&This->csFilter);
141 return hr;
144 static HRESULT DSoundRender_SendSampleData(DSoundRenderImpl* This, const BYTE *data, DWORD size)
146 HRESULT hr = S_OK;
147 LPBYTE lpbuf1 = NULL;
148 LPBYTE lpbuf2 = NULL;
149 DWORD dwsize1 = 0;
150 DWORD dwsize2 = 0;
151 DWORD size2;
152 DWORD play_pos,buf_free;
154 do {
156 hr = DSoundRender_GetPos(This, &play_pos, NULL);
157 if (hr != DS_OK)
159 ERR("GetPos returned error: %x\n", hr);
160 break;
162 if (This->write_pos <= play_pos)
163 buf_free = play_pos-This->write_pos;
164 else
165 buf_free = This->buf_size - This->write_pos + play_pos;
167 /* Wait for enough of the buffer to empty before filling it */
168 if(buf_free < This->buf_size/20)
170 DWORD ret;
171 This->in_loop = 1;
172 LeaveCriticalSection(&This->csFilter);
173 ret = WaitForSingleObject(This->blocked, 50);
174 if (ret != WAIT_TIMEOUT)
175 ERR("%x\n", ret);
176 EnterCriticalSection(&This->csFilter);
177 This->in_loop = 0;
178 if (This->pInputPin->flushing)
179 return VFW_E_WRONG_STATE;
180 if (This->state == State_Stopped)
181 return VFW_E_WRONG_STATE;
182 continue;
185 size2 = min(buf_free, size);
186 hr = IDirectSoundBuffer_Lock(This->dsbuffer, This->write_pos, size2, (LPVOID *)&lpbuf1, &dwsize1, (LPVOID *)&lpbuf2, &dwsize2, 0);
187 if (hr != DS_OK) {
188 ERR("Unable to lock sound buffer! (%x)\n", hr);
189 break;
191 /* TRACE("write_pos=%d, size=%d, sz1=%d, sz2=%d\n", This->write_pos, size2, dwsize1, dwsize2); */
193 memcpy(lpbuf1, data, dwsize1);
194 if (dwsize2)
195 memcpy(lpbuf2, data + dwsize1, dwsize2);
197 hr = IDirectSoundBuffer_Unlock(This->dsbuffer, lpbuf1, dwsize1, lpbuf2, dwsize2);
198 if (hr != DS_OK)
199 ERR("Unable to unlock sound buffer! (%x)\n", hr);
201 size -= dwsize1 + dwsize2;
202 data += dwsize1 + dwsize2;
203 This->write_pos += dwsize1 + dwsize2;
204 if (This->write_pos >= This->buf_size)
206 This->write_pos -= This->buf_size;
207 This->write_loops++;
209 } while (size && This->state == State_Running);
211 return hr;
214 static HRESULT DSoundRender_Sample(LPVOID iface, IMediaSample * pSample)
216 DSoundRenderImpl *This = iface;
217 LPBYTE pbSrcStream = NULL;
218 LONG cbSrcStream = 0;
219 REFERENCE_TIME tStart, tStop;
220 HRESULT hr;
221 AM_MEDIA_TYPE *amt;
223 TRACE("%p %p\n", iface, pSample);
225 /* Slightly incorrect, Pause completes when a frame is received so we should signal
226 * pause completion here, but for sound playing a single frame doesn't make sense
229 EnterCriticalSection(&This->csFilter);
231 if (This->pInputPin->end_of_stream || This->pInputPin->flushing)
233 LeaveCriticalSection(&This->csFilter);
234 return S_FALSE;
237 if (This->state == State_Stopped)
239 LeaveCriticalSection(&This->csFilter);
240 return VFW_E_WRONG_STATE;
243 if (IMediaSample_GetMediaType(pSample, &amt) == S_OK)
245 AM_MEDIA_TYPE *orig = &This->pInputPin->pin.mtCurrent;
246 WAVEFORMATEX *origfmt = (WAVEFORMATEX *)orig->pbFormat;
247 WAVEFORMATEX *newfmt = (WAVEFORMATEX *)amt->pbFormat;
249 if (origfmt->wFormatTag == newfmt->wFormatTag &&
250 origfmt->nChannels == newfmt->nChannels &&
251 origfmt->nBlockAlign == newfmt->nBlockAlign &&
252 origfmt->wBitsPerSample == newfmt->wBitsPerSample &&
253 origfmt->cbSize == newfmt->cbSize)
255 if (origfmt->nSamplesPerSec != newfmt->nSamplesPerSec)
257 hr = IDirectSoundBuffer_SetFrequency(This->dsbuffer,
258 newfmt->nSamplesPerSec);
259 if (FAILED(hr))
261 LeaveCriticalSection(&This->csFilter);
262 return VFW_E_TYPE_NOT_ACCEPTED;
264 FreeMediaType(orig);
265 CopyMediaType(orig, amt);
266 IMediaSample_SetMediaType(pSample, NULL);
269 else
271 LeaveCriticalSection(&This->csFilter);
272 return VFW_E_TYPE_NOT_ACCEPTED;
276 hr = IMediaSample_GetPointer(pSample, &pbSrcStream);
277 if (FAILED(hr))
279 ERR("Cannot get pointer to sample data (%x)\n", hr);
280 LeaveCriticalSection(&This->csFilter);
281 return hr;
284 hr = IMediaSample_GetTime(pSample, &tStart, &tStop);
285 if (FAILED(hr))
286 ERR("Cannot get sample time (%x)\n", hr);
287 else
288 MediaSeekingPassThru_RegisterMediaTime(This->seekthru_unk, tStart);
290 if (This->rtLastStop != tStart && (IMediaSample_IsDiscontinuity(pSample) == S_FALSE))
291 WARN("Unexpected discontinuity: Last: %u.%03u, tStart: %u.%03u\n",
292 (DWORD)(This->rtLastStop / 10000000), (DWORD)((This->rtLastStop / 10000)%1000),
293 (DWORD)(tStart / 10000000), (DWORD)((tStart / 10000)%1000));
294 This->rtLastStop = tStop;
296 if (IMediaSample_IsPreroll(pSample) == S_OK)
298 TRACE("Preroll!\n");
299 LeaveCriticalSection(&This->csFilter);
300 return S_OK;
303 if (This->state == State_Paused)
305 SetEvent(This->state_change);
306 LeaveCriticalSection(&This->csFilter);
307 WaitForSingleObject(This->blocked, INFINITE);
308 EnterCriticalSection(&This->csFilter);
309 if (This->state == State_Stopped)
311 LeaveCriticalSection(&This->csFilter);
312 return VFW_E_WRONG_STATE;
315 if (This->state == State_Paused)
317 /* Assuming we return because of flushing */
318 TRACE("Flushing\n");
319 LeaveCriticalSection(&This->csFilter);
320 return S_OK;
322 SetEvent(This->state_change);
325 cbSrcStream = IMediaSample_GetActualDataLength(pSample);
326 TRACE("Sample data ptr = %p, size = %d\n", pbSrcStream, cbSrcStream);
328 #if 0 /* For debugging purpose */
330 int i;
331 for(i = 0; i < cbSrcStream; i++)
333 if ((i!=0) && !(i%16))
334 TRACE("\n");
335 TRACE("%02x ", pbSrcStream[i]);
337 TRACE("\n");
339 #endif
341 hr = DSoundRender_SendSampleData(This, pbSrcStream, cbSrcStream);
342 SetEvent(This->state_change);
343 LeaveCriticalSection(&This->csFilter);
344 return hr;
347 static HRESULT DSoundRender_QueryAccept(LPVOID iface, const AM_MEDIA_TYPE * pmt)
349 WAVEFORMATEX* format;
351 if (!IsEqualIID(&pmt->majortype, &MEDIATYPE_Audio))
352 return S_FALSE;
354 format = (WAVEFORMATEX*)pmt->pbFormat;
355 TRACE("Format = %p\n", format);
356 TRACE("wFormatTag = %x %x\n", format->wFormatTag, WAVE_FORMAT_PCM);
357 TRACE("nChannels = %d\n", format->nChannels);
358 TRACE("nSamplesPerSec = %d\n", format->nAvgBytesPerSec);
359 TRACE("nAvgBytesPerSec = %d\n", format->nAvgBytesPerSec);
360 TRACE("nBlockAlign = %d\n", format->nBlockAlign);
361 TRACE("wBitsPerSample = %d\n", format->wBitsPerSample);
363 if (!IsEqualIID(&pmt->subtype, &MEDIASUBTYPE_PCM))
364 return S_FALSE;
366 return S_OK;
369 HRESULT DSoundRender_create(IUnknown * pUnkOuter, LPVOID * ppv)
371 HRESULT hr;
372 PIN_INFO piInput;
373 DSoundRenderImpl * pDSoundRender;
375 TRACE("(%p, %p)\n", pUnkOuter, ppv);
377 *ppv = NULL;
379 if (pUnkOuter)
380 return CLASS_E_NOAGGREGATION;
382 pDSoundRender = CoTaskMemAlloc(sizeof(DSoundRenderImpl));
383 if (!pDSoundRender)
384 return E_OUTOFMEMORY;
385 ZeroMemory(pDSoundRender, sizeof(DSoundRenderImpl));
387 pDSoundRender->lpVtbl = &DSoundRender_Vtbl;
388 pDSoundRender->IBasicAudio_vtbl = &IBasicAudio_Vtbl;
389 pDSoundRender->IReferenceClock_vtbl = &IReferenceClock_Vtbl;
390 pDSoundRender->IAMDirectSound_vtbl = &IAMDirectSound_Vtbl;
391 pDSoundRender->refCount = 1;
392 InitializeCriticalSection(&pDSoundRender->csFilter);
393 pDSoundRender->csFilter.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": DSoundRenderImpl.csFilter");
394 pDSoundRender->state = State_Stopped;
396 /* construct input pin */
397 piInput.dir = PINDIR_INPUT;
398 piInput.pFilter = (IBaseFilter *)pDSoundRender;
399 lstrcpynW(piInput.achName, wcsInputPinName, sizeof(piInput.achName) / sizeof(piInput.achName[0]));
400 hr = InputPin_Construct(&DSoundRender_InputPin_Vtbl, &piInput, DSoundRender_Sample, pDSoundRender, DSoundRender_QueryAccept, NULL, &pDSoundRender->csFilter, NULL, (IPin **)&pDSoundRender->pInputPin);
402 if (SUCCEEDED(hr))
404 hr = DirectSoundCreate8(NULL, &pDSoundRender->dsound, NULL);
405 if (FAILED(hr))
406 ERR("Cannot create Direct Sound object (%x)\n", hr);
407 else
408 IDirectSound_SetCooperativeLevel(pDSoundRender->dsound, GetDesktopWindow(), DSSCL_PRIORITY);
411 if (SUCCEEDED(hr))
413 ISeekingPassThru *passthru;
414 pDSoundRender->state_change = CreateEventW(NULL, TRUE, TRUE, NULL);
415 pDSoundRender->blocked = CreateEventW(NULL, TRUE, TRUE, NULL);
416 hr = CoCreateInstance(&CLSID_SeekingPassThru, (IUnknown*)pDSoundRender, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void**)&pDSoundRender->seekthru_unk);
417 if (!pDSoundRender->state_change || !pDSoundRender->blocked || FAILED(hr))
419 IUnknown_Release((IUnknown *)pDSoundRender);
420 return HRESULT_FROM_WIN32(GetLastError());
423 IUnknown_QueryInterface(pDSoundRender->seekthru_unk, &IID_ISeekingPassThru, (void**)&passthru);
424 ISeekingPassThru_Init(passthru, TRUE, (IPin*)pDSoundRender->pInputPin);
425 ISeekingPassThru_Release(passthru);
426 *ppv = pDSoundRender;
428 else
430 if (pDSoundRender->pInputPin)
431 IPin_Release((IPin*)pDSoundRender->pInputPin);
432 pDSoundRender->csFilter.DebugInfo->Spare[0] = 0;
433 DeleteCriticalSection(&pDSoundRender->csFilter);
434 CoTaskMemFree(pDSoundRender);
437 return hr;
440 static HRESULT WINAPI DSoundRender_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv)
442 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
443 TRACE("(%p, %p)->(%s, %p)\n", This, iface, qzdebugstr_guid(riid), ppv);
445 *ppv = NULL;
447 if (IsEqualIID(riid, &IID_IUnknown))
448 *ppv = This;
449 else if (IsEqualIID(riid, &IID_IPersist))
450 *ppv = This;
451 else if (IsEqualIID(riid, &IID_IMediaFilter))
452 *ppv = This;
453 else if (IsEqualIID(riid, &IID_IBaseFilter))
454 *ppv = This;
455 else if (IsEqualIID(riid, &IID_IBasicAudio))
456 *ppv = &This->IBasicAudio_vtbl;
457 else if (IsEqualIID(riid, &IID_IReferenceClock))
458 *ppv = &This->IReferenceClock_vtbl;
459 else if (IsEqualIID(riid, &IID_IMediaSeeking))
460 return IUnknown_QueryInterface(This->seekthru_unk, riid, ppv);
461 else if (IsEqualIID(riid, &IID_IAMDirectSound))
462 *ppv = &This->IAMDirectSound_vtbl;
464 if (*ppv)
466 IUnknown_AddRef((IUnknown *)(*ppv));
467 return S_OK;
470 if (!IsEqualIID(riid, &IID_IPin) && !IsEqualIID(riid, &IID_IVideoWindow))
471 FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
473 return E_NOINTERFACE;
476 static ULONG WINAPI DSoundRender_AddRef(IBaseFilter * iface)
478 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
479 ULONG refCount = InterlockedIncrement(&This->refCount);
481 TRACE("(%p/%p)->() AddRef from %d\n", This, iface, refCount - 1);
483 return refCount;
486 static ULONG WINAPI DSoundRender_Release(IBaseFilter * iface)
488 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
489 ULONG refCount = InterlockedDecrement(&This->refCount);
491 TRACE("(%p)->() Release from %d\n", This, refCount + 1);
493 if (!refCount)
495 IPin *pConnectedTo;
497 if (This->pClock)
498 IReferenceClock_Release(This->pClock);
500 if (This->dsbuffer)
501 IDirectSoundBuffer_Release(This->dsbuffer);
502 This->dsbuffer = NULL;
503 if (This->dsound)
504 IDirectSound_Release(This->dsound);
505 This->dsound = NULL;
507 if (SUCCEEDED(IPin_ConnectedTo((IPin *)This->pInputPin, &pConnectedTo)))
509 IPin_Disconnect(pConnectedTo);
510 IPin_Release(pConnectedTo);
512 IPin_Disconnect((IPin *)This->pInputPin);
514 IPin_Release((IPin *)This->pInputPin);
516 This->lpVtbl = NULL;
517 This->IBasicAudio_vtbl = NULL;
518 if (This->seekthru_unk)
519 IUnknown_Release(This->seekthru_unk);
520 This->csFilter.DebugInfo->Spare[0] = 0;
521 DeleteCriticalSection(&This->csFilter);
523 CloseHandle(This->state_change);
524 CloseHandle(This->blocked);
526 TRACE("Destroying Audio Renderer\n");
527 CoTaskMemFree(This);
529 return 0;
531 else
532 return refCount;
535 /** IPersist methods **/
537 static HRESULT WINAPI DSoundRender_GetClassID(IBaseFilter * iface, CLSID * pClsid)
539 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
540 TRACE("(%p/%p)->(%p)\n", This, iface, pClsid);
542 *pClsid = CLSID_DSoundRender;
544 return S_OK;
547 /** IMediaFilter methods **/
549 static HRESULT WINAPI DSoundRender_Stop(IBaseFilter * iface)
551 HRESULT hr = S_OK;
552 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
554 TRACE("(%p/%p)->()\n", This, iface);
556 EnterCriticalSection(&This->csFilter);
558 DWORD state = 0;
559 if (This->dsbuffer)
561 hr = IDirectSoundBuffer_GetStatus(This->dsbuffer, &state);
562 if (SUCCEEDED(hr))
564 if (state & DSBSTATUS_PLAYING)
565 hr = IDirectSoundBuffer_Stop(This->dsbuffer);
568 if (SUCCEEDED(hr))
569 This->state = State_Stopped;
571 /* Complete our transition */
572 SetEvent(This->state_change);
573 SetEvent(This->blocked);
574 MediaSeekingPassThru_ResetMediaTime(This->seekthru_unk);
576 LeaveCriticalSection(&This->csFilter);
578 return hr;
581 static HRESULT WINAPI DSoundRender_Pause(IBaseFilter * iface)
583 HRESULT hr = S_OK;
584 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
586 TRACE("(%p/%p)->()\n", This, iface);
588 EnterCriticalSection(&This->csFilter);
589 if (This->state != State_Paused)
591 DWORD state = 0;
592 if (This->state == State_Stopped)
594 This->pInputPin->end_of_stream = 0;
597 if (This->dsbuffer)
599 hr = IDirectSoundBuffer_GetStatus(This->dsbuffer, &state);
600 if (SUCCEEDED(hr))
602 if (state & DSBSTATUS_PLAYING)
603 hr = IDirectSoundBuffer_Stop(This->dsbuffer);
606 if (SUCCEEDED(hr))
607 This->state = State_Paused;
609 ResetEvent(This->blocked);
610 ResetEvent(This->state_change);
612 LeaveCriticalSection(&This->csFilter);
614 return hr;
617 static HRESULT WINAPI DSoundRender_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
619 HRESULT hr = S_OK;
620 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
622 TRACE("(%p/%p)->(%s)\n", This, iface, wine_dbgstr_longlong(tStart));
624 EnterCriticalSection(&This->csFilter);
626 This->rtStreamStart = tStart;
627 if (This->state == State_Paused)
629 /* Unblock our thread, state changing from paused to running doesn't need a reset for state change */
630 SetEvent(This->blocked);
632 else if (This->state == State_Stopped)
634 ResetEvent(This->state_change);
635 This->pInputPin->end_of_stream = 0;
637 ResetEvent(This->blocked);
639 This->state = State_Running;
641 LeaveCriticalSection(&This->csFilter);
643 return hr;
646 static HRESULT WINAPI DSoundRender_GetState(IBaseFilter * iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState)
648 HRESULT hr;
649 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
651 TRACE("(%p/%p)->(%d, %p)\n", This, iface, dwMilliSecsTimeout, pState);
653 if (WaitForSingleObject(This->state_change, dwMilliSecsTimeout) == WAIT_TIMEOUT)
654 hr = VFW_S_STATE_INTERMEDIATE;
655 else
656 hr = S_OK;
658 EnterCriticalSection(&This->csFilter);
660 *pState = This->state;
662 LeaveCriticalSection(&This->csFilter);
664 return hr;
667 static HRESULT WINAPI DSoundRender_SetSyncSource(IBaseFilter * iface, IReferenceClock *pClock)
669 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
671 TRACE("(%p/%p)->(%p)\n", This, iface, pClock);
673 EnterCriticalSection(&This->csFilter);
675 if (This->pClock)
676 IReferenceClock_Release(This->pClock);
677 This->pClock = pClock;
678 if (This->pClock)
679 IReferenceClock_AddRef(This->pClock);
681 LeaveCriticalSection(&This->csFilter);
683 return S_OK;
686 static HRESULT WINAPI DSoundRender_GetSyncSource(IBaseFilter * iface, IReferenceClock **ppClock)
688 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
690 TRACE("(%p/%p)->(%p)\n", This, iface, ppClock);
692 EnterCriticalSection(&This->csFilter);
694 *ppClock = This->pClock;
695 if (This->pClock)
696 IReferenceClock_AddRef(This->pClock);
698 LeaveCriticalSection(&This->csFilter);
700 return S_OK;
703 /** IBaseFilter implementation **/
705 static IPin* WINAPI DSoundRender_GetPin(IBaseFilter *iface, int pos)
707 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
709 if (pos >= 1 || pos < 0)
710 return NULL;
712 IPin_AddRef((IPin*)This->pInputPin);
713 return (IPin*)This->pInputPin;
716 static LONG WINAPI DSoundRender_GetPinCount(IBaseFilter *iface)
718 /* Our pins are static, not changing so setting static tick count is ok */
719 return 1;
722 static LONG WINAPI DSoundRender_GetPinVersion(IBaseFilter *iface)
724 /* Our pins are static, not changing so setting static tick count is ok */
725 return 0;
728 static HRESULT WINAPI DSoundRender_EnumPins(IBaseFilter * iface, IEnumPins **ppEnum)
730 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
732 TRACE("(%p/%p)->(%p)\n", This, iface, ppEnum);
734 return EnumPins_Construct(iface, DSoundRender_GetPin, DSoundRender_GetPinCount, DSoundRender_GetPinVersion, ppEnum);
737 static HRESULT WINAPI DSoundRender_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin)
739 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
741 TRACE("(%p/%p)->(%s,%p)\n", This, iface, debugstr_w(Id), ppPin);
743 FIXME("DSoundRender::FindPin(...)\n");
745 /* FIXME: critical section */
747 return E_NOTIMPL;
750 static HRESULT WINAPI DSoundRender_QueryFilterInfo(IBaseFilter * iface, FILTER_INFO *pInfo)
752 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
754 TRACE("(%p/%p)->(%p)\n", This, iface, pInfo);
756 strcpyW(pInfo->achName, This->filterInfo.achName);
757 pInfo->pGraph = This->filterInfo.pGraph;
759 if (pInfo->pGraph)
760 IFilterGraph_AddRef(pInfo->pGraph);
762 return S_OK;
765 static HRESULT WINAPI DSoundRender_JoinFilterGraph(IBaseFilter * iface, IFilterGraph *pGraph, LPCWSTR pName)
767 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
769 TRACE("(%p/%p)->(%p, %s)\n", This, iface, pGraph, debugstr_w(pName));
771 EnterCriticalSection(&This->csFilter);
773 if (pName)
774 strcpyW(This->filterInfo.achName, pName);
775 else
776 *This->filterInfo.achName = '\0';
777 This->filterInfo.pGraph = pGraph; /* NOTE: do NOT increase ref. count */
779 LeaveCriticalSection(&This->csFilter);
781 return S_OK;
784 static HRESULT WINAPI DSoundRender_QueryVendorInfo(IBaseFilter * iface, LPWSTR *pVendorInfo)
786 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
787 TRACE("(%p/%p)->(%p)\n", This, iface, pVendorInfo);
788 return E_NOTIMPL;
791 static const IBaseFilterVtbl DSoundRender_Vtbl =
793 DSoundRender_QueryInterface,
794 DSoundRender_AddRef,
795 DSoundRender_Release,
796 DSoundRender_GetClassID,
797 DSoundRender_Stop,
798 DSoundRender_Pause,
799 DSoundRender_Run,
800 DSoundRender_GetState,
801 DSoundRender_SetSyncSource,
802 DSoundRender_GetSyncSource,
803 DSoundRender_EnumPins,
804 DSoundRender_FindPin,
805 DSoundRender_QueryFilterInfo,
806 DSoundRender_JoinFilterGraph,
807 DSoundRender_QueryVendorInfo
810 static HRESULT WINAPI DSoundRender_InputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
812 InputPin *This = (InputPin *)iface;
813 PIN_DIRECTION pindirReceive;
814 DSoundRenderImpl *DSImpl;
815 HRESULT hr = S_OK;
817 TRACE("(%p)->(%p, %p)\n", This, pReceivePin, pmt);
818 dump_AM_MEDIA_TYPE(pmt);
820 EnterCriticalSection(This->pin.pCritSec);
822 DSImpl = (DSoundRenderImpl*)This->pin.pinInfo.pFilter;
823 DSImpl->rtLastStop = -1;
825 if (This->pin.pConnectedTo)
826 hr = VFW_E_ALREADY_CONNECTED;
828 if (SUCCEEDED(hr) && This->fnQueryAccept(This->pUserData, pmt) != S_OK)
829 hr = VFW_E_TYPE_NOT_ACCEPTED;
831 if (SUCCEEDED(hr))
833 IPin_QueryDirection(pReceivePin, &pindirReceive);
835 if (pindirReceive != PINDIR_OUTPUT)
837 ERR("Can't connect from non-output pin\n");
838 hr = VFW_E_INVALID_DIRECTION;
842 if (SUCCEEDED(hr))
844 WAVEFORMATEX *format;
845 DSBUFFERDESC buf_desc;
847 TRACE("MajorType %s\n", debugstr_guid(&pmt->majortype));
848 TRACE("SubType %s\n", debugstr_guid(&pmt->subtype));
849 TRACE("Format %s\n", debugstr_guid(&pmt->formattype));
850 TRACE("Size %d\n", pmt->cbFormat);
852 format = (WAVEFORMATEX*)pmt->pbFormat;
854 DSImpl->buf_size = format->nAvgBytesPerSec;
856 memset(&buf_desc,0,sizeof(DSBUFFERDESC));
857 buf_desc.dwSize = sizeof(DSBUFFERDESC);
858 buf_desc.dwFlags = DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLPAN |
859 DSBCAPS_CTRLFREQUENCY |
860 DSBCAPS_GETCURRENTPOSITION2;
861 buf_desc.dwBufferBytes = DSImpl->buf_size;
862 buf_desc.lpwfxFormat = format;
863 hr = IDirectSound_CreateSoundBuffer(DSImpl->dsound, &buf_desc, &DSImpl->dsbuffer, NULL);
864 if (FAILED(hr))
865 ERR("Can't create sound buffer (%x)\n", hr);
868 if (SUCCEEDED(hr))
870 hr = IDirectSoundBuffer_SetVolume(DSImpl->dsbuffer, DSImpl->volume);
871 if (FAILED(hr))
872 ERR("Can't set volume to %d (%x)\n", DSImpl->volume, hr);
874 hr = IDirectSoundBuffer_SetPan(DSImpl->dsbuffer, DSImpl->pan);
875 if (FAILED(hr))
876 ERR("Can't set pan to %d (%x)\n", DSImpl->pan, hr);
878 DSImpl->write_pos = 0;
879 hr = S_OK;
882 if (SUCCEEDED(hr))
884 CopyMediaType(&This->pin.mtCurrent, pmt);
885 This->pin.pConnectedTo = pReceivePin;
886 IPin_AddRef(pReceivePin);
888 else if (hr != VFW_E_ALREADY_CONNECTED)
890 if (DSImpl->dsbuffer)
891 IDirectSoundBuffer_Release(DSImpl->dsbuffer);
892 DSImpl->dsbuffer = NULL;
895 LeaveCriticalSection(This->pin.pCritSec);
897 return hr;
900 static HRESULT WINAPI DSoundRender_InputPin_Disconnect(IPin * iface)
902 BasePin *This = (BasePin*)iface;
903 DSoundRenderImpl *DSImpl;
905 TRACE("(%p)->()\n", iface);
907 DSImpl = (DSoundRenderImpl*)This->pinInfo.pFilter;
908 if (DSImpl->dsbuffer)
909 IDirectSoundBuffer_Release(DSImpl->dsbuffer);
910 DSImpl->dsbuffer = NULL;
912 return BasePinImpl_Disconnect(iface);
915 static HRESULT WINAPI DSoundRender_InputPin_EndOfStream(IPin * iface)
917 InputPin* This = (InputPin*)iface;
918 DSoundRenderImpl *me = (DSoundRenderImpl*)This->pin.pinInfo.pFilter;
919 IMediaEventSink* pEventSink;
920 HRESULT hr;
922 EnterCriticalSection(This->pin.pCritSec);
924 TRACE("(%p/%p)->()\n", This, iface);
925 hr = InputPin_EndOfStream(iface);
926 if (hr != S_OK)
928 ERR("%08x\n", hr);
929 LeaveCriticalSection(This->pin.pCritSec);
930 return hr;
933 hr = IFilterGraph_QueryInterface(me->filterInfo.pGraph, &IID_IMediaEventSink, (LPVOID*)&pEventSink);
934 if (SUCCEEDED(hr))
936 BYTE * silence;
938 silence = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, me->buf_size);
939 if (silence)
941 memset(silence, 0, me->buf_size);
942 DSoundRender_SendSampleData((DSoundRenderImpl*)This->pin.pinInfo.pFilter, silence, me->buf_size);
943 HeapFree(GetProcessHeap(), 0, silence);
946 hr = IMediaEventSink_Notify(pEventSink, EC_COMPLETE, S_OK, 0);
947 IMediaEventSink_Release(pEventSink);
949 MediaSeekingPassThru_EOS(me->seekthru_unk);
950 LeaveCriticalSection(This->pin.pCritSec);
952 return hr;
955 static HRESULT WINAPI DSoundRender_InputPin_BeginFlush(IPin * iface)
957 InputPin *This = (InputPin *)iface;
958 DSoundRenderImpl *pFilter = (DSoundRenderImpl *)This->pin.pinInfo.pFilter;
959 HRESULT hr;
961 TRACE("\n");
963 EnterCriticalSection(This->pin.pCritSec);
964 hr = InputPin_BeginFlush(iface);
965 SetEvent(pFilter->blocked);
966 LeaveCriticalSection(This->pin.pCritSec);
968 return hr;
971 static HRESULT WINAPI DSoundRender_InputPin_EndFlush(IPin * iface)
973 InputPin *This = (InputPin *)iface;
974 DSoundRenderImpl *pFilter = (DSoundRenderImpl *)This->pin.pinInfo.pFilter;
975 HRESULT hr;
977 TRACE("\n");
979 EnterCriticalSection(This->pin.pCritSec);
980 if (pFilter->in_loop) {
981 ResetEvent(pFilter->state_change);
982 LeaveCriticalSection(This->pin.pCritSec);
983 WaitForSingleObject(pFilter->state_change, -1);
984 EnterCriticalSection(This->pin.pCritSec);
986 if (pFilter->state != State_Stopped)
987 ResetEvent(pFilter->blocked);
989 if (pFilter->dsbuffer)
991 LPBYTE buffer;
992 DWORD size;
993 IDirectSoundBuffer_Stop(pFilter->dsbuffer);
995 /* Force a reset */
996 IDirectSoundBuffer_SetCurrentPosition(pFilter->dsbuffer, 0);
997 pFilter->write_pos = pFilter->last_play_pos = 0;
998 ++pFilter->play_loops;
999 pFilter->write_loops = pFilter->play_loops;
1001 IDirectSoundBuffer_Lock(pFilter->dsbuffer, 0, 0, (LPVOID *)&buffer, &size, NULL, NULL, DSBLOCK_ENTIREBUFFER);
1002 memset(buffer, 0, size);
1003 IDirectSoundBuffer_Unlock(pFilter->dsbuffer, buffer, size, NULL, 0);
1005 hr = InputPin_EndFlush(iface);
1006 LeaveCriticalSection(This->pin.pCritSec);
1007 MediaSeekingPassThru_ResetMediaTime(pFilter->seekthru_unk);
1009 return hr;
1012 static const IPinVtbl DSoundRender_InputPin_Vtbl =
1014 InputPin_QueryInterface,
1015 BasePinImpl_AddRef,
1016 InputPin_Release,
1017 InputPin_Connect,
1018 DSoundRender_InputPin_ReceiveConnection,
1019 DSoundRender_InputPin_Disconnect,
1020 BasePinImpl_ConnectedTo,
1021 BasePinImpl_ConnectionMediaType,
1022 BasePinImpl_QueryPinInfo,
1023 BasePinImpl_QueryDirection,
1024 BasePinImpl_QueryId,
1025 InputPin_QueryAccept,
1026 BasePinImpl_EnumMediaTypes,
1027 BasePinImpl_QueryInternalConnections,
1028 DSoundRender_InputPin_EndOfStream,
1029 DSoundRender_InputPin_BeginFlush,
1030 DSoundRender_InputPin_EndFlush,
1031 InputPin_NewSegment
1034 /*** IUnknown methods ***/
1035 static HRESULT WINAPI Basicaudio_QueryInterface(IBasicAudio *iface,
1036 REFIID riid,
1037 LPVOID*ppvObj) {
1038 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1040 TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
1042 return DSoundRender_QueryInterface((IBaseFilter*)This, riid, ppvObj);
1045 static ULONG WINAPI Basicaudio_AddRef(IBasicAudio *iface) {
1046 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1048 TRACE("(%p/%p)->()\n", This, iface);
1050 return DSoundRender_AddRef((IBaseFilter*)This);
1053 static ULONG WINAPI Basicaudio_Release(IBasicAudio *iface) {
1054 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1056 TRACE("(%p/%p)->()\n", This, iface);
1058 return DSoundRender_Release((IBaseFilter*)This);
1061 /*** IDispatch methods ***/
1062 static HRESULT WINAPI Basicaudio_GetTypeInfoCount(IBasicAudio *iface,
1063 UINT*pctinfo) {
1064 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1066 TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pctinfo);
1068 return S_OK;
1071 static HRESULT WINAPI Basicaudio_GetTypeInfo(IBasicAudio *iface,
1072 UINT iTInfo,
1073 LCID lcid,
1074 ITypeInfo**ppTInfo) {
1075 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1077 TRACE("(%p/%p)->(%d, %d, %p): stub !!!\n", This, iface, iTInfo, lcid, ppTInfo);
1079 return S_OK;
1082 static HRESULT WINAPI Basicaudio_GetIDsOfNames(IBasicAudio *iface,
1083 REFIID riid,
1084 LPOLESTR*rgszNames,
1085 UINT cNames,
1086 LCID lcid,
1087 DISPID*rgDispId) {
1088 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1090 TRACE("(%p/%p)->(%s (%p), %p, %d, %d, %p): stub !!!\n", This, iface, debugstr_guid(riid), riid, rgszNames, cNames, lcid, rgDispId);
1092 return S_OK;
1095 static HRESULT WINAPI Basicaudio_Invoke(IBasicAudio *iface,
1096 DISPID dispIdMember,
1097 REFIID riid,
1098 LCID lcid,
1099 WORD wFlags,
1100 DISPPARAMS*pDispParams,
1101 VARIANT*pVarResult,
1102 EXCEPINFO*pExepInfo,
1103 UINT*puArgErr) {
1104 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1106 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);
1108 return S_OK;
1111 /*** IBasicAudio methods ***/
1112 static HRESULT WINAPI Basicaudio_put_Volume(IBasicAudio *iface,
1113 LONG lVolume) {
1114 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1116 TRACE("(%p/%p)->(%d)\n", This, iface, lVolume);
1118 if (lVolume > DSBVOLUME_MAX || lVolume < DSBVOLUME_MIN)
1119 return E_INVALIDARG;
1121 if (This->dsbuffer) {
1122 if (FAILED(IDirectSoundBuffer_SetVolume(This->dsbuffer, lVolume)))
1123 return E_FAIL;
1126 This->volume = lVolume;
1127 return S_OK;
1130 static HRESULT WINAPI Basicaudio_get_Volume(IBasicAudio *iface,
1131 LONG *plVolume) {
1132 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1134 TRACE("(%p/%p)->(%p)\n", This, iface, plVolume);
1136 if (!plVolume)
1137 return E_POINTER;
1139 *plVolume = This->volume;
1140 return S_OK;
1143 static HRESULT WINAPI Basicaudio_put_Balance(IBasicAudio *iface,
1144 LONG lBalance) {
1145 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1147 TRACE("(%p/%p)->(%d)\n", This, iface, lBalance);
1149 if (lBalance < DSBPAN_LEFT || lBalance > DSBPAN_RIGHT)
1150 return E_INVALIDARG;
1152 if (This->dsbuffer) {
1153 if (FAILED(IDirectSoundBuffer_SetPan(This->dsbuffer, lBalance)))
1154 return E_FAIL;
1157 This->pan = lBalance;
1158 return S_OK;
1161 static HRESULT WINAPI Basicaudio_get_Balance(IBasicAudio *iface,
1162 LONG *plBalance) {
1163 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1165 TRACE("(%p/%p)->(%p)\n", This, iface, plBalance);
1167 if (!plBalance)
1168 return E_POINTER;
1170 *plBalance = This->pan;
1171 return S_OK;
1174 static const IBasicAudioVtbl IBasicAudio_Vtbl =
1176 Basicaudio_QueryInterface,
1177 Basicaudio_AddRef,
1178 Basicaudio_Release,
1179 Basicaudio_GetTypeInfoCount,
1180 Basicaudio_GetTypeInfo,
1181 Basicaudio_GetIDsOfNames,
1182 Basicaudio_Invoke,
1183 Basicaudio_put_Volume,
1184 Basicaudio_get_Volume,
1185 Basicaudio_put_Balance,
1186 Basicaudio_get_Balance
1190 /*** IUnknown methods ***/
1191 static HRESULT WINAPI ReferenceClock_QueryInterface(IReferenceClock *iface,
1192 REFIID riid,
1193 LPVOID*ppvObj)
1195 ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1197 TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
1199 return DSoundRender_QueryInterface((IBaseFilter*)This, riid, ppvObj);
1202 static ULONG WINAPI ReferenceClock_AddRef(IReferenceClock *iface)
1204 ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1206 TRACE("(%p/%p)->()\n", This, iface);
1208 return DSoundRender_AddRef((IBaseFilter*)This);
1211 static ULONG WINAPI ReferenceClock_Release(IReferenceClock *iface)
1213 ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1215 TRACE("(%p/%p)->()\n", This, iface);
1217 return DSoundRender_Release((IBaseFilter*)This);
1220 /*** IReferenceClock methods ***/
1221 static HRESULT WINAPI ReferenceClock_GetTime(IReferenceClock *iface,
1222 REFERENCE_TIME *pTime)
1224 ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1225 HRESULT hr = E_FAIL;
1226 DWORD play_pos;
1228 TRACE("(%p/%p)->(%p)\n", This, iface, pTime);
1230 if (This->dsbuffer)
1231 hr = DSoundRender_GetPos(This, &play_pos, pTime);
1232 if (FAILED(hr))
1233 ERR("Could not get reference time (%x)!\n", hr);
1235 return hr;
1238 static HRESULT WINAPI ReferenceClock_AdviseTime(IReferenceClock *iface,
1239 REFERENCE_TIME rtBaseTime,
1240 REFERENCE_TIME rtStreamTime,
1241 HEVENT hEvent,
1242 DWORD_PTR *pdwAdviseCookie)
1244 ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1246 FIXME("(%p/%p)->(%s, %s, %p, %p): stub!\n", This, iface, wine_dbgstr_longlong(rtBaseTime), wine_dbgstr_longlong(rtStreamTime), (void*)hEvent, pdwAdviseCookie);
1248 return E_NOTIMPL;
1251 static HRESULT WINAPI ReferenceClock_AdvisePeriodic(IReferenceClock *iface,
1252 REFERENCE_TIME rtBaseTime,
1253 REFERENCE_TIME rtStreamTime,
1254 HSEMAPHORE hSemaphore,
1255 DWORD_PTR *pdwAdviseCookie)
1257 ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1259 FIXME("(%p/%p)->(%s, %s, %p, %p): stub!\n", This, iface, wine_dbgstr_longlong(rtBaseTime), wine_dbgstr_longlong(rtStreamTime), (void*)hSemaphore, pdwAdviseCookie);
1261 return E_NOTIMPL;
1264 static HRESULT WINAPI ReferenceClock_Unadvise(IReferenceClock *iface,
1265 DWORD_PTR dwAdviseCookie)
1267 ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1269 FIXME("(%p/%p)->(%p): stub!\n", This, iface, (void*)dwAdviseCookie);
1271 return S_FALSE;
1274 static const IReferenceClockVtbl IReferenceClock_Vtbl =
1276 ReferenceClock_QueryInterface,
1277 ReferenceClock_AddRef,
1278 ReferenceClock_Release,
1279 ReferenceClock_GetTime,
1280 ReferenceClock_AdviseTime,
1281 ReferenceClock_AdvisePeriodic,
1282 ReferenceClock_Unadvise
1285 /*** IUnknown methods ***/
1286 static HRESULT WINAPI AMDirectSound_QueryInterface(IAMDirectSound *iface,
1287 REFIID riid,
1288 LPVOID*ppvObj)
1290 ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1292 TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
1294 return DSoundRender_QueryInterface((IBaseFilter*)This, riid, ppvObj);
1297 static ULONG WINAPI AMDirectSound_AddRef(IAMDirectSound *iface)
1299 ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1301 TRACE("(%p/%p)->()\n", This, iface);
1303 return DSoundRender_AddRef((IBaseFilter*)This);
1306 static ULONG WINAPI AMDirectSound_Release(IAMDirectSound *iface)
1308 ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1310 TRACE("(%p/%p)->()\n", This, iface);
1312 return DSoundRender_Release((IBaseFilter*)This);
1315 /*** IAMDirectSound methods ***/
1316 static HRESULT WINAPI AMDirectSound_GetDirectSoundInterface(IAMDirectSound *iface, IDirectSound **ds)
1318 ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1320 FIXME("(%p/%p)->(%p): stub\n", This, iface, ds);
1322 return E_NOTIMPL;
1325 static HRESULT WINAPI AMDirectSound_GetPrimaryBufferInterface(IAMDirectSound *iface, IDirectSoundBuffer **buf)
1327 ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1329 FIXME("(%p/%p)->(%p): stub\n", This, iface, buf);
1331 return E_NOTIMPL;
1334 static HRESULT WINAPI AMDirectSound_GetSecondaryBufferInterface(IAMDirectSound *iface, IDirectSoundBuffer **buf)
1336 ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1338 FIXME("(%p/%p)->(%p): stub\n", This, iface, buf);
1340 return E_NOTIMPL;
1343 static HRESULT WINAPI AMDirectSound_ReleaseDirectSoundInterface(IAMDirectSound *iface, IDirectSound *ds)
1345 ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1347 FIXME("(%p/%p)->(%p): stub\n", This, iface, ds);
1349 return E_NOTIMPL;
1352 static HRESULT WINAPI AMDirectSound_ReleasePrimaryBufferInterface(IAMDirectSound *iface, IDirectSoundBuffer *buf)
1354 ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1356 FIXME("(%p/%p)->(%p): stub\n", This, iface, buf);
1358 return E_NOTIMPL;
1361 static HRESULT WINAPI AMDirectSound_ReleaseSecondaryBufferInterface(IAMDirectSound *iface, IDirectSoundBuffer *buf)
1363 ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1365 FIXME("(%p/%p)->(%p): stub\n", This, iface, buf);
1367 return E_NOTIMPL;
1370 static HRESULT WINAPI AMDirectSound_SetFocusWindow(IAMDirectSound *iface, HWND hwnd, BOOL bgsilent)
1372 ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1374 FIXME("(%p/%p)->(%p,%d): stub\n", This, iface, hwnd, bgsilent);
1376 return E_NOTIMPL;
1379 static HRESULT WINAPI AMDirectSound_GetFocusWindow(IAMDirectSound *iface, HWND hwnd)
1381 ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1383 FIXME("(%p/%p)->(%p): stub\n", This, iface, hwnd);
1385 return E_NOTIMPL;
1388 static const IAMDirectSoundVtbl IAMDirectSound_Vtbl =
1390 AMDirectSound_QueryInterface,
1391 AMDirectSound_AddRef,
1392 AMDirectSound_Release,
1393 AMDirectSound_GetDirectSoundInterface,
1394 AMDirectSound_GetPrimaryBufferInterface,
1395 AMDirectSound_GetSecondaryBufferInterface,
1396 AMDirectSound_ReleaseDirectSoundInterface,
1397 AMDirectSound_ReleasePrimaryBufferInterface,
1398 AMDirectSound_ReleaseSecondaryBufferInterface,
1399 AMDirectSound_SetFocusWindow,
1400 AMDirectSound_GetFocusWindow