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