2 * Audio Renderer (CLSID_AudioRender)
5 * - implements IRefereneceClock.
6 * - implements seeking.
8 * hidenori@a2.ctktv.ne.jp
19 #include "wine/obj_base.h"
20 #include "wine/obj_oleaut.h"
27 #include "debugtools.h"
28 DEFAULT_DEBUG_CHANNEL(quartz
);
30 #include "quartz_private.h"
34 static const WCHAR QUARTZ_AudioRender_Name
[] =
35 { 'A','u','d','i','o',' ','R','e','n','d','e','r',0 };
36 static const WCHAR QUARTZ_AudioRenderPin_Name
[] =
41 /***************************************************************************
43 * CAudioRendererImpl waveOut methods (internal)
48 HRESULT
QUARTZ_HRESULT_From_MMRESULT( MMRESULT mr
)
54 case MMSYSERR_NOERROR
:
65 void CAudioRendererImpl_waveOutEventCallback(
66 HWAVEOUT hwo
, UINT uMsg
,
67 DWORD dwInstance
, DWORD dwParam1
, DWORD dwParam2
)
69 CAudioRendererImpl
* This
= (CAudioRendererImpl
*)dwInstance
;
71 if ( uMsg
== WOM_DONE
)
72 SetEvent( This
->m_hEventRender
);
76 void CAudioRendererImpl_waveOutReset(
77 CAudioRendererImpl
* This
)
79 if ( !This
->m_fWaveOutInit
)
82 waveOutReset( This
->m_hWaveOut
);
83 SetEvent( This
->m_hEventRender
);
87 void CAudioRendererImpl_waveOutUninit(
88 CAudioRendererImpl
* This
)
94 if ( !This
->m_fWaveOutInit
)
97 waveOutReset( This
->m_hWaveOut
);
98 SetEvent( This
->m_hEventRender
);
100 for ( i
= 0; i
< WINE_QUARTZ_WAVEOUT_COUNT
; i
++ )
102 if ( This
->m_hdr
[i
].dwFlags
& WHDR_PREPARED
)
104 waveOutUnprepareHeader(
106 &This
->m_hdr
[i
], sizeof(WAVEHDR
) );
107 This
->m_hdr
[i
].dwFlags
= 0;
109 if ( This
->m_hdr
[i
].lpData
!= NULL
)
111 QUARTZ_FreeMem( This
->m_hdr
[i
].lpData
);
112 This
->m_hdr
[i
].lpData
= NULL
;
116 waveOutClose( This
->m_hWaveOut
);
117 This
->m_hWaveOut
= (HWAVEOUT
)NULL
;
118 if ( This
->m_hEventRender
!= (HANDLE
)NULL
)
120 CloseHandle( This
->m_hEventRender
);
121 This
->m_hEventRender
= (HANDLE
)NULL
;
124 This
->m_fWaveOutInit
= FALSE
;
128 HRESULT
CAudioRendererImpl_waveOutInit(
129 CAudioRendererImpl
* This
, WAVEFORMATEX
* pwfx
)
136 if ( This
->m_fWaveOutInit
)
141 if ( pwfx
->nBlockAlign
== 0 )
144 This
->m_hEventRender
= (HANDLE
)NULL
;
145 This
->m_hWaveOut
= (HWAVEOUT
)NULL
;
146 This
->m_dwBlockSize
= 0;
147 This
->m_phdrCur
= NULL
;
148 ZeroMemory( &This
->m_hdr
, sizeof(This
->m_hdr
) );
152 &This
->m_hWaveOut
, WAVE_MAPPER
, pwfx
,
153 (DWORD
)CAudioRendererImpl_waveOutEventCallback
, (DWORD
)This
,
155 hr
= QUARTZ_HRESULT_From_MMRESULT( mr
);
158 This
->m_fWaveOutInit
= TRUE
;
160 This
->m_hEventRender
= CreateEventA(
161 NULL
, TRUE
, TRUE
, NULL
);
162 if ( This
->m_hEventRender
== (HANDLE
)NULL
)
168 dwBlockSize
= pwfx
->nAvgBytesPerSec
/ pwfx
->nBlockAlign
;
169 if ( dwBlockSize
== 0 )
171 dwBlockSize
*= pwfx
->nBlockAlign
;
172 This
->m_dwBlockSize
= dwBlockSize
;
174 for ( i
= 0; i
< WINE_QUARTZ_WAVEOUT_COUNT
; i
++ )
176 This
->m_hdr
[i
].lpData
= (CHAR
*)QUARTZ_AllocMem( dwBlockSize
);
177 if ( This
->m_hdr
[i
].lpData
== NULL
)
182 mr
= waveOutPrepareHeader(
184 &This
->m_hdr
[i
], sizeof(WAVEHDR
) );
185 hr
= QUARTZ_HRESULT_From_MMRESULT( mr
);
188 This
->m_hdr
[i
].dwFlags
|= WHDR_DONE
;
189 This
->m_hdr
[i
].dwBufferLength
= dwBlockSize
;
190 This
->m_hdr
[i
].dwUser
= i
;
195 CAudioRendererImpl_waveOutUninit(This
);
200 WAVEHDR
* CAudioRendererImpl_waveOutGetBuffer(
201 CAudioRendererImpl
* This
)
205 if ( !This
->m_fWaveOutInit
)
208 if ( This
->m_phdrCur
!= NULL
)
209 return This
->m_phdrCur
;
211 for ( i
= 0; i
< WINE_QUARTZ_WAVEOUT_COUNT
; i
++ )
213 if ( This
->m_hdr
[i
].dwFlags
& WHDR_DONE
)
215 This
->m_phdrCur
= &(This
->m_hdr
[i
]);
216 This
->m_phdrCur
->dwFlags
&= ~WHDR_DONE
;
217 This
->m_phdrCur
->dwBufferLength
= 0;
218 return This
->m_phdrCur
;
226 HRESULT
CAudioRendererImpl_waveOutWriteData(
227 CAudioRendererImpl
* This
,
228 const BYTE
* pData
, DWORD cbData
, DWORD
* pcbWritten
)
234 if ( !This
->m_fWaveOutInit
)
240 if ( CAudioRendererImpl_waveOutGetBuffer(This
) == NULL
)
243 cbAvail
= This
->m_dwBlockSize
- This
->m_phdrCur
->dwBufferLength
;
244 if ( cbAvail
> cbData
)
246 memcpy( This
->m_phdrCur
->lpData
, pData
, cbAvail
);
249 This
->m_phdrCur
->dwBufferLength
+= cbAvail
;
251 *pcbWritten
= cbAvail
;
257 HRESULT
CAudioRendererImpl_waveOutFlush(
258 CAudioRendererImpl
* This
)
263 if ( !This
->m_fWaveOutInit
)
265 if ( This
->m_phdrCur
== NULL
)
268 if ( This
->m_phdrCur
->dwBufferLength
== 0 )
273 This
->m_phdrCur
, sizeof(WAVEHDR
) );
274 hr
= QUARTZ_HRESULT_From_MMRESULT( mr
);
278 This
->m_phdrCur
= NULL
;
283 HRESULT
CAudioRendererImpl_waveOutGetVolume(
284 CAudioRendererImpl
* This
,
285 DWORD
* pdwLeft
, DWORD
* pdwRight
)
291 if ( !This
->m_fWaveOutInit
)
294 mr
= waveOutGetVolume(
295 This
->m_hWaveOut
, &dwVol
);
296 hr
= QUARTZ_HRESULT_From_MMRESULT( mr
);
300 *pdwLeft
= LOWORD(dwVol
);
301 *pdwRight
= HIWORD(dwVol
);
307 HRESULT
CAudioRendererImpl_waveOutSetVolume(
308 CAudioRendererImpl
* This
,
309 DWORD dwLeft
, DWORD dwRight
)
314 if ( !This
->m_fWaveOutInit
)
317 dwVol
= dwLeft
| (dwRight
<<16);
319 mr
= waveOutSetVolume(
320 This
->m_hWaveOut
, dwVol
);
321 return QUARTZ_HRESULT_From_MMRESULT( mr
);
324 /***************************************************************************
326 * CAudioRendererImpl methods
331 static HRESULT
CAudioRendererImpl_OnActive( CBaseFilterImpl
* pImpl
)
333 CAudioRendererImpl_THIS(pImpl
,basefilter
);
336 FIXME( "(%p)\n", This
);
338 if ( This
->pPin
->pin
.pmtConn
== NULL
)
341 pwfx
= (WAVEFORMATEX
*)This
->pPin
->pin
.pmtConn
->pbFormat
;
345 This
->m_fInFlush
= FALSE
;
347 return CAudioRendererImpl_waveOutInit(This
,pwfx
);
350 static HRESULT
CAudioRendererImpl_OnInactive( CBaseFilterImpl
* pImpl
)
352 CAudioRendererImpl_THIS(pImpl
,basefilter
);
354 FIXME( "(%p)\n", This
);
356 CAudioRendererImpl_waveOutUninit(This
);
358 This
->m_fInFlush
= FALSE
;
360 TRACE("returned\n" );
365 static const CBaseFilterHandlers filterhandlers
=
367 CAudioRendererImpl_OnActive
, /* pOnActive */
368 CAudioRendererImpl_OnInactive
, /* pOnInactive */
372 /***************************************************************************
374 * CAudioRendererPinImpl methods
378 static HRESULT
CAudioRendererPinImpl_CheckMediaType( CPinBaseImpl
* pImpl
, const AM_MEDIA_TYPE
* pmt
)
380 CAudioRendererPinImpl_THIS(pImpl
,pin
);
381 const WAVEFORMATEX
* pwfx
;
383 TRACE("(%p,%p)\n",This
,pmt
);
385 if ( !IsEqualGUID( &pmt
->majortype
, &MEDIATYPE_Audio
) )
387 if ( !IsEqualGUID( &pmt
->subtype
, &MEDIASUBTYPE_PCM
) )
389 if ( !IsEqualGUID( &pmt
->formattype
, &FORMAT_WaveFormatEx
) )
391 if ( pmt
->cbFormat
< (sizeof(WAVEFORMATEX
)-sizeof(WORD
)) )
394 pwfx
= (const WAVEFORMATEX
*)pmt
->pbFormat
;
397 if ( pwfx
->wFormatTag
!= 1 )
403 static HRESULT
CAudioRendererPinImpl_Receive( CPinBaseImpl
* pImpl
, IMediaSample
* pSample
)
405 CAudioRendererPinImpl_THIS(pImpl
,pin
);
411 FIXME( "(%p,%p)\n",This
,pSample
);
413 if ( !This
->pRender
->m_fWaveOutInit
)
415 if ( This
->pRender
->m_fInFlush
)
417 if ( pSample
== NULL
)
420 hr
= IMediaSample_GetPointer( pSample
, &pData
);
423 dwDataLength
= (DWORD
)IMediaSample_GetActualDataLength( pSample
);
427 TRACE("trying to write %lu bytes\n",dwDataLength
);
429 ResetEvent( This
->pRender
->m_hEventRender
);
430 hr
= CAudioRendererImpl_waveOutWriteData(
431 This
->pRender
,pData
,dwDataLength
,&dwWritten
);
436 WaitForSingleObject( This
->pRender
->m_hEventRender
, INFINITE
);
440 dwDataLength
-= dwWritten
;
441 hr
= CAudioRendererImpl_waveOutFlush(This
->pRender
);
444 if ( dwDataLength
== 0 )
451 static HRESULT
CAudioRendererPinImpl_ReceiveCanBlock( CPinBaseImpl
* pImpl
)
453 CAudioRendererPinImpl_THIS(pImpl
,pin
);
455 TRACE( "(%p)\n", This
);
461 static HRESULT
CAudioRendererPinImpl_EndOfStream( CPinBaseImpl
* pImpl
)
463 CAudioRendererPinImpl_THIS(pImpl
,pin
);
465 FIXME( "(%p)\n", This
);
467 This
->pRender
->m_fInFlush
= FALSE
;
469 /* FIXME - don't notify twice until stopped or seeked. */
470 return CBaseFilterImpl_MediaEventNotify(
471 &This
->pRender
->basefilter
, EC_COMPLETE
,
472 (LONG_PTR
)S_OK
, (LONG_PTR
)(IBaseFilter
*)(This
->pRender
) );
475 static HRESULT
CAudioRendererPinImpl_BeginFlush( CPinBaseImpl
* pImpl
)
477 CAudioRendererPinImpl_THIS(pImpl
,pin
);
479 FIXME( "(%p)\n", This
);
481 This
->pRender
->m_fInFlush
= TRUE
;
482 CAudioRendererImpl_waveOutReset(This
->pRender
);
487 static HRESULT
CAudioRendererPinImpl_EndFlush( CPinBaseImpl
* pImpl
)
489 CAudioRendererPinImpl_THIS(pImpl
,pin
);
491 FIXME( "(%p)\n", This
);
493 This
->pRender
->m_fInFlush
= FALSE
;
498 static HRESULT
CAudioRendererPinImpl_NewSegment( CPinBaseImpl
* pImpl
, REFERENCE_TIME rtStart
, REFERENCE_TIME rtStop
, double rate
)
500 CAudioRendererPinImpl_THIS(pImpl
,pin
);
502 FIXME( "(%p)\n", This
);
504 This
->pRender
->m_fInFlush
= FALSE
;
509 static const CBasePinHandlers pinhandlers
=
511 NULL
, /* pOnPreConnect */
512 NULL
, /* pOnPostConnect */
513 NULL
, /* pOnDisconnect */
514 CAudioRendererPinImpl_CheckMediaType
, /* pCheckMediaType */
515 NULL
, /* pQualityNotify */
516 CAudioRendererPinImpl_Receive
, /* pReceive */
517 CAudioRendererPinImpl_ReceiveCanBlock
, /* pReceiveCanBlock */
518 CAudioRendererPinImpl_EndOfStream
, /* pEndOfStream */
519 CAudioRendererPinImpl_BeginFlush
, /* pBeginFlush */
520 CAudioRendererPinImpl_EndFlush
, /* pEndFlush */
521 CAudioRendererPinImpl_NewSegment
, /* pNewSegment */
525 /***************************************************************************
527 * new/delete CAudioRendererImpl
531 /* can I use offsetof safely? - FIXME? */
532 static QUARTZ_IFEntry FilterIFEntries
[] =
534 { &IID_IPersist
, offsetof(CAudioRendererImpl
,basefilter
)-offsetof(CAudioRendererImpl
,unk
) },
535 { &IID_IMediaFilter
, offsetof(CAudioRendererImpl
,basefilter
)-offsetof(CAudioRendererImpl
,unk
) },
536 { &IID_IBaseFilter
, offsetof(CAudioRendererImpl
,basefilter
)-offsetof(CAudioRendererImpl
,unk
) },
537 { &IID_IBasicAudio
, offsetof(CAudioRendererImpl
,basaud
)-offsetof(CAudioRendererImpl
,unk
) },
540 static void QUARTZ_DestroyAudioRenderer(IUnknown
* punk
)
542 CAudioRendererImpl_THIS(punk
,unk
);
544 TRACE( "(%p)\n", This
);
546 if ( This
->pPin
!= NULL
)
548 IUnknown_Release(This
->pPin
->unk
.punkControl
);
552 CAudioRendererImpl_UninitIBasicAudio(This
);
553 CBaseFilterImpl_UninitIBaseFilter(&This
->basefilter
);
556 HRESULT
QUARTZ_CreateAudioRenderer(IUnknown
* punkOuter
,void** ppobj
)
558 CAudioRendererImpl
* This
= NULL
;
561 TRACE("(%p,%p)\n",punkOuter
,ppobj
);
563 This
= (CAudioRendererImpl
*)
564 QUARTZ_AllocObj( sizeof(CAudioRendererImpl
) );
566 return E_OUTOFMEMORY
;
568 This
->m_fInFlush
= FALSE
;
569 This
->m_fWaveOutInit
= FALSE
;
570 This
->m_hEventRender
= (HANDLE
)NULL
;
572 QUARTZ_IUnkInit( &This
->unk
, punkOuter
);
574 hr
= CBaseFilterImpl_InitIBaseFilter(
576 This
->unk
.punkControl
,
578 QUARTZ_AudioRender_Name
,
582 hr
= CAudioRendererImpl_InitIBasicAudio(This
);
585 CBaseFilterImpl_UninitIBaseFilter(&This
->basefilter
);
591 QUARTZ_FreeObj(This
);
595 This
->unk
.pEntries
= FilterIFEntries
;
596 This
->unk
.dwEntries
= sizeof(FilterIFEntries
)/sizeof(FilterIFEntries
[0]);
597 This
->unk
.pOnFinalRelease
= QUARTZ_DestroyAudioRenderer
;
599 hr
= QUARTZ_CreateAudioRendererPin(
601 &This
->basefilter
.csFilter
,
604 hr
= QUARTZ_CompList_AddComp(
605 This
->basefilter
.pInPins
,
606 (IUnknown
*)&This
->pPin
->pin
,
610 IUnknown_Release( This
->unk
.punkControl
);
614 *ppobj
= (void*)&(This
->unk
);
620 /***************************************************************************
622 * new/delete CAudioRendererPinImpl
626 /* can I use offsetof safely? - FIXME? */
627 static QUARTZ_IFEntry PinIFEntries
[] =
629 { &IID_IPin
, offsetof(CAudioRendererPinImpl
,pin
)-offsetof(CAudioRendererPinImpl
,unk
) },
630 { &IID_IMemInputPin
, offsetof(CAudioRendererPinImpl
,meminput
)-offsetof(CAudioRendererPinImpl
,unk
) },
633 static void QUARTZ_DestroyAudioRendererPin(IUnknown
* punk
)
635 CAudioRendererPinImpl_THIS(punk
,unk
);
637 TRACE( "(%p)\n", This
);
639 CPinBaseImpl_UninitIPin( &This
->pin
);
640 CMemInputPinBaseImpl_UninitIMemInputPin( &This
->meminput
);
643 HRESULT
QUARTZ_CreateAudioRendererPin(
644 CAudioRendererImpl
* pFilter
,
645 CRITICAL_SECTION
* pcsPin
,
646 CAudioRendererPinImpl
** ppPin
)
648 CAudioRendererPinImpl
* This
= NULL
;
651 TRACE("(%p,%p,%p)\n",pFilter
,pcsPin
,ppPin
);
653 This
= (CAudioRendererPinImpl
*)
654 QUARTZ_AllocObj( sizeof(CAudioRendererPinImpl
) );
656 return E_OUTOFMEMORY
;
658 QUARTZ_IUnkInit( &This
->unk
, NULL
);
659 This
->pRender
= pFilter
;
661 hr
= CPinBaseImpl_InitIPin(
663 This
->unk
.punkControl
,
665 &pFilter
->basefilter
,
666 QUARTZ_AudioRenderPin_Name
,
672 hr
= CMemInputPinBaseImpl_InitIMemInputPin(
674 This
->unk
.punkControl
,
678 CPinBaseImpl_UninitIPin( &This
->pin
);
684 QUARTZ_FreeObj(This
);
688 This
->unk
.pEntries
= PinIFEntries
;
689 This
->unk
.dwEntries
= sizeof(PinIFEntries
)/sizeof(PinIFEntries
[0]);
690 This
->unk
.pOnFinalRelease
= QUARTZ_DestroyAudioRendererPin
;
694 TRACE("returned successfully.\n");
700 /***************************************************************************
702 * CAudioRendererImpl::IBasicAudio
706 static HRESULT WINAPI
707 IBasicAudio_fnQueryInterface(IBasicAudio
* iface
,REFIID riid
,void** ppobj
)
709 CAudioRendererImpl_THIS(iface
,basaud
);
711 TRACE("(%p)->()\n",This
);
713 return IUnknown_QueryInterface(This
->unk
.punkControl
,riid
,ppobj
);
717 IBasicAudio_fnAddRef(IBasicAudio
* iface
)
719 CAudioRendererImpl_THIS(iface
,basaud
);
721 TRACE("(%p)->()\n",This
);
723 return IUnknown_AddRef(This
->unk
.punkControl
);
727 IBasicAudio_fnRelease(IBasicAudio
* iface
)
729 CAudioRendererImpl_THIS(iface
,basaud
);
731 TRACE("(%p)->()\n",This
);
733 return IUnknown_Release(This
->unk
.punkControl
);
736 static HRESULT WINAPI
737 IBasicAudio_fnGetTypeInfoCount(IBasicAudio
* iface
,UINT
* pcTypeInfo
)
739 CAudioRendererImpl_THIS(iface
,basaud
);
741 FIXME("(%p)->()\n",This
);
746 static HRESULT WINAPI
747 IBasicAudio_fnGetTypeInfo(IBasicAudio
* iface
,UINT iTypeInfo
, LCID lcid
, ITypeInfo
** ppobj
)
749 CAudioRendererImpl_THIS(iface
,basaud
);
751 FIXME("(%p)->()\n",This
);
756 static HRESULT WINAPI
757 IBasicAudio_fnGetIDsOfNames(IBasicAudio
* iface
,REFIID riid
, LPOLESTR
* ppwszName
, UINT cNames
, LCID lcid
, DISPID
* pDispId
)
759 CAudioRendererImpl_THIS(iface
,basaud
);
761 FIXME("(%p)->()\n",This
);
766 static HRESULT WINAPI
767 IBasicAudio_fnInvoke(IBasicAudio
* iface
,DISPID DispId
, REFIID riid
, LCID lcid
, WORD wFlags
, DISPPARAMS
* pDispParams
, VARIANT
* pVarRes
, EXCEPINFO
* pExcepInfo
, UINT
* puArgErr
)
769 CAudioRendererImpl_THIS(iface
,basaud
);
771 FIXME("(%p)->()\n",This
);
777 static HRESULT WINAPI
778 IBasicAudio_fnput_Volume(IBasicAudio
* iface
,long lVol
)
780 CAudioRendererImpl_THIS(iface
,basaud
);
782 FIXME("(%p)->()\n",This
);
787 static HRESULT WINAPI
788 IBasicAudio_fnget_Volume(IBasicAudio
* iface
,long* plVol
)
790 CAudioRendererImpl_THIS(iface
,basaud
);
792 FIXME("(%p)->()\n",This
);
797 static HRESULT WINAPI
798 IBasicAudio_fnput_Balance(IBasicAudio
* iface
,long lBalance
)
800 CAudioRendererImpl_THIS(iface
,basaud
);
802 FIXME("(%p)->()\n",This
);
807 static HRESULT WINAPI
808 IBasicAudio_fnget_Balance(IBasicAudio
* iface
,long* plBalance
)
810 CAudioRendererImpl_THIS(iface
,basaud
);
812 FIXME("(%p)->()\n",This
);
818 static ICOM_VTABLE(IBasicAudio
) ibasicaudio
=
820 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
821 /* IUnknown fields */
822 IBasicAudio_fnQueryInterface
,
823 IBasicAudio_fnAddRef
,
824 IBasicAudio_fnRelease
,
825 /* IDispatch fields */
826 IBasicAudio_fnGetTypeInfoCount
,
827 IBasicAudio_fnGetTypeInfo
,
828 IBasicAudio_fnGetIDsOfNames
,
829 IBasicAudio_fnInvoke
,
830 /* IBasicAudio fields */
831 IBasicAudio_fnput_Volume
,
832 IBasicAudio_fnget_Volume
,
833 IBasicAudio_fnput_Balance
,
834 IBasicAudio_fnget_Balance
,
838 HRESULT
CAudioRendererImpl_InitIBasicAudio( CAudioRendererImpl
* This
)
840 TRACE("(%p)\n",This
);
841 ICOM_VTBL(&This
->basaud
) = &ibasicaudio
;
846 void CAudioRendererImpl_UninitIBasicAudio( CAudioRendererImpl
* This
)
848 TRACE("(%p)\n",This
);