d3dx9: Implement D3DXFVFFromDeclarator.
[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     DWORD in_loop;
76
77     REFERENCE_TIME play_time;
78     MediaSeekingImpl mediaSeeking;
79
80     HANDLE state_change, blocked;
81
82     LONG volume;
83     LONG pan;
84 } DSoundRenderImpl;
85
86 /* Seeking is not needed for a renderer, rely on newsegment for the appropriate changes */
87 static HRESULT sound_mod_stop(IBaseFilter *iface)
88 {
89     TRACE("(%p)\n", iface);
90     return S_OK;
91 }
92
93 static HRESULT sound_mod_start(IBaseFilter *iface)
94 {
95     TRACE("(%p)\n", iface);
96
97     return S_OK;
98 }
99
100 static HRESULT sound_mod_rate(IBaseFilter *iface)
101 {
102     DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
103
104     WAVEFORMATEX *format = (WAVEFORMATEX*)This->pInputPin->pin.mtCurrent.pbFormat;
105     DWORD freq = format->nSamplesPerSec;
106     double rate = This->mediaSeeking.dRate;
107
108     freq = (DWORD)((double)freq * rate);
109
110     TRACE("(%p)\n", iface);
111
112     if (freq > DSBFREQUENCY_MAX)
113         return VFW_E_UNSUPPORTED_AUDIO;
114
115     if (freq < DSBFREQUENCY_MIN)
116         return VFW_E_UNSUPPORTED_AUDIO;
117
118     return S_OK;
119 }
120
121 static inline HRESULT DSoundRender_GetPos(DSoundRenderImpl *This, DWORD *pPlayPos, REFERENCE_TIME *pRefTime)
122 {
123     HRESULT hr;
124
125     EnterCriticalSection(&This->csFilter);
126     {
127         DWORD state;
128         DWORD write_pos;
129
130         hr = IDirectSoundBuffer_GetStatus(This->dsbuffer, &state);
131         if (SUCCEEDED(hr) && !(state & DSBSTATUS_PLAYING) && This->state == State_Running)
132         {
133             TRACE("Not playing, kickstarting the engine\n");
134
135             hr = IDirectSoundBuffer_Play(This->dsbuffer, 0, 0, DSBPLAY_LOOPING);
136             if (FAILED(hr))
137                 ERR("Can't play sound buffer (%x)\n", hr);
138         }
139
140         if (SUCCEEDED(hr))
141             hr = IDirectSoundBuffer_GetCurrentPosition(This->dsbuffer, pPlayPos, &write_pos);
142         if (hr == S_OK)
143         {
144             DWORD play_pos = *pPlayPos;
145
146             if (play_pos < This->last_play_pos)
147                 This->play_loops++;
148             This->last_play_pos = play_pos;
149
150             /* If we really fell behind, start at the next possible position
151              * Also happens when just starting playback for the first time,
152              * or when flushing
153              */
154             if ((This->play_loops*This->buf_size)+play_pos >=
155                 (This->write_loops*This->buf_size)+This->write_pos)
156                 This->write_pos = write_pos;
157
158             if (pRefTime)
159             {
160                 REFERENCE_TIME play_time;
161                 play_time = ((REFERENCE_TIME)This->play_loops*10000000) +
162                             ((REFERENCE_TIME)play_pos*10000000/This->buf_size);
163
164                 /* Don't let time run backwards */
165                 if(play_time-This->play_time > 0)
166                     This->play_time = play_time;
167                 else
168                     hr = S_FALSE;
169
170                 *pRefTime = This->play_time;
171             }
172         }
173     }
174     LeaveCriticalSection(&This->csFilter);
175
176     return hr;
177 }
178
179 static HRESULT DSoundRender_SendSampleData(DSoundRenderImpl* This, const BYTE *data, DWORD size)
180 {
181     HRESULT hr = S_OK;
182     LPBYTE lpbuf1 = NULL;
183     LPBYTE lpbuf2 = NULL;
184     DWORD dwsize1 = 0;
185     DWORD dwsize2 = 0;
186     DWORD size2;
187     DWORD play_pos,buf_free;
188
189     do {
190
191         hr = DSoundRender_GetPos(This, &play_pos, NULL);
192         if (hr != DS_OK)
193         {
194             ERR("GetPos returned error: %x\n", hr);
195             break;
196         }
197         if (This->write_pos <= play_pos)
198              buf_free = play_pos-This->write_pos;
199         else
200              buf_free = This->buf_size - This->write_pos + play_pos;
201
202         /* Wait for enough of the buffer to empty before filling it */
203         if(buf_free < This->buf_size/20)
204         {
205             DWORD ret;
206             This->in_loop = 1;
207             LeaveCriticalSection(&This->csFilter);
208             ret = WaitForSingleObject(This->blocked, 50);
209             if (ret != WAIT_TIMEOUT)
210                 ERR("%x\n", ret);
211             EnterCriticalSection(&This->csFilter);
212             This->in_loop = 0;
213             if (This->pInputPin->flushing)
214                 return VFW_E_WRONG_STATE;
215             if (This->state == State_Stopped)
216                 return VFW_E_WRONG_STATE;
217             continue;
218         }
219
220         size2 = min(buf_free, size);
221         hr = IDirectSoundBuffer_Lock(This->dsbuffer, This->write_pos, size2, (LPVOID *)&lpbuf1, &dwsize1, (LPVOID *)&lpbuf2, &dwsize2, 0);
222         if (hr != DS_OK) {
223             ERR("Unable to lock sound buffer! (%x)\n", hr);
224             break;
225         }
226         /* TRACE("write_pos=%d, size=%d, sz1=%d, sz2=%d\n", This->write_pos, size2, dwsize1, dwsize2); */
227
228         memcpy(lpbuf1, data, dwsize1);
229         if (dwsize2)
230             memcpy(lpbuf2, data + dwsize1, dwsize2);
231
232         hr = IDirectSoundBuffer_Unlock(This->dsbuffer, lpbuf1, dwsize1, lpbuf2, dwsize2);
233         if (hr != DS_OK)
234             ERR("Unable to unlock sound buffer! (%x)\n", hr);
235
236         size -= dwsize1 + dwsize2;
237         data += dwsize1 + dwsize2;
238         This->write_pos += dwsize1 + dwsize2;
239         if (This->write_pos >= This->buf_size)
240         {
241             This->write_pos -= This->buf_size;
242             This->write_loops++;
243         }
244     } while (size && This->state == State_Running);
245
246     return hr;
247 }
248
249 static HRESULT DSoundRender_Sample(LPVOID iface, IMediaSample * pSample)
250 {
251     DSoundRenderImpl *This = iface;
252     LPBYTE pbSrcStream = NULL;
253     LONG cbSrcStream = 0;
254     REFERENCE_TIME tStart, tStop;
255     HRESULT hr;
256     AM_MEDIA_TYPE *amt;
257
258     TRACE("%p %p\n", iface, pSample);
259
260     /* Slightly incorrect, Pause completes when a frame is received so we should signal
261      * pause completion here, but for sound playing a single frame doesn't make sense
262      */
263
264     EnterCriticalSection(&This->csFilter);
265
266     if (This->pInputPin->end_of_stream || This->pInputPin->flushing)
267     {
268         LeaveCriticalSection(&This->csFilter);
269         return S_FALSE;
270     }
271
272     if (This->state == State_Stopped)
273     {
274         LeaveCriticalSection(&This->csFilter);
275         return VFW_E_WRONG_STATE;
276     }
277
278     if (IMediaSample_GetMediaType(pSample, &amt) == S_OK)
279     {
280         AM_MEDIA_TYPE *orig = &This->pInputPin->pin.mtCurrent;
281         WAVEFORMATEX *origfmt = (WAVEFORMATEX *)orig->pbFormat;
282         WAVEFORMATEX *newfmt = (WAVEFORMATEX *)amt->pbFormat;
283
284         if (origfmt->wFormatTag == newfmt->wFormatTag &&
285             origfmt->nChannels == newfmt->nChannels &&
286             origfmt->nBlockAlign == newfmt->nBlockAlign &&
287             origfmt->wBitsPerSample == newfmt->wBitsPerSample &&
288             origfmt->cbSize ==  newfmt->cbSize)
289         {
290             if (origfmt->nSamplesPerSec != newfmt->nSamplesPerSec)
291             {
292                 hr = IDirectSoundBuffer_SetFrequency(This->dsbuffer,
293                                                      newfmt->nSamplesPerSec);
294                 if (FAILED(hr))
295                 {
296                     LeaveCriticalSection(&This->csFilter);
297                     return VFW_E_TYPE_NOT_ACCEPTED;
298                 }
299                 FreeMediaType(orig);
300                 CopyMediaType(orig, amt);
301                 IMediaSample_SetMediaType(pSample, NULL);
302             }
303         }
304         else
305         {
306             LeaveCriticalSection(&This->csFilter);
307             return VFW_E_TYPE_NOT_ACCEPTED;
308         }
309     }
310
311     hr = IMediaSample_GetPointer(pSample, &pbSrcStream);
312     if (FAILED(hr))
313     {
314         ERR("Cannot get pointer to sample data (%x)\n", hr);
315         LeaveCriticalSection(&This->csFilter);
316         return hr;
317     }
318
319     hr = IMediaSample_GetTime(pSample, &tStart, &tStop);
320     if (FAILED(hr))
321         ERR("Cannot get sample time (%x)\n", hr);
322
323     if (This->rtLastStop != tStart && (IMediaSample_IsDiscontinuity(pSample) == S_FALSE))
324         WARN("Unexpected discontinuity: Last: %u.%03u, tStart: %u.%03u\n",
325             (DWORD)(This->rtLastStop / 10000000), (DWORD)((This->rtLastStop / 10000)%1000),
326             (DWORD)(tStart / 10000000), (DWORD)((tStart / 10000)%1000));
327     This->rtLastStop = tStop;
328
329     if (IMediaSample_IsPreroll(pSample) == S_OK)
330     {
331         TRACE("Preroll!\n");
332         LeaveCriticalSection(&This->csFilter);
333         return S_OK;
334     }
335
336     if (This->state == State_Paused)
337     {
338         SetEvent(This->state_change);
339         LeaveCriticalSection(&This->csFilter);
340         WaitForSingleObject(This->blocked, INFINITE);
341         EnterCriticalSection(&This->csFilter);
342         if (This->state == State_Stopped)
343         {
344             LeaveCriticalSection(&This->csFilter);
345             return VFW_E_WRONG_STATE;
346         }
347
348         if (This->state == State_Paused)
349         {
350             /* Assuming we return because of flushing */
351             TRACE("Flushing\n");
352             LeaveCriticalSection(&This->csFilter);
353             return S_OK;
354         }
355     }
356
357     cbSrcStream = IMediaSample_GetActualDataLength(pSample);
358     TRACE("Sample data ptr = %p, size = %d\n", pbSrcStream, cbSrcStream);
359
360 #if 0 /* For debugging purpose */
361     {
362         int i;
363         for(i = 0; i < cbSrcStream; i++)
364         {
365             if ((i!=0) && !(i%16))
366                 TRACE("\n");
367             TRACE("%02x ", pbSrcStream[i]);
368         }
369         TRACE("\n");
370     }
371 #endif
372
373     hr = DSoundRender_SendSampleData(This, pbSrcStream, cbSrcStream);
374     SetEvent(This->state_change);
375     LeaveCriticalSection(&This->csFilter);
376     return hr;
377 }
378
379 static HRESULT DSoundRender_QueryAccept(LPVOID iface, const AM_MEDIA_TYPE * pmt)
380 {
381     WAVEFORMATEX* format;
382
383     if (!IsEqualIID(&pmt->majortype, &MEDIATYPE_Audio))
384         return S_FALSE;
385
386     format =  (WAVEFORMATEX*)pmt->pbFormat;
387     TRACE("Format = %p\n", format);
388     TRACE("wFormatTag = %x %x\n", format->wFormatTag, WAVE_FORMAT_PCM);
389     TRACE("nChannels = %d\n", format->nChannels);
390     TRACE("nSamplesPerSec = %d\n", format->nAvgBytesPerSec);
391     TRACE("nAvgBytesPerSec = %d\n", format->nAvgBytesPerSec);
392     TRACE("nBlockAlign = %d\n", format->nBlockAlign);
393     TRACE("wBitsPerSample = %d\n", format->wBitsPerSample);
394
395     if (!IsEqualIID(&pmt->subtype, &MEDIASUBTYPE_PCM))
396         return S_FALSE;
397
398     return S_OK;
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     pDSoundRender->lpVtbl = &DSoundRender_Vtbl;
420     pDSoundRender->IBasicAudio_vtbl = &IBasicAudio_Vtbl;
421     pDSoundRender->IReferenceClock_vtbl = &IReferenceClock_Vtbl;
422     pDSoundRender->IAMDirectSound_vtbl = &IAMDirectSound_Vtbl;
423     pDSoundRender->refCount = 1;
424     InitializeCriticalSection(&pDSoundRender->csFilter);
425     pDSoundRender->csFilter.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": DSoundRenderImpl.csFilter");
426     pDSoundRender->state = State_Stopped;
427
428     /* construct input pin */
429     piInput.dir = PINDIR_INPUT;
430     piInput.pFilter = (IBaseFilter *)pDSoundRender;
431     lstrcpynW(piInput.achName, wcsInputPinName, sizeof(piInput.achName) / sizeof(piInput.achName[0]));
432     hr = InputPin_Construct(&DSoundRender_InputPin_Vtbl, &piInput, DSoundRender_Sample, pDSoundRender, DSoundRender_QueryAccept, NULL, &pDSoundRender->csFilter, NULL, (IPin **)&pDSoundRender->pInputPin);
433
434     if (SUCCEEDED(hr))
435     {
436         hr = DirectSoundCreate8(NULL, &pDSoundRender->dsound, NULL);
437         if (FAILED(hr))
438             ERR("Cannot create Direct Sound object (%x)\n", hr);
439         else
440             IDirectSound_SetCooperativeLevel(pDSoundRender->dsound, GetDesktopWindow(), DSSCL_PRIORITY);
441     }
442
443     if (SUCCEEDED(hr))
444     {
445         MediaSeekingImpl_Init((IBaseFilter*)pDSoundRender, sound_mod_stop, sound_mod_start, sound_mod_rate, &pDSoundRender->mediaSeeking, &pDSoundRender->csFilter);
446         pDSoundRender->mediaSeeking.lpVtbl = &IMediaSeeking_Vtbl;
447
448         pDSoundRender->state_change = CreateEventW(NULL, TRUE, TRUE, NULL);
449         pDSoundRender->blocked = CreateEventW(NULL, FALSE, FALSE, NULL);
450
451         if (!pDSoundRender->state_change || !pDSoundRender->blocked)
452         {
453             IUnknown_Release((IUnknown *)pDSoundRender);
454             return HRESULT_FROM_WIN32(GetLastError());
455         }
456
457         *ppv = pDSoundRender;
458     }
459     else
460     {
461         if (pDSoundRender->pInputPin)
462             IPin_Release((IPin*)pDSoundRender->pInputPin);
463         pDSoundRender->csFilter.DebugInfo->Spare[0] = 0;
464         DeleteCriticalSection(&pDSoundRender->csFilter);
465         CoTaskMemFree(pDSoundRender);
466     }
467
468     return hr;
469 }
470
471 static HRESULT WINAPI DSoundRender_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv)
472 {
473     DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
474     TRACE("(%p, %p)->(%s, %p)\n", This, iface, qzdebugstr_guid(riid), ppv);
475
476     *ppv = NULL;
477
478     if (IsEqualIID(riid, &IID_IUnknown))
479         *ppv = This;
480     else if (IsEqualIID(riid, &IID_IPersist))
481         *ppv = This;
482     else if (IsEqualIID(riid, &IID_IMediaFilter))
483         *ppv = This;
484     else if (IsEqualIID(riid, &IID_IBaseFilter))
485         *ppv = This;
486     else if (IsEqualIID(riid, &IID_IBasicAudio))
487         *ppv = &This->IBasicAudio_vtbl;
488     else if (IsEqualIID(riid, &IID_IReferenceClock))
489         *ppv = &This->IReferenceClock_vtbl;
490     else if (IsEqualIID(riid, &IID_IMediaSeeking))
491         *ppv = &This->mediaSeeking.lpVtbl;
492     else if (IsEqualIID(riid, &IID_IAMDirectSound))
493         *ppv = &This->IAMDirectSound_vtbl;
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_AddRef(IBaseFilter * iface)
508 {
509     DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
510     ULONG refCount = InterlockedIncrement(&This->refCount);
511
512     TRACE("(%p/%p)->() AddRef from %d\n", This, iface, refCount - 1);
513
514     return refCount;
515 }
516
517 static ULONG WINAPI DSoundRender_Release(IBaseFilter * iface)
518 {
519     DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
520     ULONG refCount = InterlockedDecrement(&This->refCount);
521
522     TRACE("(%p)->() Release from %d\n", This, refCount + 1);
523
524     if (!refCount)
525     {
526         IPin *pConnectedTo;
527
528         if (This->pClock)
529             IReferenceClock_Release(This->pClock);
530
531         if (This->dsbuffer)
532             IDirectSoundBuffer_Release(This->dsbuffer);
533         This->dsbuffer = NULL;
534         if (This->dsound)
535             IDirectSound_Release(This->dsound);
536         This->dsound = NULL;
537        
538         if (SUCCEEDED(IPin_ConnectedTo((IPin *)This->pInputPin, &pConnectedTo)))
539         {
540             IPin_Disconnect(pConnectedTo);
541             IPin_Release(pConnectedTo);
542         }
543         IPin_Disconnect((IPin *)This->pInputPin);
544
545         IPin_Release((IPin *)This->pInputPin);
546
547         This->lpVtbl = NULL;
548         This->IBasicAudio_vtbl = NULL;
549         
550         This->csFilter.DebugInfo->Spare[0] = 0;
551         DeleteCriticalSection(&This->csFilter);
552
553         CloseHandle(This->state_change);
554         CloseHandle(This->blocked);
555
556         TRACE("Destroying Audio Renderer\n");
557         CoTaskMemFree(This);
558         
559         return 0;
560     }
561     else
562         return refCount;
563 }
564
565 /** IPersist methods **/
566
567 static HRESULT WINAPI DSoundRender_GetClassID(IBaseFilter * iface, CLSID * pClsid)
568 {
569     DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
570     TRACE("(%p/%p)->(%p)\n", This, iface, pClsid);
571
572     *pClsid = CLSID_DSoundRender;
573
574     return S_OK;
575 }
576
577 /** IMediaFilter methods **/
578
579 static HRESULT WINAPI DSoundRender_Stop(IBaseFilter * iface)
580 {
581     HRESULT hr = S_OK;
582     DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
583
584     TRACE("(%p/%p)->()\n", This, iface);
585
586     EnterCriticalSection(&This->csFilter);
587     {
588         DWORD state = 0;
589         if (This->dsbuffer)
590         {
591             hr = IDirectSoundBuffer_GetStatus(This->dsbuffer, &state);
592             if (SUCCEEDED(hr))
593             {
594                 if (state & DSBSTATUS_PLAYING)
595                     hr = IDirectSoundBuffer_Stop(This->dsbuffer);
596             }
597         }
598         if (SUCCEEDED(hr))
599             This->state = State_Stopped;
600
601         /* Complete our transition */
602         SetEvent(This->state_change);
603         SetEvent(This->blocked);
604     }
605     LeaveCriticalSection(&This->csFilter);
606     
607     return hr;
608 }
609
610 static HRESULT WINAPI DSoundRender_Pause(IBaseFilter * iface)
611 {
612     HRESULT hr = S_OK;
613     DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
614     
615     TRACE("(%p/%p)->()\n", This, iface);
616
617     EnterCriticalSection(&This->csFilter);
618     if (This->state != State_Paused)
619     {
620         DWORD state = 0;
621         if (This->state == State_Stopped)
622         {
623             This->pInputPin->end_of_stream = 0;
624         }
625
626         if (This->dsbuffer)
627         {
628             hr = IDirectSoundBuffer_GetStatus(This->dsbuffer, &state);
629             if (SUCCEEDED(hr))
630             {
631                 if (state & DSBSTATUS_PLAYING)
632                     hr = IDirectSoundBuffer_Stop(This->dsbuffer);
633             }
634         }
635         if (SUCCEEDED(hr))
636             This->state = State_Paused;
637
638         ResetEvent(This->blocked);
639         ResetEvent(This->state_change);
640     }
641     LeaveCriticalSection(&This->csFilter);
642
643     return hr;
644 }
645
646 static HRESULT WINAPI DSoundRender_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
647 {
648     HRESULT hr = S_OK;
649     DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
650
651     TRACE("(%p/%p)->(%s)\n", This, iface, wine_dbgstr_longlong(tStart));
652
653     EnterCriticalSection(&This->csFilter);
654     {
655         This->rtStreamStart = tStart;
656         if (This->state == State_Paused)
657         {
658             /* Unblock our thread, state changing from paused to running doesn't need a reset for state change */
659             SetEvent(This->blocked);
660         }
661         else if (This->state == State_Stopped)
662         {
663             ResetEvent(This->state_change);
664             This->pInputPin->end_of_stream = 0;
665         }
666         ResetEvent(This->blocked);
667
668         This->state = State_Running;
669     }
670     LeaveCriticalSection(&This->csFilter);
671
672     return hr;
673 }
674
675 static HRESULT WINAPI DSoundRender_GetState(IBaseFilter * iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState)
676 {
677     HRESULT hr;
678     DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
679
680     TRACE("(%p/%p)->(%d, %p)\n", This, iface, dwMilliSecsTimeout, pState);
681
682     if (WaitForSingleObject(This->state_change, dwMilliSecsTimeout) == WAIT_TIMEOUT)
683         hr = VFW_S_STATE_INTERMEDIATE;
684     else
685         hr = S_OK;
686
687     EnterCriticalSection(&This->csFilter);
688     {
689         *pState = This->state;
690     }
691     LeaveCriticalSection(&This->csFilter);
692
693     return hr;
694 }
695
696 static HRESULT WINAPI DSoundRender_SetSyncSource(IBaseFilter * iface, IReferenceClock *pClock)
697 {
698     DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
699
700     TRACE("(%p/%p)->(%p)\n", This, iface, pClock);
701
702     EnterCriticalSection(&This->csFilter);
703     {
704         if (This->pClock)
705             IReferenceClock_Release(This->pClock);
706         This->pClock = pClock;
707         if (This->pClock)
708             IReferenceClock_AddRef(This->pClock);
709     }
710     LeaveCriticalSection(&This->csFilter);
711
712     return S_OK;
713 }
714
715 static HRESULT WINAPI DSoundRender_GetSyncSource(IBaseFilter * iface, IReferenceClock **ppClock)
716 {
717     DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
718
719     TRACE("(%p/%p)->(%p)\n", This, iface, ppClock);
720
721     EnterCriticalSection(&This->csFilter);
722     {
723         *ppClock = This->pClock;
724         if (This->pClock)
725             IReferenceClock_AddRef(This->pClock);
726     }
727     LeaveCriticalSection(&This->csFilter);
728     
729     return S_OK;
730 }
731
732 /** IBaseFilter implementation **/
733
734 static HRESULT DSoundRender_GetPin(IBaseFilter *iface, ULONG pos, IPin **pin, DWORD *lastsynctick)
735 {
736     DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
737
738     /* Our pins are static, not changing so setting static tick count is ok */
739     *lastsynctick = 0;
740
741     if (pos >= 1)
742         return S_FALSE;
743
744     *pin = (IPin *)This->pInputPin;
745     IPin_AddRef(*pin);
746     return S_OK;
747 }
748
749 static HRESULT WINAPI DSoundRender_EnumPins(IBaseFilter * iface, IEnumPins **ppEnum)
750 {
751     DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
752
753     TRACE("(%p/%p)->(%p)\n", This, iface, ppEnum);
754
755     return IEnumPinsImpl_Construct(ppEnum, DSoundRender_GetPin, iface);
756 }
757
758 static HRESULT WINAPI DSoundRender_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin)
759 {
760     DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
761
762     TRACE("(%p/%p)->(%s,%p)\n", This, iface, debugstr_w(Id), ppPin);
763     
764     FIXME("DSoundRender::FindPin(...)\n");
765
766     /* FIXME: critical section */
767
768     return E_NOTIMPL;
769 }
770
771 static HRESULT WINAPI DSoundRender_QueryFilterInfo(IBaseFilter * iface, FILTER_INFO *pInfo)
772 {
773     DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
774
775     TRACE("(%p/%p)->(%p)\n", This, iface, pInfo);
776
777     strcpyW(pInfo->achName, This->filterInfo.achName);
778     pInfo->pGraph = This->filterInfo.pGraph;
779
780     if (pInfo->pGraph)
781         IFilterGraph_AddRef(pInfo->pGraph);
782     
783     return S_OK;
784 }
785
786 static HRESULT WINAPI DSoundRender_JoinFilterGraph(IBaseFilter * iface, IFilterGraph *pGraph, LPCWSTR pName)
787 {
788     DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
789
790     TRACE("(%p/%p)->(%p, %s)\n", This, iface, pGraph, debugstr_w(pName));
791
792     EnterCriticalSection(&This->csFilter);
793     {
794         if (pName)
795             strcpyW(This->filterInfo.achName, pName);
796         else
797             *This->filterInfo.achName = '\0';
798         This->filterInfo.pGraph = pGraph; /* NOTE: do NOT increase ref. count */
799     }
800     LeaveCriticalSection(&This->csFilter);
801
802     return S_OK;
803 }
804
805 static HRESULT WINAPI DSoundRender_QueryVendorInfo(IBaseFilter * iface, LPWSTR *pVendorInfo)
806 {
807     DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
808     TRACE("(%p/%p)->(%p)\n", This, iface, pVendorInfo);
809     return E_NOTIMPL;
810 }
811
812 static const IBaseFilterVtbl DSoundRender_Vtbl =
813 {
814     DSoundRender_QueryInterface,
815     DSoundRender_AddRef,
816     DSoundRender_Release,
817     DSoundRender_GetClassID,
818     DSoundRender_Stop,
819     DSoundRender_Pause,
820     DSoundRender_Run,
821     DSoundRender_GetState,
822     DSoundRender_SetSyncSource,
823     DSoundRender_GetSyncSource,
824     DSoundRender_EnumPins,
825     DSoundRender_FindPin,
826     DSoundRender_QueryFilterInfo,
827     DSoundRender_JoinFilterGraph,
828     DSoundRender_QueryVendorInfo
829 };
830
831 static HRESULT WINAPI DSoundRender_InputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
832 {
833     InputPin *This = (InputPin *)iface;
834     PIN_DIRECTION pindirReceive;
835     DSoundRenderImpl *DSImpl;
836     HRESULT hr = S_OK;
837
838     TRACE("(%p)->(%p, %p)\n", This, pReceivePin, pmt);
839     dump_AM_MEDIA_TYPE(pmt);
840
841     EnterCriticalSection(This->pin.pCritSec);
842     {
843         DSImpl = (DSoundRenderImpl*)This->pin.pinInfo.pFilter;
844         DSImpl->rtLastStop = -1;
845
846         if (This->pin.pConnectedTo)
847             hr = VFW_E_ALREADY_CONNECTED;
848
849         if (SUCCEEDED(hr) && This->pin.fnQueryAccept(This->pin.pUserData, pmt) != S_OK)
850             hr = VFW_E_TYPE_NOT_ACCEPTED;
851
852         if (SUCCEEDED(hr))
853         {
854             IPin_QueryDirection(pReceivePin, &pindirReceive);
855
856             if (pindirReceive != PINDIR_OUTPUT)
857             {
858                 ERR("Can't connect from non-output pin\n");
859                 hr = VFW_E_INVALID_DIRECTION;
860             }
861         }
862
863         if (SUCCEEDED(hr))
864         {
865             WAVEFORMATEX *format;
866             DSBUFFERDESC buf_desc;
867
868             TRACE("MajorType %s\n", debugstr_guid(&pmt->majortype));
869             TRACE("SubType %s\n", debugstr_guid(&pmt->subtype));
870             TRACE("Format %s\n", debugstr_guid(&pmt->formattype));
871             TRACE("Size %d\n", pmt->cbFormat);
872
873             format = (WAVEFORMATEX*)pmt->pbFormat;
874
875             DSImpl->buf_size = format->nAvgBytesPerSec;
876
877             memset(&buf_desc,0,sizeof(DSBUFFERDESC));
878             buf_desc.dwSize = sizeof(DSBUFFERDESC);
879             buf_desc.dwFlags = DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLPAN |
880                                DSBCAPS_CTRLFREQUENCY |
881                                DSBCAPS_GETCURRENTPOSITION2;
882             buf_desc.dwBufferBytes = DSImpl->buf_size;
883             buf_desc.lpwfxFormat = format;
884             hr = IDirectSound_CreateSoundBuffer(DSImpl->dsound, &buf_desc, &DSImpl->dsbuffer, NULL);
885             if (FAILED(hr))
886                 ERR("Can't create sound buffer (%x)\n", hr);
887         }
888
889         if (SUCCEEDED(hr))
890         {
891             hr = IDirectSoundBuffer_SetVolume(DSImpl->dsbuffer, DSImpl->volume);
892             if (FAILED(hr))
893                 ERR("Can't set volume to %d (%x)\n", DSImpl->volume, hr);
894
895             hr = IDirectSoundBuffer_SetPan(DSImpl->dsbuffer, DSImpl->pan);
896             if (FAILED(hr))
897                 ERR("Can't set pan to %d (%x)\n", DSImpl->pan, hr);
898
899             DSImpl->write_pos = 0;
900             hr = S_OK;
901         }
902
903         if (SUCCEEDED(hr))
904         {
905             CopyMediaType(&This->pin.mtCurrent, pmt);
906             This->pin.pConnectedTo = pReceivePin;
907             IPin_AddRef(pReceivePin);
908         }
909         else if (hr != VFW_E_ALREADY_CONNECTED)
910         {
911             if (DSImpl->dsbuffer)
912                 IDirectSoundBuffer_Release(DSImpl->dsbuffer);
913             DSImpl->dsbuffer = NULL;
914         }
915     }
916     LeaveCriticalSection(This->pin.pCritSec);
917
918     return hr;
919 }
920
921 static HRESULT WINAPI DSoundRender_InputPin_Disconnect(IPin * iface)
922 {
923     IPinImpl *This = (IPinImpl*)iface;
924     DSoundRenderImpl *DSImpl;
925
926     TRACE("(%p)->()\n", iface);
927
928     DSImpl = (DSoundRenderImpl*)This->pinInfo.pFilter;
929     if (DSImpl->dsbuffer)
930         IDirectSoundBuffer_Release(DSImpl->dsbuffer);
931     DSImpl->dsbuffer = NULL;
932
933     return IPinImpl_Disconnect(iface);
934 }
935
936 static HRESULT WINAPI DSoundRender_InputPin_EndOfStream(IPin * iface)
937 {
938     InputPin* This = (InputPin*)iface;
939     DSoundRenderImpl *me = (DSoundRenderImpl*)This->pin.pinInfo.pFilter;
940     IMediaEventSink* pEventSink;
941     HRESULT hr;
942
943     EnterCriticalSection(This->pin.pCritSec);
944
945     TRACE("(%p/%p)->()\n", This, iface);
946     hr = InputPin_EndOfStream(iface);
947     if (hr != S_OK)
948     {
949         ERR("%08x\n", hr);
950         LeaveCriticalSection(This->pin.pCritSec);
951         return hr;
952     }
953
954     hr = IFilterGraph_QueryInterface(me->filterInfo.pGraph, &IID_IMediaEventSink, (LPVOID*)&pEventSink);
955     if (SUCCEEDED(hr))
956     {
957         BYTE * silence;
958
959         silence = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, me->buf_size);
960         if (silence)
961         {
962             memset(silence, 0, me->buf_size);
963             DSoundRender_SendSampleData((DSoundRenderImpl*)This->pin.pinInfo.pFilter, silence, me->buf_size);
964             HeapFree(GetProcessHeap(), 0, silence);
965         }
966
967         hr = IMediaEventSink_Notify(pEventSink, EC_COMPLETE, S_OK, 0);
968         IMediaEventSink_Release(pEventSink);
969     }
970     LeaveCriticalSection(This->pin.pCritSec);
971
972     return hr;
973 }
974
975 static HRESULT WINAPI DSoundRender_InputPin_BeginFlush(IPin * iface)
976 {
977     InputPin *This = (InputPin *)iface;
978     DSoundRenderImpl *pFilter = (DSoundRenderImpl *)This->pin.pinInfo.pFilter;
979     HRESULT hr;
980
981     TRACE("\n");
982
983     EnterCriticalSection(This->pin.pCritSec);
984     hr = InputPin_BeginFlush(iface);
985     SetEvent(pFilter->blocked);
986     LeaveCriticalSection(This->pin.pCritSec);
987
988     return hr;
989 }
990
991 static HRESULT WINAPI DSoundRender_InputPin_EndFlush(IPin * iface)
992 {
993     InputPin *This = (InputPin *)iface;
994     DSoundRenderImpl *pFilter = (DSoundRenderImpl *)This->pin.pinInfo.pFilter;
995     HRESULT hr;
996
997     TRACE("\n");
998
999     EnterCriticalSection(This->pin.pCritSec);
1000     if (pFilter->in_loop) {
1001         ResetEvent(pFilter->state_change);
1002         LeaveCriticalSection(This->pin.pCritSec);
1003         WaitForSingleObject(pFilter->state_change, -1);
1004         EnterCriticalSection(This->pin.pCritSec);
1005     }
1006     if (pFilter->state != State_Stopped)
1007         ResetEvent(pFilter->blocked);
1008
1009     if (pFilter->dsbuffer)
1010     {
1011         LPBYTE buffer;
1012         DWORD size;
1013         IDirectSoundBuffer_Stop(pFilter->dsbuffer);
1014
1015         /* Force a reset */
1016         IDirectSoundBuffer_SetCurrentPosition(pFilter->dsbuffer, 0);
1017         pFilter->write_pos = pFilter->last_play_pos = 0;
1018         ++pFilter->play_loops;
1019         pFilter->write_loops = pFilter->play_loops;
1020
1021         IDirectSoundBuffer_Lock(pFilter->dsbuffer, 0, 0, (LPVOID *)&buffer, &size, NULL, NULL, DSBLOCK_ENTIREBUFFER);
1022         memset(buffer, 0, size);
1023         IDirectSoundBuffer_Unlock(pFilter->dsbuffer, buffer, size, NULL, 0);
1024     }
1025     hr = InputPin_EndFlush(iface);
1026     LeaveCriticalSection(This->pin.pCritSec);
1027
1028     return hr;
1029 }
1030
1031 static const IPinVtbl DSoundRender_InputPin_Vtbl =
1032 {
1033     InputPin_QueryInterface,
1034     IPinImpl_AddRef,
1035     InputPin_Release,
1036     InputPin_Connect,
1037     DSoundRender_InputPin_ReceiveConnection,
1038     DSoundRender_InputPin_Disconnect,
1039     IPinImpl_ConnectedTo,
1040     IPinImpl_ConnectionMediaType,
1041     IPinImpl_QueryPinInfo,
1042     IPinImpl_QueryDirection,
1043     IPinImpl_QueryId,
1044     IPinImpl_QueryAccept,
1045     IPinImpl_EnumMediaTypes,
1046     IPinImpl_QueryInternalConnections,
1047     DSoundRender_InputPin_EndOfStream,
1048     DSoundRender_InputPin_BeginFlush,
1049     DSoundRender_InputPin_EndFlush,
1050     InputPin_NewSegment
1051 };
1052
1053 /*** IUnknown methods ***/
1054 static HRESULT WINAPI Basicaudio_QueryInterface(IBasicAudio *iface,
1055                                                 REFIID riid,
1056                                                 LPVOID*ppvObj) {
1057     ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1058
1059     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
1060
1061     return DSoundRender_QueryInterface((IBaseFilter*)This, riid, ppvObj);
1062 }
1063
1064 static ULONG WINAPI Basicaudio_AddRef(IBasicAudio *iface) {
1065     ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1066
1067     TRACE("(%p/%p)->()\n", This, iface);
1068
1069     return DSoundRender_AddRef((IBaseFilter*)This);
1070 }
1071
1072 static ULONG WINAPI Basicaudio_Release(IBasicAudio *iface) {
1073     ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1074
1075     TRACE("(%p/%p)->()\n", This, iface);
1076
1077     return DSoundRender_Release((IBaseFilter*)This);
1078 }
1079
1080 /*** IDispatch methods ***/
1081 static HRESULT WINAPI Basicaudio_GetTypeInfoCount(IBasicAudio *iface,
1082                                                   UINT*pctinfo) {
1083     ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1084
1085     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pctinfo);
1086
1087     return S_OK;
1088 }
1089
1090 static HRESULT WINAPI Basicaudio_GetTypeInfo(IBasicAudio *iface,
1091                                              UINT iTInfo,
1092                                              LCID lcid,
1093                                              ITypeInfo**ppTInfo) {
1094     ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1095
1096     TRACE("(%p/%p)->(%d, %d, %p): stub !!!\n", This, iface, iTInfo, lcid, ppTInfo);
1097
1098     return S_OK;
1099 }
1100
1101 static HRESULT WINAPI Basicaudio_GetIDsOfNames(IBasicAudio *iface,
1102                                                REFIID riid,
1103                                                LPOLESTR*rgszNames,
1104                                                UINT cNames,
1105                                                LCID lcid,
1106                                                DISPID*rgDispId) {
1107     ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1108
1109     TRACE("(%p/%p)->(%s (%p), %p, %d, %d, %p): stub !!!\n", This, iface, debugstr_guid(riid), riid, rgszNames, cNames, lcid, rgDispId);
1110
1111     return S_OK;
1112 }
1113
1114 static HRESULT WINAPI Basicaudio_Invoke(IBasicAudio *iface,
1115                                         DISPID dispIdMember,
1116                                         REFIID riid,
1117                                         LCID lcid,
1118                                         WORD wFlags,
1119                                         DISPPARAMS*pDispParams,
1120                                         VARIANT*pVarResult,
1121                                         EXCEPINFO*pExepInfo,
1122                                         UINT*puArgErr) {
1123     ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1124
1125     TRACE("(%p/%p)->(%d, %s (%p), %d, %04x, %p, %p, %p, %p): stub !!!\n", This, iface, dispIdMember, debugstr_guid(riid), riid, lcid, wFlags, pDispParams, pVarResult, pExepInfo, puArgErr);
1126
1127     return S_OK;
1128 }
1129
1130 /*** IBasicAudio methods ***/
1131 static HRESULT WINAPI Basicaudio_put_Volume(IBasicAudio *iface,
1132                                             LONG lVolume) {
1133     ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1134
1135     TRACE("(%p/%p)->(%d)\n", This, iface, lVolume);
1136
1137     if (lVolume > DSBVOLUME_MAX || lVolume < DSBVOLUME_MIN)
1138         return E_INVALIDARG;
1139
1140     if (This->dsbuffer) {
1141         if (FAILED(IDirectSoundBuffer_SetVolume(This->dsbuffer, lVolume)))
1142             return E_FAIL;
1143     }
1144
1145     This->volume = lVolume;
1146     return S_OK;
1147 }
1148
1149 static HRESULT WINAPI Basicaudio_get_Volume(IBasicAudio *iface,
1150                                             LONG *plVolume) {
1151     ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1152
1153     TRACE("(%p/%p)->(%p)\n", This, iface, plVolume);
1154
1155     if (!plVolume)
1156         return E_POINTER;
1157
1158     *plVolume = This->volume;
1159     return S_OK;
1160 }
1161
1162 static HRESULT WINAPI Basicaudio_put_Balance(IBasicAudio *iface,
1163                                              LONG lBalance) {
1164     ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1165
1166     TRACE("(%p/%p)->(%d)\n", This, iface, lBalance);
1167
1168     if (lBalance < DSBPAN_LEFT || lBalance > DSBPAN_RIGHT)
1169         return E_INVALIDARG;
1170
1171     if (This->dsbuffer) {
1172         if (FAILED(IDirectSoundBuffer_SetPan(This->dsbuffer, lBalance)))
1173             return E_FAIL;
1174     }
1175
1176     This->pan = lBalance;
1177     return S_OK;
1178 }
1179
1180 static HRESULT WINAPI Basicaudio_get_Balance(IBasicAudio *iface,
1181                                              LONG *plBalance) {
1182     ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
1183
1184     TRACE("(%p/%p)->(%p)\n", This, iface, plBalance);
1185
1186     if (!plBalance)
1187         return E_POINTER;
1188
1189     *plBalance = This->pan;
1190     return S_OK;
1191 }
1192
1193 static const IBasicAudioVtbl IBasicAudio_Vtbl =
1194 {
1195     Basicaudio_QueryInterface,
1196     Basicaudio_AddRef,
1197     Basicaudio_Release,
1198     Basicaudio_GetTypeInfoCount,
1199     Basicaudio_GetTypeInfo,
1200     Basicaudio_GetIDsOfNames,
1201     Basicaudio_Invoke,
1202     Basicaudio_put_Volume,
1203     Basicaudio_get_Volume,
1204     Basicaudio_put_Balance,
1205     Basicaudio_get_Balance
1206 };
1207
1208
1209 /*** IUnknown methods ***/
1210 static HRESULT WINAPI ReferenceClock_QueryInterface(IReferenceClock *iface,
1211                                                 REFIID riid,
1212                                                 LPVOID*ppvObj)
1213 {
1214     ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1215
1216     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
1217
1218     return DSoundRender_QueryInterface((IBaseFilter*)This, riid, ppvObj);
1219 }
1220
1221 static ULONG WINAPI ReferenceClock_AddRef(IReferenceClock *iface)
1222 {
1223     ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1224
1225     TRACE("(%p/%p)->()\n", This, iface);
1226
1227     return DSoundRender_AddRef((IBaseFilter*)This);
1228 }
1229
1230 static ULONG WINAPI ReferenceClock_Release(IReferenceClock *iface)
1231 {
1232     ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1233
1234     TRACE("(%p/%p)->()\n", This, iface);
1235
1236     return DSoundRender_Release((IBaseFilter*)This);
1237 }
1238
1239 /*** IReferenceClock methods ***/
1240 static HRESULT WINAPI ReferenceClock_GetTime(IReferenceClock *iface,
1241                                              REFERENCE_TIME *pTime)
1242 {
1243     ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1244     HRESULT hr = E_FAIL;
1245     DWORD play_pos;
1246
1247     TRACE("(%p/%p)->(%p)\n", This, iface, pTime);
1248
1249     if (This->dsbuffer)
1250         hr = DSoundRender_GetPos(This, &play_pos, pTime);
1251     if (FAILED(hr))
1252         ERR("Could not get reference time (%x)!\n", hr);
1253
1254     return hr;
1255 }
1256
1257 static HRESULT WINAPI ReferenceClock_AdviseTime(IReferenceClock *iface,
1258                                                 REFERENCE_TIME rtBaseTime,
1259                                                 REFERENCE_TIME rtStreamTime,
1260                                                 HEVENT hEvent,
1261                                                 DWORD_PTR *pdwAdviseCookie)
1262 {
1263     ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1264
1265     FIXME("(%p/%p)->(%s, %s, %p, %p): stub!\n", This, iface, wine_dbgstr_longlong(rtBaseTime), wine_dbgstr_longlong(rtStreamTime), (void*)hEvent, pdwAdviseCookie);
1266
1267     return E_NOTIMPL;
1268 }
1269
1270 static HRESULT WINAPI ReferenceClock_AdvisePeriodic(IReferenceClock *iface,
1271                                                     REFERENCE_TIME rtBaseTime,
1272                                                     REFERENCE_TIME rtStreamTime,
1273                                                     HSEMAPHORE hSemaphore,
1274                                                     DWORD_PTR *pdwAdviseCookie)
1275 {
1276     ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1277
1278     FIXME("(%p/%p)->(%s, %s, %p, %p): stub!\n", This, iface, wine_dbgstr_longlong(rtBaseTime), wine_dbgstr_longlong(rtStreamTime), (void*)hSemaphore, pdwAdviseCookie);
1279
1280     return E_NOTIMPL;
1281 }
1282
1283 static HRESULT WINAPI ReferenceClock_Unadvise(IReferenceClock *iface,
1284                                               DWORD_PTR dwAdviseCookie)
1285 {
1286     ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1287
1288     FIXME("(%p/%p)->(%p): stub!\n", This, iface, (void*)dwAdviseCookie);
1289
1290     return S_FALSE;
1291 }
1292
1293 static const IReferenceClockVtbl IReferenceClock_Vtbl =
1294 {
1295     ReferenceClock_QueryInterface,
1296     ReferenceClock_AddRef,
1297     ReferenceClock_Release,
1298     ReferenceClock_GetTime,
1299     ReferenceClock_AdviseTime,
1300     ReferenceClock_AdvisePeriodic,
1301     ReferenceClock_Unadvise
1302 };
1303
1304 static inline DSoundRenderImpl *impl_from_IMediaSeeking( IMediaSeeking *iface )
1305 {
1306     return (DSoundRenderImpl *)((char*)iface - FIELD_OFFSET(DSoundRenderImpl, mediaSeeking.lpVtbl));
1307 }
1308
1309 static HRESULT WINAPI sound_seek_QueryInterface(IMediaSeeking * iface, REFIID riid, LPVOID * ppv)
1310 {
1311     DSoundRenderImpl *This = impl_from_IMediaSeeking(iface);
1312
1313     return IUnknown_QueryInterface((IUnknown *)This, riid, ppv);
1314 }
1315
1316 static ULONG WINAPI sound_seek_AddRef(IMediaSeeking * iface)
1317 {
1318     DSoundRenderImpl *This = impl_from_IMediaSeeking(iface);
1319
1320     return IUnknown_AddRef((IUnknown *)This);
1321 }
1322
1323 static ULONG WINAPI sound_seek_Release(IMediaSeeking * iface)
1324 {
1325     DSoundRenderImpl *This = impl_from_IMediaSeeking(iface);
1326
1327     return IUnknown_Release((IUnknown *)This);
1328 }
1329
1330 static const IMediaSeekingVtbl IMediaSeeking_Vtbl =
1331 {
1332     sound_seek_QueryInterface,
1333     sound_seek_AddRef,
1334     sound_seek_Release,
1335     MediaSeekingImpl_GetCapabilities,
1336     MediaSeekingImpl_CheckCapabilities,
1337     MediaSeekingImpl_IsFormatSupported,
1338     MediaSeekingImpl_QueryPreferredFormat,
1339     MediaSeekingImpl_GetTimeFormat,
1340     MediaSeekingImpl_IsUsingTimeFormat,
1341     MediaSeekingImpl_SetTimeFormat,
1342     MediaSeekingImpl_GetDuration,
1343     MediaSeekingImpl_GetStopPosition,
1344     MediaSeekingImpl_GetCurrentPosition,
1345     MediaSeekingImpl_ConvertTimeFormat,
1346     MediaSeekingImpl_SetPositions,
1347     MediaSeekingImpl_GetPositions,
1348     MediaSeekingImpl_GetAvailable,
1349     MediaSeekingImpl_SetRate,
1350     MediaSeekingImpl_GetRate,
1351     MediaSeekingImpl_GetPreroll
1352 };
1353
1354 /*** IUnknown methods ***/
1355 static HRESULT WINAPI AMDirectSound_QueryInterface(IAMDirectSound *iface,
1356                                                 REFIID riid,
1357                                                 LPVOID*ppvObj)
1358 {
1359     ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1360
1361     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
1362
1363     return DSoundRender_QueryInterface((IBaseFilter*)This, riid, ppvObj);
1364 }
1365
1366 static ULONG WINAPI AMDirectSound_AddRef(IAMDirectSound *iface)
1367 {
1368     ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1369
1370     TRACE("(%p/%p)->()\n", This, iface);
1371
1372     return DSoundRender_AddRef((IBaseFilter*)This);
1373 }
1374
1375 static ULONG WINAPI AMDirectSound_Release(IAMDirectSound *iface)
1376 {
1377     ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1378
1379     TRACE("(%p/%p)->()\n", This, iface);
1380
1381     return DSoundRender_Release((IBaseFilter*)This);
1382 }
1383
1384 /*** IAMDirectSound methods ***/
1385 static HRESULT WINAPI AMDirectSound_GetDirectSoundInterface(IAMDirectSound *iface,  IDirectSound **ds)
1386 {
1387     ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1388
1389     FIXME("(%p/%p)->(%p): stub\n", This, iface, ds);
1390
1391     return E_NOTIMPL;
1392 }
1393
1394 static HRESULT WINAPI AMDirectSound_GetPrimaryBufferInterface(IAMDirectSound *iface, IDirectSoundBuffer **buf)
1395 {
1396     ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1397
1398     FIXME("(%p/%p)->(%p): stub\n", This, iface, buf);
1399
1400     return E_NOTIMPL;
1401 }
1402
1403 static HRESULT WINAPI AMDirectSound_GetSecondaryBufferInterface(IAMDirectSound *iface, IDirectSoundBuffer **buf)
1404 {
1405     ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1406
1407     FIXME("(%p/%p)->(%p): stub\n", This, iface, buf);
1408
1409     return E_NOTIMPL;
1410 }
1411
1412 static HRESULT WINAPI AMDirectSound_ReleaseDirectSoundInterface(IAMDirectSound *iface, IDirectSound *ds)
1413 {
1414     ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1415
1416     FIXME("(%p/%p)->(%p): stub\n", This, iface, ds);
1417
1418     return E_NOTIMPL;
1419 }
1420
1421 static HRESULT WINAPI AMDirectSound_ReleasePrimaryBufferInterface(IAMDirectSound *iface, IDirectSoundBuffer *buf)
1422 {
1423     ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1424
1425     FIXME("(%p/%p)->(%p): stub\n", This, iface, buf);
1426
1427     return E_NOTIMPL;
1428 }
1429
1430 static HRESULT WINAPI AMDirectSound_ReleaseSecondaryBufferInterface(IAMDirectSound *iface, IDirectSoundBuffer *buf)
1431 {
1432     ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1433
1434     FIXME("(%p/%p)->(%p): stub\n", This, iface, buf);
1435
1436     return E_NOTIMPL;
1437 }
1438
1439 static HRESULT WINAPI AMDirectSound_SetFocusWindow(IAMDirectSound *iface, HWND hwnd, BOOL bgsilent)
1440 {
1441     ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1442
1443     FIXME("(%p/%p)->(%p,%d): stub\n", This, iface, hwnd, bgsilent);
1444
1445     return E_NOTIMPL;
1446 }
1447
1448 static HRESULT WINAPI AMDirectSound_GetFocusWindow(IAMDirectSound *iface, HWND hwnd)
1449 {
1450     ICOM_THIS_MULTI(DSoundRenderImpl, IAMDirectSound_vtbl, iface);
1451
1452     FIXME("(%p/%p)->(%p): stub\n", This, iface, hwnd);
1453
1454     return E_NOTIMPL;
1455 }
1456
1457 static const IAMDirectSoundVtbl IAMDirectSound_Vtbl =
1458 {
1459     AMDirectSound_QueryInterface,
1460     AMDirectSound_AddRef,
1461     AMDirectSound_Release,
1462     AMDirectSound_GetDirectSoundInterface,
1463     AMDirectSound_GetPrimaryBufferInterface,
1464     AMDirectSound_GetSecondaryBufferInterface,
1465     AMDirectSound_ReleaseDirectSoundInterface,
1466     AMDirectSound_ReleasePrimaryBufferInterface,
1467     AMDirectSound_ReleaseSecondaryBufferInterface,
1468     AMDirectSound_SetFocusWindow,
1469     AMDirectSound_GetFocusWindow
1470 };