quartz: Don't clean up in avi decoder if driver isn't opened.
[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
36 #include "wine/unicode.h"
37 #include "wine/debug.h"
38
39 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
40
41 static const WCHAR wcsInputPinName[] = {'i','n','p','u','t',' ','p','i','n',0};
42
43 static const IBaseFilterVtbl DSoundRender_Vtbl;
44 static const IPinVtbl DSoundRender_InputPin_Vtbl;
45 static const IMemInputPinVtbl MemInputPin_Vtbl; 
46 static const IBasicAudioVtbl IBasicAudio_Vtbl;
47 static const IReferenceClockVtbl IReferenceClock_Vtbl;
48 static const IMediaSeekingVtbl IMediaSeeking_Vtbl;
49
50 typedef struct DSoundRenderImpl
51 {
52     const IBaseFilterVtbl * lpVtbl;
53     const IBasicAudioVtbl *IBasicAudio_vtbl;
54     const IReferenceClockVtbl *IReferenceClock_vtbl;
55
56     LONG refCount;
57     CRITICAL_SECTION csFilter;
58     FILTER_STATE state;
59     REFERENCE_TIME rtStreamStart;
60     IReferenceClock * pClock;
61     FILTER_INFO filterInfo;
62
63     InputPin * pInputPin;
64     IPin ** ppPins;
65
66     LPDIRECTSOUND dsound;
67     LPDIRECTSOUNDBUFFER dsbuffer;
68     DWORD buf_size;
69     DWORD write_pos;
70     DWORD write_loops;
71
72     DWORD last_play_pos;
73     DWORD play_loops;
74
75     REFERENCE_TIME play_time;
76     MediaSeekingImpl mediaSeeking;
77
78     long volume;
79     long pan;
80 } DSoundRenderImpl;
81
82 static HRESULT sound_mod_stop(IBaseFilter *iface)
83 {
84     FIXME("(%p) stub\n", iface);
85     return S_OK;
86 }
87
88 static HRESULT sound_mod_start(IBaseFilter *iface)
89 {
90     FIXME("(%p) stub\n", iface);
91     return S_OK;
92 }
93
94 static HRESULT sound_mod_rate(IBaseFilter *iface)
95 {
96     FIXME("(%p) stub\n", iface);
97     return S_OK;
98 }
99
100 static inline HRESULT DSoundRender_GetPos(DSoundRenderImpl *This, DWORD *pPlayPos, REFERENCE_TIME *pRefTime)
101 {
102     HRESULT hr;
103
104     EnterCriticalSection(&This->csFilter);
105     {
106         DWORD state;
107         DWORD write_pos;
108
109         hr = IDirectSoundBuffer_GetStatus(This->dsbuffer, &state);
110         if (SUCCEEDED(hr) && !(state & DSBSTATUS_PLAYING) && This->state == State_Running)
111         {
112             TRACE("Not playing, kickstarting the engine\n");
113
114             hr = IDirectSoundBuffer_Play(This->dsbuffer, 0, 0, DSBPLAY_LOOPING);
115             if (FAILED(hr))
116                 ERR("Can't play sound buffer (%x)\n", hr);
117         }
118
119         if (SUCCEEDED(hr))
120             hr = IDirectSoundBuffer_GetCurrentPosition(This->dsbuffer, pPlayPos, &write_pos);
121         if (hr == S_OK)
122         {
123             DWORD play_pos = *pPlayPos;
124
125             if (play_pos < This->last_play_pos)
126                 This->play_loops++;
127             This->last_play_pos = play_pos;
128
129             /* If we really fell behind, start at the next possible position
130              * Also happens when just starting playback for the first time,
131              * or when flushing
132              */
133             if ((This->play_loops*This->buf_size)+play_pos >=
134                 (This->write_loops*This->buf_size)+This->write_pos)
135                 This->write_pos = write_pos;
136
137             if (pRefTime)
138             {
139                 REFERENCE_TIME play_time;
140                 play_time = ((REFERENCE_TIME)This->play_loops*10000000) +
141                             ((REFERENCE_TIME)play_pos*10000000/This->buf_size);
142
143                 /* Don't let time run backwards */
144                 if(play_time-This->play_time > 0)
145                     This->play_time = play_time;
146                 else
147                     hr = S_FALSE;
148
149                 *pRefTime = This->play_time;
150             }
151         }
152     }
153     LeaveCriticalSection(&This->csFilter);
154
155     return hr;
156 }
157
158 static HRESULT DSoundRender_SendSampleData(DSoundRenderImpl* This, const BYTE *data, DWORD size)
159 {
160     HRESULT hr = S_OK;
161     LPBYTE lpbuf1 = NULL;
162     LPBYTE lpbuf2 = NULL;
163     DWORD dwsize1 = 0;
164     DWORD dwsize2 = 0;
165     DWORD size2;
166     DWORD play_pos,buf_free;
167
168     do {
169
170         hr = DSoundRender_GetPos(This, &play_pos, NULL);
171         if (hr != DS_OK)
172         {
173             ERR("GetPos returned error: %x\n", hr);
174             break;
175         }
176         if (This->write_pos <= play_pos)
177              buf_free = play_pos-This->write_pos;
178         else
179              buf_free = This->buf_size - This->write_pos + play_pos;
180
181         /* Wait for enough of the buffer to empty before filling it */
182         if(buf_free < This->buf_size/4)
183         {
184             Sleep(50);
185             continue;
186         }
187
188         size2 = min(buf_free, size);
189         hr = IDirectSoundBuffer_Lock(This->dsbuffer, This->write_pos, size2, (LPVOID *)&lpbuf1, &dwsize1, (LPVOID *)&lpbuf2, &dwsize2, 0);
190         if (hr != DS_OK) {
191             ERR("Unable to lock sound buffer! (%x)\n", hr);
192             break;
193         }
194         /* TRACE("write_pos=%d, size=%d, sz1=%d, sz2=%d\n", This->write_pos, size2, dwsize1, dwsize2); */
195
196         memcpy(lpbuf1, data, dwsize1);
197         if (dwsize2)
198             memcpy(lpbuf2, data + dwsize1, dwsize2);
199
200         hr = IDirectSoundBuffer_Unlock(This->dsbuffer, lpbuf1, dwsize1, lpbuf2, dwsize2);
201         if (hr != DS_OK)
202             ERR("Unable to unlock sound buffer! (%x)\n", hr);
203
204         size -= dwsize1 + dwsize2;
205         data += dwsize1 + dwsize2;
206         This->write_pos += dwsize1 + dwsize2;
207         if (This->write_pos >= This->buf_size)
208         {
209             This->write_pos -= This->buf_size;
210             This->write_loops++;
211         }
212     } while (size && This->state == State_Running);
213
214     return hr;
215 }
216
217 static HRESULT DSoundRender_Sample(LPVOID iface, IMediaSample * pSample)
218 {
219     DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
220     LPBYTE pbSrcStream = NULL;
221     long cbSrcStream = 0;
222     REFERENCE_TIME tStart, tStop;
223     HRESULT hr;
224
225     TRACE("%p %p\n", iface, pSample);
226
227     if (This->state == State_Paused)
228         return S_FALSE;
229
230     if (This->state == State_Stopped)
231         return VFW_E_WRONG_STATE;
232
233     hr = IMediaSample_GetPointer(pSample, &pbSrcStream);
234     if (FAILED(hr))
235     {
236         ERR("Cannot get pointer to sample data (%x)\n", hr);
237         return hr;
238     }
239
240     hr = IMediaSample_GetTime(pSample, &tStart, &tStop);
241     if (FAILED(hr))
242         ERR("Cannot get sample time (%x)\n", hr);
243
244     cbSrcStream = IMediaSample_GetActualDataLength(pSample);
245     TRACE("Sample data ptr = %p, size = %ld\n", pbSrcStream, cbSrcStream);
246
247 #if 0 /* For debugging purpose */
248     {
249         int i;
250         for(i = 0; i < cbSrcStream; i++)
251         {
252             if ((i!=0) && !(i%16))
253                 TRACE("\n");
254             TRACE("%02x ", pbSrcStream[i]);
255         }
256         TRACE("\n");
257     }
258 #endif
259
260     return DSoundRender_SendSampleData(This, pbSrcStream, cbSrcStream);
261 }
262
263 static HRESULT DSoundRender_QueryAccept(LPVOID iface, const AM_MEDIA_TYPE * pmt)
264 {
265     WAVEFORMATEX* format = (WAVEFORMATEX*)pmt->pbFormat;
266     TRACE("wFormatTag = %x %x\n", format->wFormatTag, WAVE_FORMAT_PCM);
267     TRACE("nChannels = %d\n", format->nChannels);
268     TRACE("nSamplesPerSec = %d\n", format->nAvgBytesPerSec);
269     TRACE("nAvgBytesPerSec = %d\n", format->nAvgBytesPerSec);
270     TRACE("nBlockAlign = %d\n", format->nBlockAlign);
271     TRACE("wBitsPerSample = %d\n", format->wBitsPerSample);
272
273     if (IsEqualIID(&pmt->majortype, &MEDIATYPE_Audio) && IsEqualIID(&pmt->subtype, &MEDIASUBTYPE_PCM))
274         return S_OK;
275     return S_FALSE;
276 }
277
278 HRESULT DSoundRender_create(IUnknown * pUnkOuter, LPVOID * ppv)
279 {
280     HRESULT hr;
281     PIN_INFO piInput;
282     DSoundRenderImpl * pDSoundRender;
283
284     TRACE("(%p, %p)\n", pUnkOuter, ppv);
285
286     *ppv = NULL;
287
288     if (pUnkOuter)
289         return CLASS_E_NOAGGREGATION;
290     
291     pDSoundRender = CoTaskMemAlloc(sizeof(DSoundRenderImpl));
292     if (!pDSoundRender)
293         return E_OUTOFMEMORY;
294     ZeroMemory(pDSoundRender, sizeof(DSoundRenderImpl));
295
296     pDSoundRender->lpVtbl = &DSoundRender_Vtbl;
297     pDSoundRender->IBasicAudio_vtbl = &IBasicAudio_Vtbl;
298     pDSoundRender->IReferenceClock_vtbl = &IReferenceClock_Vtbl;
299     pDSoundRender->refCount = 1;
300     InitializeCriticalSection(&pDSoundRender->csFilter);
301     pDSoundRender->csFilter.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": DSoundRenderImpl.csFilter");
302     pDSoundRender->state = State_Stopped;
303
304     pDSoundRender->ppPins = CoTaskMemAlloc(1 * sizeof(IPin *));
305     if (!pDSoundRender->ppPins)
306     {
307         pDSoundRender->csFilter.DebugInfo->Spare[0] = 0;
308         DeleteCriticalSection(&pDSoundRender->csFilter);
309         CoTaskMemFree(pDSoundRender);
310         return E_OUTOFMEMORY;
311     }
312
313     /* construct input pin */
314     piInput.dir = PINDIR_INPUT;
315     piInput.pFilter = (IBaseFilter *)pDSoundRender;
316     lstrcpynW(piInput.achName, wcsInputPinName, sizeof(piInput.achName) / sizeof(piInput.achName[0]));
317     hr = InputPin_Construct(&DSoundRender_InputPin_Vtbl, &piInput, DSoundRender_Sample, pDSoundRender, DSoundRender_QueryAccept, NULL, &pDSoundRender->csFilter, (IPin **)&pDSoundRender->pInputPin);
318
319     if (SUCCEEDED(hr))
320     {
321         hr = DirectSoundCreate(NULL, &pDSoundRender->dsound, NULL);
322         if (FAILED(hr))
323             ERR("Cannot create Direct Sound object (%x)\n", hr);
324     }
325
326     if (SUCCEEDED(hr))
327     {
328         MediaSeekingImpl_Init((IBaseFilter*)pDSoundRender, sound_mod_stop, sound_mod_start, sound_mod_rate, &pDSoundRender->mediaSeeking, &pDSoundRender->csFilter);
329         pDSoundRender->mediaSeeking.lpVtbl = &IMediaSeeking_Vtbl;
330
331         pDSoundRender->ppPins[0] = (IPin *)pDSoundRender->pInputPin;
332         *ppv = (LPVOID)pDSoundRender;
333     }
334     else
335     {
336         if (pDSoundRender->pInputPin)
337             IPin_Release((IPin*)pDSoundRender->pInputPin);
338         CoTaskMemFree(pDSoundRender->ppPins);
339         pDSoundRender->csFilter.DebugInfo->Spare[0] = 0;
340         DeleteCriticalSection(&pDSoundRender->csFilter);
341         CoTaskMemFree(pDSoundRender);
342     }
343
344     return hr;
345 }
346
347 static HRESULT WINAPI DSoundRender_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv)
348 {
349     DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
350     TRACE("(%p, %p)->(%s, %p)\n", This, iface, qzdebugstr_guid(riid), ppv);
351
352     *ppv = NULL;
353
354     if (IsEqualIID(riid, &IID_IUnknown))
355         *ppv = (LPVOID)This;
356     else if (IsEqualIID(riid, &IID_IPersist))
357         *ppv = (LPVOID)This;
358     else if (IsEqualIID(riid, &IID_IMediaFilter))
359         *ppv = (LPVOID)This;
360     else if (IsEqualIID(riid, &IID_IBaseFilter))
361         *ppv = (LPVOID)This;
362     else if (IsEqualIID(riid, &IID_IBasicAudio))
363         *ppv = (LPVOID)&(This->IBasicAudio_vtbl);
364     else if (IsEqualIID(riid, &IID_IReferenceClock))
365         *ppv = (LPVOID)&(This->IReferenceClock_vtbl);
366     else if (IsEqualIID(riid, &IID_IMediaSeeking))
367         *ppv = &This->mediaSeeking.lpVtbl;
368
369     if (*ppv)
370     {
371         IUnknown_AddRef((IUnknown *)(*ppv));
372         return S_OK;
373     }
374
375     if (!IsEqualIID(riid, &IID_IPin))
376         FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
377
378     return E_NOINTERFACE;
379 }
380
381 static ULONG WINAPI DSoundRender_AddRef(IBaseFilter * iface)
382 {
383     DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
384     ULONG refCount = InterlockedIncrement(&This->refCount);
385
386     TRACE("(%p/%p)->() AddRef from %d\n", This, iface, refCount - 1);
387
388     return refCount;
389 }
390
391 static ULONG WINAPI DSoundRender_Release(IBaseFilter * iface)
392 {
393     DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
394     ULONG refCount = InterlockedDecrement(&This->refCount);
395
396     TRACE("(%p)->() Release from %d\n", This, refCount + 1);
397
398     if (!refCount)
399     {
400         IPin *pConnectedTo;
401
402         if (This->pClock)
403             IReferenceClock_Release(This->pClock);
404
405         if (This->dsbuffer)
406             IDirectSoundBuffer_Release(This->dsbuffer);
407         This->dsbuffer = NULL;
408         if (This->dsound)
409             IDirectSound_Release(This->dsound);
410         This->dsound = NULL;
411        
412         if (SUCCEEDED(IPin_ConnectedTo(This->ppPins[0], &pConnectedTo)))
413         {
414             IPin_Disconnect(pConnectedTo);
415             IPin_Release(pConnectedTo);
416         }
417         IPin_Disconnect(This->ppPins[0]);
418
419         IPin_Release(This->ppPins[0]);
420         
421         CoTaskMemFree(This->ppPins);
422         This->lpVtbl = NULL;
423         This->IBasicAudio_vtbl = NULL;
424         
425         This->csFilter.DebugInfo->Spare[0] = 0;
426         DeleteCriticalSection(&This->csFilter);
427
428         TRACE("Destroying Audio Renderer\n");
429         CoTaskMemFree(This);
430         
431         return 0;
432     }
433     else
434         return refCount;
435 }
436
437 /** IPersist methods **/
438
439 static HRESULT WINAPI DSoundRender_GetClassID(IBaseFilter * iface, CLSID * pClsid)
440 {
441     DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
442     TRACE("(%p/%p)->(%p)\n", This, iface, pClsid);
443
444     *pClsid = CLSID_DSoundRender;
445
446     return S_OK;
447 }
448
449 /** IMediaFilter methods **/
450
451 static HRESULT WINAPI DSoundRender_Stop(IBaseFilter * iface)
452 {
453     HRESULT hr = S_OK;
454     DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
455
456     TRACE("(%p/%p)->()\n", This, iface);
457
458     EnterCriticalSection(&This->csFilter);
459     {
460         DWORD state = 0;
461         if (This->dsbuffer)
462         {
463             hr = IDirectSoundBuffer_GetStatus(This->dsbuffer, &state);
464             if (SUCCEEDED(hr))
465             {
466                 if (state & DSBSTATUS_PLAYING)
467                     hr = IDirectSoundBuffer_Stop(This->dsbuffer);
468             }
469         }
470         if (SUCCEEDED(hr))
471             This->state = State_Stopped;
472     }
473     LeaveCriticalSection(&This->csFilter);
474     
475     return hr;
476 }
477
478 static HRESULT WINAPI DSoundRender_Pause(IBaseFilter * iface)
479 {
480     HRESULT hr = S_OK;
481     DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
482     
483     TRACE("(%p/%p)->()\n", This, iface);
484
485     EnterCriticalSection(&This->csFilter);
486     {
487         DWORD state = 0;
488         if (This->state == State_Stopped)
489             This->pInputPin->end_of_stream = 0;
490
491         if (This->dsbuffer)
492         {
493             hr = IDirectSoundBuffer_GetStatus(This->dsbuffer, &state);
494             if (SUCCEEDED(hr))
495             {
496                 if (state & DSBSTATUS_PLAYING)
497                     hr = IDirectSoundBuffer_Stop(This->dsbuffer);
498             }
499         }
500         if (SUCCEEDED(hr))
501             This->state = State_Paused;
502     }
503     LeaveCriticalSection(&This->csFilter);
504
505     return hr;
506 }
507
508 static HRESULT WINAPI DSoundRender_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
509 {
510     HRESULT hr = S_OK;
511     DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
512
513     TRACE("(%p/%p)->(%s)\n", This, iface, wine_dbgstr_longlong(tStart));
514
515     EnterCriticalSection(&This->csFilter);
516     {
517         This->rtStreamStart = tStart;
518         This->state = State_Running;
519         This->pInputPin->end_of_stream = 0;
520     }
521     LeaveCriticalSection(&This->csFilter);
522
523     return hr;
524 }
525
526 static HRESULT WINAPI DSoundRender_GetState(IBaseFilter * iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState)
527 {
528     DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
529
530     TRACE("(%p/%p)->(%d, %p)\n", This, iface, dwMilliSecsTimeout, pState);
531
532     EnterCriticalSection(&This->csFilter);
533     {
534         *pState = This->state;
535     }
536     LeaveCriticalSection(&This->csFilter);
537
538     return S_OK;
539 }
540
541 static HRESULT WINAPI DSoundRender_SetSyncSource(IBaseFilter * iface, IReferenceClock *pClock)
542 {
543     DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
544
545     TRACE("(%p/%p)->(%p)\n", This, iface, pClock);
546
547     EnterCriticalSection(&This->csFilter);
548     {
549         if (This->pClock)
550             IReferenceClock_Release(This->pClock);
551         This->pClock = pClock;
552         if (This->pClock)
553             IReferenceClock_AddRef(This->pClock);
554     }
555     LeaveCriticalSection(&This->csFilter);
556
557     return S_OK;
558 }
559
560 static HRESULT WINAPI DSoundRender_GetSyncSource(IBaseFilter * iface, IReferenceClock **ppClock)
561 {
562     DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
563
564     TRACE("(%p/%p)->(%p)\n", This, iface, ppClock);
565
566     EnterCriticalSection(&This->csFilter);
567     {
568         *ppClock = This->pClock;
569         IReferenceClock_AddRef(This->pClock);
570     }
571     LeaveCriticalSection(&This->csFilter);
572     
573     return S_OK;
574 }
575
576 /** IBaseFilter implementation **/
577
578 static HRESULT WINAPI DSoundRender_EnumPins(IBaseFilter * iface, IEnumPins **ppEnum)
579 {
580     ENUMPINDETAILS epd;
581     DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
582
583     TRACE("(%p/%p)->(%p)\n", This, iface, ppEnum);
584
585     epd.cPins = 1; /* input pin */
586     epd.ppPins = This->ppPins;
587     return IEnumPinsImpl_Construct(&epd, ppEnum);
588 }
589
590 static HRESULT WINAPI DSoundRender_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin)
591 {
592     DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
593
594     TRACE("(%p/%p)->(%s,%p)\n", This, iface, debugstr_w(Id), ppPin);
595     
596     FIXME("DSoundRender::FindPin(...)\n");
597
598     /* FIXME: critical section */
599
600     return E_NOTIMPL;
601 }
602
603 static HRESULT WINAPI DSoundRender_QueryFilterInfo(IBaseFilter * iface, FILTER_INFO *pInfo)
604 {
605     DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
606
607     TRACE("(%p/%p)->(%p)\n", This, iface, pInfo);
608
609     strcpyW(pInfo->achName, This->filterInfo.achName);
610     pInfo->pGraph = This->filterInfo.pGraph;
611
612     if (pInfo->pGraph)
613         IFilterGraph_AddRef(pInfo->pGraph);
614     
615     return S_OK;
616 }
617
618 static HRESULT WINAPI DSoundRender_JoinFilterGraph(IBaseFilter * iface, IFilterGraph *pGraph, LPCWSTR pName)
619 {
620     DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
621
622     TRACE("(%p/%p)->(%p, %s)\n", This, iface, pGraph, debugstr_w(pName));
623
624     EnterCriticalSection(&This->csFilter);
625     {
626         if (pName)
627             strcpyW(This->filterInfo.achName, pName);
628         else
629             *This->filterInfo.achName = '\0';
630         This->filterInfo.pGraph = pGraph; /* NOTE: do NOT increase ref. count */
631     }
632     LeaveCriticalSection(&This->csFilter);
633
634     return S_OK;
635 }
636
637 static HRESULT WINAPI DSoundRender_QueryVendorInfo(IBaseFilter * iface, LPWSTR *pVendorInfo)
638 {
639     DSoundRenderImpl *This = (DSoundRenderImpl *)iface;
640     TRACE("(%p/%p)->(%p)\n", This, iface, pVendorInfo);
641     return E_NOTIMPL;
642 }
643
644 static const IBaseFilterVtbl DSoundRender_Vtbl =
645 {
646     DSoundRender_QueryInterface,
647     DSoundRender_AddRef,
648     DSoundRender_Release,
649     DSoundRender_GetClassID,
650     DSoundRender_Stop,
651     DSoundRender_Pause,
652     DSoundRender_Run,
653     DSoundRender_GetState,
654     DSoundRender_SetSyncSource,
655     DSoundRender_GetSyncSource,
656     DSoundRender_EnumPins,
657     DSoundRender_FindPin,
658     DSoundRender_QueryFilterInfo,
659     DSoundRender_JoinFilterGraph,
660     DSoundRender_QueryVendorInfo
661 };
662
663 static HRESULT WINAPI DSoundRender_InputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
664 {
665     InputPin *This = (InputPin *)iface;
666     PIN_DIRECTION pindirReceive;
667     DSoundRenderImpl *DSImpl;
668     HRESULT hr = S_OK;
669
670     TRACE("(%p)->(%p, %p)\n", This, pReceivePin, pmt);
671     dump_AM_MEDIA_TYPE(pmt);
672
673     EnterCriticalSection(This->pin.pCritSec);
674     {
675         DSImpl = (DSoundRenderImpl*)This->pin.pinInfo.pFilter;
676
677         if (This->pin.pConnectedTo)
678             hr = VFW_E_ALREADY_CONNECTED;
679
680         if (SUCCEEDED(hr) && This->pin.fnQueryAccept(This->pin.pUserData, pmt) != S_OK)
681             hr = VFW_E_TYPE_NOT_ACCEPTED;
682
683         if (SUCCEEDED(hr))
684         {
685             IPin_QueryDirection(pReceivePin, &pindirReceive);
686
687             if (pindirReceive != PINDIR_OUTPUT)
688             {
689                 ERR("Can't connect from non-output pin\n");
690                 hr = VFW_E_INVALID_DIRECTION;
691             }
692         }
693
694         if (SUCCEEDED(hr))
695         {
696             WAVEFORMATEX *format;
697             DSBUFFERDESC buf_desc;
698
699             TRACE("MajorType %s\n", debugstr_guid(&pmt->majortype));
700             TRACE("SubType %s\n", debugstr_guid(&pmt->subtype));
701             TRACE("Format %s\n", debugstr_guid(&pmt->formattype));
702             TRACE("Size %d\n", pmt->cbFormat);
703
704             format = (WAVEFORMATEX*)pmt->pbFormat;
705
706             DSImpl->buf_size = format->nAvgBytesPerSec;
707
708             memset(&buf_desc,0,sizeof(DSBUFFERDESC));
709             buf_desc.dwSize = sizeof(DSBUFFERDESC);
710             buf_desc.dwFlags = DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLPAN |
711                                DSBCAPS_CTRLFREQUENCY |
712                                DSBCAPS_GETCURRENTPOSITION2;
713             buf_desc.dwBufferBytes = DSImpl->buf_size;
714             buf_desc.lpwfxFormat = format;
715             hr = IDirectSound_CreateSoundBuffer(DSImpl->dsound, &buf_desc, &DSImpl->dsbuffer, NULL);
716             if (FAILED(hr))
717                 ERR("Can't create sound buffer (%x)\n", hr);
718         }
719
720         if (SUCCEEDED(hr))
721         {
722             hr = IDirectSoundBuffer_SetVolume(DSImpl->dsbuffer, DSImpl->volume);
723             if (FAILED(hr))
724                 ERR("Can't set volume to %ld (%x)\n", DSImpl->volume, hr);
725
726             hr = IDirectSoundBuffer_SetPan(DSImpl->dsbuffer, DSImpl->pan);
727             if (FAILED(hr))
728                 ERR("Can't set pan to %ld (%x)\n", DSImpl->pan, hr);
729
730             DSImpl->write_pos = 0;
731             hr = S_OK;
732         }
733
734         if (SUCCEEDED(hr))
735         {
736             CopyMediaType(&This->pin.mtCurrent, pmt);
737             This->pin.pConnectedTo = pReceivePin;
738             IPin_AddRef(pReceivePin);
739         }
740         else
741         {
742             if (DSImpl->dsbuffer)
743                 IDirectSoundBuffer_Release(DSImpl->dsbuffer);
744             DSImpl->dsbuffer = NULL;
745         }
746     }
747     LeaveCriticalSection(This->pin.pCritSec);
748
749     return hr;
750 }
751
752 static HRESULT WINAPI DSoundRender_InputPin_Disconnect(IPin * iface)
753 {
754     IPinImpl *This = (IPinImpl*)iface;
755     DSoundRenderImpl *DSImpl;
756
757     TRACE("(%p)->()\n", iface);
758
759     DSImpl = (DSoundRenderImpl*)This->pinInfo.pFilter;
760     if (DSImpl->dsbuffer)
761         IDirectSoundBuffer_Release(DSImpl->dsbuffer);
762     DSImpl->dsbuffer = NULL;
763
764     return IPinImpl_Disconnect(iface);
765 }
766
767 static HRESULT WINAPI DSoundRender_InputPin_EndOfStream(IPin * iface)
768 {
769     InputPin* This = (InputPin*)iface;
770     DSoundRenderImpl *me = (DSoundRenderImpl*)This->pin.pinInfo.pFilter;
771     IMediaEventSink* pEventSink;
772     HRESULT hr;
773
774     EnterCriticalSection(This->pin.pCritSec);
775
776     TRACE("(%p/%p)->()\n", This, iface);
777     InputPin_EndOfStream(iface);
778
779     hr = IFilterGraph_QueryInterface(me->filterInfo.pGraph, &IID_IMediaEventSink, (LPVOID*)&pEventSink);
780     if (SUCCEEDED(hr))
781     {
782         BYTE * silence;
783
784         silence = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, me->buf_size);
785         if (silence)
786         {
787             memset(silence, 0, me->buf_size);
788             DSoundRender_SendSampleData((DSoundRenderImpl*)This->pin.pinInfo.pFilter, silence, me->buf_size);
789             HeapFree(GetProcessHeap(), 0, silence);
790         }
791
792         hr = IMediaEventSink_Notify(pEventSink, EC_COMPLETE, S_OK, 0);
793         IMediaEventSink_Release(pEventSink);
794     }
795     LeaveCriticalSection(This->pin.pCritSec);
796
797     return hr;
798 }
799
800 static HRESULT WINAPI DSoundRender_InputPin_BeginFlush(IPin * iface)
801 {
802     InputPin *This = (InputPin *)iface;
803     DSoundRenderImpl *pFilter = (DSoundRenderImpl *)This->pin.pinInfo.pFilter;
804     HRESULT hr;
805     LPBYTE buffer;
806     DWORD size;
807
808     TRACE("\n");
809
810     EnterCriticalSection(This->pin.pCritSec);
811     hr = InputPin_BeginFlush(iface);
812
813     if (pFilter->dsbuffer)
814     {
815         IDirectSoundBuffer_Stop(pFilter->dsbuffer);
816
817         /* Force a reset */
818         IDirectSoundBuffer_SetCurrentPosition(pFilter->dsbuffer, 0);
819         pFilter->write_pos = pFilter->last_play_pos = 0;
820         ++pFilter->play_loops;
821         pFilter->write_loops = pFilter->play_loops;
822
823         IDirectSoundBuffer_Lock(pFilter->dsbuffer, 0, 0, (LPVOID *)&buffer, &size, NULL, NULL, DSBLOCK_ENTIREBUFFER);
824         memset(buffer, 0, size);
825         IDirectSoundBuffer_Unlock(pFilter->dsbuffer, buffer, size, NULL, 0);
826     }
827     LeaveCriticalSection(This->pin.pCritSec);
828
829     return hr;
830 }
831
832 static const IPinVtbl DSoundRender_InputPin_Vtbl =
833 {
834     InputPin_QueryInterface,
835     IPinImpl_AddRef,
836     InputPin_Release,
837     InputPin_Connect,
838     DSoundRender_InputPin_ReceiveConnection,
839     DSoundRender_InputPin_Disconnect,
840     IPinImpl_ConnectedTo,
841     IPinImpl_ConnectionMediaType,
842     IPinImpl_QueryPinInfo,
843     IPinImpl_QueryDirection,
844     IPinImpl_QueryId,
845     IPinImpl_QueryAccept,
846     IPinImpl_EnumMediaTypes,
847     IPinImpl_QueryInternalConnections,
848     DSoundRender_InputPin_EndOfStream,
849     DSoundRender_InputPin_BeginFlush,
850     InputPin_EndFlush,
851     InputPin_NewSegment
852 };
853
854 static const IMemInputPinVtbl MemInputPin_Vtbl = 
855 {
856     MemInputPin_QueryInterface,
857     MemInputPin_AddRef,
858     MemInputPin_Release,
859     MemInputPin_GetAllocator,
860     MemInputPin_NotifyAllocator,
861     MemInputPin_GetAllocatorRequirements,
862     MemInputPin_Receive,
863     MemInputPin_ReceiveMultiple,
864     MemInputPin_ReceiveCanBlock
865 };
866
867 /*** IUnknown methods ***/
868 static HRESULT WINAPI Basicaudio_QueryInterface(IBasicAudio *iface,
869                                                 REFIID riid,
870                                                 LPVOID*ppvObj) {
871     ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
872
873     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
874
875     return DSoundRender_QueryInterface((IBaseFilter*)This, riid, ppvObj);
876 }
877
878 static ULONG WINAPI Basicaudio_AddRef(IBasicAudio *iface) {
879     ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
880
881     TRACE("(%p/%p)->()\n", This, iface);
882
883     return DSoundRender_AddRef((IBaseFilter*)This);
884 }
885
886 static ULONG WINAPI Basicaudio_Release(IBasicAudio *iface) {
887     ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
888
889     TRACE("(%p/%p)->()\n", This, iface);
890
891     return DSoundRender_Release((IBaseFilter*)This);
892 }
893
894 /*** IDispatch methods ***/
895 static HRESULT WINAPI Basicaudio_GetTypeInfoCount(IBasicAudio *iface,
896                                                   UINT*pctinfo) {
897     ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
898
899     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pctinfo);
900
901     return S_OK;
902 }
903
904 static HRESULT WINAPI Basicaudio_GetTypeInfo(IBasicAudio *iface,
905                                              UINT iTInfo,
906                                              LCID lcid,
907                                              ITypeInfo**ppTInfo) {
908     ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
909
910     TRACE("(%p/%p)->(%d, %d, %p): stub !!!\n", This, iface, iTInfo, lcid, ppTInfo);
911
912     return S_OK;
913 }
914
915 static HRESULT WINAPI Basicaudio_GetIDsOfNames(IBasicAudio *iface,
916                                                REFIID riid,
917                                                LPOLESTR*rgszNames,
918                                                UINT cNames,
919                                                LCID lcid,
920                                                DISPID*rgDispId) {
921     ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
922
923     TRACE("(%p/%p)->(%s (%p), %p, %d, %d, %p): stub !!!\n", This, iface, debugstr_guid(riid), riid, rgszNames, cNames, lcid, rgDispId);
924
925     return S_OK;
926 }
927
928 static HRESULT WINAPI Basicaudio_Invoke(IBasicAudio *iface,
929                                         DISPID dispIdMember,
930                                         REFIID riid,
931                                         LCID lcid,
932                                         WORD wFlags,
933                                         DISPPARAMS*pDispParams,
934                                         VARIANT*pVarResult,
935                                         EXCEPINFO*pExepInfo,
936                                         UINT*puArgErr) {
937     ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
938
939     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);
940
941     return S_OK;
942 }
943
944 /*** IBasicAudio methods ***/
945 static HRESULT WINAPI Basicaudio_put_Volume(IBasicAudio *iface,
946                                             long lVolume) {
947     ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
948
949     TRACE("(%p/%p)->(%ld)\n", This, iface, lVolume);
950
951     if (lVolume > DSBVOLUME_MAX || lVolume < DSBVOLUME_MIN)
952         return E_INVALIDARG;
953
954     if (This->dsbuffer) {
955         if (FAILED(IDirectSoundBuffer_SetVolume(This->dsbuffer, lVolume)))
956             return E_FAIL;
957     }
958
959     This->volume = lVolume;
960     return S_OK;
961 }
962
963 static HRESULT WINAPI Basicaudio_get_Volume(IBasicAudio *iface,
964                                             long *plVolume) {
965     ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
966
967     TRACE("(%p/%p)->(%p)\n", This, iface, plVolume);
968
969     if (!plVolume)
970         return E_POINTER;
971
972     *plVolume = This->volume;
973     return S_OK;
974 }
975
976 static HRESULT WINAPI Basicaudio_put_Balance(IBasicAudio *iface,
977                                              long lBalance) {
978     ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
979
980     TRACE("(%p/%p)->(%ld)\n", This, iface, lBalance);
981
982     if (lBalance < DSBPAN_LEFT || lBalance > DSBPAN_RIGHT)
983         return E_INVALIDARG;
984
985     if (This->dsbuffer) {
986         if (FAILED(IDirectSoundBuffer_SetPan(This->dsbuffer, lBalance)))
987             return E_FAIL;
988     }
989
990     This->pan = lBalance;
991     return S_OK;
992 }
993
994 static HRESULT WINAPI Basicaudio_get_Balance(IBasicAudio *iface,
995                                              long *plBalance) {
996     ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface);
997
998     TRACE("(%p/%p)->(%p)\n", This, iface, plBalance);
999
1000     if (!plBalance)
1001         return E_POINTER;
1002
1003     *plBalance = This->pan;
1004     return S_OK;
1005 }
1006
1007 static const IBasicAudioVtbl IBasicAudio_Vtbl =
1008 {
1009     Basicaudio_QueryInterface,
1010     Basicaudio_AddRef,
1011     Basicaudio_Release,
1012     Basicaudio_GetTypeInfoCount,
1013     Basicaudio_GetTypeInfo,
1014     Basicaudio_GetIDsOfNames,
1015     Basicaudio_Invoke,
1016     Basicaudio_put_Volume,
1017     Basicaudio_get_Volume,
1018     Basicaudio_put_Balance,
1019     Basicaudio_get_Balance
1020 };
1021
1022
1023 /*** IUnknown methods ***/
1024 static HRESULT WINAPI ReferenceClock_QueryInterface(IReferenceClock *iface,
1025                                                 REFIID riid,
1026                                                 LPVOID*ppvObj)
1027 {
1028     ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1029
1030     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
1031
1032     return DSoundRender_QueryInterface((IBaseFilter*)This, riid, ppvObj);
1033 }
1034
1035 static ULONG WINAPI ReferenceClock_AddRef(IReferenceClock *iface)
1036 {
1037     ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1038
1039     TRACE("(%p/%p)->()\n", This, iface);
1040
1041     return DSoundRender_AddRef((IBaseFilter*)This);
1042 }
1043
1044 static ULONG WINAPI ReferenceClock_Release(IReferenceClock *iface)
1045 {
1046     ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1047
1048     TRACE("(%p/%p)->()\n", This, iface);
1049
1050     return DSoundRender_Release((IBaseFilter*)This);
1051 }
1052
1053 /*** IReferenceClock methods ***/
1054 static HRESULT WINAPI ReferenceClock_GetTime(IReferenceClock *iface,
1055                                              REFERENCE_TIME *pTime)
1056 {
1057     ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1058     HRESULT hr = E_FAIL;
1059     DWORD play_pos;
1060
1061     TRACE("(%p/%p)->(%p)\n", This, iface, pTime);
1062
1063     if (This->dsbuffer)
1064         hr = DSoundRender_GetPos(This, &play_pos, pTime);
1065     if (FAILED(hr))
1066         ERR("Could not get reference time (%x)!\n", hr);
1067
1068     return hr;
1069 }
1070
1071 static HRESULT WINAPI ReferenceClock_AdviseTime(IReferenceClock *iface,
1072                                                 REFERENCE_TIME rtBaseTime,
1073                                                 REFERENCE_TIME rtStreamTime,
1074                                                 HEVENT hEvent,
1075                                                 DWORD_PTR *pdwAdviseCookie)
1076 {
1077     ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1078
1079     FIXME("(%p/%p)->(%s, %s, %p, %p): stub!\n", This, iface, wine_dbgstr_longlong(rtBaseTime), wine_dbgstr_longlong(rtStreamTime), (void*)hEvent, pdwAdviseCookie);
1080
1081     return E_NOTIMPL;
1082 }
1083
1084 static HRESULT WINAPI ReferenceClock_AdvisePeriodic(IReferenceClock *iface,
1085                                                     REFERENCE_TIME rtBaseTime,
1086                                                     REFERENCE_TIME rtStreamTime,
1087                                                     HSEMAPHORE hSemaphore,
1088                                                     DWORD_PTR *pdwAdviseCookie)
1089 {
1090     ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1091
1092     FIXME("(%p/%p)->(%s, %s, %p, %p): stub!\n", This, iface, wine_dbgstr_longlong(rtBaseTime), wine_dbgstr_longlong(rtStreamTime), (void*)hSemaphore, pdwAdviseCookie);
1093
1094     return E_NOTIMPL;
1095 }
1096
1097 static HRESULT WINAPI ReferenceClock_Unadvise(IReferenceClock *iface,
1098                                               DWORD_PTR dwAdviseCookie)
1099 {
1100     ICOM_THIS_MULTI(DSoundRenderImpl, IReferenceClock_vtbl, iface);
1101
1102     FIXME("(%p/%p)->(%p): stub!\n", This, iface, (void*)dwAdviseCookie);
1103
1104     return S_FALSE;
1105 }
1106
1107 static const IReferenceClockVtbl IReferenceClock_Vtbl =
1108 {
1109     ReferenceClock_QueryInterface,
1110     ReferenceClock_AddRef,
1111     ReferenceClock_Release,
1112     ReferenceClock_GetTime,
1113     ReferenceClock_AdviseTime,
1114     ReferenceClock_AdvisePeriodic,
1115     ReferenceClock_Unadvise
1116 };
1117
1118 static inline DSoundRenderImpl *impl_from_IMediaSeeking( IMediaSeeking *iface )
1119 {
1120     return (DSoundRenderImpl *)((char*)iface - FIELD_OFFSET(DSoundRenderImpl, mediaSeeking.lpVtbl));
1121 }
1122
1123 static HRESULT WINAPI sound_seek_QueryInterface(IMediaSeeking * iface, REFIID riid, LPVOID * ppv)
1124 {
1125     DSoundRenderImpl *This = impl_from_IMediaSeeking(iface);
1126
1127     return IUnknown_QueryInterface((IUnknown *)This, riid, ppv);
1128 }
1129
1130 static ULONG WINAPI sound_seek_AddRef(IMediaSeeking * iface)
1131 {
1132     DSoundRenderImpl *This = impl_from_IMediaSeeking(iface);
1133
1134     return IUnknown_AddRef((IUnknown *)This);
1135 }
1136
1137 static ULONG WINAPI sound_seek_Release(IMediaSeeking * iface)
1138 {
1139     DSoundRenderImpl *This = impl_from_IMediaSeeking(iface);
1140
1141     return IUnknown_Release((IUnknown *)This);
1142 }
1143
1144 static const IMediaSeekingVtbl IMediaSeeking_Vtbl =
1145 {
1146     sound_seek_QueryInterface,
1147     sound_seek_AddRef,
1148     sound_seek_Release,
1149     MediaSeekingImpl_GetCapabilities,
1150     MediaSeekingImpl_CheckCapabilities,
1151     MediaSeekingImpl_IsFormatSupported,
1152     MediaSeekingImpl_QueryPreferredFormat,
1153     MediaSeekingImpl_GetTimeFormat,
1154     MediaSeekingImpl_IsUsingTimeFormat,
1155     MediaSeekingImpl_SetTimeFormat,
1156     MediaSeekingImpl_GetDuration,
1157     MediaSeekingImpl_GetStopPosition,
1158     MediaSeekingImpl_GetCurrentPosition,
1159     MediaSeekingImpl_ConvertTimeFormat,
1160     MediaSeekingImpl_SetPositions,
1161     MediaSeekingImpl_GetPositions,
1162     MediaSeekingImpl_GetAvailable,
1163     MediaSeekingImpl_SetRate,
1164     MediaSeekingImpl_GetRate,
1165     MediaSeekingImpl_GetPreroll
1166 };