d3dcompiler_43: Make asmshader_error() and set_rel_reg() static.
[wine/multimedia.git] / dlls / quartz / dsoundrender.c
blob8631cd58949296366eca8aa4f738ae11c77da81c
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;
75 DWORD in_loop;
77 REFERENCE_TIME play_time;
78 MediaSeekingImpl mediaSeeking;
80 HANDLE state_change, blocked;
82 LONG volume;
83 LONG pan;
84 } DSoundRenderImpl;
86 /* Seeking is not needed for a renderer, rely on newsegment for the appropriate changes */
87 static HRESULT sound_mod_stop(IBaseFilter *iface)
89 TRACE("(%p)\n", iface);
90 return S_OK;
93 static HRESULT sound_mod_start(IBaseFilter *iface)
95 TRACE("(%p)\n", iface);
97 return S_OK;
100 static HRESULT sound_mod_rate(IBaseFilter *iface)
102 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
104 WAVEFORMATEX *format = (WAVEFORMATEX*)This->pInputPin->pin.mtCurrent.pbFormat;
105 DWORD freq = format->nSamplesPerSec;
106 double rate = This->mediaSeeking.dRate;
108 freq = (DWORD)((double)freq * rate);
110 TRACE("(%p)\n", iface);
112 if (freq > DSBFREQUENCY_MAX)
113 return VFW_E_UNSUPPORTED_AUDIO;
115 if (freq < DSBFREQUENCY_MIN)
116 return VFW_E_UNSUPPORTED_AUDIO;
118 return S_OK;
121 static inline HRESULT DSoundRender_GetPos(DSoundRenderImpl *This, DWORD *pPlayPos, REFERENCE_TIME *pRefTime)
123 HRESULT hr;
125 EnterCriticalSection(&This->csFilter);
127 DWORD state;
128 DWORD write_pos;
130 hr = IDirectSoundBuffer_GetStatus(This->dsbuffer, &state);
131 if (SUCCEEDED(hr) && !(state & DSBSTATUS_PLAYING) && This->state == State_Running)
133 TRACE("Not playing, kickstarting the engine\n");
135 hr = IDirectSoundBuffer_Play(This->dsbuffer, 0, 0, DSBPLAY_LOOPING);
136 if (FAILED(hr))
137 ERR("Can't play sound buffer (%x)\n", hr);
140 if (SUCCEEDED(hr))
141 hr = IDirectSoundBuffer_GetCurrentPosition(This->dsbuffer, pPlayPos, &write_pos);
142 if (hr == S_OK)
144 DWORD play_pos = *pPlayPos;
146 if (play_pos < This->last_play_pos)
147 This->play_loops++;
148 This->last_play_pos = play_pos;
150 /* If we really fell behind, start at the next possible position
151 * Also happens when just starting playback for the first time,
152 * or when flushing
154 if ((This->play_loops*This->buf_size)+play_pos >=
155 (This->write_loops*This->buf_size)+This->write_pos)
156 This->write_pos = write_pos;
158 if (pRefTime)
160 REFERENCE_TIME play_time;
161 play_time = ((REFERENCE_TIME)This->play_loops*10000000) +
162 ((REFERENCE_TIME)play_pos*10000000/This->buf_size);
164 /* Don't let time run backwards */
165 if(play_time-This->play_time > 0)
166 This->play_time = play_time;
167 else
168 hr = S_FALSE;
170 *pRefTime = This->play_time;
174 LeaveCriticalSection(&This->csFilter);
176 return hr;
179 static HRESULT DSoundRender_SendSampleData(DSoundRenderImpl* This, const BYTE *data, DWORD size)
181 HRESULT hr = S_OK;
182 LPBYTE lpbuf1 = NULL;
183 LPBYTE lpbuf2 = NULL;
184 DWORD dwsize1 = 0;
185 DWORD dwsize2 = 0;
186 DWORD size2;
187 DWORD play_pos,buf_free;
189 do {
191 hr = DSoundRender_GetPos(This, &play_pos, NULL);
192 if (hr != DS_OK)
194 ERR("GetPos returned error: %x\n", hr);
195 break;
197 if (This->write_pos <= play_pos)
198 buf_free = play_pos-This->write_pos;
199 else
200 buf_free = This->buf_size - This->write_pos + play_pos;
202 /* Wait for enough of the buffer to empty before filling it */
203 if(buf_free < This->buf_size/20)
205 DWORD ret;
206 This->in_loop = 1;
207 LeaveCriticalSection(&This->csFilter);
208 ret = WaitForSingleObject(This->blocked, 50);
209 if (ret != WAIT_TIMEOUT)
210 ERR("%x\n", ret);
211 EnterCriticalSection(&This->csFilter);
212 This->in_loop = 0;
213 if (This->pInputPin->flushing)
214 return VFW_E_WRONG_STATE;
215 if (This->state == State_Stopped)
216 return VFW_E_WRONG_STATE;
217 continue;
220 size2 = min(buf_free, size);
221 hr = IDirectSoundBuffer_Lock(This->dsbuffer, This->write_pos, size2, (LPVOID *)&lpbuf1, &dwsize1, (LPVOID *)&lpbuf2, &dwsize2, 0);
222 if (hr != DS_OK) {
223 ERR("Unable to lock sound buffer! (%x)\n", hr);
224 break;
226 /* TRACE("write_pos=%d, size=%d, sz1=%d, sz2=%d\n", This->write_pos, size2, dwsize1, dwsize2); */
228 memcpy(lpbuf1, data, dwsize1);
229 if (dwsize2)
230 memcpy(lpbuf2, data + dwsize1, dwsize2);
232 hr = IDirectSoundBuffer_Unlock(This->dsbuffer, lpbuf1, dwsize1, lpbuf2, dwsize2);
233 if (hr != DS_OK)
234 ERR("Unable to unlock sound buffer! (%x)\n", hr);
236 size -= dwsize1 + dwsize2;
237 data += dwsize1 + dwsize2;
238 This->write_pos += dwsize1 + dwsize2;
239 if (This->write_pos >= This->buf_size)
241 This->write_pos -= This->buf_size;
242 This->write_loops++;
244 } while (size && This->state == State_Running);
246 return hr;
249 static HRESULT DSoundRender_Sample(LPVOID iface, IMediaSample * pSample)
251 DSoundRenderImpl *This = iface;
252 LPBYTE pbSrcStream = NULL;
253 LONG cbSrcStream = 0;
254 REFERENCE_TIME tStart, tStop;
255 HRESULT hr;
256 AM_MEDIA_TYPE *amt;
258 TRACE("%p %p\n", iface, pSample);
260 /* Slightly incorrect, Pause completes when a frame is received so we should signal
261 * pause completion here, but for sound playing a single frame doesn't make sense
264 EnterCriticalSection(&This->csFilter);
266 if (This->pInputPin->end_of_stream || This->pInputPin->flushing)
268 LeaveCriticalSection(&This->csFilter);
269 return S_FALSE;
272 if (This->state == State_Stopped)
274 LeaveCriticalSection(&This->csFilter);
275 return VFW_E_WRONG_STATE;
278 if (IMediaSample_GetMediaType(pSample, &amt) == S_OK)
280 AM_MEDIA_TYPE *orig = &This->pInputPin->pin.mtCurrent;
281 WAVEFORMATEX *origfmt = (WAVEFORMATEX *)orig->pbFormat;
282 WAVEFORMATEX *newfmt = (WAVEFORMATEX *)amt->pbFormat;
284 if (origfmt->wFormatTag == newfmt->wFormatTag &&
285 origfmt->nChannels == newfmt->nChannels &&
286 origfmt->nBlockAlign == newfmt->nBlockAlign &&
287 origfmt->wBitsPerSample == newfmt->wBitsPerSample &&
288 origfmt->cbSize == newfmt->cbSize)
290 if (origfmt->nSamplesPerSec != newfmt->nSamplesPerSec)
292 hr = IDirectSoundBuffer_SetFrequency(This->dsbuffer,
293 newfmt->nSamplesPerSec);
294 if (FAILED(hr))
296 LeaveCriticalSection(&This->csFilter);
297 return VFW_E_TYPE_NOT_ACCEPTED;
299 FreeMediaType(orig);
300 CopyMediaType(orig, amt);
301 IMediaSample_SetMediaType(pSample, NULL);
304 else
306 LeaveCriticalSection(&This->csFilter);
307 return VFW_E_TYPE_NOT_ACCEPTED;
311 hr = IMediaSample_GetPointer(pSample, &pbSrcStream);
312 if (FAILED(hr))
314 ERR("Cannot get pointer to sample data (%x)\n", hr);
315 LeaveCriticalSection(&This->csFilter);
316 return hr;
319 hr = IMediaSample_GetTime(pSample, &tStart, &tStop);
320 if (FAILED(hr))
321 ERR("Cannot get sample time (%x)\n", hr);
323 if (This->rtLastStop != tStart && (IMediaSample_IsDiscontinuity(pSample) == S_FALSE))
324 WARN("Unexpected discontinuity: Last: %u.%03u, tStart: %u.%03u\n",
325 (DWORD)(This->rtLastStop / 10000000), (DWORD)((This->rtLastStop / 10000)%1000),
326 (DWORD)(tStart / 10000000), (DWORD)((tStart / 10000)%1000));
327 This->rtLastStop = tStop;
329 if (IMediaSample_IsPreroll(pSample) == S_OK)
331 TRACE("Preroll!\n");
332 LeaveCriticalSection(&This->csFilter);
333 return S_OK;
336 if (This->state == State_Paused)
338 SetEvent(This->state_change);
339 LeaveCriticalSection(&This->csFilter);
340 WaitForSingleObject(This->blocked, INFINITE);
341 EnterCriticalSection(&This->csFilter);
342 if (This->state == State_Stopped)
344 LeaveCriticalSection(&This->csFilter);
345 return VFW_E_WRONG_STATE;
348 if (This->state == State_Paused)
350 /* Assuming we return because of flushing */
351 TRACE("Flushing\n");
352 LeaveCriticalSection(&This->csFilter);
353 return S_OK;
357 cbSrcStream = IMediaSample_GetActualDataLength(pSample);
358 TRACE("Sample data ptr = %p, size = %d\n", pbSrcStream, cbSrcStream);
360 #if 0 /* For debugging purpose */
362 int i;
363 for(i = 0; i < cbSrcStream; i++)
365 if ((i!=0) && !(i%16))
366 TRACE("\n");
367 TRACE("%02x ", pbSrcStream[i]);
369 TRACE("\n");
371 #endif
373 hr = DSoundRender_SendSampleData(This, pbSrcStream, cbSrcStream);
374 SetEvent(This->state_change);
375 LeaveCriticalSection(&This->csFilter);
376 return hr;
379 static HRESULT DSoundRender_QueryAccept(LPVOID iface, const AM_MEDIA_TYPE * pmt)
381 WAVEFORMATEX* format;
383 if (!IsEqualIID(&pmt->majortype, &MEDIATYPE_Audio))
384 return S_FALSE;
386 format = (WAVEFORMATEX*)pmt->pbFormat;
387 TRACE("Format = %p\n", format);
388 TRACE("wFormatTag = %x %x\n", format->wFormatTag, WAVE_FORMAT_PCM);
389 TRACE("nChannels = %d\n", format->nChannels);
390 TRACE("nSamplesPerSec = %d\n", format->nAvgBytesPerSec);
391 TRACE("nAvgBytesPerSec = %d\n", format->nAvgBytesPerSec);
392 TRACE("nBlockAlign = %d\n", format->nBlockAlign);
393 TRACE("wBitsPerSample = %d\n", format->wBitsPerSample);
395 if (!IsEqualIID(&pmt->subtype, &MEDIASUBTYPE_PCM))
396 return S_FALSE;
398 return S_OK;
401 HRESULT DSoundRender_create(IUnknown * pUnkOuter, LPVOID * ppv)
403 HRESULT hr;
404 PIN_INFO piInput;
405 DSoundRenderImpl * pDSoundRender;
407 TRACE("(%p, %p)\n", pUnkOuter, ppv);
409 *ppv = NULL;
411 if (pUnkOuter)
412 return CLASS_E_NOAGGREGATION;
414 pDSoundRender = CoTaskMemAlloc(sizeof(DSoundRenderImpl));
415 if (!pDSoundRender)
416 return E_OUTOFMEMORY;
417 ZeroMemory(pDSoundRender, sizeof(DSoundRenderImpl));
419 pDSoundRender->lpVtbl = &DSoundRender_Vtbl;
420 pDSoundRender->IBasicAudio_vtbl = &IBasicAudio_Vtbl;
421 pDSoundRender->IReferenceClock_vtbl = &IReferenceClock_Vtbl;
422 pDSoundRender->IAMDirectSound_vtbl = &IAMDirectSound_Vtbl;
423 pDSoundRender->refCount = 1;
424 InitializeCriticalSection(&pDSoundRender->csFilter);
425 pDSoundRender->csFilter.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": DSoundRenderImpl.csFilter");
426 pDSoundRender->state = State_Stopped;
428 /* construct input pin */
429 piInput.dir = PINDIR_INPUT;
430 piInput.pFilter = (IBaseFilter *)pDSoundRender;
431 lstrcpynW(piInput.achName, wcsInputPinName, sizeof(piInput.achName) / sizeof(piInput.achName[0]));
432 hr = InputPin_Construct(&DSoundRender_InputPin_Vtbl, &piInput, DSoundRender_Sample, pDSoundRender, DSoundRender_QueryAccept, NULL, &pDSoundRender->csFilter, NULL, (IPin **)&pDSoundRender->pInputPin);
434 if (SUCCEEDED(hr))
436 hr = DirectSoundCreate8(NULL, &pDSoundRender->dsound, NULL);
437 if (FAILED(hr))
438 ERR("Cannot create Direct Sound object (%x)\n", hr);
439 else
440 IDirectSound_SetCooperativeLevel(pDSoundRender->dsound, GetDesktopWindow(), DSSCL_PRIORITY);
443 if (SUCCEEDED(hr))
445 MediaSeekingImpl_Init((IBaseFilter*)pDSoundRender, sound_mod_stop, sound_mod_start, sound_mod_rate, &pDSoundRender->mediaSeeking, &pDSoundRender->csFilter);
446 pDSoundRender->mediaSeeking.lpVtbl = &IMediaSeeking_Vtbl;
448 pDSoundRender->state_change = CreateEventW(NULL, TRUE, TRUE, NULL);
449 pDSoundRender->blocked = CreateEventW(NULL, FALSE, FALSE, NULL);
451 if (!pDSoundRender->state_change || !pDSoundRender->blocked)
453 IUnknown_Release((IUnknown *)pDSoundRender);
454 return HRESULT_FROM_WIN32(GetLastError());
457 *ppv = pDSoundRender;
459 else
461 if (pDSoundRender->pInputPin)
462 IPin_Release((IPin*)pDSoundRender->pInputPin);
463 pDSoundRender->csFilter.DebugInfo->Spare[0] = 0;
464 DeleteCriticalSection(&pDSoundRender->csFilter);
465 CoTaskMemFree(pDSoundRender);
468 return hr;
471 static HRESULT WINAPI DSoundRender_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv)
473 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
474 TRACE("(%p, %p)->(%s, %p)\n", This, iface, qzdebugstr_guid(riid), ppv);
476 *ppv = NULL;
478 if (IsEqualIID(riid, &IID_IUnknown))
479 *ppv = This;
480 else if (IsEqualIID(riid, &IID_IPersist))
481 *ppv = This;
482 else if (IsEqualIID(riid, &IID_IMediaFilter))
483 *ppv = This;
484 else if (IsEqualIID(riid, &IID_IBaseFilter))
485 *ppv = This;
486 else if (IsEqualIID(riid, &IID_IBasicAudio))
487 *ppv = &This->IBasicAudio_vtbl;
488 else if (IsEqualIID(riid, &IID_IReferenceClock))
489 *ppv = &This->IReferenceClock_vtbl;
490 else if (IsEqualIID(riid, &IID_IMediaSeeking))
491 *ppv = &This->mediaSeeking.lpVtbl;
492 else if (IsEqualIID(riid, &IID_IAMDirectSound))
493 *ppv = &This->IAMDirectSound_vtbl;
495 if (*ppv)
497 IUnknown_AddRef((IUnknown *)(*ppv));
498 return S_OK;
501 if (!IsEqualIID(riid, &IID_IPin) && !IsEqualIID(riid, &IID_IVideoWindow))
502 FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
504 return E_NOINTERFACE;
507 static ULONG WINAPI DSoundRender_AddRef(IBaseFilter * iface)
509 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
510 ULONG refCount = InterlockedIncrement(&This->refCount);
512 TRACE("(%p/%p)->() AddRef from %d\n", This, iface, refCount - 1);
514 return refCount;
517 static ULONG WINAPI DSoundRender_Release(IBaseFilter * iface)
519 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
520 ULONG refCount = InterlockedDecrement(&This->refCount);
522 TRACE("(%p)->() Release from %d\n", This, refCount + 1);
524 if (!refCount)
526 IPin *pConnectedTo;
528 if (This->pClock)
529 IReferenceClock_Release(This->pClock);
531 if (This->dsbuffer)
532 IDirectSoundBuffer_Release(This->dsbuffer);
533 This->dsbuffer = NULL;
534 if (This->dsound)
535 IDirectSound_Release(This->dsound);
536 This->dsound = NULL;
538 if (SUCCEEDED(IPin_ConnectedTo((IPin *)This->pInputPin, &pConnectedTo)))
540 IPin_Disconnect(pConnectedTo);
541 IPin_Release(pConnectedTo);
543 IPin_Disconnect((IPin *)This->pInputPin);
545 IPin_Release((IPin *)This->pInputPin);
547 This->lpVtbl = NULL;
548 This->IBasicAudio_vtbl = NULL;
550 This->csFilter.DebugInfo->Spare[0] = 0;
551 DeleteCriticalSection(&This->csFilter);
553 CloseHandle(This->state_change);
554 CloseHandle(This->blocked);
556 TRACE("Destroying Audio Renderer\n");
557 CoTaskMemFree(This);
559 return 0;
561 else
562 return refCount;
565 /** IPersist methods **/
567 static HRESULT WINAPI DSoundRender_GetClassID(IBaseFilter * iface, CLSID * pClsid)
569 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
570 TRACE("(%p/%p)->(%p)\n", This, iface, pClsid);
572 *pClsid = CLSID_DSoundRender;
574 return S_OK;
577 /** IMediaFilter methods **/
579 static HRESULT WINAPI DSoundRender_Stop(IBaseFilter * iface)
581 HRESULT hr = S_OK;
582 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
584 TRACE("(%p/%p)->()\n", This, iface);
586 EnterCriticalSection(&This->csFilter);
588 DWORD state = 0;
589 if (This->dsbuffer)
591 hr = IDirectSoundBuffer_GetStatus(This->dsbuffer, &state);
592 if (SUCCEEDED(hr))
594 if (state & DSBSTATUS_PLAYING)
595 hr = IDirectSoundBuffer_Stop(This->dsbuffer);
598 if (SUCCEEDED(hr))
599 This->state = State_Stopped;
601 /* Complete our transition */
602 SetEvent(This->state_change);
603 SetEvent(This->blocked);
605 LeaveCriticalSection(&This->csFilter);
607 return hr;
610 static HRESULT WINAPI DSoundRender_Pause(IBaseFilter * iface)
612 HRESULT hr = S_OK;
613 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
615 TRACE("(%p/%p)->()\n", This, iface);
617 EnterCriticalSection(&This->csFilter);
618 if (This->state != State_Paused)
620 DWORD state = 0;
621 if (This->state == State_Stopped)
623 This->pInputPin->end_of_stream = 0;
626 if (This->dsbuffer)
628 hr = IDirectSoundBuffer_GetStatus(This->dsbuffer, &state);
629 if (SUCCEEDED(hr))
631 if (state & DSBSTATUS_PLAYING)
632 hr = IDirectSoundBuffer_Stop(This->dsbuffer);
635 if (SUCCEEDED(hr))
636 This->state = State_Paused;
638 ResetEvent(This->blocked);
639 ResetEvent(This->state_change);
641 LeaveCriticalSection(&This->csFilter);
643 return hr;
646 static HRESULT WINAPI DSoundRender_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
648 HRESULT hr = S_OK;
649 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
651 TRACE("(%p/%p)->(%s)\n", This, iface, wine_dbgstr_longlong(tStart));
653 EnterCriticalSection(&This->csFilter);
655 This->rtStreamStart = tStart;
656 if (This->state == State_Paused)
658 /* Unblock our thread, state changing from paused to running doesn't need a reset for state change */
659 SetEvent(This->blocked);
661 else if (This->state == State_Stopped)
663 ResetEvent(This->state_change);
664 This->pInputPin->end_of_stream = 0;
666 ResetEvent(This->blocked);
668 This->state = State_Running;
670 LeaveCriticalSection(&This->csFilter);
672 return hr;
675 static HRESULT WINAPI DSoundRender_GetState(IBaseFilter * iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState)
677 HRESULT hr;
678 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
680 TRACE("(%p/%p)->(%d, %p)\n", This, iface, dwMilliSecsTimeout, pState);
682 if (WaitForSingleObject(This->state_change, dwMilliSecsTimeout) == WAIT_TIMEOUT)
683 hr = VFW_S_STATE_INTERMEDIATE;
684 else
685 hr = S_OK;
687 EnterCriticalSection(&This->csFilter);
689 *pState = This->state;
691 LeaveCriticalSection(&This->csFilter);
693 return hr;
696 static HRESULT WINAPI DSoundRender_SetSyncSource(IBaseFilter * iface, IReferenceClock *pClock)
698 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
700 TRACE("(%p/%p)->(%p)\n", This, iface, pClock);
702 EnterCriticalSection(&This->csFilter);
704 if (This->pClock)
705 IReferenceClock_Release(This->pClock);
706 This->pClock = pClock;
707 if (This->pClock)
708 IReferenceClock_AddRef(This->pClock);
710 LeaveCriticalSection(&This->csFilter);
712 return S_OK;
715 static HRESULT WINAPI DSoundRender_GetSyncSource(IBaseFilter * iface, IReferenceClock **ppClock)
717 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
719 TRACE("(%p/%p)->(%p)\n", This, iface, ppClock);
721 EnterCriticalSection(&This->csFilter);
723 *ppClock = This->pClock;
724 if (This->pClock)
725 IReferenceClock_AddRef(This->pClock);
727 LeaveCriticalSection(&This->csFilter);
729 return S_OK;
732 /** IBaseFilter implementation **/
734 static HRESULT DSoundRender_GetPin(IBaseFilter *iface, ULONG pos, IPin **pin, DWORD *lastsynctick)
736 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
738 /* Our pins are static, not changing so setting static tick count is ok */
739 *lastsynctick = 0;
741 if (pos >= 1)
742 return S_FALSE;
744 *pin = (IPin *)This->pInputPin;
745 IPin_AddRef(*pin);
746 return S_OK;
749 static HRESULT WINAPI DSoundRender_EnumPins(IBaseFilter * iface, IEnumPins **ppEnum)
751 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
753 TRACE("(%p/%p)->(%p)\n", This, iface, ppEnum);
755 return IEnumPinsImpl_Construct(ppEnum, DSoundRender_GetPin, iface);
758 static HRESULT WINAPI DSoundRender_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin)
760 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
762 TRACE("(%p/%p)->(%s,%p)\n", This, iface, debugstr_w(Id), ppPin);
764 FIXME("DSoundRender::FindPin(...)\n");
766 /* FIXME: critical section */
768 return E_NOTIMPL;
771 static HRESULT WINAPI DSoundRender_QueryFilterInfo(IBaseFilter * iface, FILTER_INFO *pInfo)
773 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
775 TRACE("(%p/%p)->(%p)\n", This, iface, pInfo);
777 strcpyW(pInfo->achName, This->filterInfo.achName);
778 pInfo->pGraph = This->filterInfo.pGraph;
780 if (pInfo->pGraph)
781 IFilterGraph_AddRef(pInfo->pGraph);
783 return S_OK;
786 static HRESULT WINAPI DSoundRender_JoinFilterGraph(IBaseFilter * iface, IFilterGraph *pGraph, LPCWSTR pName)
788 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
790 TRACE("(%p/%p)->(%p, %s)\n", This, iface, pGraph, debugstr_w(pName));
792 EnterCriticalSection(&This->csFilter);
794 if (pName)
795 strcpyW(This->filterInfo.achName, pName);
796 else
797 *This->filterInfo.achName = '\0';
798 This->filterInfo.pGraph = pGraph; /* NOTE: do NOT increase ref. count */
800 LeaveCriticalSection(&This->csFilter);
802 return S_OK;
805 static HRESULT WINAPI DSoundRender_QueryVendorInfo(IBaseFilter * iface, LPWSTR *pVendorInfo)
807 DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
808 TRACE("(%p/%p)->(%p)\n", This, iface, pVendorInfo);
809 return E_NOTIMPL;
812 static const IBaseFilterVtbl DSoundRender_Vtbl =
814 DSoundRender_QueryInterface,
815 DSoundRender_AddRef,
816 DSoundRender_Release,
817 DSoundRender_GetClassID,
818 DSoundRender_Stop,
819 DSoundRender_Pause,
820 DSoundRender_Run,
821 DSoundRender_GetState,
822 DSoundRender_SetSyncSource,
823 DSoundRender_GetSyncSource,
824 DSoundRender_EnumPins,
825 DSoundRender_FindPin,
826 DSoundRender_QueryFilterInfo,
827 DSoundRender_JoinFilterGraph,
828 DSoundRender_QueryVendorInfo
831 static HRESULT WINAPI DSoundRender_InputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
833 InputPin *This = (InputPin *)iface;
834 PIN_DIRECTION pindirReceive;
835 DSoundRenderImpl *DSImpl;
836 HRESULT hr = S_OK;
838 TRACE("(%p)->(%p, %p)\n", This, pReceivePin, pmt);
839 dump_AM_MEDIA_TYPE(pmt);
841 EnterCriticalSection(This->pin.pCritSec);
843 DSImpl = (DSoundRenderImpl*)This->pin.pinInfo.pFilter;
844 DSImpl->rtLastStop = -1;
846 if (This->pin.pConnectedTo)
847 hr = VFW_E_ALREADY_CONNECTED;
849 if (SUCCEEDED(hr) && This->pin.fnQueryAccept(This->pin.pUserData, pmt) != S_OK)
850 hr = VFW_E_TYPE_NOT_ACCEPTED;
852 if (SUCCEEDED(hr))
854 IPin_QueryDirection(pReceivePin, &pindirReceive);
856 if (pindirReceive != PINDIR_OUTPUT)
858 ERR("Can't connect from non-output pin\n");
859 hr = VFW_E_INVALID_DIRECTION;
863 if (SUCCEEDED(hr))
865 WAVEFORMATEX *format;
866 DSBUFFERDESC buf_desc;
868 TRACE("MajorType %s\n", debugstr_guid(&pmt->majortype));
869 TRACE("SubType %s\n", debugstr_guid(&pmt->subtype));
870 TRACE("Format %s\n", debugstr_guid(&pmt->formattype));
871 TRACE("Size %d\n", pmt->cbFormat);
873 format = (WAVEFORMATEX*)pmt->pbFormat;
875 DSImpl->buf_size = format->nAvgBytesPerSec;
877 memset(&buf_desc,0,sizeof(DSBUFFERDESC));
878 buf_desc.dwSize = sizeof(DSBUFFERDESC);
879 buf_desc.dwFlags = DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLPAN |
880 DSBCAPS_CTRLFREQUENCY |
881 DSBCAPS_GETCURRENTPOSITION2;
882 buf_desc.dwBufferBytes = DSImpl->buf_size;
883 buf_desc.lpwfxFormat = format;
884 hr = IDirectSound_CreateSoundBuffer(DSImpl->dsound, &buf_desc, &DSImpl->dsbuffer, NULL);
885 if (FAILED(hr))
886 ERR("Can't create sound buffer (%x)\n", hr);
889 if (SUCCEEDED(hr))
891 hr = IDirectSoundBuffer_SetVolume(DSImpl->dsbuffer, DSImpl->volume);
892 if (FAILED(hr))
893 ERR("Can't set volume to %d (%x)\n", DSImpl->volume, hr);
895 hr = IDirectSoundBuffer_SetPan(DSImpl->dsbuffer, DSImpl->pan);
896 if (FAILED(hr))
897 ERR("Can't set pan to %d (%x)\n", DSImpl->pan, hr);
899 DSImpl->write_pos = 0;
900 hr = S_OK;
903 if (SUCCEEDED(hr))
905 CopyMediaType(&This->pin.mtCurrent, pmt);
906 This->pin.pConnectedTo = pReceivePin;
907 IPin_AddRef(pReceivePin);
909 else if (hr != VFW_E_ALREADY_CONNECTED)
911 if (DSImpl->dsbuffer)
912 IDirectSoundBuffer_Release(DSImpl->dsbuffer);
913 DSImpl->dsbuffer = NULL;
916 LeaveCriticalSection(This->pin.pCritSec);
918 return hr;
921 static HRESULT WINAPI DSoundRender_InputPin_Disconnect(IPin * iface)
923 IPinImpl *This = (IPinImpl*)iface;
924 DSoundRenderImpl *DSImpl;
926 TRACE("(%p)->()\n", iface);
928 DSImpl = (DSoundRenderImpl*)This->pinInfo.pFilter;
929 if (DSImpl->dsbuffer)
930 IDirectSoundBuffer_Release(DSImpl->dsbuffer);
931 DSImpl->dsbuffer = NULL;
933 return IPinImpl_Disconnect(iface);
936 static HRESULT WINAPI DSoundRender_InputPin_EndOfStream(IPin * iface)
938 InputPin* This = (InputPin*)iface;
939 DSoundRenderImpl *me = (DSoundRenderImpl*)This->pin.pinInfo.pFilter;
940 IMediaEventSink* pEventSink;
941 HRESULT hr;
943 EnterCriticalSection(This->pin.pCritSec);
945 TRACE("(%p/%p)->()\n", This, iface);
946 hr = InputPin_EndOfStream(iface);
947 if (hr != S_OK)
949 ERR("%08x\n", hr);
950 LeaveCriticalSection(This->pin.pCritSec);
951 return hr;
954 hr = IFilterGraph_QueryInterface(me->filterInfo.pGraph, &IID_IMediaEventSink, (LPVOID*)&pEventSink);
955 if (SUCCEEDED(hr))
957 BYTE * silence;
959 silence = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, me->buf_size);
960 if (silence)
962 memset(silence, 0, me->buf_size);
963 DSoundRender_SendSampleData((DSoundRenderImpl*)This->pin.pinInfo.pFilter, silence, me->buf_size);
964 HeapFree(GetProcessHeap(), 0, silence);
967 hr = IMediaEventSink_Notify(pEventSink, EC_COMPLETE, S_OK, 0);
968 IMediaEventSink_Release(pEventSink);
970 LeaveCriticalSection(This->pin.pCritSec);
972 return hr;
975 static HRESULT WINAPI DSoundRender_InputPin_BeginFlush(IPin * iface)
977 InputPin *This = (InputPin *)iface;
978 DSoundRenderImpl *pFilter = (DSoundRenderImpl *)This->pin.pinInfo.pFilter;
979 HRESULT hr;
981 TRACE("\n");
983 EnterCriticalSection(This->pin.pCritSec);
984 hr = InputPin_BeginFlush(iface);
985 SetEvent(pFilter->blocked);
986 LeaveCriticalSection(This->pin.pCritSec);
988 return hr;
991 static HRESULT WINAPI DSoundRender_InputPin_EndFlush(IPin * iface)
993 InputPin *This = (InputPin *)iface;
994 DSoundRenderImpl *pFilter = (DSoundRenderImpl *)This->pin.pinInfo.pFilter;
995 HRESULT hr;
997 TRACE("\n");
999 EnterCriticalSection(This->pin.pCritSec);
1000 if (pFilter->in_loop) {
1001 ResetEvent(pFilter->state_change);
1002 LeaveCriticalSection(This->pin.pCritSec);
1003 WaitForSingleObject(pFilter->state_change, -1);
1004 EnterCriticalSection(This->pin.pCritSec);
1006 if (pFilter->state != State_Stopped)
1007 ResetEvent(pFilter->blocked);
1009 if (pFilter->dsbuffer)
1011 LPBYTE buffer;
1012 DWORD size;
1013 IDirectSoundBuffer_Stop(pFilter->dsbuffer);
1015 /* Force a reset */
1016 IDirectSoundBuffer_SetCurrentPosition(pFilter->dsbuffer, 0);
1017 pFilter->write_pos = pFilter->last_play_pos = 0;
1018 ++pFilter->play_loops;
1019 pFilter->write_loops = pFilter->play_loops;
1021 IDirectSoundBuffer_Lock(pFilter->dsbuffer, 0, 0, (LPVOID *)&buffer, &size, NULL, NULL, DSBLOCK_ENTIREBUFFER);
1022 memset(buffer, 0, size);
1023 IDirectSoundBuffer_Unlock(pFilter->dsbuffer, buffer, size, NULL, 0);
1025 hr = InputPin_EndFlush(iface);
1026 LeaveCriticalSection(This->pin.pCritSec);
1028 return hr;
1031 static const IPinVtbl DSoundRender_InputPin_Vtbl =
1033 InputPin_QueryInterface,
1034 IPinImpl_AddRef,
1035 InputPin_Release,
1036 InputPin_Connect,
1037 DSoundRender_InputPin_ReceiveConnection,
1038 DSoundRender_InputPin_Disconnect,
1039 IPinImpl_ConnectedTo,
1040 IPinImpl_ConnectionMediaType,
1041 IPinImpl_QueryPinInfo,
1042 IPinImpl_QueryDirection,
1043 IPinImpl_QueryId,
1044 IPinImpl_QueryAccept,
1045 IPinImpl_EnumMediaTypes,
1046 IPinImpl_QueryInternalConnections,
1047 DSoundRender_InputPin_EndOfStream,
1048 DSoundRender_InputPin_BeginFlush,
1049 DSoundRender_InputPin_EndFlush,
1050 InputPin_NewSegment
1053 /*** IUnknown methods ***/
1054 static HRESULT WINAPI Basicaudio_QueryInterface(IBasicAudio *iface,
1055 REFIID riid,
1056 LPVOID*ppvObj) {
1057 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1059 TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
1061 return DSoundRender_QueryInterface((IBaseFilter*)This, riid, ppvObj);
1064 static ULONG WINAPI Basicaudio_AddRef(IBasicAudio *iface) {
1065 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1067 TRACE("(%p/%p)->()\n", This, iface);
1069 return DSoundRender_AddRef((IBaseFilter*)This);
1072 static ULONG WINAPI Basicaudio_Release(IBasicAudio *iface) {
1073 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1075 TRACE("(%p/%p)->()\n", This, iface);
1077 return DSoundRender_Release((IBaseFilter*)This);
1080 /*** IDispatch methods ***/
1081 static HRESULT WINAPI Basicaudio_GetTypeInfoCount(IBasicAudio *iface,
1082 UINT*pctinfo) {
1083 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1085 TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pctinfo);
1087 return S_OK;
1090 static HRESULT WINAPI Basicaudio_GetTypeInfo(IBasicAudio *iface,
1091 UINT iTInfo,
1092 LCID lcid,
1093 ITypeInfo**ppTInfo) {
1094 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1096 TRACE("(%p/%p)->(%d, %d, %p): stub !!!\n", This, iface, iTInfo, lcid, ppTInfo);
1098 return S_OK;
1101 static HRESULT WINAPI Basicaudio_GetIDsOfNames(IBasicAudio *iface,
1102 REFIID riid,
1103 LPOLESTR*rgszNames,
1104 UINT cNames,
1105 LCID lcid,
1106 DISPID*rgDispId) {
1107 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1109 TRACE("(%p/%p)->(%s (%p), %p, %d, %d, %p): stub !!!\n", This, iface, debugstr_guid(riid), riid, rgszNames, cNames, lcid, rgDispId);
1111 return S_OK;
1114 static HRESULT WINAPI Basicaudio_Invoke(IBasicAudio *iface,
1115 DISPID dispIdMember,
1116 REFIID riid,
1117 LCID lcid,
1118 WORD wFlags,
1119 DISPPARAMS*pDispParams,
1120 VARIANT*pVarResult,
1121 EXCEPINFO*pExepInfo,
1122 UINT*puArgErr) {
1123 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1125 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);
1127 return S_OK;
1130 /*** IBasicAudio methods ***/
1131 static HRESULT WINAPI Basicaudio_put_Volume(IBasicAudio *iface,
1132 LONG lVolume) {
1133 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1135 TRACE("(%p/%p)->(%d)\n", This, iface, lVolume);
1137 if (lVolume > DSBVOLUME_MAX || lVolume < DSBVOLUME_MIN)
1138 return E_INVALIDARG;
1140 if (This->dsbuffer) {
1141 if (FAILED(IDirectSoundBuffer_SetVolume(This->dsbuffer, lVolume)))
1142 return E_FAIL;
1145 This->volume = lVolume;
1146 return S_OK;
1149 static HRESULT WINAPI Basicaudio_get_Volume(IBasicAudio *iface,
1150 LONG *plVolume) {
1151 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1153 TRACE("(%p/%p)->(%p)\n", This, iface, plVolume);
1155 if (!plVolume)
1156 return E_POINTER;
1158 *plVolume = This->volume;
1159 return S_OK;
1162 static HRESULT WINAPI Basicaudio_put_Balance(IBasicAudio *iface,
1163 LONG lBalance) {
1164 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1166 TRACE("(%p/%p)->(%d)\n", This, iface, lBalance);
1168 if (lBalance < DSBPAN_LEFT || lBalance > DSBPAN_RIGHT)
1169 return E_INVALIDARG;
1171 if (This->dsbuffer) {
1172 if (FAILED(IDirectSoundBuffer_SetPan(This->dsbuffer, lBalance)))
1173 return E_FAIL;
1176 This->pan = lBalance;
1177 return S_OK;
1180 static HRESULT WINAPI Basicaudio_get_Balance(IBasicAudio *iface,
1181 LONG *plBalance) {
1182 ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1184 TRACE("(%p/%p)->(%p)\n", This, iface, plBalance);
1186 if (!plBalance)
1187 return E_POINTER;
1189 *plBalance = This->pan;
1190 return S_OK;
1193 static const IBasicAudioVtbl IBasicAudio_Vtbl =
1195 Basicaudio_QueryInterface,
1196 Basicaudio_AddRef,
1197 Basicaudio_Release,
1198 Basicaudio_GetTypeInfoCount,
1199 Basicaudio_GetTypeInfo,
1200 Basicaudio_GetIDsOfNames,
1201 Basicaudio_Invoke,
1202 Basicaudio_put_Volume,
1203 Basicaudio_get_Volume,
1204 Basicaudio_put_Balance,
1205 Basicaudio_get_Balance
1209 /*** IUnknown methods ***/
1210 static HRESULT WINAPI ReferenceClock_QueryInterface(IReferenceClock *iface,
1211 REFIID riid,
1212 LPVOID*ppvObj)
1214 ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1216 TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
1218 return DSoundRender_QueryInterface((IBaseFilter*)This, riid, ppvObj);
1221 static ULONG WINAPI ReferenceClock_AddRef(IReferenceClock *iface)
1223 ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1225 TRACE("(%p/%p)->()\n", This, iface);
1227 return DSoundRender_AddRef((IBaseFilter*)This);
1230 static ULONG WINAPI ReferenceClock_Release(IReferenceClock *iface)
1232 ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1234 TRACE("(%p/%p)->()\n", This, iface);
1236 return DSoundRender_Release((IBaseFilter*)This);
1239 /*** IReferenceClock methods ***/
1240 static HRESULT WINAPI ReferenceClock_GetTime(IReferenceClock *iface,
1241 REFERENCE_TIME *pTime)
1243 ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1244 HRESULT hr = E_FAIL;
1245 DWORD play_pos;
1247 TRACE("(%p/%p)->(%p)\n", This, iface, pTime);
1249 if (This->dsbuffer)
1250 hr = DSoundRender_GetPos(This, &play_pos, pTime);
1251 if (FAILED(hr))
1252 ERR("Could not get reference time (%x)!\n", hr);
1254 return hr;
1257 static HRESULT WINAPI ReferenceClock_AdviseTime(IReferenceClock *iface,
1258 REFERENCE_TIME rtBaseTime,
1259 REFERENCE_TIME rtStreamTime,
1260 HEVENT hEvent,
1261 DWORD_PTR *pdwAdviseCookie)
1263 ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1265 FIXME("(%p/%p)->(%s, %s, %p, %p): stub!\n", This, iface, wine_dbgstr_longlong(rtBaseTime), wine_dbgstr_longlong(rtStreamTime), (void*)hEvent, pdwAdviseCookie);
1267 return E_NOTIMPL;
1270 static HRESULT WINAPI ReferenceClock_AdvisePeriodic(IReferenceClock *iface,
1271 REFERENCE_TIME rtBaseTime,
1272 REFERENCE_TIME rtStreamTime,
1273 HSEMAPHORE hSemaphore,
1274 DWORD_PTR *pdwAdviseCookie)
1276 ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1278 FIXME("(%p/%p)->(%s, %s, %p, %p): stub!\n", This, iface, wine_dbgstr_longlong(rtBaseTime), wine_dbgstr_longlong(rtStreamTime), (void*)hSemaphore, pdwAdviseCookie);
1280 return E_NOTIMPL;
1283 static HRESULT WINAPI ReferenceClock_Unadvise(IReferenceClock *iface,
1284 DWORD_PTR dwAdviseCookie)
1286 ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1288 FIXME("(%p/%p)->(%p): stub!\n", This, iface, (void*)dwAdviseCookie);
1290 return S_FALSE;
1293 static const IReferenceClockVtbl IReferenceClock_Vtbl =
1295 ReferenceClock_QueryInterface,
1296 ReferenceClock_AddRef,
1297 ReferenceClock_Release,
1298 ReferenceClock_GetTime,
1299 ReferenceClock_AdviseTime,
1300 ReferenceClock_AdvisePeriodic,
1301 ReferenceClock_Unadvise
1304 static inline DSoundRenderImpl *impl_from_IMediaSeeking( IMediaSeeking *iface )
1306 return (DSoundRenderImpl *)((char*)iface - FIELD_OFFSET(DSoundRenderImpl, mediaSeeking.lpVtbl));
1309 static HRESULT WINAPI sound_seek_QueryInterface(IMediaSeeking * iface, REFIID riid, LPVOID * ppv)
1311 DSoundRenderImpl *This = impl_from_IMediaSeeking(iface);
1313 return IUnknown_QueryInterface((IUnknown *)This, riid, ppv);
1316 static ULONG WINAPI sound_seek_AddRef(IMediaSeeking * iface)
1318 DSoundRenderImpl *This = impl_from_IMediaSeeking(iface);
1320 return IUnknown_AddRef((IUnknown *)This);
1323 static ULONG WINAPI sound_seek_Release(IMediaSeeking * iface)
1325 DSoundRenderImpl *This = impl_from_IMediaSeeking(iface);
1327 return IUnknown_Release((IUnknown *)This);
1330 static const IMediaSeekingVtbl IMediaSeeking_Vtbl =
1332 sound_seek_QueryInterface,
1333 sound_seek_AddRef,
1334 sound_seek_Release,
1335 MediaSeekingImpl_GetCapabilities,
1336 MediaSeekingImpl_CheckCapabilities,
1337 MediaSeekingImpl_IsFormatSupported,
1338 MediaSeekingImpl_QueryPreferredFormat,
1339 MediaSeekingImpl_GetTimeFormat,
1340 MediaSeekingImpl_IsUsingTimeFormat,
1341 MediaSeekingImpl_SetTimeFormat,
1342 MediaSeekingImpl_GetDuration,
1343 MediaSeekingImpl_GetStopPosition,
1344 MediaSeekingImpl_GetCurrentPosition,
1345 MediaSeekingImpl_ConvertTimeFormat,
1346 MediaSeekingImpl_SetPositions,
1347 MediaSeekingImpl_GetPositions,
1348 MediaSeekingImpl_GetAvailable,
1349 MediaSeekingImpl_SetRate,
1350 MediaSeekingImpl_GetRate,
1351 MediaSeekingImpl_GetPreroll
1354 /*** IUnknown methods ***/
1355 static HRESULT WINAPI AMDirectSound_QueryInterface(IAMDirectSound *iface,
1356 REFIID riid,
1357 LPVOID*ppvObj)
1359 ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1361 TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
1363 return DSoundRender_QueryInterface((IBaseFilter*)This, riid, ppvObj);
1366 static ULONG WINAPI AMDirectSound_AddRef(IAMDirectSound *iface)
1368 ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1370 TRACE("(%p/%p)->()\n", This, iface);
1372 return DSoundRender_AddRef((IBaseFilter*)This);
1375 static ULONG WINAPI AMDirectSound_Release(IAMDirectSound *iface)
1377 ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1379 TRACE("(%p/%p)->()\n", This, iface);
1381 return DSoundRender_Release((IBaseFilter*)This);
1384 /*** IAMDirectSound methods ***/
1385 static HRESULT WINAPI AMDirectSound_GetDirectSoundInterface(IAMDirectSound *iface, IDirectSound **ds)
1387 ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1389 FIXME("(%p/%p)->(%p): stub\n", This, iface, ds);
1391 return E_NOTIMPL;
1394 static HRESULT WINAPI AMDirectSound_GetPrimaryBufferInterface(IAMDirectSound *iface, IDirectSoundBuffer **buf)
1396 ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1398 FIXME("(%p/%p)->(%p): stub\n", This, iface, buf);
1400 return E_NOTIMPL;
1403 static HRESULT WINAPI AMDirectSound_GetSecondaryBufferInterface(IAMDirectSound *iface, IDirectSoundBuffer **buf)
1405 ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1407 FIXME("(%p/%p)->(%p): stub\n", This, iface, buf);
1409 return E_NOTIMPL;
1412 static HRESULT WINAPI AMDirectSound_ReleaseDirectSoundInterface(IAMDirectSound *iface, IDirectSound *ds)
1414 ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1416 FIXME("(%p/%p)->(%p): stub\n", This, iface, ds);
1418 return E_NOTIMPL;
1421 static HRESULT WINAPI AMDirectSound_ReleasePrimaryBufferInterface(IAMDirectSound *iface, IDirectSoundBuffer *buf)
1423 ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1425 FIXME("(%p/%p)->(%p): stub\n", This, iface, buf);
1427 return E_NOTIMPL;
1430 static HRESULT WINAPI AMDirectSound_ReleaseSecondaryBufferInterface(IAMDirectSound *iface, IDirectSoundBuffer *buf)
1432 ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1434 FIXME("(%p/%p)->(%p): stub\n", This, iface, buf);
1436 return E_NOTIMPL;
1439 static HRESULT WINAPI AMDirectSound_SetFocusWindow(IAMDirectSound *iface, HWND hwnd, BOOL bgsilent)
1441 ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1443 FIXME("(%p/%p)->(%p,%d): stub\n", This, iface, hwnd, bgsilent);
1445 return E_NOTIMPL;
1448 static HRESULT WINAPI AMDirectSound_GetFocusWindow(IAMDirectSound *iface, HWND hwnd)
1450 ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1452 FIXME("(%p/%p)->(%p): stub\n", This, iface, hwnd);
1454 return E_NOTIMPL;
1457 static const IAMDirectSoundVtbl IAMDirectSound_Vtbl =
1459 AMDirectSound_QueryInterface,
1460 AMDirectSound_AddRef,
1461 AMDirectSound_Release,
1462 AMDirectSound_GetDirectSoundInterface,
1463 AMDirectSound_GetPrimaryBufferInterface,
1464 AMDirectSound_GetSecondaryBufferInterface,
1465 AMDirectSound_ReleaseDirectSoundInterface,
1466 AMDirectSound_ReleasePrimaryBufferInterface,
1467 AMDirectSound_ReleaseSecondaryBufferInterface,
1468 AMDirectSound_SetFocusWindow,
1469 AMDirectSound_GetFocusWindow