Various cosmetic changes.
[wine] / dlls / quartz / audren.c
1 /*
2  * Audio Renderer (CLSID_AudioRender)
3  *
4  * FIXME
5  *  - implement IReferenceClock.
6  *  - implement 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 #if 0
199 /* FIXME: Not used for now */
200
201 static HRESULT CAudioRendererImpl_waveOutPause( CAudioRendererImpl* This )
202 {
203         if ( !This->m_fWaveOutInit )
204                 return E_UNEXPECTED;
205
206         return QUARTZ_HRESULT_From_MMRESULT( waveOutPause(
207                         This->m_hWaveOut ) );
208 }
209
210 static HRESULT CAudioRendererImpl_waveOutRun( CAudioRendererImpl* This )
211 {
212         if ( !This->m_fWaveOutInit )
213                 return E_UNEXPECTED;
214
215         return QUARTZ_HRESULT_From_MMRESULT( waveOutRestart(
216                         This->m_hWaveOut ) );
217 }
218 #endif
219
220 static
221 WAVEHDR* CAudioRendererImpl_waveOutGetBuffer(
222         CAudioRendererImpl* This )
223 {
224         DWORD i;
225
226         if ( !This->m_fWaveOutInit )
227                 return NULL;
228
229         if ( This->m_phdrCur != NULL )
230                 return This->m_phdrCur;
231
232         for ( i = 0; i < WINE_QUARTZ_WAVEOUT_COUNT; i++ )
233         {
234                 if ( This->m_hdr[i].dwFlags & WHDR_DONE )
235                 {
236                         This->m_phdrCur = &(This->m_hdr[i]);
237                         This->m_phdrCur->dwFlags &= ~WHDR_DONE;
238                         This->m_phdrCur->dwBufferLength = 0;
239                         return This->m_phdrCur;
240                 }
241         }
242
243         return NULL;
244 }
245
246 static
247 HRESULT CAudioRendererImpl_waveOutWriteData(
248         CAudioRendererImpl* This,
249         const BYTE* pData, DWORD cbData, DWORD* pcbWritten )
250 {
251         DWORD   cbAvail;
252
253         *pcbWritten = 0;
254
255         if ( !This->m_fWaveOutInit )
256                 return E_UNEXPECTED;
257
258         if ( cbData == 0 )
259                 return S_OK;
260
261         if ( CAudioRendererImpl_waveOutGetBuffer(This) == NULL )
262                 return S_FALSE;
263
264         cbAvail = This->m_dwBlockSize - This->m_phdrCur->dwBufferLength;
265         if ( cbAvail > cbData )
266                 cbAvail = cbData;
267         memcpy( This->m_phdrCur->lpData, pData, cbAvail );
268         pData += cbAvail;
269         cbData -= cbAvail;
270         This->m_phdrCur->dwBufferLength += cbAvail;
271
272         *pcbWritten = cbAvail;
273
274         return S_OK;
275 }
276
277 static
278 HRESULT CAudioRendererImpl_waveOutFlush(
279         CAudioRendererImpl* This )
280 {
281         MMRESULT mr;
282         HRESULT hr;
283
284         if ( !This->m_fWaveOutInit )
285                 return E_UNEXPECTED;
286         if ( This->m_phdrCur == NULL )
287                 return E_UNEXPECTED;
288
289         if ( This->m_phdrCur->dwBufferLength == 0 )
290                 return S_OK;
291
292         mr = waveOutWrite(
293                 This->m_hWaveOut,
294                 This->m_phdrCur, sizeof(WAVEHDR) );
295         hr = QUARTZ_HRESULT_From_MMRESULT( mr );
296         if ( FAILED(hr) )
297                 return hr;
298
299         This->m_phdrCur = NULL;
300         return S_OK;
301 }
302
303 #if 0
304 /* FIXME: Not used for now */
305
306 static
307 HRESULT CAudioRendererImpl_waveOutGetVolume(
308         CAudioRendererImpl* This,
309         DWORD* pdwLeft, DWORD* pdwRight )
310 {
311         MMRESULT mr;
312         HRESULT hr;
313         DWORD   dwVol;
314
315         if ( !This->m_fWaveOutInit )
316                 return E_UNEXPECTED;
317
318         mr = waveOutGetVolume(
319                 This->m_hWaveOut, &dwVol );
320         hr = QUARTZ_HRESULT_From_MMRESULT( mr );
321         if ( FAILED(hr) )
322                 return hr;
323
324         *pdwLeft = LOWORD(dwVol);
325         *pdwRight = HIWORD(dwVol);
326
327         return NOERROR;
328 }
329
330 static
331 HRESULT CAudioRendererImpl_waveOutSetVolume(
332         CAudioRendererImpl* This,
333         DWORD dwLeft, DWORD dwRight )
334 {
335         MMRESULT mr;
336         DWORD   dwVol;
337
338         if ( !This->m_fWaveOutInit )
339                 return E_UNEXPECTED;
340
341         dwVol = dwLeft | (dwRight<<16);
342
343         mr = waveOutSetVolume(
344                 This->m_hWaveOut, dwVol );
345         return QUARTZ_HRESULT_From_MMRESULT( mr );
346 }
347 #endif
348
349 /***************************************************************************
350  *
351  *      CAudioRendererImpl methods
352  *
353  */
354
355
356 static HRESULT CAudioRendererImpl_OnActive( CBaseFilterImpl* pImpl )
357 {
358         CAudioRendererImpl_THIS(pImpl,basefilter);
359         /* HRESULT hr; */
360
361         FIXME( "(%p)\n", This );
362
363         if ( This->pPin->pin.pmtConn == NULL )
364                 return NOERROR;
365
366         This->m_fInFlush = FALSE;
367
368         /* FIXME - don't work correctly.
369         hr = CAudioRendererImpl_waveOutRun(This);
370         if ( FAILED(hr) )
371                 return hr;
372         */
373
374         return NOERROR;
375 }
376
377 static HRESULT CAudioRendererImpl_OnInactive( CBaseFilterImpl* pImpl )
378 {
379         CAudioRendererImpl_THIS(pImpl,basefilter);
380         WAVEFORMATEX*   pwfx;
381         HRESULT hr;
382
383         FIXME( "(%p)\n", This );
384
385         if ( This->pPin->pin.pmtConn == NULL )
386                 return NOERROR;
387
388         pwfx = (WAVEFORMATEX*)This->pPin->pin.pmtConn->pbFormat;
389         if ( pwfx == NULL )
390                 return E_FAIL;
391
392         This->m_fInFlush = FALSE;
393
394         hr = CAudioRendererImpl_waveOutInit(This,pwfx);
395         if ( FAILED(hr) )
396                 return hr;
397
398         /* FIXME - may cause deadlock.
399         hr = CAudioRendererImpl_waveOutPause(This);
400         if ( FAILED(hr) )
401                 return hr;
402         */
403
404         return NOERROR;
405 }
406
407 static HRESULT CAudioRendererImpl_OnStop( CBaseFilterImpl* pImpl )
408 {
409         CAudioRendererImpl_THIS(pImpl,basefilter);
410
411         FIXME( "(%p)\n", This );
412
413         CAudioRendererImpl_waveOutUninit(This);
414
415         This->m_fInFlush = FALSE;
416
417         TRACE("returned\n" );
418
419         return NOERROR;
420 }
421
422 static const CBaseFilterHandlers filterhandlers =
423 {
424         CAudioRendererImpl_OnActive, /* pOnActive */
425         CAudioRendererImpl_OnInactive, /* pOnInactive */
426         CAudioRendererImpl_OnStop, /* pOnStop */
427 };
428
429 /***************************************************************************
430  *
431  *      CAudioRendererPinImpl methods
432  *
433  */
434
435 static HRESULT CAudioRendererPinImpl_OnDisconnect( CPinBaseImpl* pImpl )
436 {
437         CAudioRendererPinImpl_THIS(pImpl,pin);
438
439         TRACE("(%p)\n",This);
440
441         if ( This->meminput.pAllocator != NULL )
442         {
443                 IMemAllocator_Decommit(This->meminput.pAllocator);
444                 IMemAllocator_Release(This->meminput.pAllocator);
445                 This->meminput.pAllocator = NULL;
446         }
447
448         return NOERROR;
449 }
450
451
452 static HRESULT CAudioRendererPinImpl_CheckMediaType( CPinBaseImpl* pImpl, const AM_MEDIA_TYPE* pmt )
453 {
454         CAudioRendererPinImpl_THIS(pImpl,pin);
455         const WAVEFORMATEX* pwfx;
456
457         TRACE("(%p,%p)\n",This,pmt);
458
459         if ( !IsEqualGUID( &pmt->majortype, &MEDIATYPE_Audio ) )
460         {
461                 TRACE("not audio\n");
462                 return E_FAIL;
463         }
464         if ( !IsEqualGUID( &pmt->subtype, &MEDIASUBTYPE_NULL ) &&
465                  !IsEqualGUID( &pmt->subtype, &MEDIASUBTYPE_PCM ) )
466         {
467                 TRACE("not PCM\n");
468                 return E_FAIL;
469         }
470         if ( !IsEqualGUID( &pmt->formattype, &FORMAT_WaveFormatEx ) )
471         {
472                 TRACE("not WAVE\n");
473                 return E_FAIL;
474         }
475
476         TRACE("testing WAVE header\n");
477
478         if ( pmt->cbFormat < (sizeof(WAVEFORMATEX)-sizeof(WORD)) )
479                 return E_FAIL;
480
481         pwfx = (const WAVEFORMATEX*)pmt->pbFormat;
482         if ( pwfx == NULL )
483                 return E_FAIL;
484         if ( pwfx->wFormatTag != 1 )
485                 return E_FAIL;
486
487         TRACE("returned successfully.\n");
488
489         return NOERROR;
490 }
491
492 static HRESULT CAudioRendererPinImpl_Receive( CPinBaseImpl* pImpl, IMediaSample* pSample )
493 {
494         CAudioRendererPinImpl_THIS(pImpl,pin);
495         HRESULT hr;
496         BYTE*   pData = NULL;
497         DWORD   dwDataLength;
498         DWORD   dwWritten;
499
500         FIXME( "(%p,%p)\n",This,pSample );
501
502         if ( !This->pRender->m_fWaveOutInit )
503                 return E_UNEXPECTED;
504         if ( This->pRender->m_fInFlush )
505                 return S_FALSE;
506         if ( pSample == NULL )
507                 return E_POINTER;
508
509         hr = IMediaSample_GetPointer( pSample, &pData );
510         if ( FAILED(hr) )
511                 return hr;
512         dwDataLength = (DWORD)IMediaSample_GetActualDataLength( pSample );
513
514         while ( 1 )
515         {
516                 TRACE("trying to write %lu bytes\n",dwDataLength);
517
518                 ResetEvent( This->pRender->m_hEventRender );
519                 hr = CAudioRendererImpl_waveOutWriteData(
520                         This->pRender,pData,dwDataLength,&dwWritten);
521                 if ( FAILED(hr) )
522                         break;
523                 if ( hr == S_FALSE )
524                 {
525                         WaitForSingleObject( This->pRender->m_hEventRender, INFINITE );
526                         continue;
527                 }
528                 pData += dwWritten;
529                 dwDataLength -= dwWritten;
530                 hr = CAudioRendererImpl_waveOutFlush(This->pRender);
531                 if ( FAILED(hr) )
532                         break;
533                 if ( dwDataLength == 0 )
534                         break;
535         }
536
537         return hr;
538 }
539
540 static HRESULT CAudioRendererPinImpl_ReceiveCanBlock( CPinBaseImpl* pImpl )
541 {
542         CAudioRendererPinImpl_THIS(pImpl,pin);
543
544         TRACE( "(%p)\n", This );
545
546         /* might block. */
547         return S_OK;
548 }
549
550 static HRESULT CAudioRendererPinImpl_EndOfStream( CPinBaseImpl* pImpl )
551 {
552         CAudioRendererPinImpl_THIS(pImpl,pin);
553
554         FIXME( "(%p)\n", This );
555
556         This->pRender->m_fInFlush = FALSE;
557
558         /* FIXME - don't notify twice until stopped or seeked. */
559         return CBaseFilterImpl_MediaEventNotify(
560                 &This->pRender->basefilter, EC_COMPLETE,
561                 (LONG_PTR)S_OK, (LONG_PTR)(IBaseFilter*)(This->pRender) );
562 }
563
564 static HRESULT CAudioRendererPinImpl_BeginFlush( CPinBaseImpl* pImpl )
565 {
566         CAudioRendererPinImpl_THIS(pImpl,pin);
567
568         FIXME( "(%p)\n", This );
569
570         This->pRender->m_fInFlush = TRUE;
571         CAudioRendererImpl_waveOutReset(This->pRender);
572
573         return NOERROR;
574 }
575
576 static HRESULT CAudioRendererPinImpl_EndFlush( CPinBaseImpl* pImpl )
577 {
578         CAudioRendererPinImpl_THIS(pImpl,pin);
579
580         FIXME( "(%p)\n", This );
581
582         This->pRender->m_fInFlush = FALSE;
583
584         return NOERROR;
585 }
586
587 static HRESULT CAudioRendererPinImpl_NewSegment( CPinBaseImpl* pImpl, REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, double rate )
588 {
589         CAudioRendererPinImpl_THIS(pImpl,pin);
590
591         FIXME( "(%p)\n", This );
592
593         This->pRender->m_fInFlush = FALSE;
594
595         return NOERROR;
596 }
597
598 static const CBasePinHandlers pinhandlers =
599 {
600         NULL, /* pOnPreConnect */
601         NULL, /* pOnPostConnect */
602         CAudioRendererPinImpl_OnDisconnect, /* pOnDisconnect */
603         CAudioRendererPinImpl_CheckMediaType, /* pCheckMediaType */
604         NULL, /* pQualityNotify */
605         CAudioRendererPinImpl_Receive, /* pReceive */
606         CAudioRendererPinImpl_ReceiveCanBlock, /* pReceiveCanBlock */
607         CAudioRendererPinImpl_EndOfStream, /* pEndOfStream */
608         CAudioRendererPinImpl_BeginFlush, /* pBeginFlush */
609         CAudioRendererPinImpl_EndFlush, /* pEndFlush */
610         CAudioRendererPinImpl_NewSegment, /* pNewSegment */
611 };
612
613
614 /***************************************************************************
615  *
616  *      new/delete CAudioRendererImpl
617  *
618  */
619
620 /* can I use offsetof safely? - FIXME? */
621 static QUARTZ_IFEntry FilterIFEntries[] =
622 {
623   { &IID_IPersist, offsetof(CAudioRendererImpl,basefilter)-offsetof(CAudioRendererImpl,unk) },
624   { &IID_IMediaFilter, offsetof(CAudioRendererImpl,basefilter)-offsetof(CAudioRendererImpl,unk) },
625   { &IID_IBaseFilter, offsetof(CAudioRendererImpl,basefilter)-offsetof(CAudioRendererImpl,unk) },
626   { &IID_IBasicAudio, offsetof(CAudioRendererImpl,basaud)-offsetof(CAudioRendererImpl,unk) },
627 };
628
629 static HRESULT CAudioRendererImpl_OnQueryInterface(
630         IUnknown* punk, const IID* piid, void** ppobj )
631 {
632         CAudioRendererImpl_THIS(punk,unk);
633
634         if ( This->pSeekPass == NULL )
635                 return E_NOINTERFACE;
636
637         if ( IsEqualGUID( &IID_IMediaPosition, piid ) ||
638                  IsEqualGUID( &IID_IMediaSeeking, piid ) )
639         {
640                 TRACE( "IMediaSeeking(or IMediaPosition) is queried\n" );
641                 return IUnknown_QueryInterface( (IUnknown*)(&This->pSeekPass->unk), piid, ppobj );
642         }
643
644         return E_NOINTERFACE;
645 }
646
647 static void QUARTZ_DestroyAudioRenderer(IUnknown* punk)
648 {
649         CAudioRendererImpl_THIS(punk,unk);
650
651         TRACE( "(%p)\n", This );
652
653         if ( This->pPin != NULL )
654         {
655                 IUnknown_Release(This->pPin->unk.punkControl);
656                 This->pPin = NULL;
657         }
658         if ( This->pSeekPass != NULL )
659         {
660                 IUnknown_Release((IUnknown*)&This->pSeekPass->unk);
661                 This->pSeekPass = NULL;
662         }
663
664         CAudioRendererImpl_UninitIBasicAudio(This);
665         CBaseFilterImpl_UninitIBaseFilter(&This->basefilter);
666
667         DeleteCriticalSection( &This->m_csReceive );
668 }
669
670 HRESULT QUARTZ_CreateAudioRenderer(IUnknown* punkOuter,void** ppobj)
671 {
672         CAudioRendererImpl*     This = NULL;
673         HRESULT hr;
674
675         TRACE("(%p,%p)\n",punkOuter,ppobj);
676
677         This = (CAudioRendererImpl*)
678                 QUARTZ_AllocObj( sizeof(CAudioRendererImpl) );
679         if ( This == NULL )
680                 return E_OUTOFMEMORY;
681         This->pSeekPass = NULL;
682         This->pPin = NULL;
683         This->m_fInFlush = FALSE;
684         This->m_fWaveOutInit = FALSE;
685         This->m_hEventRender = (HANDLE)NULL;
686
687         QUARTZ_IUnkInit( &This->unk, punkOuter );
688         This->qiext.pNext = NULL;
689         This->qiext.pOnQueryInterface = &CAudioRendererImpl_OnQueryInterface;
690         QUARTZ_IUnkAddDelegation( &This->unk, &This->qiext );
691
692         hr = CBaseFilterImpl_InitIBaseFilter(
693                 &This->basefilter,
694                 This->unk.punkControl,
695                 &CLSID_AudioRender,
696                 QUARTZ_AudioRender_Name,
697                 &filterhandlers );
698         if ( SUCCEEDED(hr) )
699         {
700                 hr = CAudioRendererImpl_InitIBasicAudio(This);
701                 if ( FAILED(hr) )
702                 {
703                         CBaseFilterImpl_UninitIBaseFilter(&This->basefilter);
704                 }
705         }
706
707         if ( FAILED(hr) )
708         {
709                 QUARTZ_FreeObj(This);
710                 return hr;
711         }
712
713         This->unk.pEntries = FilterIFEntries;
714         This->unk.dwEntries = sizeof(FilterIFEntries)/sizeof(FilterIFEntries[0]);
715         This->unk.pOnFinalRelease = QUARTZ_DestroyAudioRenderer;
716
717         InitializeCriticalSection( &This->m_csReceive );
718
719         hr = QUARTZ_CreateAudioRendererPin(
720                 This,
721                 &This->basefilter.csFilter,
722                 &This->m_csReceive,
723                 &This->pPin );
724         if ( SUCCEEDED(hr) )
725                 hr = QUARTZ_CompList_AddComp(
726                         This->basefilter.pInPins,
727                         (IUnknown*)&This->pPin->pin,
728                         NULL, 0 );
729         if ( SUCCEEDED(hr) )
730                 hr = QUARTZ_CreateSeekingPassThruInternal(
731                         (IUnknown*)&(This->unk), &This->pSeekPass,
732                         TRUE, (IPin*)&(This->pPin->pin) );
733
734         if ( FAILED(hr) )
735         {
736                 IUnknown_Release( This->unk.punkControl );
737                 return hr;
738         }
739
740         *ppobj = (void*)&(This->unk);
741
742         return S_OK;
743 }
744
745
746 /***************************************************************************
747  *
748  *      new/delete CAudioRendererPinImpl
749  *
750  */
751
752 /* can I use offsetof safely? - FIXME? */
753 static QUARTZ_IFEntry PinIFEntries[] =
754 {
755   { &IID_IPin, offsetof(CAudioRendererPinImpl,pin)-offsetof(CAudioRendererPinImpl,unk) },
756   { &IID_IMemInputPin, offsetof(CAudioRendererPinImpl,meminput)-offsetof(CAudioRendererPinImpl,unk) },
757 };
758
759 static void QUARTZ_DestroyAudioRendererPin(IUnknown* punk)
760 {
761         CAudioRendererPinImpl_THIS(punk,unk);
762
763         TRACE( "(%p)\n", This );
764
765         CPinBaseImpl_UninitIPin( &This->pin );
766         CMemInputPinBaseImpl_UninitIMemInputPin( &This->meminput );
767 }
768
769 HRESULT QUARTZ_CreateAudioRendererPin(
770         CAudioRendererImpl* pFilter,
771         CRITICAL_SECTION* pcsPin,
772         CRITICAL_SECTION* pcsPinReceive,
773         CAudioRendererPinImpl** ppPin)
774 {
775         CAudioRendererPinImpl*  This = NULL;
776         HRESULT hr;
777
778         TRACE("(%p,%p,%p,%p)\n",pFilter,pcsPin,pcsPinReceive,ppPin);
779
780         This = (CAudioRendererPinImpl*)
781                 QUARTZ_AllocObj( sizeof(CAudioRendererPinImpl) );
782         if ( This == NULL )
783                 return E_OUTOFMEMORY;
784
785         QUARTZ_IUnkInit( &This->unk, NULL );
786         This->pRender = pFilter;
787
788         hr = CPinBaseImpl_InitIPin(
789                 &This->pin,
790                 This->unk.punkControl,
791                 pcsPin, pcsPinReceive,
792                 &pFilter->basefilter,
793                 QUARTZ_AudioRenderPin_Name,
794                 FALSE,
795                 &pinhandlers );
796
797         if ( SUCCEEDED(hr) )
798         {
799                 hr = CMemInputPinBaseImpl_InitIMemInputPin(
800                         &This->meminput,
801                         This->unk.punkControl,
802                         &This->pin );
803                 if ( FAILED(hr) )
804                 {
805                         CPinBaseImpl_UninitIPin( &This->pin );
806                 }
807         }
808
809         if ( FAILED(hr) )
810         {
811                 QUARTZ_FreeObj(This);
812                 return hr;
813         }
814
815         This->unk.pEntries = PinIFEntries;
816         This->unk.dwEntries = sizeof(PinIFEntries)/sizeof(PinIFEntries[0]);
817         This->unk.pOnFinalRelease = QUARTZ_DestroyAudioRendererPin;
818
819         *ppPin = This;
820
821         TRACE("returned successfully.\n");
822
823         return S_OK;
824 }
825
826
827 /***************************************************************************
828  *
829  *      CAudioRendererImpl::IBasicAudio
830  *
831  */
832
833 static HRESULT WINAPI
834 IBasicAudio_fnQueryInterface(IBasicAudio* iface,REFIID riid,void** ppobj)
835 {
836         CAudioRendererImpl_THIS(iface,basaud);
837
838         TRACE("(%p)->()\n",This);
839
840         return IUnknown_QueryInterface(This->unk.punkControl,riid,ppobj);
841 }
842
843 static ULONG WINAPI
844 IBasicAudio_fnAddRef(IBasicAudio* iface)
845 {
846         CAudioRendererImpl_THIS(iface,basaud);
847
848         TRACE("(%p)->()\n",This);
849
850         return IUnknown_AddRef(This->unk.punkControl);
851 }
852
853 static ULONG WINAPI
854 IBasicAudio_fnRelease(IBasicAudio* iface)
855 {
856         CAudioRendererImpl_THIS(iface,basaud);
857
858         TRACE("(%p)->()\n",This);
859
860         return IUnknown_Release(This->unk.punkControl);
861 }
862
863 static HRESULT WINAPI
864 IBasicAudio_fnGetTypeInfoCount(IBasicAudio* iface,UINT* pcTypeInfo)
865 {
866         CAudioRendererImpl_THIS(iface,basaud);
867
868         FIXME("(%p)->()\n",This);
869
870         return E_NOTIMPL;
871 }
872
873 static HRESULT WINAPI
874 IBasicAudio_fnGetTypeInfo(IBasicAudio* iface,UINT iTypeInfo, LCID lcid, ITypeInfo** ppobj)
875 {
876         CAudioRendererImpl_THIS(iface,basaud);
877
878         FIXME("(%p)->()\n",This);
879
880         return E_NOTIMPL;
881 }
882
883 static HRESULT WINAPI
884 IBasicAudio_fnGetIDsOfNames(IBasicAudio* iface,REFIID riid, LPOLESTR* ppwszName, UINT cNames, LCID lcid, DISPID* pDispId)
885 {
886         CAudioRendererImpl_THIS(iface,basaud);
887
888         FIXME("(%p)->()\n",This);
889
890         return E_NOTIMPL;
891 }
892
893 static HRESULT WINAPI
894 IBasicAudio_fnInvoke(IBasicAudio* iface,DISPID DispId, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarRes, EXCEPINFO* pExcepInfo, UINT* puArgErr)
895 {
896         CAudioRendererImpl_THIS(iface,basaud);
897
898         FIXME("(%p)->()\n",This);
899
900         return E_NOTIMPL;
901 }
902
903
904 static HRESULT WINAPI
905 IBasicAudio_fnput_Volume(IBasicAudio* iface,long lVol)
906 {
907         CAudioRendererImpl_THIS(iface,basaud);
908
909         FIXME("(%p)->()\n",This);
910
911         return E_NOTIMPL;
912 }
913
914 static HRESULT WINAPI
915 IBasicAudio_fnget_Volume(IBasicAudio* iface,long* plVol)
916 {
917         CAudioRendererImpl_THIS(iface,basaud);
918
919         FIXME("(%p)->()\n",This);
920
921         return E_NOTIMPL;
922 }
923
924 static HRESULT WINAPI
925 IBasicAudio_fnput_Balance(IBasicAudio* iface,long lBalance)
926 {
927         CAudioRendererImpl_THIS(iface,basaud);
928
929         FIXME("(%p)->()\n",This);
930
931         return E_NOTIMPL;
932 }
933
934 static HRESULT WINAPI
935 IBasicAudio_fnget_Balance(IBasicAudio* iface,long* plBalance)
936 {
937         CAudioRendererImpl_THIS(iface,basaud);
938
939         FIXME("(%p)->()\n",This);
940
941         return E_NOTIMPL;
942 }
943
944
945 static ICOM_VTABLE(IBasicAudio) ibasicaudio =
946 {
947         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
948         /* IUnknown fields */
949         IBasicAudio_fnQueryInterface,
950         IBasicAudio_fnAddRef,
951         IBasicAudio_fnRelease,
952         /* IDispatch fields */
953         IBasicAudio_fnGetTypeInfoCount,
954         IBasicAudio_fnGetTypeInfo,
955         IBasicAudio_fnGetIDsOfNames,
956         IBasicAudio_fnInvoke,
957         /* IBasicAudio fields */
958         IBasicAudio_fnput_Volume,
959         IBasicAudio_fnget_Volume,
960         IBasicAudio_fnput_Balance,
961         IBasicAudio_fnget_Balance,
962 };
963
964
965 HRESULT CAudioRendererImpl_InitIBasicAudio( CAudioRendererImpl* This )
966 {
967         TRACE("(%p)\n",This);
968         ICOM_VTBL(&This->basaud) = &ibasicaudio;
969
970         return NOERROR;
971 }
972
973 void CAudioRendererImpl_UninitIBasicAudio( CAudioRendererImpl* This )
974 {
975         TRACE("(%p)\n",This);
976 }
977