2 * Audio Renderer (CLSID_AudioRender)
5 * - implements IRefereneceClock.
6 * - implements seeking.
8 * hidenori@a2.ctktv.ne.jp
25 #include "debugtools.h"
26 DEFAULT_DEBUG_CHANNEL(quartz);
28 #include "quartz_private.h"
32 static const WCHAR QUARTZ_AudioRender_Name[] =
33 { 'A','u','d','i','o',' ','R','e','n','d','e','r',0 };
34 static const WCHAR QUARTZ_AudioRenderPin_Name[] =
39 /***************************************************************************
41 * CAudioRendererImpl waveOut methods (internal)
46 HRESULT QUARTZ_HRESULT_From_MMRESULT( MMRESULT mr )
52 case MMSYSERR_NOERROR:
63 void CAudioRendererImpl_waveOutEventCallback(
64 HWAVEOUT hwo, UINT uMsg,
65 DWORD dwInstance, DWORD dwParam1, DWORD dwParam2 )
67 CAudioRendererImpl* This = (CAudioRendererImpl*)dwInstance;
69 if ( uMsg == WOM_DONE )
70 SetEvent( This->m_hEventRender );
74 void CAudioRendererImpl_waveOutReset(
75 CAudioRendererImpl* This )
77 if ( !This->m_fWaveOutInit )
80 waveOutReset( This->m_hWaveOut );
81 SetEvent( This->m_hEventRender );
85 void CAudioRendererImpl_waveOutUninit(
86 CAudioRendererImpl* This )
92 if ( !This->m_fWaveOutInit )
95 waveOutReset( This->m_hWaveOut );
96 SetEvent( This->m_hEventRender );
98 for ( i = 0; i < WINE_QUARTZ_WAVEOUT_COUNT; i++ )
100 if ( This->m_hdr[i].dwFlags & WHDR_PREPARED )
102 waveOutUnprepareHeader(
104 &This->m_hdr[i], sizeof(WAVEHDR) );
105 This->m_hdr[i].dwFlags = 0;
107 if ( This->m_hdr[i].lpData != NULL )
109 QUARTZ_FreeMem( This->m_hdr[i].lpData );
110 This->m_hdr[i].lpData = NULL;
114 waveOutClose( This->m_hWaveOut );
115 This->m_hWaveOut = (HWAVEOUT)NULL;
116 if ( This->m_hEventRender != (HANDLE)NULL )
118 CloseHandle( This->m_hEventRender );
119 This->m_hEventRender = (HANDLE)NULL;
122 This->m_fWaveOutInit = FALSE;
126 HRESULT CAudioRendererImpl_waveOutInit(
127 CAudioRendererImpl* This, WAVEFORMATEX* pwfx )
134 if ( This->m_fWaveOutInit )
139 if ( pwfx->nBlockAlign == 0 )
142 This->m_hEventRender = (HANDLE)NULL;
143 This->m_hWaveOut = (HWAVEOUT)NULL;
144 This->m_dwBlockSize = 0;
145 This->m_phdrCur = NULL;
146 ZeroMemory( &This->m_hdr, sizeof(This->m_hdr) );
150 &This->m_hWaveOut, WAVE_MAPPER, pwfx,
151 (DWORD)CAudioRendererImpl_waveOutEventCallback, (DWORD)This,
153 hr = QUARTZ_HRESULT_From_MMRESULT( mr );
156 This->m_fWaveOutInit = TRUE;
158 This->m_hEventRender = CreateEventA(
159 NULL, TRUE, TRUE, NULL );
160 if ( This->m_hEventRender == (HANDLE)NULL )
166 dwBlockSize = pwfx->nAvgBytesPerSec / pwfx->nBlockAlign;
167 if ( dwBlockSize == 0 )
169 dwBlockSize *= pwfx->nBlockAlign;
170 This->m_dwBlockSize = dwBlockSize;
172 for ( i = 0; i < WINE_QUARTZ_WAVEOUT_COUNT; i++ )
174 This->m_hdr[i].lpData = (CHAR*)QUARTZ_AllocMem( dwBlockSize );
175 if ( This->m_hdr[i].lpData == NULL )
180 mr = waveOutPrepareHeader(
182 &This->m_hdr[i], sizeof(WAVEHDR) );
183 hr = QUARTZ_HRESULT_From_MMRESULT( mr );
186 This->m_hdr[i].dwFlags |= WHDR_DONE;
187 This->m_hdr[i].dwBufferLength = dwBlockSize;
188 This->m_hdr[i].dwUser = i;
193 CAudioRendererImpl_waveOutUninit(This);
198 WAVEHDR* CAudioRendererImpl_waveOutGetBuffer(
199 CAudioRendererImpl* This )
203 if ( !This->m_fWaveOutInit )
206 if ( This->m_phdrCur != NULL )
207 return This->m_phdrCur;
209 for ( i = 0; i < WINE_QUARTZ_WAVEOUT_COUNT; i++ )
211 if ( This->m_hdr[i].dwFlags & WHDR_DONE )
213 This->m_phdrCur = &(This->m_hdr[i]);
214 This->m_phdrCur->dwFlags &= ~WHDR_DONE;
215 This->m_phdrCur->dwBufferLength = 0;
216 return This->m_phdrCur;
224 HRESULT CAudioRendererImpl_waveOutWriteData(
225 CAudioRendererImpl* This,
226 const BYTE* pData, DWORD cbData, DWORD* pcbWritten )
232 if ( !This->m_fWaveOutInit )
238 if ( CAudioRendererImpl_waveOutGetBuffer(This) == NULL )
241 cbAvail = This->m_dwBlockSize - This->m_phdrCur->dwBufferLength;
242 if ( cbAvail > cbData )
244 memcpy( This->m_phdrCur->lpData, pData, cbAvail );
247 This->m_phdrCur->dwBufferLength += cbAvail;
249 *pcbWritten = cbAvail;
255 HRESULT CAudioRendererImpl_waveOutFlush(
256 CAudioRendererImpl* This )
261 if ( !This->m_fWaveOutInit )
263 if ( This->m_phdrCur == NULL )
266 if ( This->m_phdrCur->dwBufferLength == 0 )
271 This->m_phdrCur, sizeof(WAVEHDR) );
272 hr = QUARTZ_HRESULT_From_MMRESULT( mr );
276 This->m_phdrCur = NULL;
281 HRESULT CAudioRendererImpl_waveOutGetVolume(
282 CAudioRendererImpl* This,
283 DWORD* pdwLeft, DWORD* pdwRight )
289 if ( !This->m_fWaveOutInit )
292 mr = waveOutGetVolume(
293 This->m_hWaveOut, &dwVol );
294 hr = QUARTZ_HRESULT_From_MMRESULT( mr );
298 *pdwLeft = LOWORD(dwVol);
299 *pdwRight = HIWORD(dwVol);
305 HRESULT CAudioRendererImpl_waveOutSetVolume(
306 CAudioRendererImpl* This,
307 DWORD dwLeft, DWORD dwRight )
312 if ( !This->m_fWaveOutInit )
315 dwVol = dwLeft | (dwRight<<16);
317 mr = waveOutSetVolume(
318 This->m_hWaveOut, dwVol );
319 return QUARTZ_HRESULT_From_MMRESULT( mr );
322 /***************************************************************************
324 * CAudioRendererImpl methods
329 static HRESULT CAudioRendererImpl_OnActive( CBaseFilterImpl* pImpl )
331 CAudioRendererImpl_THIS(pImpl,basefilter);
334 FIXME( "(%p)\n", This );
336 if ( This->pPin->pin.pmtConn == NULL )
339 pwfx = (WAVEFORMATEX*)This->pPin->pin.pmtConn->pbFormat;
343 This->m_fInFlush = FALSE;
345 return CAudioRendererImpl_waveOutInit(This,pwfx);
348 static HRESULT CAudioRendererImpl_OnInactive( CBaseFilterImpl* pImpl )
350 CAudioRendererImpl_THIS(pImpl,basefilter);
352 FIXME( "(%p)\n", This );
354 CAudioRendererImpl_waveOutUninit(This);
356 This->m_fInFlush = FALSE;
358 TRACE("returned\n" );
363 static const CBaseFilterHandlers filterhandlers =
365 CAudioRendererImpl_OnActive, /* pOnActive */
366 CAudioRendererImpl_OnInactive, /* pOnInactive */
370 /***************************************************************************
372 * CAudioRendererPinImpl methods
376 static HRESULT CAudioRendererPinImpl_CheckMediaType( CPinBaseImpl* pImpl, const AM_MEDIA_TYPE* pmt )
378 CAudioRendererPinImpl_THIS(pImpl,pin);
379 const WAVEFORMATEX* pwfx;
381 TRACE("(%p,%p)\n",This,pmt);
383 if ( !IsEqualGUID( &pmt->majortype, &MEDIATYPE_Audio ) )
385 if ( !IsEqualGUID( &pmt->subtype, &MEDIASUBTYPE_PCM ) )
387 if ( !IsEqualGUID( &pmt->formattype, &FORMAT_WaveFormatEx ) )
389 if ( pmt->cbFormat < (sizeof(WAVEFORMATEX)-sizeof(WORD)) )
392 pwfx = (const WAVEFORMATEX*)pmt->pbFormat;
395 if ( pwfx->wFormatTag != 1 )
401 static HRESULT CAudioRendererPinImpl_Receive( CPinBaseImpl* pImpl, IMediaSample* pSample )
403 CAudioRendererPinImpl_THIS(pImpl,pin);
409 FIXME( "(%p,%p)\n",This,pSample );
411 if ( !This->pRender->m_fWaveOutInit )
413 if ( This->pRender->m_fInFlush )
415 if ( pSample == NULL )
418 hr = IMediaSample_GetPointer( pSample, &pData );
421 dwDataLength = (DWORD)IMediaSample_GetActualDataLength( pSample );
425 TRACE("trying to write %lu bytes\n",dwDataLength);
427 ResetEvent( This->pRender->m_hEventRender );
428 hr = CAudioRendererImpl_waveOutWriteData(
429 This->pRender,pData,dwDataLength,&dwWritten);
434 WaitForSingleObject( This->pRender->m_hEventRender, INFINITE );
438 dwDataLength -= dwWritten;
439 hr = CAudioRendererImpl_waveOutFlush(This->pRender);
442 if ( dwDataLength == 0 )
449 static HRESULT CAudioRendererPinImpl_ReceiveCanBlock( CPinBaseImpl* pImpl )
451 CAudioRendererPinImpl_THIS(pImpl,pin);
453 TRACE( "(%p)\n", This );
459 static HRESULT CAudioRendererPinImpl_EndOfStream( CPinBaseImpl* pImpl )
461 CAudioRendererPinImpl_THIS(pImpl,pin);
463 FIXME( "(%p)\n", This );
465 This->pRender->m_fInFlush = FALSE;
467 /* FIXME - don't notify twice until stopped or seeked. */
468 return CBaseFilterImpl_MediaEventNotify(
469 &This->pRender->basefilter, EC_COMPLETE,
470 (LONG_PTR)S_OK, (LONG_PTR)(IBaseFilter*)(This->pRender) );
473 static HRESULT CAudioRendererPinImpl_BeginFlush( CPinBaseImpl* pImpl )
475 CAudioRendererPinImpl_THIS(pImpl,pin);
477 FIXME( "(%p)\n", This );
479 This->pRender->m_fInFlush = TRUE;
480 CAudioRendererImpl_waveOutReset(This->pRender);
485 static HRESULT CAudioRendererPinImpl_EndFlush( CPinBaseImpl* pImpl )
487 CAudioRendererPinImpl_THIS(pImpl,pin);
489 FIXME( "(%p)\n", This );
491 This->pRender->m_fInFlush = FALSE;
496 static HRESULT CAudioRendererPinImpl_NewSegment( CPinBaseImpl* pImpl, REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, double rate )
498 CAudioRendererPinImpl_THIS(pImpl,pin);
500 FIXME( "(%p)\n", This );
502 This->pRender->m_fInFlush = FALSE;
507 static const CBasePinHandlers pinhandlers =
509 NULL, /* pOnPreConnect */
510 NULL, /* pOnPostConnect */
511 NULL, /* pOnDisconnect */
512 CAudioRendererPinImpl_CheckMediaType, /* pCheckMediaType */
513 NULL, /* pQualityNotify */
514 CAudioRendererPinImpl_Receive, /* pReceive */
515 CAudioRendererPinImpl_ReceiveCanBlock, /* pReceiveCanBlock */
516 CAudioRendererPinImpl_EndOfStream, /* pEndOfStream */
517 CAudioRendererPinImpl_BeginFlush, /* pBeginFlush */
518 CAudioRendererPinImpl_EndFlush, /* pEndFlush */
519 CAudioRendererPinImpl_NewSegment, /* pNewSegment */
523 /***************************************************************************
525 * new/delete CAudioRendererImpl
529 /* can I use offsetof safely? - FIXME? */
530 static QUARTZ_IFEntry FilterIFEntries[] =
532 { &IID_IPersist, offsetof(CAudioRendererImpl,basefilter)-offsetof(CAudioRendererImpl,unk) },
533 { &IID_IMediaFilter, offsetof(CAudioRendererImpl,basefilter)-offsetof(CAudioRendererImpl,unk) },
534 { &IID_IBaseFilter, offsetof(CAudioRendererImpl,basefilter)-offsetof(CAudioRendererImpl,unk) },
535 { &IID_IBasicAudio, offsetof(CAudioRendererImpl,basaud)-offsetof(CAudioRendererImpl,unk) },
538 static void QUARTZ_DestroyAudioRenderer(IUnknown* punk)
540 CAudioRendererImpl_THIS(punk,unk);
542 TRACE( "(%p)\n", This );
544 if ( This->pPin != NULL )
546 IUnknown_Release(This->pPin->unk.punkControl);
550 CAudioRendererImpl_UninitIBasicAudio(This);
551 CBaseFilterImpl_UninitIBaseFilter(&This->basefilter);
554 HRESULT QUARTZ_CreateAudioRenderer(IUnknown* punkOuter,void** ppobj)
556 CAudioRendererImpl* This = NULL;
559 TRACE("(%p,%p)\n",punkOuter,ppobj);
561 This = (CAudioRendererImpl*)
562 QUARTZ_AllocObj( sizeof(CAudioRendererImpl) );
564 return E_OUTOFMEMORY;
566 This->m_fInFlush = FALSE;
567 This->m_fWaveOutInit = FALSE;
568 This->m_hEventRender = (HANDLE)NULL;
570 QUARTZ_IUnkInit( &This->unk, punkOuter );
572 hr = CBaseFilterImpl_InitIBaseFilter(
574 This->unk.punkControl,
576 QUARTZ_AudioRender_Name,
580 hr = CAudioRendererImpl_InitIBasicAudio(This);
583 CBaseFilterImpl_UninitIBaseFilter(&This->basefilter);
589 QUARTZ_FreeObj(This);
593 This->unk.pEntries = FilterIFEntries;
594 This->unk.dwEntries = sizeof(FilterIFEntries)/sizeof(FilterIFEntries[0]);
595 This->unk.pOnFinalRelease = QUARTZ_DestroyAudioRenderer;
597 hr = QUARTZ_CreateAudioRendererPin(
599 &This->basefilter.csFilter,
602 hr = QUARTZ_CompList_AddComp(
603 This->basefilter.pInPins,
604 (IUnknown*)&This->pPin->pin,
608 IUnknown_Release( This->unk.punkControl );
612 *ppobj = (void*)&(This->unk);
618 /***************************************************************************
620 * new/delete CAudioRendererPinImpl
624 /* can I use offsetof safely? - FIXME? */
625 static QUARTZ_IFEntry PinIFEntries[] =
627 { &IID_IPin, offsetof(CAudioRendererPinImpl,pin)-offsetof(CAudioRendererPinImpl,unk) },
628 { &IID_IMemInputPin, offsetof(CAudioRendererPinImpl,meminput)-offsetof(CAudioRendererPinImpl,unk) },
631 static void QUARTZ_DestroyAudioRendererPin(IUnknown* punk)
633 CAudioRendererPinImpl_THIS(punk,unk);
635 TRACE( "(%p)\n", This );
637 CPinBaseImpl_UninitIPin( &This->pin );
638 CMemInputPinBaseImpl_UninitIMemInputPin( &This->meminput );
641 HRESULT QUARTZ_CreateAudioRendererPin(
642 CAudioRendererImpl* pFilter,
643 CRITICAL_SECTION* pcsPin,
644 CAudioRendererPinImpl** ppPin)
646 CAudioRendererPinImpl* This = NULL;
649 TRACE("(%p,%p,%p)\n",pFilter,pcsPin,ppPin);
651 This = (CAudioRendererPinImpl*)
652 QUARTZ_AllocObj( sizeof(CAudioRendererPinImpl) );
654 return E_OUTOFMEMORY;
656 QUARTZ_IUnkInit( &This->unk, NULL );
657 This->pRender = pFilter;
659 hr = CPinBaseImpl_InitIPin(
661 This->unk.punkControl,
663 &pFilter->basefilter,
664 QUARTZ_AudioRenderPin_Name,
670 hr = CMemInputPinBaseImpl_InitIMemInputPin(
672 This->unk.punkControl,
676 CPinBaseImpl_UninitIPin( &This->pin );
682 QUARTZ_FreeObj(This);
686 This->unk.pEntries = PinIFEntries;
687 This->unk.dwEntries = sizeof(PinIFEntries)/sizeof(PinIFEntries[0]);
688 This->unk.pOnFinalRelease = QUARTZ_DestroyAudioRendererPin;
692 TRACE("returned successfully.\n");
698 /***************************************************************************
700 * CAudioRendererImpl::IBasicAudio
704 static HRESULT WINAPI
705 IBasicAudio_fnQueryInterface(IBasicAudio* iface,REFIID riid,void** ppobj)
707 CAudioRendererImpl_THIS(iface,basaud);
709 TRACE("(%p)->()\n",This);
711 return IUnknown_QueryInterface(This->unk.punkControl,riid,ppobj);
715 IBasicAudio_fnAddRef(IBasicAudio* iface)
717 CAudioRendererImpl_THIS(iface,basaud);
719 TRACE("(%p)->()\n",This);
721 return IUnknown_AddRef(This->unk.punkControl);
725 IBasicAudio_fnRelease(IBasicAudio* iface)
727 CAudioRendererImpl_THIS(iface,basaud);
729 TRACE("(%p)->()\n",This);
731 return IUnknown_Release(This->unk.punkControl);
734 static HRESULT WINAPI
735 IBasicAudio_fnGetTypeInfoCount(IBasicAudio* iface,UINT* pcTypeInfo)
737 CAudioRendererImpl_THIS(iface,basaud);
739 FIXME("(%p)->()\n",This);
744 static HRESULT WINAPI
745 IBasicAudio_fnGetTypeInfo(IBasicAudio* iface,UINT iTypeInfo, LCID lcid, ITypeInfo** ppobj)
747 CAudioRendererImpl_THIS(iface,basaud);
749 FIXME("(%p)->()\n",This);
754 static HRESULT WINAPI
755 IBasicAudio_fnGetIDsOfNames(IBasicAudio* iface,REFIID riid, LPOLESTR* ppwszName, UINT cNames, LCID lcid, DISPID* pDispId)
757 CAudioRendererImpl_THIS(iface,basaud);
759 FIXME("(%p)->()\n",This);
764 static HRESULT WINAPI
765 IBasicAudio_fnInvoke(IBasicAudio* iface,DISPID DispId, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarRes, EXCEPINFO* pExcepInfo, UINT* puArgErr)
767 CAudioRendererImpl_THIS(iface,basaud);
769 FIXME("(%p)->()\n",This);
775 static HRESULT WINAPI
776 IBasicAudio_fnput_Volume(IBasicAudio* iface,long lVol)
778 CAudioRendererImpl_THIS(iface,basaud);
780 FIXME("(%p)->()\n",This);
785 static HRESULT WINAPI
786 IBasicAudio_fnget_Volume(IBasicAudio* iface,long* plVol)
788 CAudioRendererImpl_THIS(iface,basaud);
790 FIXME("(%p)->()\n",This);
795 static HRESULT WINAPI
796 IBasicAudio_fnput_Balance(IBasicAudio* iface,long lBalance)
798 CAudioRendererImpl_THIS(iface,basaud);
800 FIXME("(%p)->()\n",This);
805 static HRESULT WINAPI
806 IBasicAudio_fnget_Balance(IBasicAudio* iface,long* plBalance)
808 CAudioRendererImpl_THIS(iface,basaud);
810 FIXME("(%p)->()\n",This);
816 static ICOM_VTABLE(IBasicAudio) ibasicaudio =
818 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
819 /* IUnknown fields */
820 IBasicAudio_fnQueryInterface,
821 IBasicAudio_fnAddRef,
822 IBasicAudio_fnRelease,
823 /* IDispatch fields */
824 IBasicAudio_fnGetTypeInfoCount,
825 IBasicAudio_fnGetTypeInfo,
826 IBasicAudio_fnGetIDsOfNames,
827 IBasicAudio_fnInvoke,
828 /* IBasicAudio fields */
829 IBasicAudio_fnput_Volume,
830 IBasicAudio_fnget_Volume,
831 IBasicAudio_fnput_Balance,
832 IBasicAudio_fnget_Balance,
836 HRESULT CAudioRendererImpl_InitIBasicAudio( CAudioRendererImpl* This )
838 TRACE("(%p)\n",This);
839 ICOM_VTBL(&This->basaud) = &ibasicaudio;
844 void CAudioRendererImpl_UninitIBasicAudio( CAudioRendererImpl* This )
846 TRACE("(%p)\n",This);