quartz: Add IAMFilterMiscFlags to directsound renderer.
[wine] / dlls / quartz / dsoundrender.c
1 /*
2  * Direct Sound Audio Renderer
3  *
4  * Copyright 2004 Christian Costa
5  *
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.
10  *
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.
15  *
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
19  */
20
21 #include "config.h"
22
23 #include "quartz_private.h"
24 #include "control_private.h"
25 #include "pin.h"
26
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"
36
37 #include "wine/unicode.h"
38 #include "wine/debug.h"
39
40 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
41
42 static const WCHAR wcsInputPinName[] = {'i','n','p','u','t',' ','p','i','n',0};
43
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;
50 static const IAMFilterMiscFlagsVtbl IAMFilterMiscFlags_Vtbl;
51
52 typedef struct DSoundRenderImpl
53 {
54     BaseFilter filter;
55
56     const IBasicAudioVtbl *IBasicAudio_vtbl;
57     const IReferenceClockVtbl *IReferenceClock_vtbl;
58     const IAMDirectSoundVtbl *IAMDirectSound_vtbl;
59     const IAMFilterMiscFlagsVtbl *IAMFilterMiscFlags_vtbl;
60     IUnknown *seekthru_unk;
61
62     REFERENCE_TIME rtLastStop;
63
64     BaseInputPin * pInputPin;
65
66     IDirectSound8 *dsound;
67     LPDIRECTSOUNDBUFFER dsbuffer;
68     DWORD buf_size;
69     DWORD write_pos;
70     DWORD write_loops;
71
72     DWORD last_play_pos;
73     DWORD play_loops;
74     DWORD in_loop;
75
76     REFERENCE_TIME play_time;
77
78     HANDLE state_change, blocked;
79
80     LONG volume;
81     LONG pan;
82 } DSoundRenderImpl;
83
84 static inline HRESULT DSoundRender_GetPos(DSoundRenderImpl *This, DWORD *pPlayPos, REFERENCE_TIME *pRefTime)
85 {
86     HRESULT hr;
87
88     EnterCriticalSection(&This->filter.csFilter);
89     {
90         DWORD state;
91         DWORD write_pos;
92
93         hr = IDirectSoundBuffer_GetStatus(This->dsbuffer, &state);
94         if (SUCCEEDED(hr) && !(state & DSBSTATUS_PLAYING) && This->filter.state == State_Running)
95         {
96             TRACE("Not playing, kickstarting the engine\n");
97
98             hr = IDirectSoundBuffer_Play(This->dsbuffer, 0, 0, DSBPLAY_LOOPING);
99             if (FAILED(hr))
100                 ERR("Can't play sound buffer (%x)\n", hr);
101         }
102
103         if (SUCCEEDED(hr))
104             hr = IDirectSoundBuffer_GetCurrentPosition(This->dsbuffer, pPlayPos, &write_pos);
105         if (hr == S_OK)
106         {
107             DWORD play_pos = *pPlayPos;
108
109             if (play_pos < This->last_play_pos)
110                 This->play_loops++;
111             This->last_play_pos = play_pos;
112
113             /* If we really fell behind, start at the next possible position
114              * Also happens when just starting playback for the first time,
115              * or when flushing
116              */
117             if ((This->play_loops*This->buf_size)+play_pos >=
118                 (This->write_loops*This->buf_size)+This->write_pos)
119                 This->write_pos = write_pos;
120
121             if (pRefTime)
122             {
123                 REFERENCE_TIME play_time;
124                 play_time = ((REFERENCE_TIME)This->play_loops*10000000) +
125                             ((REFERENCE_TIME)play_pos*10000000/This->buf_size);
126
127                 /* Don't let time run backwards */
128                 if(play_time-This->play_time > 0)
129                     This->play_time = play_time;
130                 else
131                     hr = S_FALSE;
132
133                 *pRefTime = This->play_time;
134             }
135         }
136     }
137     LeaveCriticalSection(&This->filter.csFilter);
138
139     return hr;
140 }
141
142 static HRESULT DSoundRender_SendSampleData(DSoundRenderImpl* This, const BYTE *data, DWORD size)
143 {
144     HRESULT hr = S_OK;
145     LPBYTE lpbuf1 = NULL;
146     LPBYTE lpbuf2 = NULL;
147     DWORD dwsize1 = 0;
148     DWORD dwsize2 = 0;
149     DWORD size2;
150     DWORD play_pos,buf_free;
151
152     do {
153
154         hr = DSoundRender_GetPos(This, &play_pos, NULL);
155         if (hr != DS_OK)
156         {
157             ERR("GetPos returned error: %x\n", hr);
158             break;
159         }
160         if (This->write_pos <= play_pos)
161              buf_free = play_pos-This->write_pos;
162         else
163              buf_free = This->buf_size - This->write_pos + play_pos;
164
165         /* Wait for enough of the buffer to empty before filling it */
166         if(buf_free < This->buf_size/20)
167         {
168             DWORD ret;
169             This->in_loop = 1;
170             LeaveCriticalSection(&This->filter.csFilter);
171             ret = WaitForSingleObject(This->blocked, 50);
172             if (ret != WAIT_TIMEOUT)
173                 ERR("%x\n", ret);
174             EnterCriticalSection(&This->filter.csFilter);
175             This->in_loop = 0;
176             if (This->pInputPin->flushing)
177                 return VFW_E_WRONG_STATE;
178             if (This->filter.state == State_Stopped)
179                 return VFW_E_WRONG_STATE;
180             continue;
181         }
182
183         size2 = min(buf_free, size);
184         hr = IDirectSoundBuffer_Lock(This->dsbuffer, This->write_pos, size2, (LPVOID *)&lpbuf1, &dwsize1, (LPVOID *)&lpbuf2, &dwsize2, 0);
185         if (hr != DS_OK) {
186             ERR("Unable to lock sound buffer! (%x)\n", hr);
187             break;
188         }
189         /* TRACE("write_pos=%d, size=%d, sz1=%d, sz2=%d\n", This->write_pos, size2, dwsize1, dwsize2); */
190
191         memcpy(lpbuf1, data, dwsize1);
192         if (dwsize2)
193             memcpy(lpbuf2, data + dwsize1, dwsize2);
194
195         hr = IDirectSoundBuffer_Unlock(This->dsbuffer, lpbuf1, dwsize1, lpbuf2, dwsize2);
196         if (hr != DS_OK)
197             ERR("Unable to unlock sound buffer! (%x)\n", hr);
198
199         size -= dwsize1 + dwsize2;
200         data += dwsize1 + dwsize2;
201         This->write_pos += dwsize1 + dwsize2;
202         if (This->write_pos >= This->buf_size)
203         {
204             This->write_pos -= This->buf_size;
205             This->write_loops++;
206         }
207     } while (size && This->filter.state == State_Running);
208
209     return hr;
210 }
211
212 static HRESULT WINAPI DSoundRender_Receive(BaseInputPin *pin, IMediaSample * pSample)
213 {
214     DSoundRenderImpl *This = (DSoundRenderImpl*)pin->pin.pinInfo.pFilter;
215     LPBYTE pbSrcStream = NULL;
216     LONG cbSrcStream = 0;
217     REFERENCE_TIME tStart, tStop;
218     HRESULT hr;
219     AM_MEDIA_TYPE *amt;
220
221     TRACE("%p %p\n", pin, pSample);
222
223     /* Slightly incorrect, Pause completes when a frame is received so we should signal
224      * pause completion here, but for sound playing a single frame doesn't make sense
225      */
226
227     EnterCriticalSection(&This->filter.csFilter);
228
229     if (This->pInputPin->end_of_stream || This->pInputPin->flushing)
230     {
231         LeaveCriticalSection(&This->filter.csFilter);
232         return S_FALSE;
233     }
234
235     if (This->filter.state == State_Stopped)
236     {
237         LeaveCriticalSection(&This->filter.csFilter);
238         return VFW_E_WRONG_STATE;
239     }
240
241     if (IMediaSample_GetMediaType(pSample, &amt) == S_OK)
242     {
243         AM_MEDIA_TYPE *orig = &This->pInputPin->pin.mtCurrent;
244         WAVEFORMATEX *origfmt = (WAVEFORMATEX *)orig->pbFormat;
245         WAVEFORMATEX *newfmt = (WAVEFORMATEX *)amt->pbFormat;
246
247         if (origfmt->wFormatTag == newfmt->wFormatTag &&
248             origfmt->nChannels == newfmt->nChannels &&
249             origfmt->nBlockAlign == newfmt->nBlockAlign &&
250             origfmt->wBitsPerSample == newfmt->wBitsPerSample &&
251             origfmt->cbSize ==  newfmt->cbSize)
252         {
253             if (origfmt->nSamplesPerSec != newfmt->nSamplesPerSec)
254             {
255                 hr = IDirectSoundBuffer_SetFrequency(This->dsbuffer,
256                                                      newfmt->nSamplesPerSec);
257                 if (FAILED(hr))
258                 {
259                     LeaveCriticalSection(&This->filter.csFilter);
260                     return VFW_E_TYPE_NOT_ACCEPTED;
261                 }
262                 FreeMediaType(orig);
263                 CopyMediaType(orig, amt);
264                 IMediaSample_SetMediaType(pSample, NULL);
265             }
266         }
267         else
268         {
269             LeaveCriticalSection(&This->filter.csFilter);
270             return VFW_E_TYPE_NOT_ACCEPTED;
271         }
272     }
273
274     hr = IMediaSample_GetPointer(pSample, &pbSrcStream);
275     if (FAILED(hr))
276     {
277         ERR("Cannot get pointer to sample data (%x)\n", hr);
278         LeaveCriticalSection(&This->filter.csFilter);
279         return hr;
280     }
281
282     hr = IMediaSample_GetTime(pSample, &tStart, &tStop);
283     if (FAILED(hr))
284         ERR("Cannot get sample time (%x)\n", hr);
285     else
286         MediaSeekingPassThru_RegisterMediaTime(This->seekthru_unk, tStart);
287
288     if (This->rtLastStop != tStart && (IMediaSample_IsDiscontinuity(pSample) == S_FALSE))
289         WARN("Unexpected discontinuity: Last: %u.%03u, tStart: %u.%03u\n",
290             (DWORD)(This->rtLastStop / 10000000), (DWORD)((This->rtLastStop / 10000)%1000),
291             (DWORD)(tStart / 10000000), (DWORD)((tStart / 10000)%1000));
292     This->rtLastStop = tStop;
293
294     if (IMediaSample_IsPreroll(pSample) == S_OK)
295     {
296         TRACE("Preroll!\n");
297         LeaveCriticalSection(&This->filter.csFilter);
298         return S_OK;
299     }
300
301     if (This->filter.state == State_Paused)
302     {
303         SetEvent(This->state_change);
304         LeaveCriticalSection(&This->filter.csFilter);
305         WaitForSingleObject(This->blocked, INFINITE);
306         EnterCriticalSection(&This->filter.csFilter);
307         if (This->filter.state == State_Stopped)
308         {
309             LeaveCriticalSection(&This->filter.csFilter);
310             return VFW_E_WRONG_STATE;
311         }
312
313         if (This->filter.state == State_Paused)
314         {
315             /* Assuming we return because of flushing */
316             TRACE("Flushing\n");
317             LeaveCriticalSection(&This->filter.csFilter);
318             return S_OK;
319         }
320         SetEvent(This->state_change);
321     }
322
323     cbSrcStream = IMediaSample_GetActualDataLength(pSample);
324     TRACE("Sample data ptr = %p, size = %d\n", pbSrcStream, cbSrcStream);
325
326 #if 0 /* For debugging purpose */
327     {
328         int i;
329         for(i = 0; i < cbSrcStream; i++)
330         {
331             if ((i!=0) && !(i%16))
332                 TRACE("\n");
333             TRACE("%02x ", pbSrcStream[i]);
334         }
335         TRACE("\n");
336     }
337 #endif
338
339     hr = DSoundRender_SendSampleData(This, pbSrcStream, cbSrcStream);
340     SetEvent(This->state_change);
341     LeaveCriticalSection(&This->filter.csFilter);
342     return hr;
343 }
344
345 static HRESULT WINAPI DSoundRender_CheckMediaType(BasePin *iface, const AM_MEDIA_TYPE * pmt)
346 {
347     WAVEFORMATEX* format;
348
349     if (!IsEqualIID(&pmt->majortype, &MEDIATYPE_Audio))
350         return S_FALSE;
351
352     format =  (WAVEFORMATEX*)pmt->pbFormat;
353     TRACE("Format = %p\n", format);
354     TRACE("wFormatTag = %x %x\n", format->wFormatTag, WAVE_FORMAT_PCM);
355     TRACE("nChannels = %d\n", format->nChannels);
356     TRACE("nSamplesPerSec = %d\n", format->nAvgBytesPerSec);
357     TRACE("nAvgBytesPerSec = %d\n", format->nAvgBytesPerSec);
358     TRACE("nBlockAlign = %d\n", format->nBlockAlign);
359     TRACE("wBitsPerSample = %d\n", format->wBitsPerSample);
360
361     if (!IsEqualIID(&pmt->subtype, &MEDIASUBTYPE_PCM))
362         return S_FALSE;
363
364     return S_OK;
365 }
366
367 static IPin* WINAPI DSoundRender_GetPin(BaseFilter *iface, int pos)
368 {
369     DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
370
371     if (pos >= 1 || pos < 0)
372         return NULL;
373
374     IPin_AddRef((IPin*)This->pInputPin);
375     return (IPin*)This->pInputPin;
376 }
377
378 static LONG WINAPI DSoundRender_GetPinCount(BaseFilter *iface)
379 {
380     /* Our pins are static */
381     return 1;
382 }
383
384 static const BaseFilterFuncTable BaseFuncTable = {
385     DSoundRender_GetPin,
386     DSoundRender_GetPinCount
387 };
388
389 static const  BasePinFuncTable input_BaseFuncTable = {
390     DSoundRender_CheckMediaType,
391     NULL,
392     BasePinImpl_GetMediaTypeVersion,
393     BasePinImpl_GetMediaType
394 };
395
396 static const BaseInputPinFuncTable input_BaseInputFuncTable = {
397     DSoundRender_Receive
398 };
399
400
401 HRESULT DSoundRender_create(IUnknown * pUnkOuter, LPVOID * ppv)
402 {
403     HRESULT hr;
404     PIN_INFO piInput;
405     DSoundRenderImpl * pDSoundRender;
406
407     TRACE("(%p, %p)\n", pUnkOuter, ppv);
408
409     *ppv = NULL;
410
411     if (pUnkOuter)
412         return CLASS_E_NOAGGREGATION;
413     
414     pDSoundRender = CoTaskMemAlloc(sizeof(DSoundRenderImpl));
415     if (!pDSoundRender)
416         return E_OUTOFMEMORY;
417     ZeroMemory(pDSoundRender, sizeof(DSoundRenderImpl));
418
419     BaseFilter_Init(&pDSoundRender->filter, &DSoundRender_Vtbl, &CLSID_DSoundRender, (DWORD_PTR)(__FILE__ ": DSoundRenderImpl.csFilter"), &BaseFuncTable);
420
421     pDSoundRender->IBasicAudio_vtbl = &IBasicAudio_Vtbl;
422     pDSoundRender->IReferenceClock_vtbl = &IReferenceClock_Vtbl;
423     pDSoundRender->IAMDirectSound_vtbl = &IAMDirectSound_Vtbl;
424     pDSoundRender->IAMFilterMiscFlags_vtbl = &IAMFilterMiscFlags_Vtbl;
425
426     /* construct input pin */
427     piInput.dir = PINDIR_INPUT;
428     piInput.pFilter = (IBaseFilter *)pDSoundRender;
429     lstrcpynW(piInput.achName, wcsInputPinName, sizeof(piInput.achName) / sizeof(piInput.achName[0]));
430     hr = BaseInputPin_Construct(&DSoundRender_InputPin_Vtbl, &piInput, &input_BaseFuncTable, &input_BaseInputFuncTable, &pDSoundRender->filter.csFilter, NULL, (IPin **)&pDSoundRender->pInputPin);
431
432     if (SUCCEEDED(hr))
433     {
434         hr = DirectSoundCreate8(NULL, &pDSoundRender->dsound, NULL);
435         if (FAILED(hr))
436             ERR("Cannot create Direct Sound object (%x)\n", hr);
437         else
438             IDirectSound_SetCooperativeLevel(pDSoundRender->dsound, GetDesktopWindow(), DSSCL_PRIORITY);
439     }
440
441     if (SUCCEEDED(hr))
442     {
443         ISeekingPassThru *passthru;
444         pDSoundRender->state_change = CreateEventW(NULL, TRUE, TRUE, NULL);
445         pDSoundRender->blocked = CreateEventW(NULL, TRUE, TRUE, NULL);
446         hr = CoCreateInstance(&CLSID_SeekingPassThru, (IUnknown*)pDSoundRender, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void**)&pDSoundRender->seekthru_unk);
447         if (!pDSoundRender->state_change || !pDSoundRender->blocked || FAILED(hr))
448         {
449             IUnknown_Release((IUnknown *)pDSoundRender);
450             return HRESULT_FROM_WIN32(GetLastError());
451         }
452
453         IUnknown_QueryInterface(pDSoundRender->seekthru_unk, &IID_ISeekingPassThru, (void**)&passthru);
454         ISeekingPassThru_Init(passthru, TRUE, (IPin*)pDSoundRender->pInputPin);
455         ISeekingPassThru_Release(passthru);
456         *ppv = pDSoundRender;
457     }
458     else
459     {
460         if (pDSoundRender->pInputPin)
461             IPin_Release((IPin*)pDSoundRender->pInputPin);
462         BaseFilterImpl_Release((IBaseFilter*)pDSoundRender);
463         CoTaskMemFree(pDSoundRender);
464     }
465
466     return hr;
467 }
468
469 static HRESULT WINAPI DSoundRender_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv)
470 {
471     DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
472     TRACE("(%p, %p)->(%s, %p)\n", This, iface, qzdebugstr_guid(riid), ppv);
473
474     *ppv = NULL;
475
476     if (IsEqualIID(riid, &IID_IUnknown))
477         *ppv = This;
478     else if (IsEqualIID(riid, &IID_IPersist))
479         *ppv = This;
480     else if (IsEqualIID(riid, &IID_IMediaFilter))
481         *ppv = This;
482     else if (IsEqualIID(riid, &IID_IBaseFilter))
483         *ppv = This;
484     else if (IsEqualIID(riid, &IID_IBasicAudio))
485         *ppv = &This->IBasicAudio_vtbl;
486     else if (IsEqualIID(riid, &IID_IReferenceClock))
487         *ppv = &This->IReferenceClock_vtbl;
488     else if (IsEqualIID(riid, &IID_IMediaSeeking))
489         return IUnknown_QueryInterface(This->seekthru_unk, riid, ppv);
490     else if (IsEqualIID(riid, &IID_IAMDirectSound))
491         *ppv = &This->IAMDirectSound_vtbl;
492     else if (IsEqualIID(riid, &IID_IAMFilterMiscFlags))
493         *ppv = &This->IAMFilterMiscFlags_vtbl;
494
495     if (*ppv)
496     {
497         IUnknown_AddRef((IUnknown *)(*ppv));
498         return S_OK;
499     }
500
501     if (!IsEqualIID(riid, &IID_IPin) && !IsEqualIID(riid, &IID_IVideoWindow))
502         FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
503
504     return E_NOINTERFACE;
505 }
506
507 static ULONG WINAPI DSoundRender_Release(IBaseFilter * iface)
508 {
509     DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
510     ULONG refCount = BaseFilterImpl_Release(iface);
511
512     TRACE("(%p)->() Release from %d\n", This, refCount + 1);
513
514     if (!refCount)
515     {
516         IPin *pConnectedTo;
517
518         if (This->dsbuffer)
519             IDirectSoundBuffer_Release(This->dsbuffer);
520         This->dsbuffer = NULL;
521         if (This->dsound)
522             IDirectSound_Release(This->dsound);
523         This->dsound = NULL;
524        
525         if (SUCCEEDED(IPin_ConnectedTo((IPin *)This->pInputPin, &pConnectedTo)))
526         {
527             IPin_Disconnect(pConnectedTo);
528             IPin_Release(pConnectedTo);
529         }
530         IPin_Disconnect((IPin *)This->pInputPin);
531
532         IPin_Release((IPin *)This->pInputPin);
533
534         This->IBasicAudio_vtbl = NULL;
535         if (This->seekthru_unk)
536             IUnknown_Release(This->seekthru_unk);
537
538         CloseHandle(This->state_change);
539         CloseHandle(This->blocked);
540
541         TRACE("Destroying Audio Renderer\n");
542         CoTaskMemFree(This);
543         
544         return 0;
545     }
546     else
547         return refCount;
548 }
549
550 /** IMediaFilter methods **/
551
552 static HRESULT WINAPI DSoundRender_Stop(IBaseFilter * iface)
553 {
554     HRESULT hr = S_OK;
555     DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
556
557     TRACE("(%p/%p)->()\n", This, iface);
558
559     EnterCriticalSection(&This->filter.csFilter);
560     {
561         DWORD state = 0;
562         if (This->dsbuffer)
563         {
564             hr = IDirectSoundBuffer_GetStatus(This->dsbuffer, &state);
565             if (SUCCEEDED(hr))
566             {
567                 if (state & DSBSTATUS_PLAYING)
568                     hr = IDirectSoundBuffer_Stop(This->dsbuffer);
569             }
570         }
571         if (SUCCEEDED(hr))
572             This->filter.state = State_Stopped;
573
574         /* Complete our transition */
575         SetEvent(This->state_change);
576         SetEvent(This->blocked);
577         MediaSeekingPassThru_ResetMediaTime(This->seekthru_unk);
578     }
579     LeaveCriticalSection(&This->filter.csFilter);
580     
581     return hr;
582 }
583
584 static HRESULT WINAPI DSoundRender_Pause(IBaseFilter * iface)
585 {
586     HRESULT hr = S_OK;
587     DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
588     
589     TRACE("(%p/%p)->()\n", This, iface);
590
591     EnterCriticalSection(&This->filter.csFilter);
592     if (This->filter.state != State_Paused)
593     {
594         DWORD state = 0;
595         if (This->filter.state == State_Stopped)
596         {
597             This->pInputPin->end_of_stream = 0;
598         }
599
600         if (This->dsbuffer)
601         {
602             hr = IDirectSoundBuffer_GetStatus(This->dsbuffer, &state);
603             if (SUCCEEDED(hr))
604             {
605                 if (state & DSBSTATUS_PLAYING)
606                     hr = IDirectSoundBuffer_Stop(This->dsbuffer);
607             }
608         }
609         if (SUCCEEDED(hr))
610             This->filter.state = State_Paused;
611
612         ResetEvent(This->blocked);
613         ResetEvent(This->state_change);
614     }
615     LeaveCriticalSection(&This->filter.csFilter);
616
617     return hr;
618 }
619
620 static HRESULT WINAPI DSoundRender_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
621 {
622     HRESULT hr = S_OK;
623     DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
624
625     TRACE("(%p/%p)->(%s)\n", This, iface, wine_dbgstr_longlong(tStart));
626
627     EnterCriticalSection(&This->filter.csFilter);
628     if (This->pInputPin->pin.pConnectedTo)
629     {
630         This->filter.rtStreamStart = tStart;
631         if (This->filter.state == State_Paused)
632         {
633             /* Unblock our thread, state changing from paused to running doesn't need a reset for state change */
634             SetEvent(This->blocked);
635         }
636         else if (This->filter.state == State_Stopped)
637         {
638             ResetEvent(This->state_change);
639             This->pInputPin->end_of_stream = 0;
640         }
641         ResetEvent(This->blocked);
642     } else if (This->filter.filterInfo.pGraph) {
643         IMediaEventSink *pEventSink;
644         hr = IFilterGraph_QueryInterface(This->filter.filterInfo.pGraph, &IID_IMediaEventSink, (LPVOID*)&pEventSink);
645         if (SUCCEEDED(hr))
646         {
647             hr = IMediaEventSink_Notify(pEventSink, EC_COMPLETE, S_OK, (LONG_PTR)This);
648             IMediaEventSink_Release(pEventSink);
649         }
650         hr = S_OK;
651     }
652     if (SUCCEEDED(hr))
653         This->filter.state = State_Running;
654     LeaveCriticalSection(&This->filter.csFilter);
655
656     return hr;
657 }
658
659 static HRESULT WINAPI DSoundRender_GetState(IBaseFilter * iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState)
660 {
661     HRESULT hr;
662     DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
663
664     TRACE("(%p/%p)->(%d, %p)\n", This, iface, dwMilliSecsTimeout, pState);
665
666     if (WaitForSingleObject(This->state_change, dwMilliSecsTimeout) == WAIT_TIMEOUT)
667         hr = VFW_S_STATE_INTERMEDIATE;
668     else
669         hr = S_OK;
670
671     BaseFilterImpl_GetState(iface, dwMilliSecsTimeout, pState);
672
673     return hr;
674 }
675
676 /** IBaseFilter implementation **/
677
678 static HRESULT WINAPI DSoundRender_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin)
679 {
680     DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
681
682     TRACE("(%p/%p)->(%s,%p)\n", This, iface, debugstr_w(Id), ppPin);
683     
684     FIXME("DSoundRender::FindPin(...)\n");
685
686     /* FIXME: critical section */
687
688     return E_NOTIMPL;
689 }
690
691 static const IBaseFilterVtbl DSoundRender_Vtbl =
692 {
693     DSoundRender_QueryInterface,
694     BaseFilterImpl_AddRef,
695     DSoundRender_Release,
696     BaseFilterImpl_GetClassID,
697     DSoundRender_Stop,
698     DSoundRender_Pause,
699     DSoundRender_Run,
700     DSoundRender_GetState,
701     BaseFilterImpl_SetSyncSource,
702     BaseFilterImpl_GetSyncSource,
703     BaseFilterImpl_EnumPins,
704     DSoundRender_FindPin,
705     BaseFilterImpl_QueryFilterInfo,
706     BaseFilterImpl_JoinFilterGraph,
707     BaseFilterImpl_QueryVendorInfo
708 };
709
710 static HRESULT WINAPI DSoundRender_InputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
711 {
712     BaseInputPin *This = (BaseInputPin *)iface;
713     PIN_DIRECTION pindirReceive;
714     DSoundRenderImpl *DSImpl;
715     HRESULT hr = S_OK;
716
717     TRACE("(%p)->(%p, %p)\n", This, pReceivePin, pmt);
718     dump_AM_MEDIA_TYPE(pmt);
719
720     EnterCriticalSection(This->pin.pCritSec);
721     {
722         DSImpl = (DSoundRenderImpl*)This->pin.pinInfo.pFilter;
723         DSImpl->rtLastStop = -1;
724
725         if (This->pin.pConnectedTo)
726             hr = VFW_E_ALREADY_CONNECTED;
727
728         if (SUCCEEDED(hr) && This->pin.pFuncsTable->pfnCheckMediaType((BasePin*)This, pmt) != S_OK)
729             hr = VFW_E_TYPE_NOT_ACCEPTED;
730
731         if (SUCCEEDED(hr))
732         {
733             IPin_QueryDirection(pReceivePin, &pindirReceive);
734
735             if (pindirReceive != PINDIR_OUTPUT)
736             {
737                 ERR("Can't connect from non-output pin\n");
738                 hr = VFW_E_INVALID_DIRECTION;
739             }
740         }
741
742         if (SUCCEEDED(hr))
743         {
744             WAVEFORMATEX *format;
745             DSBUFFERDESC buf_desc;
746
747             TRACE("MajorType %s\n", debugstr_guid(&pmt->majortype));
748             TRACE("SubType %s\n", debugstr_guid(&pmt->subtype));
749             TRACE("Format %s\n", debugstr_guid(&pmt->formattype));
750             TRACE("Size %d\n", pmt->cbFormat);
751
752             format = (WAVEFORMATEX*)pmt->pbFormat;
753
754             DSImpl->buf_size = format->nAvgBytesPerSec;
755
756             memset(&buf_desc,0,sizeof(DSBUFFERDESC));
757             buf_desc.dwSize = sizeof(DSBUFFERDESC);
758             buf_desc.dwFlags = DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLPAN |
759                                DSBCAPS_CTRLFREQUENCY |
760                                DSBCAPS_GETCURRENTPOSITION2;
761             buf_desc.dwBufferBytes = DSImpl->buf_size;
762             buf_desc.lpwfxFormat = format;
763             hr = IDirectSound_CreateSoundBuffer(DSImpl->dsound, &buf_desc, &DSImpl->dsbuffer, NULL);
764             if (FAILED(hr))
765                 ERR("Can't create sound buffer (%x)\n", hr);
766         }
767
768         if (SUCCEEDED(hr))
769         {
770             hr = IDirectSoundBuffer_SetVolume(DSImpl->dsbuffer, DSImpl->volume);
771             if (FAILED(hr))
772                 ERR("Can't set volume to %d (%x)\n", DSImpl->volume, hr);
773
774             hr = IDirectSoundBuffer_SetPan(DSImpl->dsbuffer, DSImpl->pan);
775             if (FAILED(hr))
776                 ERR("Can't set pan to %d (%x)\n", DSImpl->pan, hr);
777
778             DSImpl->write_pos = 0;
779             hr = S_OK;
780         }
781
782         if (SUCCEEDED(hr))
783         {
784             CopyMediaType(&This->pin.mtCurrent, pmt);
785             This->pin.pConnectedTo = pReceivePin;
786             IPin_AddRef(pReceivePin);
787         }
788         else if (hr != VFW_E_ALREADY_CONNECTED)
789         {
790             if (DSImpl->dsbuffer)
791                 IDirectSoundBuffer_Release(DSImpl->dsbuffer);
792             DSImpl->dsbuffer = NULL;
793         }
794     }
795     LeaveCriticalSection(This->pin.pCritSec);
796
797     return hr;
798 }
799
800 static HRESULT WINAPI DSoundRender_InputPin_Disconnect(IPin * iface)
801 {
802     BasePin *This = (BasePin*)iface;
803     DSoundRenderImpl *DSImpl;
804
805     TRACE("(%p)->()\n", iface);
806
807     DSImpl = (DSoundRenderImpl*)This->pinInfo.pFilter;
808     if (DSImpl->dsbuffer)
809         IDirectSoundBuffer_Release(DSImpl->dsbuffer);
810     DSImpl->dsbuffer = NULL;
811
812     return BasePinImpl_Disconnect(iface);
813 }
814
815 static HRESULT WINAPI DSoundRender_InputPin_EndOfStream(IPin * iface)
816 {
817     BaseInputPin* This = (BaseInputPin*)iface;
818     DSoundRenderImpl *me = (DSoundRenderImpl*)This->pin.pinInfo.pFilter;
819     IMediaEventSink* pEventSink;
820     BYTE *silence;
821     HRESULT hr;
822
823     EnterCriticalSection(This->pin.pCritSec);
824
825     TRACE("(%p/%p)->()\n", This, iface);
826     hr = BaseInputPinImpl_EndOfStream(iface);
827     if (hr != S_OK)
828     {
829         ERR("%08x\n", hr);
830         LeaveCriticalSection(This->pin.pCritSec);
831         return hr;
832     }
833
834     silence = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, me->buf_size);
835     if (silence)
836     {
837         memset(silence, 0, me->buf_size);
838         DSoundRender_SendSampleData(me, silence, me->buf_size);
839         HeapFree(GetProcessHeap(), 0, silence);
840     }
841
842     if (me->filter.filterInfo.pGraph)
843     {
844         hr = IFilterGraph_QueryInterface(me->filter.filterInfo.pGraph, &IID_IMediaEventSink, (LPVOID*)&pEventSink);
845         if (SUCCEEDED(hr))
846         {
847             hr = IMediaEventSink_Notify(pEventSink, EC_COMPLETE, S_OK, (LONG_PTR)me);
848             IMediaEventSink_Release(pEventSink);
849         }
850     }
851     MediaSeekingPassThru_EOS(me->seekthru_unk);
852     LeaveCriticalSection(This->pin.pCritSec);
853
854     return hr;
855 }
856
857 static HRESULT WINAPI DSoundRender_InputPin_BeginFlush(IPin * iface)
858 {
859     BaseInputPin *This = (BaseInputPin *)iface;
860     DSoundRenderImpl *pFilter = (DSoundRenderImpl *)This->pin.pinInfo.pFilter;
861     HRESULT hr;
862
863     TRACE("\n");
864
865     EnterCriticalSection(This->pin.pCritSec);
866     hr = BaseInputPinImpl_BeginFlush(iface);
867     SetEvent(pFilter->blocked);
868     LeaveCriticalSection(This->pin.pCritSec);
869
870     return hr;
871 }
872
873 static HRESULT WINAPI DSoundRender_InputPin_EndFlush(IPin * iface)
874 {
875     BaseInputPin *This = (BaseInputPin *)iface;
876     DSoundRenderImpl *pFilter = (DSoundRenderImpl *)This->pin.pinInfo.pFilter;
877     HRESULT hr;
878
879     TRACE("\n");
880
881     EnterCriticalSection(This->pin.pCritSec);
882     if (pFilter->in_loop) {
883         ResetEvent(pFilter->state_change);
884         LeaveCriticalSection(This->pin.pCritSec);
885         WaitForSingleObject(pFilter->state_change, -1);
886         EnterCriticalSection(This->pin.pCritSec);
887     }
888     if (pFilter->filter.state != State_Stopped)
889         ResetEvent(pFilter->blocked);
890
891     if (pFilter->dsbuffer)
892     {
893         LPBYTE buffer;
894         DWORD size;
895         IDirectSoundBuffer_Stop(pFilter->dsbuffer);
896
897         /* Force a reset */
898         IDirectSoundBuffer_SetCurrentPosition(pFilter->dsbuffer, 0);
899         pFilter->write_pos = pFilter->last_play_pos = 0;
900         ++pFilter->play_loops;
901         pFilter->write_loops = pFilter->play_loops;
902
903         IDirectSoundBuffer_Lock(pFilter->dsbuffer, 0, 0, (LPVOID *)&buffer, &size, NULL, NULL, DSBLOCK_ENTIREBUFFER);
904         memset(buffer, 0, size);
905         IDirectSoundBuffer_Unlock(pFilter->dsbuffer, buffer, size, NULL, 0);
906     }
907     hr = BaseInputPinImpl_EndFlush(iface);
908     LeaveCriticalSection(This->pin.pCritSec);
909     MediaSeekingPassThru_ResetMediaTime(pFilter->seekthru_unk);
910
911     return hr;
912 }
913
914 static const IPinVtbl DSoundRender_InputPin_Vtbl =
915 {
916     BaseInputPinImpl_QueryInterface,
917     BasePinImpl_AddRef,
918     BaseInputPinImpl_Release,
919     BaseInputPinImpl_Connect,
920     DSoundRender_InputPin_ReceiveConnection,
921     DSoundRender_InputPin_Disconnect,
922     BasePinImpl_ConnectedTo,
923     BasePinImpl_ConnectionMediaType,
924     BasePinImpl_QueryPinInfo,
925     BasePinImpl_QueryDirection,
926     BasePinImpl_QueryId,
927     BaseInputPinImpl_QueryAccept,
928     BasePinImpl_EnumMediaTypes,
929     BasePinImpl_QueryInternalConnections,
930     DSoundRender_InputPin_EndOfStream,
931     DSoundRender_InputPin_BeginFlush,
932     DSoundRender_InputPin_EndFlush,
933     BaseInputPinImpl_NewSegment
934 };
935
936 /*** IUnknown methods ***/
937 static HRESULT WINAPI Basicaudio_QueryInterface(IBasicAudio *iface,
938                                                 REFIID riid,
939                                                 LPVOID*ppvObj) {
940     ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
941
942     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
943
944     return DSoundRender_QueryInterface((IBaseFilter*)This, riid, ppvObj);
945 }
946
947 static ULONG WINAPI Basicaudio_AddRef(IBasicAudio *iface) {
948     ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
949
950     TRACE("(%p/%p)->()\n", This, iface);
951
952     return BaseFilterImpl_AddRef((IBaseFilter*)This);
953 }
954
955 static ULONG WINAPI Basicaudio_Release(IBasicAudio *iface) {
956     ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
957
958     TRACE("(%p/%p)->()\n", This, iface);
959
960     return DSoundRender_Release((IBaseFilter*)This);
961 }
962
963 /*** IDispatch methods ***/
964 static HRESULT WINAPI Basicaudio_GetTypeInfoCount(IBasicAudio *iface,
965                                                   UINT*pctinfo) {
966     ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
967
968     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pctinfo);
969
970     return S_OK;
971 }
972
973 static HRESULT WINAPI Basicaudio_GetTypeInfo(IBasicAudio *iface,
974                                              UINT iTInfo,
975                                              LCID lcid,
976                                              ITypeInfo**ppTInfo) {
977     ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
978
979     TRACE("(%p/%p)->(%d, %d, %p): stub !!!\n", This, iface, iTInfo, lcid, ppTInfo);
980
981     return S_OK;
982 }
983
984 static HRESULT WINAPI Basicaudio_GetIDsOfNames(IBasicAudio *iface,
985                                                REFIID riid,
986                                                LPOLESTR*rgszNames,
987                                                UINT cNames,
988                                                LCID lcid,
989                                                DISPID*rgDispId) {
990     ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
991
992     TRACE("(%p/%p)->(%s (%p), %p, %d, %d, %p): stub !!!\n", This, iface, debugstr_guid(riid), riid, rgszNames, cNames, lcid, rgDispId);
993
994     return S_OK;
995 }
996
997 static HRESULT WINAPI Basicaudio_Invoke(IBasicAudio *iface,
998                                         DISPID dispIdMember,
999                                         REFIID riid,
1000                                         LCID lcid,
1001                                         WORD wFlags,
1002                                         DISPPARAMS*pDispParams,
1003                                         VARIANT*pVarResult,
1004                                         EXCEPINFO*pExepInfo,
1005                                         UINT*puArgErr) {
1006     ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1007
1008     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);
1009
1010     return S_OK;
1011 }
1012
1013 /*** IBasicAudio methods ***/
1014 static HRESULT WINAPI Basicaudio_put_Volume(IBasicAudio *iface,
1015                                             LONG lVolume) {
1016     ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1017
1018     TRACE("(%p/%p)->(%d)\n", This, iface, lVolume);
1019
1020     if (lVolume > DSBVOLUME_MAX || lVolume < DSBVOLUME_MIN)
1021         return E_INVALIDARG;
1022
1023     if (This->dsbuffer) {
1024         if (FAILED(IDirectSoundBuffer_SetVolume(This->dsbuffer, lVolume)))
1025             return E_FAIL;
1026     }
1027
1028     This->volume = lVolume;
1029     return S_OK;
1030 }
1031
1032 static HRESULT WINAPI Basicaudio_get_Volume(IBasicAudio *iface,
1033                                             LONG *plVolume) {
1034     ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1035
1036     TRACE("(%p/%p)->(%p)\n", This, iface, plVolume);
1037
1038     if (!plVolume)
1039         return E_POINTER;
1040
1041     *plVolume = This->volume;
1042     return S_OK;
1043 }
1044
1045 static HRESULT WINAPI Basicaudio_put_Balance(IBasicAudio *iface,
1046                                              LONG lBalance) {
1047     ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1048
1049     TRACE("(%p/%p)->(%d)\n", This, iface, lBalance);
1050
1051     if (lBalance < DSBPAN_LEFT || lBalance > DSBPAN_RIGHT)
1052         return E_INVALIDARG;
1053
1054     if (This->dsbuffer) {
1055         if (FAILED(IDirectSoundBuffer_SetPan(This->dsbuffer, lBalance)))
1056             return E_FAIL;
1057     }
1058
1059     This->pan = lBalance;
1060     return S_OK;
1061 }
1062
1063 static HRESULT WINAPI Basicaudio_get_Balance(IBasicAudio *iface,
1064                                              LONG *plBalance) {
1065     ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1066
1067     TRACE("(%p/%p)->(%p)\n", This, iface, plBalance);
1068
1069     if (!plBalance)
1070         return E_POINTER;
1071
1072     *plBalance = This->pan;
1073     return S_OK;
1074 }
1075
1076 static const IBasicAudioVtbl IBasicAudio_Vtbl =
1077 {
1078     Basicaudio_QueryInterface,
1079     Basicaudio_AddRef,
1080     Basicaudio_Release,
1081     Basicaudio_GetTypeInfoCount,
1082     Basicaudio_GetTypeInfo,
1083     Basicaudio_GetIDsOfNames,
1084     Basicaudio_Invoke,
1085     Basicaudio_put_Volume,
1086     Basicaudio_get_Volume,
1087     Basicaudio_put_Balance,
1088     Basicaudio_get_Balance
1089 };
1090
1091
1092 /*** IUnknown methods ***/
1093 static HRESULT WINAPI ReferenceClock_QueryInterface(IReferenceClock *iface,
1094                                                 REFIID riid,
1095                                                 LPVOID*ppvObj)
1096 {
1097     ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1098
1099     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
1100
1101     return DSoundRender_QueryInterface((IBaseFilter*)This, riid, ppvObj);
1102 }
1103
1104 static ULONG WINAPI ReferenceClock_AddRef(IReferenceClock *iface)
1105 {
1106     ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1107
1108     TRACE("(%p/%p)->()\n", This, iface);
1109
1110     return BaseFilterImpl_AddRef((IBaseFilter*)This);
1111 }
1112
1113 static ULONG WINAPI ReferenceClock_Release(IReferenceClock *iface)
1114 {
1115     ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1116
1117     TRACE("(%p/%p)->()\n", This, iface);
1118
1119     return DSoundRender_Release((IBaseFilter*)This);
1120 }
1121
1122 /*** IReferenceClock methods ***/
1123 static HRESULT WINAPI ReferenceClock_GetTime(IReferenceClock *iface,
1124                                              REFERENCE_TIME *pTime)
1125 {
1126     ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1127     HRESULT hr = E_FAIL;
1128     DWORD play_pos;
1129
1130     TRACE("(%p/%p)->(%p)\n", This, iface, pTime);
1131
1132     if (This->dsbuffer)
1133         hr = DSoundRender_GetPos(This, &play_pos, pTime);
1134     if (FAILED(hr))
1135         ERR("Could not get reference time (%x)!\n", hr);
1136
1137     return hr;
1138 }
1139
1140 static HRESULT WINAPI ReferenceClock_AdviseTime(IReferenceClock *iface,
1141                                                 REFERENCE_TIME rtBaseTime,
1142                                                 REFERENCE_TIME rtStreamTime,
1143                                                 HEVENT hEvent,
1144                                                 DWORD_PTR *pdwAdviseCookie)
1145 {
1146     ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1147
1148     FIXME("(%p/%p)->(%s, %s, %p, %p): stub!\n", This, iface, wine_dbgstr_longlong(rtBaseTime), wine_dbgstr_longlong(rtStreamTime), (void*)hEvent, pdwAdviseCookie);
1149
1150     return E_NOTIMPL;
1151 }
1152
1153 static HRESULT WINAPI ReferenceClock_AdvisePeriodic(IReferenceClock *iface,
1154                                                     REFERENCE_TIME rtBaseTime,
1155                                                     REFERENCE_TIME rtStreamTime,
1156                                                     HSEMAPHORE hSemaphore,
1157                                                     DWORD_PTR *pdwAdviseCookie)
1158 {
1159     ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1160
1161     FIXME("(%p/%p)->(%s, %s, %p, %p): stub!\n", This, iface, wine_dbgstr_longlong(rtBaseTime), wine_dbgstr_longlong(rtStreamTime), (void*)hSemaphore, pdwAdviseCookie);
1162
1163     return E_NOTIMPL;
1164 }
1165
1166 static HRESULT WINAPI ReferenceClock_Unadvise(IReferenceClock *iface,
1167                                               DWORD_PTR dwAdviseCookie)
1168 {
1169     ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1170
1171     FIXME("(%p/%p)->(%p): stub!\n", This, iface, (void*)dwAdviseCookie);
1172
1173     return S_FALSE;
1174 }
1175
1176 static const IReferenceClockVtbl IReferenceClock_Vtbl =
1177 {
1178     ReferenceClock_QueryInterface,
1179     ReferenceClock_AddRef,
1180     ReferenceClock_Release,
1181     ReferenceClock_GetTime,
1182     ReferenceClock_AdviseTime,
1183     ReferenceClock_AdvisePeriodic,
1184     ReferenceClock_Unadvise
1185 };
1186
1187 /*** IUnknown methods ***/
1188 static HRESULT WINAPI AMDirectSound_QueryInterface(IAMDirectSound *iface,
1189                                                 REFIID riid,
1190                                                 LPVOID*ppvObj)
1191 {
1192     ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1193
1194     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
1195
1196     return DSoundRender_QueryInterface((IBaseFilter*)This, riid, ppvObj);
1197 }
1198
1199 static ULONG WINAPI AMDirectSound_AddRef(IAMDirectSound *iface)
1200 {
1201     ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1202
1203     TRACE("(%p/%p)->()\n", This, iface);
1204
1205     return BaseFilterImpl_AddRef((IBaseFilter*)This);
1206 }
1207
1208 static ULONG WINAPI AMDirectSound_Release(IAMDirectSound *iface)
1209 {
1210     ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1211
1212     TRACE("(%p/%p)->()\n", This, iface);
1213
1214     return DSoundRender_Release((IBaseFilter*)This);
1215 }
1216
1217 /*** IAMDirectSound methods ***/
1218 static HRESULT WINAPI AMDirectSound_GetDirectSoundInterface(IAMDirectSound *iface,  IDirectSound **ds)
1219 {
1220     ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1221
1222     FIXME("(%p/%p)->(%p): stub\n", This, iface, ds);
1223
1224     return E_NOTIMPL;
1225 }
1226
1227 static HRESULT WINAPI AMDirectSound_GetPrimaryBufferInterface(IAMDirectSound *iface, IDirectSoundBuffer **buf)
1228 {
1229     ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1230
1231     FIXME("(%p/%p)->(%p): stub\n", This, iface, buf);
1232
1233     return E_NOTIMPL;
1234 }
1235
1236 static HRESULT WINAPI AMDirectSound_GetSecondaryBufferInterface(IAMDirectSound *iface, IDirectSoundBuffer **buf)
1237 {
1238     ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1239
1240     FIXME("(%p/%p)->(%p): stub\n", This, iface, buf);
1241
1242     return E_NOTIMPL;
1243 }
1244
1245 static HRESULT WINAPI AMDirectSound_ReleaseDirectSoundInterface(IAMDirectSound *iface, IDirectSound *ds)
1246 {
1247     ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1248
1249     FIXME("(%p/%p)->(%p): stub\n", This, iface, ds);
1250
1251     return E_NOTIMPL;
1252 }
1253
1254 static HRESULT WINAPI AMDirectSound_ReleasePrimaryBufferInterface(IAMDirectSound *iface, IDirectSoundBuffer *buf)
1255 {
1256     ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1257
1258     FIXME("(%p/%p)->(%p): stub\n", This, iface, buf);
1259
1260     return E_NOTIMPL;
1261 }
1262
1263 static HRESULT WINAPI AMDirectSound_ReleaseSecondaryBufferInterface(IAMDirectSound *iface, IDirectSoundBuffer *buf)
1264 {
1265     ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1266
1267     FIXME("(%p/%p)->(%p): stub\n", This, iface, buf);
1268
1269     return E_NOTIMPL;
1270 }
1271
1272 static HRESULT WINAPI AMDirectSound_SetFocusWindow(IAMDirectSound *iface, HWND hwnd, BOOL bgsilent)
1273 {
1274     ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1275
1276     FIXME("(%p/%p)->(%p,%d): stub\n", This, iface, hwnd, bgsilent);
1277
1278     return E_NOTIMPL;
1279 }
1280
1281 static HRESULT WINAPI AMDirectSound_GetFocusWindow(IAMDirectSound *iface, HWND hwnd)
1282 {
1283     ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1284
1285     FIXME("(%p/%p)->(%p): stub\n", This, iface, hwnd);
1286
1287     return E_NOTIMPL;
1288 }
1289
1290 static const IAMDirectSoundVtbl IAMDirectSound_Vtbl =
1291 {
1292     AMDirectSound_QueryInterface,
1293     AMDirectSound_AddRef,
1294     AMDirectSound_Release,
1295     AMDirectSound_GetDirectSoundInterface,
1296     AMDirectSound_GetPrimaryBufferInterface,
1297     AMDirectSound_GetSecondaryBufferInterface,
1298     AMDirectSound_ReleaseDirectSoundInterface,
1299     AMDirectSound_ReleasePrimaryBufferInterface,
1300     AMDirectSound_ReleaseSecondaryBufferInterface,
1301     AMDirectSound_SetFocusWindow,
1302     AMDirectSound_GetFocusWindow
1303 };
1304
1305 static DSoundRenderImpl *from_IAMFilterMiscFlags(IAMFilterMiscFlags *iface) {
1306     return (DSoundRenderImpl*)((char*)iface - offsetof(DSoundRenderImpl, IAMFilterMiscFlags_vtbl));
1307 }
1308
1309 static HRESULT WINAPI AMFilterMiscFlags_QueryInterface(IAMFilterMiscFlags *iface, const REFIID riid, void **ppv) {
1310     DSoundRenderImpl *This = from_IAMFilterMiscFlags(iface);
1311     return IUnknown_QueryInterface((IUnknown*)This, riid, ppv);
1312 }
1313
1314 static ULONG WINAPI AMFilterMiscFlags_AddRef(IAMFilterMiscFlags *iface) {
1315     DSoundRenderImpl *This = from_IAMFilterMiscFlags(iface);
1316     return IUnknown_AddRef((IUnknown*)This);
1317 }
1318
1319 static ULONG WINAPI AMFilterMiscFlags_Release(IAMFilterMiscFlags *iface) {
1320     DSoundRenderImpl *This = from_IAMFilterMiscFlags(iface);
1321     return IUnknown_Release((IUnknown*)This);
1322 }
1323
1324 static ULONG WINAPI AMFilterMiscFlags_GetMiscFlags(IAMFilterMiscFlags *iface) {
1325     return AM_FILTER_MISC_FLAGS_IS_RENDERER;
1326 }
1327
1328 static const IAMFilterMiscFlagsVtbl IAMFilterMiscFlags_Vtbl = {
1329     AMFilterMiscFlags_QueryInterface,
1330     AMFilterMiscFlags_AddRef,
1331     AMFilterMiscFlags_Release,
1332     AMFilterMiscFlags_GetMiscFlags
1333 };