Now using the NT CD interface.
[wine] / dlls / quartz / audren.c
1 /*
2  * Audio Renderer (CLSID_AudioRender)
3  *
4  * FIXME
5  *  - implements IRefereneceClock.
6  *  - implements seeking.
7  *
8  * hidenori@a2.ctktv.ne.jp
9  */
10
11 #include "config.h"
12
13 #include "windef.h"
14 #include "winbase.h"
15 #include "wingdi.h"
16 #include "winuser.h"
17 #include "mmsystem.h"
18 #include "winerror.h"
19 #include "strmif.h"
20 #include "control.h"
21 #include "vfwmsgs.h"
22 #include "uuids.h"
23 #include "evcode.h"
24
25 #include "debugtools.h"
26 DEFAULT_DEBUG_CHANNEL(quartz);
27
28 #include "quartz_private.h"
29 #include "audren.h"
30 #include "seekpass.h"
31
32
33 static const WCHAR QUARTZ_AudioRender_Name[] =
34 { 'A','u','d','i','o',' ','R','e','n','d','e','r',0 };
35 static const WCHAR QUARTZ_AudioRenderPin_Name[] =
36 { 'I','n',0 };
37
38
39
40 /***************************************************************************
41  *
42  *      CAudioRendererImpl waveOut methods (internal)
43  *
44  */
45
46 static
47 HRESULT QUARTZ_HRESULT_From_MMRESULT( MMRESULT mr )
48 {
49         HRESULT hr = E_FAIL;
50
51         switch ( mr )
52         {
53         case MMSYSERR_NOERROR:
54                 hr = S_OK;
55                 break;
56         case MMSYSERR_NOMEM:
57                 hr = E_OUTOFMEMORY;
58                 break;
59         }
60
61         return hr;
62 }
63
64 void CAudioRendererImpl_waveOutEventCallback(
65         HWAVEOUT hwo, UINT uMsg,
66         DWORD dwInstance, DWORD dwParam1, DWORD dwParam2 )
67 {
68         CAudioRendererImpl* This = (CAudioRendererImpl*)dwInstance;
69
70         if ( uMsg == WOM_DONE )
71                 SetEvent( This->m_hEventRender );
72 }
73
74 static
75 void CAudioRendererImpl_waveOutReset(
76         CAudioRendererImpl* This )
77 {
78         if ( !This->m_fWaveOutInit )
79                 return;
80
81         waveOutReset( This->m_hWaveOut );
82         SetEvent( This->m_hEventRender );
83 }
84
85 static
86 void CAudioRendererImpl_waveOutUninit(
87         CAudioRendererImpl* This )
88 {
89         DWORD i;
90
91         TRACE("(%p)\n",This);
92
93         if ( !This->m_fWaveOutInit )
94                 return;
95
96         waveOutReset( This->m_hWaveOut );
97         SetEvent( This->m_hEventRender );
98
99         for ( i = 0; i < WINE_QUARTZ_WAVEOUT_COUNT; i++ )
100         {
101                 if ( This->m_hdr[i].dwFlags & WHDR_PREPARED )
102                 {
103                         waveOutUnprepareHeader(
104                                 This->m_hWaveOut,
105                                 &This->m_hdr[i], sizeof(WAVEHDR) );
106                         This->m_hdr[i].dwFlags = 0;
107                 }
108                 if ( This->m_hdr[i].lpData != NULL )
109                 {
110                         QUARTZ_FreeMem( This->m_hdr[i].lpData );
111                         This->m_hdr[i].lpData = NULL;
112                 }
113         }
114
115         waveOutClose( This->m_hWaveOut );
116         This->m_hWaveOut = (HWAVEOUT)NULL;
117         if ( This->m_hEventRender != (HANDLE)NULL )
118         {
119                 CloseHandle( This->m_hEventRender );
120                 This->m_hEventRender = (HANDLE)NULL;
121         }
122
123         This->m_fWaveOutInit = FALSE;
124 }
125
126 static
127 HRESULT CAudioRendererImpl_waveOutInit(
128         CAudioRendererImpl* This, WAVEFORMATEX* pwfx )
129 {
130         MMRESULT mr;
131         HRESULT hr;
132         DWORD i;
133         DWORD dwBlockSize;
134
135         if ( This->m_fWaveOutInit )
136                 return NOERROR;
137
138         if ( pwfx == NULL )
139                 return E_POINTER;
140         if ( pwfx->nBlockAlign == 0 )
141                 return E_INVALIDARG;
142
143         This->m_hEventRender = (HANDLE)NULL;
144         This->m_hWaveOut = (HWAVEOUT)NULL;
145         This->m_dwBlockSize = 0;
146         This->m_phdrCur = NULL;
147         ZeroMemory( &This->m_hdr, sizeof(This->m_hdr) );
148
149
150         mr = waveOutOpen(
151                 &This->m_hWaveOut, WAVE_MAPPER, pwfx,
152                 (DWORD)CAudioRendererImpl_waveOutEventCallback, (DWORD)This,
153                 CALLBACK_FUNCTION );
154         hr = QUARTZ_HRESULT_From_MMRESULT( mr );
155         if ( FAILED(hr) )
156                 return hr;
157         This->m_fWaveOutInit = TRUE;
158
159         This->m_hEventRender = CreateEventA(
160                 NULL, TRUE, TRUE, NULL );
161         if ( This->m_hEventRender == (HANDLE)NULL )
162         {
163                 hr = E_OUTOFMEMORY;
164                 goto err;
165         }
166
167         dwBlockSize = pwfx->nAvgBytesPerSec / pwfx->nBlockAlign;
168         if ( dwBlockSize == 0 )
169                 dwBlockSize = 1;
170         dwBlockSize *= pwfx->nBlockAlign;
171         This->m_dwBlockSize = dwBlockSize;
172
173         for ( i = 0; i < WINE_QUARTZ_WAVEOUT_COUNT; i++ )
174         {
175                 This->m_hdr[i].lpData = (CHAR*)QUARTZ_AllocMem( dwBlockSize );
176                 if ( This->m_hdr[i].lpData == NULL )
177                 {
178                         hr = E_OUTOFMEMORY;
179                         goto err;
180                 }
181                 mr = waveOutPrepareHeader(
182                                 This->m_hWaveOut,
183                                 &This->m_hdr[i], sizeof(WAVEHDR) );
184                 hr = QUARTZ_HRESULT_From_MMRESULT( mr );
185                 if ( FAILED(hr) )
186                         goto err;
187                 This->m_hdr[i].dwFlags |= WHDR_DONE;
188                 This->m_hdr[i].dwBufferLength = dwBlockSize;
189                 This->m_hdr[i].dwUser = i;
190         }
191
192         return S_OK;
193 err:
194         CAudioRendererImpl_waveOutUninit(This);
195         return hr;
196 }
197
198 static HRESULT CAudioRendererImpl_waveOutPause( CAudioRendererImpl* This )
199 {
200         if ( !This->m_fWaveOutInit )
201                 return E_UNEXPECTED;
202
203         return QUARTZ_HRESULT_From_MMRESULT( waveOutPause(
204                         This->m_hWaveOut ) );
205 }
206
207 static HRESULT CAudioRendererImpl_waveOutRun( CAudioRendererImpl* This )
208 {
209         if ( !This->m_fWaveOutInit )
210                 return E_UNEXPECTED;
211
212         return QUARTZ_HRESULT_From_MMRESULT( waveOutRestart(
213                         This->m_hWaveOut ) );
214 }
215
216 static
217 WAVEHDR* CAudioRendererImpl_waveOutGetBuffer(
218         CAudioRendererImpl* This )
219 {
220         DWORD i;
221
222         if ( !This->m_fWaveOutInit )
223                 return NULL;
224
225         if ( This->m_phdrCur != NULL )
226                 return This->m_phdrCur;
227
228         for ( i = 0; i < WINE_QUARTZ_WAVEOUT_COUNT; i++ )
229         {
230                 if ( This->m_hdr[i].dwFlags & WHDR_DONE )
231                 {
232                         This->m_phdrCur = &(This->m_hdr[i]);
233                         This->m_phdrCur->dwFlags &= ~WHDR_DONE;
234                         This->m_phdrCur->dwBufferLength = 0;
235                         return This->m_phdrCur;
236                 }
237         }
238
239         return NULL;
240 }
241
242 static
243 HRESULT CAudioRendererImpl_waveOutWriteData(
244         CAudioRendererImpl* This,
245         const BYTE* pData, DWORD cbData, DWORD* pcbWritten )
246 {
247         DWORD   cbAvail;
248
249         *pcbWritten = 0;
250
251         if ( !This->m_fWaveOutInit )
252                 return E_UNEXPECTED;
253
254         if ( cbData == 0 )
255                 return S_OK;
256
257         if ( CAudioRendererImpl_waveOutGetBuffer(This) == NULL )
258                 return S_FALSE;
259
260         cbAvail = This->m_dwBlockSize - This->m_phdrCur->dwBufferLength;
261         if ( cbAvail > cbData )
262                 cbAvail = cbData;
263         memcpy( This->m_phdrCur->lpData, pData, cbAvail );
264         pData += cbAvail;
265         cbData -= cbAvail;
266         This->m_phdrCur->dwBufferLength += cbAvail;
267
268         *pcbWritten = cbAvail;
269
270         return S_OK;
271 }
272
273 static
274 HRESULT CAudioRendererImpl_waveOutFlush(
275         CAudioRendererImpl* This )
276 {
277         MMRESULT mr;
278         HRESULT hr;
279
280         if ( !This->m_fWaveOutInit )
281                 return E_UNEXPECTED;
282         if ( This->m_phdrCur == NULL )
283                 return E_UNEXPECTED;
284
285         if ( This->m_phdrCur->dwBufferLength == 0 )
286                 return S_OK;
287
288         mr = waveOutWrite(
289                 This->m_hWaveOut,
290                 This->m_phdrCur, sizeof(WAVEHDR) );
291         hr = QUARTZ_HRESULT_From_MMRESULT( mr );
292         if ( FAILED(hr) )
293                 return hr;
294
295         This->m_phdrCur = NULL;
296         return S_OK;
297 }
298
299 static
300 HRESULT CAudioRendererImpl_waveOutGetVolume(
301         CAudioRendererImpl* This,
302         DWORD* pdwLeft, DWORD* pdwRight )
303 {
304         MMRESULT mr;
305         HRESULT hr;
306         DWORD   dwVol;
307
308         if ( !This->m_fWaveOutInit )
309                 return E_UNEXPECTED;
310
311         mr = waveOutGetVolume(
312                 This->m_hWaveOut, &dwVol );
313         hr = QUARTZ_HRESULT_From_MMRESULT( mr );
314         if ( FAILED(hr) )
315                 return hr;
316
317         *pdwLeft = LOWORD(dwVol);
318         *pdwRight = HIWORD(dwVol);
319
320         return NOERROR;
321 }
322
323 static
324 HRESULT CAudioRendererImpl_waveOutSetVolume(
325         CAudioRendererImpl* This,
326         DWORD dwLeft, DWORD dwRight )
327 {
328         MMRESULT mr;
329         DWORD   dwVol;
330
331         if ( !This->m_fWaveOutInit )
332                 return E_UNEXPECTED;
333
334         dwVol = dwLeft | (dwRight<<16);
335
336         mr = waveOutSetVolume(
337                 This->m_hWaveOut, dwVol );
338         return QUARTZ_HRESULT_From_MMRESULT( mr );
339 }
340
341 /***************************************************************************
342  *
343  *      CAudioRendererImpl methods
344  *
345  */
346
347
348 static HRESULT CAudioRendererImpl_OnActive( CBaseFilterImpl* pImpl )
349 {
350         CAudioRendererImpl_THIS(pImpl,basefilter);
351         HRESULT hr;
352
353         FIXME( "(%p)\n", This );
354
355         if ( This->pPin->pin.pmtConn == NULL )
356                 return NOERROR;
357
358         This->m_fInFlush = FALSE;
359
360         /* FIXME - don't work correctly.
361         hr = CAudioRendererImpl_waveOutRun(This);
362         if ( FAILED(hr) )
363                 return hr;
364         */
365
366         return NOERROR;
367 }
368
369 static HRESULT CAudioRendererImpl_OnInactive( CBaseFilterImpl* pImpl )
370 {
371         CAudioRendererImpl_THIS(pImpl,basefilter);
372         WAVEFORMATEX*   pwfx;
373         HRESULT hr;
374
375         FIXME( "(%p)\n", This );
376
377         if ( This->pPin->pin.pmtConn == NULL )
378                 return NOERROR;
379
380         pwfx = (WAVEFORMATEX*)This->pPin->pin.pmtConn->pbFormat;
381         if ( pwfx == NULL )
382                 return E_FAIL;
383
384         This->m_fInFlush = FALSE;
385
386         hr = CAudioRendererImpl_waveOutInit(This,pwfx);
387         if ( FAILED(hr) )
388                 return hr;
389
390         /* FIXME - may cause deadlock.
391         hr = CAudioRendererImpl_waveOutPause(This);
392         if ( FAILED(hr) )
393                 return hr;
394         */
395
396         return NOERROR;
397 }
398
399 static HRESULT CAudioRendererImpl_OnStop( CBaseFilterImpl* pImpl )
400 {
401         CAudioRendererImpl_THIS(pImpl,basefilter);
402
403         FIXME( "(%p)\n", This );
404
405         CAudioRendererImpl_waveOutUninit(This);
406
407         This->m_fInFlush = FALSE;
408
409         TRACE("returned\n" );
410
411         return NOERROR;
412 }
413
414 static const CBaseFilterHandlers filterhandlers =
415 {
416         CAudioRendererImpl_OnActive, /* pOnActive */
417         CAudioRendererImpl_OnInactive, /* pOnInactive */
418         CAudioRendererImpl_OnStop, /* pOnStop */
419 };
420
421 /***************************************************************************
422  *
423  *      CAudioRendererPinImpl methods
424  *
425  */
426
427 static HRESULT CAudioRendererPinImpl_OnDisconnect( CPinBaseImpl* pImpl )
428 {
429         CAudioRendererPinImpl_THIS(pImpl,pin);
430
431         TRACE("(%p)\n",This);
432
433         if ( This->meminput.pAllocator != NULL )
434         {
435                 IMemAllocator_Decommit(This->meminput.pAllocator);
436                 IMemAllocator_Release(This->meminput.pAllocator);
437                 This->meminput.pAllocator = NULL;
438         }
439
440         return NOERROR;
441 }
442
443
444 static HRESULT CAudioRendererPinImpl_CheckMediaType( CPinBaseImpl* pImpl, const AM_MEDIA_TYPE* pmt )
445 {
446         CAudioRendererPinImpl_THIS(pImpl,pin);
447         const WAVEFORMATEX* pwfx;
448
449         TRACE("(%p,%p)\n",This,pmt);
450
451         if ( !IsEqualGUID( &pmt->majortype, &MEDIATYPE_Audio ) )
452         {
453                 TRACE("not audio\n");
454                 return E_FAIL;
455         }
456         if ( !IsEqualGUID( &pmt->subtype, &MEDIASUBTYPE_NULL ) &&
457                  !IsEqualGUID( &pmt->subtype, &MEDIASUBTYPE_PCM ) )
458         {
459                 TRACE("not PCM\n");
460                 return E_FAIL;
461         }
462         if ( !IsEqualGUID( &pmt->formattype, &FORMAT_WaveFormatEx ) )
463         {
464                 TRACE("not WAVE\n");
465                 return E_FAIL;
466         }
467
468         TRACE("testing WAVE header\n");
469
470         if ( pmt->cbFormat < (sizeof(WAVEFORMATEX)-sizeof(WORD)) )
471                 return E_FAIL;
472
473         pwfx = (const WAVEFORMATEX*)pmt->pbFormat;
474         if ( pwfx == NULL )
475                 return E_FAIL;
476         if ( pwfx->wFormatTag != 1 )
477                 return E_FAIL;
478
479         TRACE("returned successfully.\n");
480
481         return NOERROR;
482 }
483
484 static HRESULT CAudioRendererPinImpl_Receive( CPinBaseImpl* pImpl, IMediaSample* pSample )
485 {
486         CAudioRendererPinImpl_THIS(pImpl,pin);
487         HRESULT hr;
488         BYTE*   pData = NULL;
489         DWORD   dwDataLength;
490         DWORD   dwWritten;
491
492         FIXME( "(%p,%p)\n",This,pSample );
493
494         if ( !This->pRender->m_fWaveOutInit )
495                 return E_UNEXPECTED;
496         if ( This->pRender->m_fInFlush )
497                 return S_FALSE;
498         if ( pSample == NULL )
499                 return E_POINTER;
500
501         hr = IMediaSample_GetPointer( pSample, &pData );
502         if ( FAILED(hr) )
503                 return hr;
504         dwDataLength = (DWORD)IMediaSample_GetActualDataLength( pSample );
505
506         while ( 1 )
507         {
508                 TRACE("trying to write %lu bytes\n",dwDataLength);
509
510                 ResetEvent( This->pRender->m_hEventRender );
511                 hr = CAudioRendererImpl_waveOutWriteData(
512                         This->pRender,pData,dwDataLength,&dwWritten);
513                 if ( FAILED(hr) )
514                         break;
515                 if ( hr == S_FALSE )
516                 {
517                         WaitForSingleObject( This->pRender->m_hEventRender, INFINITE );
518                         continue;
519                 }
520                 pData += dwWritten;
521                 dwDataLength -= dwWritten;
522                 hr = CAudioRendererImpl_waveOutFlush(This->pRender);
523                 if ( FAILED(hr) )
524                         break;
525                 if ( dwDataLength == 0 )
526                         break;
527         }
528
529         return hr;
530 }
531
532 static HRESULT CAudioRendererPinImpl_ReceiveCanBlock( CPinBaseImpl* pImpl )
533 {
534         CAudioRendererPinImpl_THIS(pImpl,pin);
535
536         TRACE( "(%p)\n", This );
537
538         /* might block. */
539         return S_OK;
540 }
541
542 static HRESULT CAudioRendererPinImpl_EndOfStream( CPinBaseImpl* pImpl )
543 {
544         CAudioRendererPinImpl_THIS(pImpl,pin);
545
546         FIXME( "(%p)\n", This );
547
548         This->pRender->m_fInFlush = FALSE;
549
550         /* FIXME - don't notify twice until stopped or seeked. */
551         return CBaseFilterImpl_MediaEventNotify(
552                 &This->pRender->basefilter, EC_COMPLETE,
553                 (LONG_PTR)S_OK, (LONG_PTR)(IBaseFilter*)(This->pRender) );
554 }
555
556 static HRESULT CAudioRendererPinImpl_BeginFlush( CPinBaseImpl* pImpl )
557 {
558         CAudioRendererPinImpl_THIS(pImpl,pin);
559
560         FIXME( "(%p)\n", This );
561
562         This->pRender->m_fInFlush = TRUE;
563         CAudioRendererImpl_waveOutReset(This->pRender);
564
565         return NOERROR;
566 }
567
568 static HRESULT CAudioRendererPinImpl_EndFlush( CPinBaseImpl* pImpl )
569 {
570         CAudioRendererPinImpl_THIS(pImpl,pin);
571
572         FIXME( "(%p)\n", This );
573
574         This->pRender->m_fInFlush = FALSE;
575
576         return NOERROR;
577 }
578
579 static HRESULT CAudioRendererPinImpl_NewSegment( CPinBaseImpl* pImpl, REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, double rate )
580 {
581         CAudioRendererPinImpl_THIS(pImpl,pin);
582
583         FIXME( "(%p)\n", This );
584
585         This->pRender->m_fInFlush = FALSE;
586
587         return NOERROR;
588 }
589
590 static const CBasePinHandlers pinhandlers =
591 {
592         NULL, /* pOnPreConnect */
593         NULL, /* pOnPostConnect */
594         CAudioRendererPinImpl_OnDisconnect, /* pOnDisconnect */
595         CAudioRendererPinImpl_CheckMediaType, /* pCheckMediaType */
596         NULL, /* pQualityNotify */
597         CAudioRendererPinImpl_Receive, /* pReceive */
598         CAudioRendererPinImpl_ReceiveCanBlock, /* pReceiveCanBlock */
599         CAudioRendererPinImpl_EndOfStream, /* pEndOfStream */
600         CAudioRendererPinImpl_BeginFlush, /* pBeginFlush */
601         CAudioRendererPinImpl_EndFlush, /* pEndFlush */
602         CAudioRendererPinImpl_NewSegment, /* pNewSegment */
603 };
604
605
606 /***************************************************************************
607  *
608  *      new/delete CAudioRendererImpl
609  *
610  */
611
612 /* can I use offsetof safely? - FIXME? */
613 static QUARTZ_IFEntry FilterIFEntries[] =
614 {
615   { &IID_IPersist, offsetof(CAudioRendererImpl,basefilter)-offsetof(CAudioRendererImpl,unk) },
616   { &IID_IMediaFilter, offsetof(CAudioRendererImpl,basefilter)-offsetof(CAudioRendererImpl,unk) },
617   { &IID_IBaseFilter, offsetof(CAudioRendererImpl,basefilter)-offsetof(CAudioRendererImpl,unk) },
618   { &IID_IBasicAudio, offsetof(CAudioRendererImpl,basaud)-offsetof(CAudioRendererImpl,unk) },
619 };
620
621 static HRESULT CAudioRendererImpl_OnQueryInterface(
622         IUnknown* punk, const IID* piid, void** ppobj )
623 {
624         CAudioRendererImpl_THIS(punk,unk);
625
626         if ( This->pSeekPass == NULL )
627                 return E_NOINTERFACE;
628
629         if ( IsEqualGUID( &IID_IMediaPosition, piid ) ||
630                  IsEqualGUID( &IID_IMediaSeeking, piid ) )
631         {
632                 TRACE( "IMediaSeeking(or IMediaPosition) is queried\n" );
633                 return IUnknown_QueryInterface( (IUnknown*)(&This->pSeekPass->unk), piid, ppobj );
634         }
635
636         return E_NOINTERFACE;
637 }
638
639 static void QUARTZ_DestroyAudioRenderer(IUnknown* punk)
640 {
641         CAudioRendererImpl_THIS(punk,unk);
642
643         TRACE( "(%p)\n", This );
644
645         if ( This->pPin != NULL )
646         {
647                 IUnknown_Release(This->pPin->unk.punkControl);
648                 This->pPin = NULL;
649         }
650         if ( This->pSeekPass != NULL )
651         {
652                 IUnknown_Release((IUnknown*)&This->pSeekPass->unk);
653                 This->pSeekPass = NULL;
654         }
655
656         CAudioRendererImpl_UninitIBasicAudio(This);
657         CBaseFilterImpl_UninitIBaseFilter(&This->basefilter);
658 }
659
660 HRESULT QUARTZ_CreateAudioRenderer(IUnknown* punkOuter,void** ppobj)
661 {
662         CAudioRendererImpl*     This = NULL;
663         HRESULT hr;
664
665         TRACE("(%p,%p)\n",punkOuter,ppobj);
666
667         This = (CAudioRendererImpl*)
668                 QUARTZ_AllocObj( sizeof(CAudioRendererImpl) );
669         if ( This == NULL )
670                 return E_OUTOFMEMORY;
671         This->pSeekPass = NULL;
672         This->pPin = NULL;
673         This->m_fInFlush = FALSE;
674         This->m_fWaveOutInit = FALSE;
675         This->m_hEventRender = (HANDLE)NULL;
676
677         QUARTZ_IUnkInit( &This->unk, punkOuter );
678         This->qiext.pNext = NULL;
679         This->qiext.pOnQueryInterface = &CAudioRendererImpl_OnQueryInterface;
680         QUARTZ_IUnkAddDelegation( &This->unk, &This->qiext );
681
682         hr = CBaseFilterImpl_InitIBaseFilter(
683                 &This->basefilter,
684                 This->unk.punkControl,
685                 &CLSID_AudioRender,
686                 QUARTZ_AudioRender_Name,
687                 &filterhandlers );
688         if ( SUCCEEDED(hr) )
689         {
690                 hr = CAudioRendererImpl_InitIBasicAudio(This);
691                 if ( FAILED(hr) )
692                 {
693                         CBaseFilterImpl_UninitIBaseFilter(&This->basefilter);
694                 }
695         }
696
697         if ( FAILED(hr) )
698         {
699                 QUARTZ_FreeObj(This);
700                 return hr;
701         }
702
703         This->unk.pEntries = FilterIFEntries;
704         This->unk.dwEntries = sizeof(FilterIFEntries)/sizeof(FilterIFEntries[0]);
705         This->unk.pOnFinalRelease = QUARTZ_DestroyAudioRenderer;
706
707         hr = QUARTZ_CreateAudioRendererPin(
708                 This,
709                 &This->basefilter.csFilter,
710                 &This->pPin );
711         if ( SUCCEEDED(hr) )
712                 hr = QUARTZ_CompList_AddComp(
713                         This->basefilter.pInPins,
714                         (IUnknown*)&This->pPin->pin,
715                         NULL, 0 );
716         if ( SUCCEEDED(hr) )
717                 hr = QUARTZ_CreateSeekingPassThruInternal(
718                         (IUnknown*)&(This->unk), &This->pSeekPass,
719                         TRUE, (IPin*)&(This->pPin->pin) );
720
721         if ( FAILED(hr) )
722         {
723                 IUnknown_Release( This->unk.punkControl );
724                 return hr;
725         }
726
727         *ppobj = (void*)&(This->unk);
728
729         return S_OK;
730 }
731
732
733 /***************************************************************************
734  *
735  *      new/delete CAudioRendererPinImpl
736  *
737  */
738
739 /* can I use offsetof safely? - FIXME? */
740 static QUARTZ_IFEntry PinIFEntries[] =
741 {
742   { &IID_IPin, offsetof(CAudioRendererPinImpl,pin)-offsetof(CAudioRendererPinImpl,unk) },
743   { &IID_IMemInputPin, offsetof(CAudioRendererPinImpl,meminput)-offsetof(CAudioRendererPinImpl,unk) },
744 };
745
746 static void QUARTZ_DestroyAudioRendererPin(IUnknown* punk)
747 {
748         CAudioRendererPinImpl_THIS(punk,unk);
749
750         TRACE( "(%p)\n", This );
751
752         CPinBaseImpl_UninitIPin( &This->pin );
753         CMemInputPinBaseImpl_UninitIMemInputPin( &This->meminput );
754 }
755
756 HRESULT QUARTZ_CreateAudioRendererPin(
757         CAudioRendererImpl* pFilter,
758         CRITICAL_SECTION* pcsPin,
759         CAudioRendererPinImpl** ppPin)
760 {
761         CAudioRendererPinImpl*  This = NULL;
762         HRESULT hr;
763
764         TRACE("(%p,%p,%p)\n",pFilter,pcsPin,ppPin);
765
766         This = (CAudioRendererPinImpl*)
767                 QUARTZ_AllocObj( sizeof(CAudioRendererPinImpl) );
768         if ( This == NULL )
769                 return E_OUTOFMEMORY;
770
771         QUARTZ_IUnkInit( &This->unk, NULL );
772         This->pRender = pFilter;
773
774         hr = CPinBaseImpl_InitIPin(
775                 &This->pin,
776                 This->unk.punkControl,
777                 pcsPin,
778                 &pFilter->basefilter,
779                 QUARTZ_AudioRenderPin_Name,
780                 FALSE,
781                 &pinhandlers );
782
783         if ( SUCCEEDED(hr) )
784         {
785                 hr = CMemInputPinBaseImpl_InitIMemInputPin(
786                         &This->meminput,
787                         This->unk.punkControl,
788                         &This->pin );
789                 if ( FAILED(hr) )
790                 {
791                         CPinBaseImpl_UninitIPin( &This->pin );
792                 }
793         }
794
795         if ( FAILED(hr) )
796         {
797                 QUARTZ_FreeObj(This);
798                 return hr;
799         }
800
801         This->unk.pEntries = PinIFEntries;
802         This->unk.dwEntries = sizeof(PinIFEntries)/sizeof(PinIFEntries[0]);
803         This->unk.pOnFinalRelease = QUARTZ_DestroyAudioRendererPin;
804
805         *ppPin = This;
806
807         TRACE("returned successfully.\n");
808
809         return S_OK;
810 }
811
812
813 /***************************************************************************
814  *
815  *      CAudioRendererImpl::IBasicAudio
816  *
817  */
818
819 static HRESULT WINAPI
820 IBasicAudio_fnQueryInterface(IBasicAudio* iface,REFIID riid,void** ppobj)
821 {
822         CAudioRendererImpl_THIS(iface,basaud);
823
824         TRACE("(%p)->()\n",This);
825
826         return IUnknown_QueryInterface(This->unk.punkControl,riid,ppobj);
827 }
828
829 static ULONG WINAPI
830 IBasicAudio_fnAddRef(IBasicAudio* iface)
831 {
832         CAudioRendererImpl_THIS(iface,basaud);
833
834         TRACE("(%p)->()\n",This);
835
836         return IUnknown_AddRef(This->unk.punkControl);
837 }
838
839 static ULONG WINAPI
840 IBasicAudio_fnRelease(IBasicAudio* iface)
841 {
842         CAudioRendererImpl_THIS(iface,basaud);
843
844         TRACE("(%p)->()\n",This);
845
846         return IUnknown_Release(This->unk.punkControl);
847 }
848
849 static HRESULT WINAPI
850 IBasicAudio_fnGetTypeInfoCount(IBasicAudio* iface,UINT* pcTypeInfo)
851 {
852         CAudioRendererImpl_THIS(iface,basaud);
853
854         FIXME("(%p)->()\n",This);
855
856         return E_NOTIMPL;
857 }
858
859 static HRESULT WINAPI
860 IBasicAudio_fnGetTypeInfo(IBasicAudio* iface,UINT iTypeInfo, LCID lcid, ITypeInfo** ppobj)
861 {
862         CAudioRendererImpl_THIS(iface,basaud);
863
864         FIXME("(%p)->()\n",This);
865
866         return E_NOTIMPL;
867 }
868
869 static HRESULT WINAPI
870 IBasicAudio_fnGetIDsOfNames(IBasicAudio* iface,REFIID riid, LPOLESTR* ppwszName, UINT cNames, LCID lcid, DISPID* pDispId)
871 {
872         CAudioRendererImpl_THIS(iface,basaud);
873
874         FIXME("(%p)->()\n",This);
875
876         return E_NOTIMPL;
877 }
878
879 static HRESULT WINAPI
880 IBasicAudio_fnInvoke(IBasicAudio* iface,DISPID DispId, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarRes, EXCEPINFO* pExcepInfo, UINT* puArgErr)
881 {
882         CAudioRendererImpl_THIS(iface,basaud);
883
884         FIXME("(%p)->()\n",This);
885
886         return E_NOTIMPL;
887 }
888
889
890 static HRESULT WINAPI
891 IBasicAudio_fnput_Volume(IBasicAudio* iface,long lVol)
892 {
893         CAudioRendererImpl_THIS(iface,basaud);
894
895         FIXME("(%p)->()\n",This);
896
897         return E_NOTIMPL;
898 }
899
900 static HRESULT WINAPI
901 IBasicAudio_fnget_Volume(IBasicAudio* iface,long* plVol)
902 {
903         CAudioRendererImpl_THIS(iface,basaud);
904
905         FIXME("(%p)->()\n",This);
906
907         return E_NOTIMPL;
908 }
909
910 static HRESULT WINAPI
911 IBasicAudio_fnput_Balance(IBasicAudio* iface,long lBalance)
912 {
913         CAudioRendererImpl_THIS(iface,basaud);
914
915         FIXME("(%p)->()\n",This);
916
917         return E_NOTIMPL;
918 }
919
920 static HRESULT WINAPI
921 IBasicAudio_fnget_Balance(IBasicAudio* iface,long* plBalance)
922 {
923         CAudioRendererImpl_THIS(iface,basaud);
924
925         FIXME("(%p)->()\n",This);
926
927         return E_NOTIMPL;
928 }
929
930
931 static ICOM_VTABLE(IBasicAudio) ibasicaudio =
932 {
933         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
934         /* IUnknown fields */
935         IBasicAudio_fnQueryInterface,
936         IBasicAudio_fnAddRef,
937         IBasicAudio_fnRelease,
938         /* IDispatch fields */
939         IBasicAudio_fnGetTypeInfoCount,
940         IBasicAudio_fnGetTypeInfo,
941         IBasicAudio_fnGetIDsOfNames,
942         IBasicAudio_fnInvoke,
943         /* IBasicAudio fields */
944         IBasicAudio_fnput_Volume,
945         IBasicAudio_fnget_Volume,
946         IBasicAudio_fnput_Balance,
947         IBasicAudio_fnget_Balance,
948 };
949
950
951 HRESULT CAudioRendererImpl_InitIBasicAudio( CAudioRendererImpl* This )
952 {
953         TRACE("(%p)\n",This);
954         ICOM_VTBL(&This->basaud) = &ibasicaudio;
955
956         return NOERROR;
957 }
958
959 void CAudioRendererImpl_UninitIBasicAudio( CAudioRendererImpl* This )
960 {
961         TRACE("(%p)\n",This);
962 }
963