quartz: Use MediaSeekingPassThru for DirectSound renderer.
[wine/multimedia.git] / dlls / quartz / dsoundrender.c
blob043f328dae00bf37e27a60cf4e87adf0e93141fb
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 HRESULT DSoundRender_GetPin(IBaseFilter *iface, ULONG pos, IPin **pin, DWORD *lastsynctick)
707 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
709 /* Our pins are static, not changing so setting static tick count is ok */
710 *lastsynctick = 0;
712 if (pos >= 1)
713 return S_FALSE;
715 *pin = (IPin *)This->pInputPin;
716 IPin_AddRef(*pin);
717 return S_OK;
720 static HRESULT WINAPI DSoundRender_EnumPins(IBaseFilter * iface, IEnumPins **ppEnum)
722 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
724 TRACE("(%p/%p)->(%p)\n", This, iface, ppEnum);
726 return IEnumPinsImpl_Construct(ppEnum, DSoundRender_GetPin, iface);
729 static HRESULT WINAPI DSoundRender_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin)
731 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
733 TRACE("(%p/%p)->(%s,%p)\n", This, iface, debugstr_w(Id), ppPin);
735 FIXME("DSoundRender::FindPin(...)\n");
737 /* FIXME: critical section */
739 return E_NOTIMPL;
742 static HRESULT WINAPI DSoundRender_QueryFilterInfo(IBaseFilter * iface, FILTER_INFO *pInfo)
744 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
746 TRACE("(%p/%p)->(%p)\n", This, iface, pInfo);
748 strcpyW(pInfo->achName, This->filterInfo.achName);
749 pInfo->pGraph = This->filterInfo.pGraph;
751 if (pInfo->pGraph)
752 IFilterGraph_AddRef(pInfo->pGraph);
754 return S_OK;
757 static HRESULT WINAPI DSoundRender_JoinFilterGraph(IBaseFilter * iface, IFilterGraph *pGraph, LPCWSTR pName)
759 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
761 TRACE("(%p/%p)->(%p, %s)\n", This, iface, pGraph, debugstr_w(pName));
763 EnterCriticalSection(&This->csFilter);
765 if (pName)
766 strcpyW(This->filterInfo.achName, pName);
767 else
768 *This->filterInfo.achName = '\0';
769 This->filterInfo.pGraph = pGraph; /* NOTE: do NOT increase ref. count */
771 LeaveCriticalSection(&This->csFilter);
773 return S_OK;
776 static HRESULT WINAPI DSoundRender_QueryVendorInfo(IBaseFilter * iface, LPWSTR *pVendorInfo)
778 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
779 TRACE("(%p/%p)->(%p)\n", This, iface, pVendorInfo);
780 return E_NOTIMPL;
783 static const IBaseFilterVtbl DSoundRender_Vtbl =
785 DSoundRender_QueryInterface,
786 DSoundRender_AddRef,
787 DSoundRender_Release,
788 DSoundRender_GetClassID,
789 DSoundRender_Stop,
790 DSoundRender_Pause,
791 DSoundRender_Run,
792 DSoundRender_GetState,
793 DSoundRender_SetSyncSource,
794 DSoundRender_GetSyncSource,
795 DSoundRender_EnumPins,
796 DSoundRender_FindPin,
797 DSoundRender_QueryFilterInfo,
798 DSoundRender_JoinFilterGraph,
799 DSoundRender_QueryVendorInfo
802 static HRESULT WINAPI DSoundRender_InputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
804 InputPin *This = (InputPin *)iface;
805 PIN_DIRECTION pindirReceive;
806 DSoundRenderImpl *DSImpl;
807 HRESULT hr = S_OK;
809 TRACE("(%p)->(%p, %p)\n", This, pReceivePin, pmt);
810 dump_AM_MEDIA_TYPE(pmt);
812 EnterCriticalSection(This->pin.pCritSec);
814 DSImpl = (DSoundRenderImpl*)This->pin.pinInfo.pFilter;
815 DSImpl->rtLastStop = -1;
817 if (This->pin.pConnectedTo)
818 hr = VFW_E_ALREADY_CONNECTED;
820 if (SUCCEEDED(hr) && This->pin.fnQueryAccept(This->pin.pUserData, pmt) != S_OK)
821 hr = VFW_E_TYPE_NOT_ACCEPTED;
823 if (SUCCEEDED(hr))
825 IPin_QueryDirection(pReceivePin, &pindirReceive);
827 if (pindirReceive != PINDIR_OUTPUT)
829 ERR("Can't connect from non-output pin\n");
830 hr = VFW_E_INVALID_DIRECTION;
834 if (SUCCEEDED(hr))
836 WAVEFORMATEX *format;
837 DSBUFFERDESC buf_desc;
839 TRACE("MajorType %s\n", debugstr_guid(&pmt->majortype));
840 TRACE("SubType %s\n", debugstr_guid(&pmt->subtype));
841 TRACE("Format %s\n", debugstr_guid(&pmt->formattype));
842 TRACE("Size %d\n", pmt->cbFormat);
844 format = (WAVEFORMATEX*)pmt->pbFormat;
846 DSImpl->buf_size = format->nAvgBytesPerSec;
848 memset(&buf_desc,0,sizeof(DSBUFFERDESC));
849 buf_desc.dwSize = sizeof(DSBUFFERDESC);
850 buf_desc.dwFlags = DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLPAN |
851 DSBCAPS_CTRLFREQUENCY |
852 DSBCAPS_GETCURRENTPOSITION2;
853 buf_desc.dwBufferBytes = DSImpl->buf_size;
854 buf_desc.lpwfxFormat = format;
855 hr = IDirectSound_CreateSoundBuffer(DSImpl->dsound, &buf_desc, &DSImpl->dsbuffer, NULL);
856 if (FAILED(hr))
857 ERR("Can't create sound buffer (%x)\n", hr);
860 if (SUCCEEDED(hr))
862 hr = IDirectSoundBuffer_SetVolume(DSImpl->dsbuffer, DSImpl->volume);
863 if (FAILED(hr))
864 ERR("Can't set volume to %d (%x)\n", DSImpl->volume, hr);
866 hr = IDirectSoundBuffer_SetPan(DSImpl->dsbuffer, DSImpl->pan);
867 if (FAILED(hr))
868 ERR("Can't set pan to %d (%x)\n", DSImpl->pan, hr);
870 DSImpl->write_pos = 0;
871 hr = S_OK;
874 if (SUCCEEDED(hr))
876 CopyMediaType(&This->pin.mtCurrent, pmt);
877 This->pin.pConnectedTo = pReceivePin;
878 IPin_AddRef(pReceivePin);
880 else if (hr != VFW_E_ALREADY_CONNECTED)
882 if (DSImpl->dsbuffer)
883 IDirectSoundBuffer_Release(DSImpl->dsbuffer);
884 DSImpl->dsbuffer = NULL;
887 LeaveCriticalSection(This->pin.pCritSec);
889 return hr;
892 static HRESULT WINAPI DSoundRender_InputPin_Disconnect(IPin * iface)
894 IPinImpl *This = (IPinImpl*)iface;
895 DSoundRenderImpl *DSImpl;
897 TRACE("(%p)->()\n", iface);
899 DSImpl = (DSoundRenderImpl*)This->pinInfo.pFilter;
900 if (DSImpl->dsbuffer)
901 IDirectSoundBuffer_Release(DSImpl->dsbuffer);
902 DSImpl->dsbuffer = NULL;
904 return IPinImpl_Disconnect(iface);
907 static HRESULT WINAPI DSoundRender_InputPin_EndOfStream(IPin * iface)
909 InputPin* This = (InputPin*)iface;
910 DSoundRenderImpl *me = (DSoundRenderImpl*)This->pin.pinInfo.pFilter;
911 IMediaEventSink* pEventSink;
912 HRESULT hr;
914 EnterCriticalSection(This->pin.pCritSec);
916 TRACE("(%p/%p)->()\n", This, iface);
917 hr = InputPin_EndOfStream(iface);
918 if (hr != S_OK)
920 ERR("%08x\n", hr);
921 LeaveCriticalSection(This->pin.pCritSec);
922 return hr;
925 hr = IFilterGraph_QueryInterface(me->filterInfo.pGraph, &IID_IMediaEventSink, (LPVOID*)&pEventSink);
926 if (SUCCEEDED(hr))
928 BYTE * silence;
930 silence = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, me->buf_size);
931 if (silence)
933 memset(silence, 0, me->buf_size);
934 DSoundRender_SendSampleData((DSoundRenderImpl*)This->pin.pinInfo.pFilter, silence, me->buf_size);
935 HeapFree(GetProcessHeap(), 0, silence);
938 hr = IMediaEventSink_Notify(pEventSink, EC_COMPLETE, S_OK, 0);
939 IMediaEventSink_Release(pEventSink);
941 MediaSeekingPassThru_EOS(me->seekthru_unk);
942 LeaveCriticalSection(This->pin.pCritSec);
944 return hr;
947 static HRESULT WINAPI DSoundRender_InputPin_BeginFlush(IPin * iface)
949 InputPin *This = (InputPin *)iface;
950 DSoundRenderImpl *pFilter = (DSoundRenderImpl *)This->pin.pinInfo.pFilter;
951 HRESULT hr;
953 TRACE("\n");
955 EnterCriticalSection(This->pin.pCritSec);
956 hr = InputPin_BeginFlush(iface);
957 SetEvent(pFilter->blocked);
958 LeaveCriticalSection(This->pin.pCritSec);
960 return hr;
963 static HRESULT WINAPI DSoundRender_InputPin_EndFlush(IPin * iface)
965 InputPin *This = (InputPin *)iface;
966 DSoundRenderImpl *pFilter = (DSoundRenderImpl *)This->pin.pinInfo.pFilter;
967 HRESULT hr;
969 TRACE("\n");
971 EnterCriticalSection(This->pin.pCritSec);
972 if (pFilter->in_loop) {
973 ResetEvent(pFilter->state_change);
974 LeaveCriticalSection(This->pin.pCritSec);
975 WaitForSingleObject(pFilter->state_change, -1);
976 EnterCriticalSection(This->pin.pCritSec);
978 if (pFilter->state != State_Stopped)
979 ResetEvent(pFilter->blocked);
981 if (pFilter->dsbuffer)
983 LPBYTE buffer;
984 DWORD size;
985 IDirectSoundBuffer_Stop(pFilter->dsbuffer);
987 /* Force a reset */
988 IDirectSoundBuffer_SetCurrentPosition(pFilter->dsbuffer, 0);
989 pFilter->write_pos = pFilter->last_play_pos = 0;
990 ++pFilter->play_loops;
991 pFilter->write_loops = pFilter->play_loops;
993 IDirectSoundBuffer_Lock(pFilter->dsbuffer, 0, 0, (LPVOID *)&buffer, &size, NULL, NULL, DSBLOCK_ENTIREBUFFER);
994 memset(buffer, 0, size);
995 IDirectSoundBuffer_Unlock(pFilter->dsbuffer, buffer, size, NULL, 0);
997 hr = InputPin_EndFlush(iface);
998 LeaveCriticalSection(This->pin.pCritSec);
999 MediaSeekingPassThru_ResetMediaTime(pFilter->seekthru_unk);
1001 return hr;
1004 static const IPinVtbl DSoundRender_InputPin_Vtbl =
1006 InputPin_QueryInterface,
1007 IPinImpl_AddRef,
1008 InputPin_Release,
1009 InputPin_Connect,
1010 DSoundRender_InputPin_ReceiveConnection,
1011 DSoundRender_InputPin_Disconnect,
1012 IPinImpl_ConnectedTo,
1013 IPinImpl_ConnectionMediaType,
1014 IPinImpl_QueryPinInfo,
1015 IPinImpl_QueryDirection,
1016 IPinImpl_QueryId,
1017 IPinImpl_QueryAccept,
1018 IPinImpl_EnumMediaTypes,
1019 IPinImpl_QueryInternalConnections,
1020 DSoundRender_InputPin_EndOfStream,
1021 DSoundRender_InputPin_BeginFlush,
1022 DSoundRender_InputPin_EndFlush,
1023 InputPin_NewSegment
1026 /*** IUnknown methods ***/
1027 static HRESULT WINAPI Basicaudio_QueryInterface(IBasicAudio *iface,
1028 REFIID riid,
1029 LPVOID*ppvObj) {
1030 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1032 TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
1034 return DSoundRender_QueryInterface((IBaseFilter*)This, riid, ppvObj);
1037 static ULONG WINAPI Basicaudio_AddRef(IBasicAudio *iface) {
1038 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1040 TRACE("(%p/%p)->()\n", This, iface);
1042 return DSoundRender_AddRef((IBaseFilter*)This);
1045 static ULONG WINAPI Basicaudio_Release(IBasicAudio *iface) {
1046 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1048 TRACE("(%p/%p)->()\n", This, iface);
1050 return DSoundRender_Release((IBaseFilter*)This);
1053 /*** IDispatch methods ***/
1054 static HRESULT WINAPI Basicaudio_GetTypeInfoCount(IBasicAudio *iface,
1055 UINT*pctinfo) {
1056 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1058 TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pctinfo);
1060 return S_OK;
1063 static HRESULT WINAPI Basicaudio_GetTypeInfo(IBasicAudio *iface,
1064 UINT iTInfo,
1065 LCID lcid,
1066 ITypeInfo**ppTInfo) {
1067 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1069 TRACE("(%p/%p)->(%d, %d, %p): stub !!!\n", This, iface, iTInfo, lcid, ppTInfo);
1071 return S_OK;
1074 static HRESULT WINAPI Basicaudio_GetIDsOfNames(IBasicAudio *iface,
1075 REFIID riid,
1076 LPOLESTR*rgszNames,
1077 UINT cNames,
1078 LCID lcid,
1079 DISPID*rgDispId) {
1080 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1082 TRACE("(%p/%p)->(%s (%p), %p, %d, %d, %p): stub !!!\n", This, iface, debugstr_guid(riid), riid, rgszNames, cNames, lcid, rgDispId);
1084 return S_OK;
1087 static HRESULT WINAPI Basicaudio_Invoke(IBasicAudio *iface,
1088 DISPID dispIdMember,
1089 REFIID riid,
1090 LCID lcid,
1091 WORD wFlags,
1092 DISPPARAMS*pDispParams,
1093 VARIANT*pVarResult,
1094 EXCEPINFO*pExepInfo,
1095 UINT*puArgErr) {
1096 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1098 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);
1100 return S_OK;
1103 /*** IBasicAudio methods ***/
1104 static HRESULT WINAPI Basicaudio_put_Volume(IBasicAudio *iface,
1105 LONG lVolume) {
1106 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1108 TRACE("(%p/%p)->(%d)\n", This, iface, lVolume);
1110 if (lVolume > DSBVOLUME_MAX || lVolume < DSBVOLUME_MIN)
1111 return E_INVALIDARG;
1113 if (This->dsbuffer) {
1114 if (FAILED(IDirectSoundBuffer_SetVolume(This->dsbuffer, lVolume)))
1115 return E_FAIL;
1118 This->volume = lVolume;
1119 return S_OK;
1122 static HRESULT WINAPI Basicaudio_get_Volume(IBasicAudio *iface,
1123 LONG *plVolume) {
1124 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1126 TRACE("(%p/%p)->(%p)\n", This, iface, plVolume);
1128 if (!plVolume)
1129 return E_POINTER;
1131 *plVolume = This->volume;
1132 return S_OK;
1135 static HRESULT WINAPI Basicaudio_put_Balance(IBasicAudio *iface,
1136 LONG lBalance) {
1137 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1139 TRACE("(%p/%p)->(%d)\n", This, iface, lBalance);
1141 if (lBalance < DSBPAN_LEFT || lBalance > DSBPAN_RIGHT)
1142 return E_INVALIDARG;
1144 if (This->dsbuffer) {
1145 if (FAILED(IDirectSoundBuffer_SetPan(This->dsbuffer, lBalance)))
1146 return E_FAIL;
1149 This->pan = lBalance;
1150 return S_OK;
1153 static HRESULT WINAPI Basicaudio_get_Balance(IBasicAudio *iface,
1154 LONG *plBalance) {
1155 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1157 TRACE("(%p/%p)->(%p)\n", This, iface, plBalance);
1159 if (!plBalance)
1160 return E_POINTER;
1162 *plBalance = This->pan;
1163 return S_OK;
1166 static const IBasicAudioVtbl IBasicAudio_Vtbl =
1168 Basicaudio_QueryInterface,
1169 Basicaudio_AddRef,
1170 Basicaudio_Release,
1171 Basicaudio_GetTypeInfoCount,
1172 Basicaudio_GetTypeInfo,
1173 Basicaudio_GetIDsOfNames,
1174 Basicaudio_Invoke,
1175 Basicaudio_put_Volume,
1176 Basicaudio_get_Volume,
1177 Basicaudio_put_Balance,
1178 Basicaudio_get_Balance
1182 /*** IUnknown methods ***/
1183 static HRESULT WINAPI ReferenceClock_QueryInterface(IReferenceClock *iface,
1184 REFIID riid,
1185 LPVOID*ppvObj)
1187 ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1189 TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
1191 return DSoundRender_QueryInterface((IBaseFilter*)This, riid, ppvObj);
1194 static ULONG WINAPI ReferenceClock_AddRef(IReferenceClock *iface)
1196 ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1198 TRACE("(%p/%p)->()\n", This, iface);
1200 return DSoundRender_AddRef((IBaseFilter*)This);
1203 static ULONG WINAPI ReferenceClock_Release(IReferenceClock *iface)
1205 ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1207 TRACE("(%p/%p)->()\n", This, iface);
1209 return DSoundRender_Release((IBaseFilter*)This);
1212 /*** IReferenceClock methods ***/
1213 static HRESULT WINAPI ReferenceClock_GetTime(IReferenceClock *iface,
1214 REFERENCE_TIME *pTime)
1216 ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1217 HRESULT hr = E_FAIL;
1218 DWORD play_pos;
1220 TRACE("(%p/%p)->(%p)\n", This, iface, pTime);
1222 if (This->dsbuffer)
1223 hr = DSoundRender_GetPos(This, &play_pos, pTime);
1224 if (FAILED(hr))
1225 ERR("Could not get reference time (%x)!\n", hr);
1227 return hr;
1230 static HRESULT WINAPI ReferenceClock_AdviseTime(IReferenceClock *iface,
1231 REFERENCE_TIME rtBaseTime,
1232 REFERENCE_TIME rtStreamTime,
1233 HEVENT hEvent,
1234 DWORD_PTR *pdwAdviseCookie)
1236 ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1238 FIXME("(%p/%p)->(%s, %s, %p, %p): stub!\n", This, iface, wine_dbgstr_longlong(rtBaseTime), wine_dbgstr_longlong(rtStreamTime), (void*)hEvent, pdwAdviseCookie);
1240 return E_NOTIMPL;
1243 static HRESULT WINAPI ReferenceClock_AdvisePeriodic(IReferenceClock *iface,
1244 REFERENCE_TIME rtBaseTime,
1245 REFERENCE_TIME rtStreamTime,
1246 HSEMAPHORE hSemaphore,
1247 DWORD_PTR *pdwAdviseCookie)
1249 ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1251 FIXME("(%p/%p)->(%s, %s, %p, %p): stub!\n", This, iface, wine_dbgstr_longlong(rtBaseTime), wine_dbgstr_longlong(rtStreamTime), (void*)hSemaphore, pdwAdviseCookie);
1253 return E_NOTIMPL;
1256 static HRESULT WINAPI ReferenceClock_Unadvise(IReferenceClock *iface,
1257 DWORD_PTR dwAdviseCookie)
1259 ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1261 FIXME("(%p/%p)->(%p): stub!\n", This, iface, (void*)dwAdviseCookie);
1263 return S_FALSE;
1266 static const IReferenceClockVtbl IReferenceClock_Vtbl =
1268 ReferenceClock_QueryInterface,
1269 ReferenceClock_AddRef,
1270 ReferenceClock_Release,
1271 ReferenceClock_GetTime,
1272 ReferenceClock_AdviseTime,
1273 ReferenceClock_AdvisePeriodic,
1274 ReferenceClock_Unadvise
1277 /*** IUnknown methods ***/
1278 static HRESULT WINAPI AMDirectSound_QueryInterface(IAMDirectSound *iface,
1279 REFIID riid,
1280 LPVOID*ppvObj)
1282 ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1284 TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
1286 return DSoundRender_QueryInterface((IBaseFilter*)This, riid, ppvObj);
1289 static ULONG WINAPI AMDirectSound_AddRef(IAMDirectSound *iface)
1291 ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1293 TRACE("(%p/%p)->()\n", This, iface);
1295 return DSoundRender_AddRef((IBaseFilter*)This);
1298 static ULONG WINAPI AMDirectSound_Release(IAMDirectSound *iface)
1300 ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1302 TRACE("(%p/%p)->()\n", This, iface);
1304 return DSoundRender_Release((IBaseFilter*)This);
1307 /*** IAMDirectSound methods ***/
1308 static HRESULT WINAPI AMDirectSound_GetDirectSoundInterface(IAMDirectSound *iface, IDirectSound **ds)
1310 ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1312 FIXME("(%p/%p)->(%p): stub\n", This, iface, ds);
1314 return E_NOTIMPL;
1317 static HRESULT WINAPI AMDirectSound_GetPrimaryBufferInterface(IAMDirectSound *iface, IDirectSoundBuffer **buf)
1319 ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1321 FIXME("(%p/%p)->(%p): stub\n", This, iface, buf);
1323 return E_NOTIMPL;
1326 static HRESULT WINAPI AMDirectSound_GetSecondaryBufferInterface(IAMDirectSound *iface, IDirectSoundBuffer **buf)
1328 ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1330 FIXME("(%p/%p)->(%p): stub\n", This, iface, buf);
1332 return E_NOTIMPL;
1335 static HRESULT WINAPI AMDirectSound_ReleaseDirectSoundInterface(IAMDirectSound *iface, IDirectSound *ds)
1337 ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1339 FIXME("(%p/%p)->(%p): stub\n", This, iface, ds);
1341 return E_NOTIMPL;
1344 static HRESULT WINAPI AMDirectSound_ReleasePrimaryBufferInterface(IAMDirectSound *iface, IDirectSoundBuffer *buf)
1346 ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1348 FIXME("(%p/%p)->(%p): stub\n", This, iface, buf);
1350 return E_NOTIMPL;
1353 static HRESULT WINAPI AMDirectSound_ReleaseSecondaryBufferInterface(IAMDirectSound *iface, IDirectSoundBuffer *buf)
1355 ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1357 FIXME("(%p/%p)->(%p): stub\n", This, iface, buf);
1359 return E_NOTIMPL;
1362 static HRESULT WINAPI AMDirectSound_SetFocusWindow(IAMDirectSound *iface, HWND hwnd, BOOL bgsilent)
1364 ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1366 FIXME("(%p/%p)->(%p,%d): stub\n", This, iface, hwnd, bgsilent);
1368 return E_NOTIMPL;
1371 static HRESULT WINAPI AMDirectSound_GetFocusWindow(IAMDirectSound *iface, HWND hwnd)
1373 ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1375 FIXME("(%p/%p)->(%p): stub\n", This, iface, hwnd);
1377 return E_NOTIMPL;
1380 static const IAMDirectSoundVtbl IAMDirectSound_Vtbl =
1382 AMDirectSound_QueryInterface,
1383 AMDirectSound_AddRef,
1384 AMDirectSound_Release,
1385 AMDirectSound_GetDirectSoundInterface,
1386 AMDirectSound_GetPrimaryBufferInterface,
1387 AMDirectSound_GetSecondaryBufferInterface,
1388 AMDirectSound_ReleaseDirectSoundInterface,
1389 AMDirectSound_ReleasePrimaryBufferInterface,
1390 AMDirectSound_ReleaseSecondaryBufferInterface,
1391 AMDirectSound_SetFocusWindow,
1392 AMDirectSound_GetFocusWindow