comctl32/mru: In EnumMRUListA, ensure that the string is NULL terminated and the...
[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
51 typedef struct DSoundRenderImpl
52 {
53     const IBaseFilterVtbl * lpVtbl;
54     const IBasicAudioVtbl *IBasicAudio_vtbl;
55     const IReferenceClockVtbl *IReferenceClock_vtbl;
56     const IAMDirectSoundVtbl *IAMDirectSound_vtbl;
57
58     LONG refCount;
59     CRITICAL_SECTION csFilter;
60     FILTER_STATE state;
61     REFERENCE_TIME rtStreamStart, rtLastStop;
62     IReferenceClock * pClock;
63     FILTER_INFO filterInfo;
64
65     InputPin * pInputPin;
66
67     IDirectSound8 *dsound;
68     LPDIRECTSOUNDBUFFER dsbuffer;
69     DWORD buf_size;
70     DWORD write_pos;
71     DWORD write_loops;
72
73     DWORD last_play_pos;
74     DWORD play_loops;
75
76     REFERENCE_TIME play_time;
77     MediaSeekingImpl mediaSeeking;
78
79     HANDLE state_change, blocked;
80
81     long volume;
82     long pan;
83 } DSoundRenderImpl;
84
85 /* Seeking is not needed for a renderer, rely on newsegment for the appropriate changes */
86 static HRESULT sound_mod_stop(IBaseFilter *iface)
87 {
88     TRACE("(%p)\n", iface);
89     return S_OK;
90 }
91
92 static HRESULT sound_mod_start(IBaseFilter *iface)
93 {
94     TRACE("(%p)\n", iface);
95
96     return S_OK;
97 }
98
99 static HRESULT sound_mod_rate(IBaseFilter *iface)
100 {
101     DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
102
103     WAVEFORMATEX *format = (WAVEFORMATEX*)This->pInputPin->pin.mtCurrent.pbFormat;
104     DWORD freq = format->nSamplesPerSec;
105     double rate = This->mediaSeeking.dRate;
106
107     freq = (DWORD)((double)freq * rate);
108
109     TRACE("(%p)\n", iface);
110
111     if (freq > DSBFREQUENCY_MAX)
112         return VFW_E_UNSUPPORTED_AUDIO;
113
114     if (freq < DSBFREQUENCY_MIN)
115         return VFW_E_UNSUPPORTED_AUDIO;
116
117     return S_OK;
118 }
119
120 static inline HRESULT DSoundRender_GetPos(DSoundRenderImpl *This, DWORD *pPlayPos, REFERENCE_TIME *pRefTime)
121 {
122     HRESULT hr;
123
124     EnterCriticalSection(&This->csFilter);
125     {
126         DWORD state;
127         DWORD write_pos;
128
129         hr = IDirectSoundBuffer_GetStatus(This->dsbuffer, &state);
130         if (SUCCEEDED(hr) && !(state & DSBSTATUS_PLAYING) && This->state == State_Running)
131         {
132             TRACE("Not playing, kickstarting the engine\n");
133
134             hr = IDirectSoundBuffer_Play(This->dsbuffer, 0, 0, DSBPLAY_LOOPING);
135             if (FAILED(hr))
136                 ERR("Can't play sound buffer (%x)\n", hr);
137         }
138
139         if (SUCCEEDED(hr))
140             hr = IDirectSoundBuffer_GetCurrentPosition(This->dsbuffer, pPlayPos, &write_pos);
141         if (hr == S_OK)
142         {
143             DWORD play_pos = *pPlayPos;
144
145             if (play_pos < This->last_play_pos)
146                 This->play_loops++;
147             This->last_play_pos = play_pos;
148
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
152              */
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;
156
157             if (pRefTime)
158             {
159                 REFERENCE_TIME play_time;
160                 play_time = ((REFERENCE_TIME)This->play_loops*10000000) +
161                             ((REFERENCE_TIME)play_pos*10000000/This->buf_size);
162
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;
168
169                 *pRefTime = This->play_time;
170             }
171         }
172     }
173     LeaveCriticalSection(&This->csFilter);
174
175     return hr;
176 }
177
178 static HRESULT DSoundRender_SendSampleData(DSoundRenderImpl* This, const BYTE *data, DWORD size)
179 {
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;
187
188     do {
189
190         hr = DSoundRender_GetPos(This, &play_pos, NULL);
191         if (hr != DS_OK)
192         {
193             ERR("GetPos returned error: %x\n", hr);
194             break;
195         }
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;
200
201         /* Wait for enough of the buffer to empty before filling it */
202         if(buf_free < This->buf_size/4)
203         {
204             Sleep(50);
205             continue;
206         }
207
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;
213         }
214         /* TRACE("write_pos=%d, size=%d, sz1=%d, sz2=%d\n", This->write_pos, size2, dwsize1, dwsize2); */
215
216         memcpy(lpbuf1, data, dwsize1);
217         if (dwsize2)
218             memcpy(lpbuf2, data + dwsize1, dwsize2);
219
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);
223
224         size -= dwsize1 + dwsize2;
225         data += dwsize1 + dwsize2;
226         This->write_pos += dwsize1 + dwsize2;
227         if (This->write_pos >= This->buf_size)
228         {
229             This->write_pos -= This->buf_size;
230             This->write_loops++;
231         }
232     } while (size && This->state == State_Running);
233
234     return hr;
235 }
236
237 static HRESULT DSoundRender_Sample(LPVOID iface, IMediaSample * pSample)
238 {
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;
245
246     TRACE("%p %p\n", iface, pSample);
247
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
250      */
251
252     EnterCriticalSection(&This->csFilter);
253
254     if (This->pInputPin->end_of_stream || This->pInputPin->flushing)
255     {
256         LeaveCriticalSection(&This->csFilter);
257         return S_FALSE;
258     }
259
260     if (This->state == State_Stopped)
261     {
262         LeaveCriticalSection(&This->csFilter);
263         return VFW_E_WRONG_STATE;
264     }
265
266     if (IMediaSample_GetMediaType(pSample, &amt) == S_OK)
267     {
268         AM_MEDIA_TYPE *orig = &This->pInputPin->pin.mtCurrent;
269         WAVEFORMATEX *origfmt = (WAVEFORMATEX *)orig->pbFormat;
270         WAVEFORMATEX *newfmt = (WAVEFORMATEX *)amt->pbFormat;
271
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)
277         {
278             if (origfmt->nSamplesPerSec != newfmt->nSamplesPerSec)
279             {
280                 hr = IDirectSoundBuffer_SetFrequency(This->dsbuffer,
281                                                      newfmt->nSamplesPerSec);
282                 if (FAILED(hr))
283                 {
284                     LeaveCriticalSection(&This->csFilter);
285                     return VFW_E_TYPE_NOT_ACCEPTED;
286                 }
287                 FreeMediaType(orig);
288                 CopyMediaType(orig, amt);
289                 IMediaSample_SetMediaType(pSample, NULL);
290             }
291         }
292         else
293         {
294             LeaveCriticalSection(&This->csFilter);
295             return VFW_E_TYPE_NOT_ACCEPTED;
296         }
297     }
298
299     SetEvent(This->state_change);
300
301     hr = IMediaSample_GetPointer(pSample, &pbSrcStream);
302     if (FAILED(hr))
303     {
304         ERR("Cannot get pointer to sample data (%x)\n", hr);
305         LeaveCriticalSection(&This->csFilter);
306         return hr;
307     }
308
309     hr = IMediaSample_GetTime(pSample, &tStart, &tStop);
310     if (FAILED(hr))
311         ERR("Cannot get sample time (%x)\n", hr);
312
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;
318
319     if (IMediaSample_IsPreroll(pSample) == S_OK)
320     {
321         TRACE("Preroll!\n");
322         LeaveCriticalSection(&This->csFilter);
323         return S_OK;
324     }
325
326     if (This->state == State_Paused)
327     {
328         LeaveCriticalSection(&This->csFilter);
329         WaitForSingleObject(This->blocked, INFINITE);
330         EnterCriticalSection(&This->csFilter);
331         if (This->state == State_Stopped)
332         {
333             LeaveCriticalSection(&This->csFilter);
334             return VFW_E_WRONG_STATE;
335         }
336
337         if (This->state == State_Paused)
338         {
339             /* Assuming we return because of flushing */
340             TRACE("Flushing\n");
341             LeaveCriticalSection(&This->csFilter);
342             return S_OK;
343         }
344     }
345
346     cbSrcStream = IMediaSample_GetActualDataLength(pSample);
347     TRACE("Sample data ptr = %p, size = %ld\n", pbSrcStream, cbSrcStream);
348
349 #if 0 /* For debugging purpose */
350     {
351         int i;
352         for(i = 0; i < cbSrcStream; i++)
353         {
354             if ((i!=0) && !(i%16))
355                 TRACE("\n");
356             TRACE("%02x ", pbSrcStream[i]);
357         }
358         TRACE("\n");
359     }
360 #endif
361
362     hr = DSoundRender_SendSampleData(This, pbSrcStream, cbSrcStream);
363     LeaveCriticalSection(&This->csFilter);
364     return hr;
365 }
366
367 static HRESULT DSoundRender_QueryAccept(LPVOID iface, const AM_MEDIA_TYPE * pmt)
368 {
369     WAVEFORMATEX* format;
370
371     if (!IsEqualIID(&pmt->majortype, &MEDIATYPE_Audio))
372         return S_FALSE;
373
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);
382
383     if (!IsEqualIID(&pmt->subtype, &MEDIASUBTYPE_PCM))
384         return S_FALSE;
385
386     return S_OK;
387 }
388
389 HRESULT DSoundRender_create(IUnknown * pUnkOuter, LPVOID * ppv)
390 {
391     HRESULT hr;
392     PIN_INFO piInput;
393     DSoundRenderImpl * pDSoundRender;
394
395     TRACE("(%p, %p)\n", pUnkOuter, ppv);
396
397     *ppv = NULL;
398
399     if (pUnkOuter)
400         return CLASS_E_NOAGGREGATION;
401     
402     pDSoundRender = CoTaskMemAlloc(sizeof(DSoundRenderImpl));
403     if (!pDSoundRender)
404         return E_OUTOFMEMORY;
405     ZeroMemory(pDSoundRender, sizeof(DSoundRenderImpl));
406
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;
415
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);
421
422     if (SUCCEEDED(hr))
423     {
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);
429     }
430
431     if (SUCCEEDED(hr))
432     {
433         MediaSeekingImpl_Init((IBaseFilter*)pDSoundRender, sound_mod_stop, sound_mod_start, sound_mod_rate, &pDSoundRender->mediaSeeking, &pDSoundRender->csFilter);
434         pDSoundRender->mediaSeeking.lpVtbl = &IMediaSeeking_Vtbl;
435
436         pDSoundRender->state_change = CreateEventW(NULL, TRUE, TRUE, NULL);
437         pDSoundRender->blocked = CreateEventW(NULL, FALSE, FALSE, NULL);
438
439         if (!pDSoundRender->state_change || !pDSoundRender->blocked)
440         {
441             IUnknown_Release((IUnknown *)pDSoundRender);
442             return HRESULT_FROM_WIN32(GetLastError());
443         }
444
445         *ppv = pDSoundRender;
446     }
447     else
448     {
449         if (pDSoundRender->pInputPin)
450             IPin_Release((IPin*)pDSoundRender->pInputPin);
451         pDSoundRender->csFilter.DebugInfo->Spare[0] = 0;
452         DeleteCriticalSection(&pDSoundRender->csFilter);
453         CoTaskMemFree(pDSoundRender);
454     }
455
456     return hr;
457 }
458
459 static HRESULT WINAPI DSoundRender_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv)
460 {
461     DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
462     TRACE("(%p, %p)->(%s, %p)\n", This, iface, qzdebugstr_guid(riid), ppv);
463
464     *ppv = NULL;
465
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;
482
483     if (*ppv)
484     {
485         IUnknown_AddRef((IUnknown *)(*ppv));
486         return S_OK;
487     }
488
489     if (!IsEqualIID(riid, &IID_IPin) && !IsEqualIID(riid, &IID_IVideoWindow))
490         FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
491
492     return E_NOINTERFACE;
493 }
494
495 static ULONG WINAPI DSoundRender_AddRef(IBaseFilter * iface)
496 {
497     DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
498     ULONG refCount = InterlockedIncrement(&This->refCount);
499
500     TRACE("(%p/%p)->() AddRef from %d\n", This, iface, refCount - 1);
501
502     return refCount;
503 }
504
505 static ULONG WINAPI DSoundRender_Release(IBaseFilter * iface)
506 {
507     DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
508     ULONG refCount = InterlockedDecrement(&This->refCount);
509
510     TRACE("(%p)->() Release from %d\n", This, refCount + 1);
511
512     if (!refCount)
513     {
514         IPin *pConnectedTo;
515
516         if (This->pClock)
517             IReferenceClock_Release(This->pClock);
518
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;
525        
526         if (SUCCEEDED(IPin_ConnectedTo((IPin *)This->pInputPin, &pConnectedTo)))
527         {
528             IPin_Disconnect(pConnectedTo);
529             IPin_Release(pConnectedTo);
530         }
531         IPin_Disconnect((IPin *)This->pInputPin);
532
533         IPin_Release((IPin *)This->pInputPin);
534
535         This->lpVtbl = NULL;
536         This->IBasicAudio_vtbl = NULL;
537         
538         This->csFilter.DebugInfo->Spare[0] = 0;
539         DeleteCriticalSection(&This->csFilter);
540
541         CloseHandle(This->state_change);
542         CloseHandle(This->blocked);
543
544         TRACE("Destroying Audio Renderer\n");
545         CoTaskMemFree(This);
546         
547         return 0;
548     }
549     else
550         return refCount;
551 }
552
553 /** IPersist methods **/
554
555 static HRESULT WINAPI DSoundRender_GetClassID(IBaseFilter * iface, CLSID * pClsid)
556 {
557     DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
558     TRACE("(%p/%p)->(%p)\n", This, iface, pClsid);
559
560     *pClsid = CLSID_DSoundRender;
561
562     return S_OK;
563 }
564
565 /** IMediaFilter methods **/
566
567 static HRESULT WINAPI DSoundRender_Stop(IBaseFilter * iface)
568 {
569     HRESULT hr = S_OK;
570     DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
571
572     TRACE("(%p/%p)->()\n", This, iface);
573
574     EnterCriticalSection(&This->csFilter);
575     {
576         DWORD state = 0;
577         if (This->dsbuffer)
578         {
579             hr = IDirectSoundBuffer_GetStatus(This->dsbuffer, &state);
580             if (SUCCEEDED(hr))
581             {
582                 if (state & DSBSTATUS_PLAYING)
583                     hr = IDirectSoundBuffer_Stop(This->dsbuffer);
584             }
585         }
586         if (SUCCEEDED(hr))
587             This->state = State_Stopped;
588
589         /* Complete our transition */
590         SetEvent(This->state_change);
591         SetEvent(This->blocked);
592     }
593     LeaveCriticalSection(&This->csFilter);
594     
595     return hr;
596 }
597
598 static HRESULT WINAPI DSoundRender_Pause(IBaseFilter * iface)
599 {
600     HRESULT hr = S_OK;
601     DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
602     
603     TRACE("(%p/%p)->()\n", This, iface);
604
605     EnterCriticalSection(&This->csFilter);
606     if (This->state != State_Paused)
607     {
608         DWORD state = 0;
609         if (This->state == State_Stopped)
610         {
611             This->pInputPin->end_of_stream = 0;
612         }
613
614         if (This->dsbuffer)
615         {
616             hr = IDirectSoundBuffer_GetStatus(This->dsbuffer, &state);
617             if (SUCCEEDED(hr))
618             {
619                 if (state & DSBSTATUS_PLAYING)
620                     hr = IDirectSoundBuffer_Stop(This->dsbuffer);
621             }
622         }
623         if (SUCCEEDED(hr))
624             This->state = State_Paused;
625
626         ResetEvent(This->blocked);
627         ResetEvent(This->state_change);
628     }
629     LeaveCriticalSection(&This->csFilter);
630
631     return hr;
632 }
633
634 static HRESULT WINAPI DSoundRender_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
635 {
636     HRESULT hr = S_OK;
637     DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
638
639     TRACE("(%p/%p)->(%s)\n", This, iface, wine_dbgstr_longlong(tStart));
640
641     EnterCriticalSection(&This->csFilter);
642     {
643         This->rtStreamStart = tStart;
644         if (This->state == State_Paused)
645         {
646             /* Unblock our thread, state changing from paused to running doesn't need a reset for state change */
647             SetEvent(This->blocked);
648         }
649         else if (This->state == State_Stopped)
650         {
651             ResetEvent(This->state_change);
652             This->pInputPin->end_of_stream = 0;
653         }
654
655         This->state = State_Running;
656     }
657     LeaveCriticalSection(&This->csFilter);
658
659     return hr;
660 }
661
662 static HRESULT WINAPI DSoundRender_GetState(IBaseFilter * iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState)
663 {
664     HRESULT hr;
665     DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
666
667     TRACE("(%p/%p)->(%d, %p)\n", This, iface, dwMilliSecsTimeout, pState);
668
669     if (WaitForSingleObject(This->state_change, dwMilliSecsTimeout) == WAIT_TIMEOUT)
670         hr = VFW_S_STATE_INTERMEDIATE;
671     else
672         hr = S_OK;
673
674     EnterCriticalSection(&This->csFilter);
675     {
676         *pState = This->state;
677     }
678     LeaveCriticalSection(&This->csFilter);
679
680     return S_OK;
681 }
682
683 static HRESULT WINAPI DSoundRender_SetSyncSource(IBaseFilter * iface, IReferenceClock *pClock)
684 {
685     DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
686
687     TRACE("(%p/%p)->(%p)\n", This, iface, pClock);
688
689     EnterCriticalSection(&This->csFilter);
690     {
691         if (This->pClock)
692             IReferenceClock_Release(This->pClock);
693         This->pClock = pClock;
694         if (This->pClock)
695             IReferenceClock_AddRef(This->pClock);
696     }
697     LeaveCriticalSection(&This->csFilter);
698
699     return S_OK;
700 }
701
702 static HRESULT WINAPI DSoundRender_GetSyncSource(IBaseFilter * iface, IReferenceClock **ppClock)
703 {
704     DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
705
706     TRACE("(%p/%p)->(%p)\n", This, iface, ppClock);
707
708     EnterCriticalSection(&This->csFilter);
709     {
710         *ppClock = This->pClock;
711         if (This->pClock)
712             IReferenceClock_AddRef(This->pClock);
713     }
714     LeaveCriticalSection(&This->csFilter);
715     
716     return S_OK;
717 }
718
719 /** IBaseFilter implementation **/
720
721 static HRESULT DSoundRender_GetPin(IBaseFilter *iface, ULONG pos, IPin **pin, DWORD *lastsynctick)
722 {
723     DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
724
725     /* Our pins are static, not changing so setting static tick count is ok */
726     *lastsynctick = 0;
727
728     if (pos >= 1)
729         return S_FALSE;
730
731     *pin = (IPin *)This->pInputPin;
732     IPin_AddRef(*pin);
733     return S_OK;
734 }
735
736 static HRESULT WINAPI DSoundRender_EnumPins(IBaseFilter * iface, IEnumPins **ppEnum)
737 {
738     DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
739
740     TRACE("(%p/%p)->(%p)\n", This, iface, ppEnum);
741
742     return IEnumPinsImpl_Construct(ppEnum, DSoundRender_GetPin, iface);
743 }
744
745 static HRESULT WINAPI DSoundRender_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin)
746 {
747     DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
748
749     TRACE("(%p/%p)->(%s,%p)\n", This, iface, debugstr_w(Id), ppPin);
750     
751     FIXME("DSoundRender::FindPin(...)\n");
752
753     /* FIXME: critical section */
754
755     return E_NOTIMPL;
756 }
757
758 static HRESULT WINAPI DSoundRender_QueryFilterInfo(IBaseFilter * iface, FILTER_INFO *pInfo)
759 {
760     DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
761
762     TRACE("(%p/%p)->(%p)\n", This, iface, pInfo);
763
764     strcpyW(pInfo->achName, This->filterInfo.achName);
765     pInfo->pGraph = This->filterInfo.pGraph;
766
767     if (pInfo->pGraph)
768         IFilterGraph_AddRef(pInfo->pGraph);
769     
770     return S_OK;
771 }
772
773 static HRESULT WINAPI DSoundRender_JoinFilterGraph(IBaseFilter * iface, IFilterGraph *pGraph, LPCWSTR pName)
774 {
775     DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
776
777     TRACE("(%p/%p)->(%p, %s)\n", This, iface, pGraph, debugstr_w(pName));
778
779     EnterCriticalSection(&This->csFilter);
780     {
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 */
786     }
787     LeaveCriticalSection(&This->csFilter);
788
789     return S_OK;
790 }
791
792 static HRESULT WINAPI DSoundRender_QueryVendorInfo(IBaseFilter * iface, LPWSTR *pVendorInfo)
793 {
794     DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
795     TRACE("(%p/%p)->(%p)\n", This, iface, pVendorInfo);
796     return E_NOTIMPL;
797 }
798
799 static const IBaseFilterVtbl DSoundRender_Vtbl =
800 {
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
816 };
817
818 static HRESULT WINAPI DSoundRender_InputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
819 {
820     InputPin *This = (InputPin *)iface;
821     PIN_DIRECTION pindirReceive;
822     DSoundRenderImpl *DSImpl;
823     HRESULT hr = S_OK;
824
825     TRACE("(%p)->(%p, %p)\n", This, pReceivePin, pmt);
826     dump_AM_MEDIA_TYPE(pmt);
827
828     EnterCriticalSection(This->pin.pCritSec);
829     {
830         DSImpl = (DSoundRenderImpl*)This->pin.pinInfo.pFilter;
831         DSImpl->rtLastStop = -1;
832
833         if (This->pin.pConnectedTo)
834             hr = VFW_E_ALREADY_CONNECTED;
835
836         if (SUCCEEDED(hr) && This->pin.fnQueryAccept(This->pin.pUserData, pmt) != S_OK)
837             hr = VFW_E_TYPE_NOT_ACCEPTED;
838
839         if (SUCCEEDED(hr))
840         {
841             IPin_QueryDirection(pReceivePin, &pindirReceive);
842
843             if (pindirReceive != PINDIR_OUTPUT)
844             {
845                 ERR("Can't connect from non-output pin\n");
846                 hr = VFW_E_INVALID_DIRECTION;
847             }
848         }
849
850         if (SUCCEEDED(hr))
851         {
852             WAVEFORMATEX *format;
853             DSBUFFERDESC buf_desc;
854
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);
859
860             format = (WAVEFORMATEX*)pmt->pbFormat;
861
862             DSImpl->buf_size = format->nAvgBytesPerSec;
863
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);
874         }
875
876         if (SUCCEEDED(hr))
877         {
878             hr = IDirectSoundBuffer_SetVolume(DSImpl->dsbuffer, DSImpl->volume);
879             if (FAILED(hr))
880                 ERR("Can't set volume to %ld (%x)\n", DSImpl->volume, hr);
881
882             hr = IDirectSoundBuffer_SetPan(DSImpl->dsbuffer, DSImpl->pan);
883             if (FAILED(hr))
884                 ERR("Can't set pan to %ld (%x)\n", DSImpl->pan, hr);
885
886             DSImpl->write_pos = 0;
887             hr = S_OK;
888         }
889
890         if (SUCCEEDED(hr))
891         {
892             CopyMediaType(&This->pin.mtCurrent, pmt);
893             This->pin.pConnectedTo = pReceivePin;
894             IPin_AddRef(pReceivePin);
895         }
896         else if (hr != VFW_E_ALREADY_CONNECTED)
897         {
898             if (DSImpl->dsbuffer)
899                 IDirectSoundBuffer_Release(DSImpl->dsbuffer);
900             DSImpl->dsbuffer = NULL;
901         }
902     }
903     LeaveCriticalSection(This->pin.pCritSec);
904
905     return hr;
906 }
907
908 static HRESULT WINAPI DSoundRender_InputPin_Disconnect(IPin * iface)
909 {
910     IPinImpl *This = (IPinImpl*)iface;
911     DSoundRenderImpl *DSImpl;
912
913     TRACE("(%p)->()\n", iface);
914
915     DSImpl = (DSoundRenderImpl*)This->pinInfo.pFilter;
916     if (DSImpl->dsbuffer)
917         IDirectSoundBuffer_Release(DSImpl->dsbuffer);
918     DSImpl->dsbuffer = NULL;
919
920     return IPinImpl_Disconnect(iface);
921 }
922
923 static HRESULT WINAPI DSoundRender_InputPin_EndOfStream(IPin * iface)
924 {
925     InputPin* This = (InputPin*)iface;
926     DSoundRenderImpl *me = (DSoundRenderImpl*)This->pin.pinInfo.pFilter;
927     IMediaEventSink* pEventSink;
928     HRESULT hr;
929
930     EnterCriticalSection(This->pin.pCritSec);
931
932     TRACE("(%p/%p)->()\n", This, iface);
933     hr = InputPin_EndOfStream(iface);
934     if (hr != S_OK)
935     {
936         ERR("%08x\n", hr);
937         LeaveCriticalSection(This->pin.pCritSec);
938         return hr;
939     }
940
941     hr = IFilterGraph_QueryInterface(me->filterInfo.pGraph, &IID_IMediaEventSink, (LPVOID*)&pEventSink);
942     if (SUCCEEDED(hr))
943     {
944         BYTE * silence;
945
946         silence = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, me->buf_size);
947         if (silence)
948         {
949             memset(silence, 0, me->buf_size);
950             DSoundRender_SendSampleData((DSoundRenderImpl*)This->pin.pinInfo.pFilter, silence, me->buf_size);
951             HeapFree(GetProcessHeap(), 0, silence);
952         }
953
954         hr = IMediaEventSink_Notify(pEventSink, EC_COMPLETE, S_OK, 0);
955         IMediaEventSink_Release(pEventSink);
956     }
957     LeaveCriticalSection(This->pin.pCritSec);
958
959     return hr;
960 }
961
962 static HRESULT WINAPI DSoundRender_InputPin_BeginFlush(IPin * iface)
963 {
964     InputPin *This = (InputPin *)iface;
965     DSoundRenderImpl *pFilter = (DSoundRenderImpl *)This->pin.pinInfo.pFilter;
966     HRESULT hr;
967     LPBYTE buffer;
968     DWORD size;
969
970     TRACE("\n");
971
972     EnterCriticalSection(This->pin.pCritSec);
973     hr = InputPin_BeginFlush(iface);
974
975     if (pFilter->dsbuffer)
976     {
977         IDirectSoundBuffer_Stop(pFilter->dsbuffer);
978
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;
984
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);
988     }
989
990     if (pFilter->state == State_Paused)
991         SetEvent(pFilter->blocked);
992     LeaveCriticalSection(This->pin.pCritSec);
993
994     return hr;
995 }
996
997 static HRESULT WINAPI DSoundRender_InputPin_EndFlush(IPin * iface)
998 {
999     InputPin *This = (InputPin *)iface;
1000     DSoundRenderImpl *pFilter = (DSoundRenderImpl *)This->pin.pinInfo.pFilter;
1001     HRESULT hr;
1002
1003     TRACE("\n");
1004
1005     EnterCriticalSection(This->pin.pCritSec);
1006     hr = InputPin_EndFlush(iface);
1007
1008     if (pFilter->state == State_Paused)
1009         SetEvent(pFilter->blocked);
1010     LeaveCriticalSection(This->pin.pCritSec);
1011
1012     return hr;
1013 }
1014
1015 static const IPinVtbl DSoundRender_InputPin_Vtbl =
1016 {
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
1035 };
1036
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);
1042
1043     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
1044
1045     return DSoundRender_QueryInterface((IBaseFilter*)This, riid, ppvObj);
1046 }
1047
1048 static ULONG WINAPI Basicaudio_AddRef(IBasicAudio *iface) {
1049     ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1050
1051     TRACE("(%p/%p)->()\n", This, iface);
1052
1053     return DSoundRender_AddRef((IBaseFilter*)This);
1054 }
1055
1056 static ULONG WINAPI Basicaudio_Release(IBasicAudio *iface) {
1057     ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1058
1059     TRACE("(%p/%p)->()\n", This, iface);
1060
1061     return DSoundRender_Release((IBaseFilter*)This);
1062 }
1063
1064 /*** IDispatch methods ***/
1065 static HRESULT WINAPI Basicaudio_GetTypeInfoCount(IBasicAudio *iface,
1066                                                   UINT*pctinfo) {
1067     ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1068
1069     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pctinfo);
1070
1071     return S_OK;
1072 }
1073
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);
1079
1080     TRACE("(%p/%p)->(%d, %d, %p): stub !!!\n", This, iface, iTInfo, lcid, ppTInfo);
1081
1082     return S_OK;
1083 }
1084
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);
1092
1093     TRACE("(%p/%p)->(%s (%p), %p, %d, %d, %p): stub !!!\n", This, iface, debugstr_guid(riid), riid, rgszNames, cNames, lcid, rgDispId);
1094
1095     return S_OK;
1096 }
1097
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);
1108
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);
1110
1111     return S_OK;
1112 }
1113
1114 /*** IBasicAudio methods ***/
1115 static HRESULT WINAPI Basicaudio_put_Volume(IBasicAudio *iface,
1116                                             LONG lVolume) {
1117     ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1118
1119     TRACE("(%p/%p)->(%d)\n", This, iface, lVolume);
1120
1121     if (lVolume > DSBVOLUME_MAX || lVolume < DSBVOLUME_MIN)
1122         return E_INVALIDARG;
1123
1124     if (This->dsbuffer) {
1125         if (FAILED(IDirectSoundBuffer_SetVolume(This->dsbuffer, lVolume)))
1126             return E_FAIL;
1127     }
1128
1129     This->volume = lVolume;
1130     return S_OK;
1131 }
1132
1133 static HRESULT WINAPI Basicaudio_get_Volume(IBasicAudio *iface,
1134                                             LONG *plVolume) {
1135     ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1136
1137     TRACE("(%p/%p)->(%p)\n", This, iface, plVolume);
1138
1139     if (!plVolume)
1140         return E_POINTER;
1141
1142     *plVolume = This->volume;
1143     return S_OK;
1144 }
1145
1146 static HRESULT WINAPI Basicaudio_put_Balance(IBasicAudio *iface,
1147                                              LONG lBalance) {
1148     ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1149
1150     TRACE("(%p/%p)->(%d)\n", This, iface, lBalance);
1151
1152     if (lBalance < DSBPAN_LEFT || lBalance > DSBPAN_RIGHT)
1153         return E_INVALIDARG;
1154
1155     if (This->dsbuffer) {
1156         if (FAILED(IDirectSoundBuffer_SetPan(This->dsbuffer, lBalance)))
1157             return E_FAIL;
1158     }
1159
1160     This->pan = lBalance;
1161     return S_OK;
1162 }
1163
1164 static HRESULT WINAPI Basicaudio_get_Balance(IBasicAudio *iface,
1165                                              LONG *plBalance) {
1166     ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1167
1168     TRACE("(%p/%p)->(%p)\n", This, iface, plBalance);
1169
1170     if (!plBalance)
1171         return E_POINTER;
1172
1173     *plBalance = This->pan;
1174     return S_OK;
1175 }
1176
1177 static const IBasicAudioVtbl IBasicAudio_Vtbl =
1178 {
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
1190 };
1191
1192
1193 /*** IUnknown methods ***/
1194 static HRESULT WINAPI ReferenceClock_QueryInterface(IReferenceClock *iface,
1195                                                 REFIID riid,
1196                                                 LPVOID*ppvObj)
1197 {
1198     ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1199
1200     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
1201
1202     return DSoundRender_QueryInterface((IBaseFilter*)This, riid, ppvObj);
1203 }
1204
1205 static ULONG WINAPI ReferenceClock_AddRef(IReferenceClock *iface)
1206 {
1207     ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1208
1209     TRACE("(%p/%p)->()\n", This, iface);
1210
1211     return DSoundRender_AddRef((IBaseFilter*)This);
1212 }
1213
1214 static ULONG WINAPI ReferenceClock_Release(IReferenceClock *iface)
1215 {
1216     ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1217
1218     TRACE("(%p/%p)->()\n", This, iface);
1219
1220     return DSoundRender_Release((IBaseFilter*)This);
1221 }
1222
1223 /*** IReferenceClock methods ***/
1224 static HRESULT WINAPI ReferenceClock_GetTime(IReferenceClock *iface,
1225                                              REFERENCE_TIME *pTime)
1226 {
1227     ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1228     HRESULT hr = E_FAIL;
1229     DWORD play_pos;
1230
1231     TRACE("(%p/%p)->(%p)\n", This, iface, pTime);
1232
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);
1237
1238     return hr;
1239 }
1240
1241 static HRESULT WINAPI ReferenceClock_AdviseTime(IReferenceClock *iface,
1242                                                 REFERENCE_TIME rtBaseTime,
1243                                                 REFERENCE_TIME rtStreamTime,
1244                                                 HEVENT hEvent,
1245                                                 DWORD_PTR *pdwAdviseCookie)
1246 {
1247     ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1248
1249     FIXME("(%p/%p)->(%s, %s, %p, %p): stub!\n", This, iface, wine_dbgstr_longlong(rtBaseTime), wine_dbgstr_longlong(rtStreamTime), (void*)hEvent, pdwAdviseCookie);
1250
1251     return E_NOTIMPL;
1252 }
1253
1254 static HRESULT WINAPI ReferenceClock_AdvisePeriodic(IReferenceClock *iface,
1255                                                     REFERENCE_TIME rtBaseTime,
1256                                                     REFERENCE_TIME rtStreamTime,
1257                                                     HSEMAPHORE hSemaphore,
1258                                                     DWORD_PTR *pdwAdviseCookie)
1259 {
1260     ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1261
1262     FIXME("(%p/%p)->(%s, %s, %p, %p): stub!\n", This, iface, wine_dbgstr_longlong(rtBaseTime), wine_dbgstr_longlong(rtStreamTime), (void*)hSemaphore, pdwAdviseCookie);
1263
1264     return E_NOTIMPL;
1265 }
1266
1267 static HRESULT WINAPI ReferenceClock_Unadvise(IReferenceClock *iface,
1268                                               DWORD_PTR dwAdviseCookie)
1269 {
1270     ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1271
1272     FIXME("(%p/%p)->(%p): stub!\n", This, iface, (void*)dwAdviseCookie);
1273
1274     return S_FALSE;
1275 }
1276
1277 static const IReferenceClockVtbl IReferenceClock_Vtbl =
1278 {
1279     ReferenceClock_QueryInterface,
1280     ReferenceClock_AddRef,
1281     ReferenceClock_Release,
1282     ReferenceClock_GetTime,
1283     ReferenceClock_AdviseTime,
1284     ReferenceClock_AdvisePeriodic,
1285     ReferenceClock_Unadvise
1286 };
1287
1288 static inline DSoundRenderImpl *impl_from_IMediaSeeking( IMediaSeeking *iface )
1289 {
1290     return (DSoundRenderImpl *)((char*)iface - FIELD_OFFSET(DSoundRenderImpl, mediaSeeking.lpVtbl));
1291 }
1292
1293 static HRESULT WINAPI sound_seek_QueryInterface(IMediaSeeking * iface, REFIID riid, LPVOID * ppv)
1294 {
1295     DSoundRenderImpl *This = impl_from_IMediaSeeking(iface);
1296
1297     return IUnknown_QueryInterface((IUnknown *)This, riid, ppv);
1298 }
1299
1300 static ULONG WINAPI sound_seek_AddRef(IMediaSeeking * iface)
1301 {
1302     DSoundRenderImpl *This = impl_from_IMediaSeeking(iface);
1303
1304     return IUnknown_AddRef((IUnknown *)This);
1305 }
1306
1307 static ULONG WINAPI sound_seek_Release(IMediaSeeking * iface)
1308 {
1309     DSoundRenderImpl *This = impl_from_IMediaSeeking(iface);
1310
1311     return IUnknown_Release((IUnknown *)This);
1312 }
1313
1314 static const IMediaSeekingVtbl IMediaSeeking_Vtbl =
1315 {
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
1336 };
1337
1338 /*** IUnknown methods ***/
1339 static HRESULT WINAPI AMDirectSound_QueryInterface(IAMDirectSound *iface,
1340                                                 REFIID riid,
1341                                                 LPVOID*ppvObj)
1342 {
1343     ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1344
1345     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
1346
1347     return DSoundRender_QueryInterface((IBaseFilter*)This, riid, ppvObj);
1348 }
1349
1350 static ULONG WINAPI AMDirectSound_AddRef(IAMDirectSound *iface)
1351 {
1352     ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1353
1354     TRACE("(%p/%p)->()\n", This, iface);
1355
1356     return DSoundRender_AddRef((IBaseFilter*)This);
1357 }
1358
1359 static ULONG WINAPI AMDirectSound_Release(IAMDirectSound *iface)
1360 {
1361     ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1362
1363     TRACE("(%p/%p)->()\n", This, iface);
1364
1365     return DSoundRender_Release((IBaseFilter*)This);
1366 }
1367
1368 /*** IAMDirectSound methods ***/
1369 static HRESULT WINAPI AMDirectSound_GetDirectSoundInterface(IAMDirectSound *iface,  IDirectSound **ds)
1370 {
1371     ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1372
1373     FIXME("(%p/%p)->(%p): stub\n", This, iface, ds);
1374
1375     return E_NOTIMPL;
1376 }
1377
1378 static HRESULT WINAPI AMDirectSound_GetPrimaryBufferInterface(IAMDirectSound *iface, IDirectSoundBuffer **buf)
1379 {
1380     ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1381
1382     FIXME("(%p/%p)->(%p): stub\n", This, iface, buf);
1383
1384     return E_NOTIMPL;
1385 }
1386
1387 static HRESULT WINAPI AMDirectSound_GetSecondaryBufferInterface(IAMDirectSound *iface, IDirectSoundBuffer **buf)
1388 {
1389     ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1390
1391     FIXME("(%p/%p)->(%p): stub\n", This, iface, buf);
1392
1393     return E_NOTIMPL;
1394 }
1395
1396 static HRESULT WINAPI AMDirectSound_ReleaseDirectSoundInterface(IAMDirectSound *iface, IDirectSound *ds)
1397 {
1398     ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1399
1400     FIXME("(%p/%p)->(%p): stub\n", This, iface, ds);
1401
1402     return E_NOTIMPL;
1403 }
1404
1405 static HRESULT WINAPI AMDirectSound_ReleasePrimaryBufferInterface(IAMDirectSound *iface, IDirectSoundBuffer *buf)
1406 {
1407     ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1408
1409     FIXME("(%p/%p)->(%p): stub\n", This, iface, buf);
1410
1411     return E_NOTIMPL;
1412 }
1413
1414 static HRESULT WINAPI AMDirectSound_ReleaseSecondaryBufferInterface(IAMDirectSound *iface, IDirectSoundBuffer *buf)
1415 {
1416     ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1417
1418     FIXME("(%p/%p)->(%p): stub\n", This, iface, buf);
1419
1420     return E_NOTIMPL;
1421 }
1422
1423 static HRESULT WINAPI AMDirectSound_SetFocusWindow(IAMDirectSound *iface, HWND hwnd, BOOL bgsilent)
1424 {
1425     ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1426
1427     FIXME("(%p/%p)->(%p,%d): stub\n", This, iface, hwnd, bgsilent);
1428
1429     return E_NOTIMPL;
1430 }
1431
1432 static HRESULT WINAPI AMDirectSound_GetFocusWindow(IAMDirectSound *iface, HWND hwnd)
1433 {
1434     ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1435
1436     FIXME("(%p/%p)->(%p): stub\n", This, iface, hwnd);
1437
1438     return E_NOTIMPL;
1439 }
1440
1441 static const IAMDirectSoundVtbl IAMDirectSound_Vtbl =
1442 {
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
1454 };