Storing an IP address in a signed int results in bugs if it starts
[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 #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
668 HRESULT QUARTZ_CreateAudioRenderer(IUnknown* punkOuter,void** ppobj)
669 {
670         CAudioRendererImpl*     This = NULL;
671         HRESULT hr;
672
673         TRACE("(%p,%p)\n",punkOuter,ppobj);
674
675         This = (CAudioRendererImpl*)
676                 QUARTZ_AllocObj( sizeof(CAudioRendererImpl) );
677         if ( This == NULL )
678                 return E_OUTOFMEMORY;
679         This->pSeekPass = NULL;
680         This->pPin = NULL;
681         This->m_fInFlush = FALSE;
682         This->m_fWaveOutInit = FALSE;
683         This->m_hEventRender = (HANDLE)NULL;
684
685         QUARTZ_IUnkInit( &This->unk, punkOuter );
686         This->qiext.pNext = NULL;
687         This->qiext.pOnQueryInterface = &CAudioRendererImpl_OnQueryInterface;
688         QUARTZ_IUnkAddDelegation( &This->unk, &This->qiext );
689
690         hr = CBaseFilterImpl_InitIBaseFilter(
691                 &This->basefilter,
692                 This->unk.punkControl,
693                 &CLSID_AudioRender,
694                 QUARTZ_AudioRender_Name,
695                 &filterhandlers );
696         if ( SUCCEEDED(hr) )
697         {
698                 hr = CAudioRendererImpl_InitIBasicAudio(This);
699                 if ( FAILED(hr) )
700                 {
701                         CBaseFilterImpl_UninitIBaseFilter(&This->basefilter);
702                 }
703         }
704
705         if ( FAILED(hr) )
706         {
707                 QUARTZ_FreeObj(This);
708                 return hr;
709         }
710
711         This->unk.pEntries = FilterIFEntries;
712         This->unk.dwEntries = sizeof(FilterIFEntries)/sizeof(FilterIFEntries[0]);
713         This->unk.pOnFinalRelease = QUARTZ_DestroyAudioRenderer;
714
715         hr = QUARTZ_CreateAudioRendererPin(
716                 This,
717                 &This->basefilter.csFilter,
718                 &This->pPin );
719         if ( SUCCEEDED(hr) )
720                 hr = QUARTZ_CompList_AddComp(
721                         This->basefilter.pInPins,
722                         (IUnknown*)&This->pPin->pin,
723                         NULL, 0 );
724         if ( SUCCEEDED(hr) )
725                 hr = QUARTZ_CreateSeekingPassThruInternal(
726                         (IUnknown*)&(This->unk), &This->pSeekPass,
727                         TRUE, (IPin*)&(This->pPin->pin) );
728
729         if ( FAILED(hr) )
730         {
731                 IUnknown_Release( This->unk.punkControl );
732                 return hr;
733         }
734
735         *ppobj = (void*)&(This->unk);
736
737         return S_OK;
738 }
739
740
741 /***************************************************************************
742  *
743  *      new/delete CAudioRendererPinImpl
744  *
745  */
746
747 /* can I use offsetof safely? - FIXME? */
748 static QUARTZ_IFEntry PinIFEntries[] =
749 {
750   { &IID_IPin, offsetof(CAudioRendererPinImpl,pin)-offsetof(CAudioRendererPinImpl,unk) },
751   { &IID_IMemInputPin, offsetof(CAudioRendererPinImpl,meminput)-offsetof(CAudioRendererPinImpl,unk) },
752 };
753
754 static void QUARTZ_DestroyAudioRendererPin(IUnknown* punk)
755 {
756         CAudioRendererPinImpl_THIS(punk,unk);
757
758         TRACE( "(%p)\n", This );
759
760         CPinBaseImpl_UninitIPin( &This->pin );
761         CMemInputPinBaseImpl_UninitIMemInputPin( &This->meminput );
762 }
763
764 HRESULT QUARTZ_CreateAudioRendererPin(
765         CAudioRendererImpl* pFilter,
766         CRITICAL_SECTION* pcsPin,
767         CAudioRendererPinImpl** ppPin)
768 {
769         CAudioRendererPinImpl*  This = NULL;
770         HRESULT hr;
771
772         TRACE("(%p,%p,%p)\n",pFilter,pcsPin,ppPin);
773
774         This = (CAudioRendererPinImpl*)
775                 QUARTZ_AllocObj( sizeof(CAudioRendererPinImpl) );
776         if ( This == NULL )
777                 return E_OUTOFMEMORY;
778
779         QUARTZ_IUnkInit( &This->unk, NULL );
780         This->pRender = pFilter;
781
782         hr = CPinBaseImpl_InitIPin(
783                 &This->pin,
784                 This->unk.punkControl,
785                 pcsPin,
786                 &pFilter->basefilter,
787                 QUARTZ_AudioRenderPin_Name,
788                 FALSE,
789                 &pinhandlers );
790
791         if ( SUCCEEDED(hr) )
792         {
793                 hr = CMemInputPinBaseImpl_InitIMemInputPin(
794                         &This->meminput,
795                         This->unk.punkControl,
796                         &This->pin );
797                 if ( FAILED(hr) )
798                 {
799                         CPinBaseImpl_UninitIPin( &This->pin );
800                 }
801         }
802
803         if ( FAILED(hr) )
804         {
805                 QUARTZ_FreeObj(This);
806                 return hr;
807         }
808
809         This->unk.pEntries = PinIFEntries;
810         This->unk.dwEntries = sizeof(PinIFEntries)/sizeof(PinIFEntries[0]);
811         This->unk.pOnFinalRelease = QUARTZ_DestroyAudioRendererPin;
812
813         *ppPin = This;
814
815         TRACE("returned successfully.\n");
816
817         return S_OK;
818 }
819
820
821 /***************************************************************************
822  *
823  *      CAudioRendererImpl::IBasicAudio
824  *
825  */
826
827 static HRESULT WINAPI
828 IBasicAudio_fnQueryInterface(IBasicAudio* iface,REFIID riid,void** ppobj)
829 {
830         CAudioRendererImpl_THIS(iface,basaud);
831
832         TRACE("(%p)->()\n",This);
833
834         return IUnknown_QueryInterface(This->unk.punkControl,riid,ppobj);
835 }
836
837 static ULONG WINAPI
838 IBasicAudio_fnAddRef(IBasicAudio* iface)
839 {
840         CAudioRendererImpl_THIS(iface,basaud);
841
842         TRACE("(%p)->()\n",This);
843
844         return IUnknown_AddRef(This->unk.punkControl);
845 }
846
847 static ULONG WINAPI
848 IBasicAudio_fnRelease(IBasicAudio* iface)
849 {
850         CAudioRendererImpl_THIS(iface,basaud);
851
852         TRACE("(%p)->()\n",This);
853
854         return IUnknown_Release(This->unk.punkControl);
855 }
856
857 static HRESULT WINAPI
858 IBasicAudio_fnGetTypeInfoCount(IBasicAudio* iface,UINT* pcTypeInfo)
859 {
860         CAudioRendererImpl_THIS(iface,basaud);
861
862         FIXME("(%p)->()\n",This);
863
864         return E_NOTIMPL;
865 }
866
867 static HRESULT WINAPI
868 IBasicAudio_fnGetTypeInfo(IBasicAudio* iface,UINT iTypeInfo, LCID lcid, ITypeInfo** ppobj)
869 {
870         CAudioRendererImpl_THIS(iface,basaud);
871
872         FIXME("(%p)->()\n",This);
873
874         return E_NOTIMPL;
875 }
876
877 static HRESULT WINAPI
878 IBasicAudio_fnGetIDsOfNames(IBasicAudio* iface,REFIID riid, LPOLESTR* ppwszName, UINT cNames, LCID lcid, DISPID* pDispId)
879 {
880         CAudioRendererImpl_THIS(iface,basaud);
881
882         FIXME("(%p)->()\n",This);
883
884         return E_NOTIMPL;
885 }
886
887 static HRESULT WINAPI
888 IBasicAudio_fnInvoke(IBasicAudio* iface,DISPID DispId, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarRes, EXCEPINFO* pExcepInfo, UINT* puArgErr)
889 {
890         CAudioRendererImpl_THIS(iface,basaud);
891
892         FIXME("(%p)->()\n",This);
893
894         return E_NOTIMPL;
895 }
896
897
898 static HRESULT WINAPI
899 IBasicAudio_fnput_Volume(IBasicAudio* iface,long lVol)
900 {
901         CAudioRendererImpl_THIS(iface,basaud);
902
903         FIXME("(%p)->()\n",This);
904
905         return E_NOTIMPL;
906 }
907
908 static HRESULT WINAPI
909 IBasicAudio_fnget_Volume(IBasicAudio* iface,long* plVol)
910 {
911         CAudioRendererImpl_THIS(iface,basaud);
912
913         FIXME("(%p)->()\n",This);
914
915         return E_NOTIMPL;
916 }
917
918 static HRESULT WINAPI
919 IBasicAudio_fnput_Balance(IBasicAudio* iface,long lBalance)
920 {
921         CAudioRendererImpl_THIS(iface,basaud);
922
923         FIXME("(%p)->()\n",This);
924
925         return E_NOTIMPL;
926 }
927
928 static HRESULT WINAPI
929 IBasicAudio_fnget_Balance(IBasicAudio* iface,long* plBalance)
930 {
931         CAudioRendererImpl_THIS(iface,basaud);
932
933         FIXME("(%p)->()\n",This);
934
935         return E_NOTIMPL;
936 }
937
938
939 static ICOM_VTABLE(IBasicAudio) ibasicaudio =
940 {
941         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
942         /* IUnknown fields */
943         IBasicAudio_fnQueryInterface,
944         IBasicAudio_fnAddRef,
945         IBasicAudio_fnRelease,
946         /* IDispatch fields */
947         IBasicAudio_fnGetTypeInfoCount,
948         IBasicAudio_fnGetTypeInfo,
949         IBasicAudio_fnGetIDsOfNames,
950         IBasicAudio_fnInvoke,
951         /* IBasicAudio fields */
952         IBasicAudio_fnput_Volume,
953         IBasicAudio_fnget_Volume,
954         IBasicAudio_fnput_Balance,
955         IBasicAudio_fnget_Balance,
956 };
957
958
959 HRESULT CAudioRendererImpl_InitIBasicAudio( CAudioRendererImpl* This )
960 {
961         TRACE("(%p)\n",This);
962         ICOM_VTBL(&This->basaud) = &ibasicaudio;
963
964         return NOERROR;
965 }
966
967 void CAudioRendererImpl_UninitIBasicAudio( CAudioRendererImpl* This )
968 {
969         TRACE("(%p)\n",This);
970 }
971