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