/* * Audio Renderer (CLSID_AudioRender) * * FIXME * - implements IRefereneceClock. * - implements seeking. * * hidenori@a2.ctktv.ne.jp */ #include "config.h" #include "windef.h" #include "winbase.h" #include "wingdi.h" #include "winuser.h" #include "mmsystem.h" #include "winerror.h" #include "strmif.h" #include "control.h" #include "vfwmsgs.h" #include "uuids.h" #include "evcode.h" #include "debugtools.h" DEFAULT_DEBUG_CHANNEL(quartz); #include "quartz_private.h" #include "audren.h" #include "seekpass.h" static const WCHAR QUARTZ_AudioRender_Name[] = { 'A','u','d','i','o',' ','R','e','n','d','e','r',0 }; static const WCHAR QUARTZ_AudioRenderPin_Name[] = { 'I','n',0 }; /*************************************************************************** * * CAudioRendererImpl waveOut methods (internal) * */ static HRESULT QUARTZ_HRESULT_From_MMRESULT( MMRESULT mr ) { HRESULT hr = E_FAIL; switch ( mr ) { case MMSYSERR_NOERROR: hr = S_OK; break; case MMSYSERR_NOMEM: hr = E_OUTOFMEMORY; break; } return hr; } void CAudioRendererImpl_waveOutEventCallback( HWAVEOUT hwo, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2 ) { CAudioRendererImpl* This = (CAudioRendererImpl*)dwInstance; if ( uMsg == WOM_DONE ) SetEvent( This->m_hEventRender ); } static void CAudioRendererImpl_waveOutReset( CAudioRendererImpl* This ) { if ( !This->m_fWaveOutInit ) return; waveOutReset( This->m_hWaveOut ); SetEvent( This->m_hEventRender ); } static void CAudioRendererImpl_waveOutUninit( CAudioRendererImpl* This ) { DWORD i; TRACE("(%p)\n",This); if ( !This->m_fWaveOutInit ) return; waveOutReset( This->m_hWaveOut ); SetEvent( This->m_hEventRender ); for ( i = 0; i < WINE_QUARTZ_WAVEOUT_COUNT; i++ ) { if ( This->m_hdr[i].dwFlags & WHDR_PREPARED ) { waveOutUnprepareHeader( This->m_hWaveOut, &This->m_hdr[i], sizeof(WAVEHDR) ); This->m_hdr[i].dwFlags = 0; } if ( This->m_hdr[i].lpData != NULL ) { QUARTZ_FreeMem( This->m_hdr[i].lpData ); This->m_hdr[i].lpData = NULL; } } waveOutClose( This->m_hWaveOut ); This->m_hWaveOut = (HWAVEOUT)NULL; if ( This->m_hEventRender != (HANDLE)NULL ) { CloseHandle( This->m_hEventRender ); This->m_hEventRender = (HANDLE)NULL; } This->m_fWaveOutInit = FALSE; } static HRESULT CAudioRendererImpl_waveOutInit( CAudioRendererImpl* This, WAVEFORMATEX* pwfx ) { MMRESULT mr; HRESULT hr; DWORD i; DWORD dwBlockSize; if ( This->m_fWaveOutInit ) return NOERROR; if ( pwfx == NULL ) return E_POINTER; if ( pwfx->nBlockAlign == 0 ) return E_INVALIDARG; This->m_hEventRender = (HANDLE)NULL; This->m_hWaveOut = (HWAVEOUT)NULL; This->m_dwBlockSize = 0; This->m_phdrCur = NULL; ZeroMemory( &This->m_hdr, sizeof(This->m_hdr) ); mr = waveOutOpen( &This->m_hWaveOut, WAVE_MAPPER, pwfx, (DWORD)CAudioRendererImpl_waveOutEventCallback, (DWORD)This, CALLBACK_FUNCTION ); hr = QUARTZ_HRESULT_From_MMRESULT( mr ); if ( FAILED(hr) ) return hr; This->m_fWaveOutInit = TRUE; This->m_hEventRender = CreateEventA( NULL, TRUE, TRUE, NULL ); if ( This->m_hEventRender == (HANDLE)NULL ) { hr = E_OUTOFMEMORY; goto err; } dwBlockSize = pwfx->nAvgBytesPerSec / pwfx->nBlockAlign; if ( dwBlockSize == 0 ) dwBlockSize = 1; dwBlockSize *= pwfx->nBlockAlign; This->m_dwBlockSize = dwBlockSize; for ( i = 0; i < WINE_QUARTZ_WAVEOUT_COUNT; i++ ) { This->m_hdr[i].lpData = (CHAR*)QUARTZ_AllocMem( dwBlockSize ); if ( This->m_hdr[i].lpData == NULL ) { hr = E_OUTOFMEMORY; goto err; } mr = waveOutPrepareHeader( This->m_hWaveOut, &This->m_hdr[i], sizeof(WAVEHDR) ); hr = QUARTZ_HRESULT_From_MMRESULT( mr ); if ( FAILED(hr) ) goto err; This->m_hdr[i].dwFlags |= WHDR_DONE; This->m_hdr[i].dwBufferLength = dwBlockSize; This->m_hdr[i].dwUser = i; } return S_OK; err: CAudioRendererImpl_waveOutUninit(This); return hr; } #if 0 /* FIXME: Not used for now */ static HRESULT CAudioRendererImpl_waveOutPause( CAudioRendererImpl* This ) { if ( !This->m_fWaveOutInit ) return E_UNEXPECTED; return QUARTZ_HRESULT_From_MMRESULT( waveOutPause( This->m_hWaveOut ) ); } static HRESULT CAudioRendererImpl_waveOutRun( CAudioRendererImpl* This ) { if ( !This->m_fWaveOutInit ) return E_UNEXPECTED; return QUARTZ_HRESULT_From_MMRESULT( waveOutRestart( This->m_hWaveOut ) ); } #endif static WAVEHDR* CAudioRendererImpl_waveOutGetBuffer( CAudioRendererImpl* This ) { DWORD i; if ( !This->m_fWaveOutInit ) return NULL; if ( This->m_phdrCur != NULL ) return This->m_phdrCur; for ( i = 0; i < WINE_QUARTZ_WAVEOUT_COUNT; i++ ) { if ( This->m_hdr[i].dwFlags & WHDR_DONE ) { This->m_phdrCur = &(This->m_hdr[i]); This->m_phdrCur->dwFlags &= ~WHDR_DONE; This->m_phdrCur->dwBufferLength = 0; return This->m_phdrCur; } } return NULL; } static HRESULT CAudioRendererImpl_waveOutWriteData( CAudioRendererImpl* This, const BYTE* pData, DWORD cbData, DWORD* pcbWritten ) { DWORD cbAvail; *pcbWritten = 0; if ( !This->m_fWaveOutInit ) return E_UNEXPECTED; if ( cbData == 0 ) return S_OK; if ( CAudioRendererImpl_waveOutGetBuffer(This) == NULL ) return S_FALSE; cbAvail = This->m_dwBlockSize - This->m_phdrCur->dwBufferLength; if ( cbAvail > cbData ) cbAvail = cbData; memcpy( This->m_phdrCur->lpData, pData, cbAvail ); pData += cbAvail; cbData -= cbAvail; This->m_phdrCur->dwBufferLength += cbAvail; *pcbWritten = cbAvail; return S_OK; } static HRESULT CAudioRendererImpl_waveOutFlush( CAudioRendererImpl* This ) { MMRESULT mr; HRESULT hr; if ( !This->m_fWaveOutInit ) return E_UNEXPECTED; if ( This->m_phdrCur == NULL ) return E_UNEXPECTED; if ( This->m_phdrCur->dwBufferLength == 0 ) return S_OK; mr = waveOutWrite( This->m_hWaveOut, This->m_phdrCur, sizeof(WAVEHDR) ); hr = QUARTZ_HRESULT_From_MMRESULT( mr ); if ( FAILED(hr) ) return hr; This->m_phdrCur = NULL; return S_OK; } #if 0 /* FIXME: Not used for now */ static HRESULT CAudioRendererImpl_waveOutGetVolume( CAudioRendererImpl* This, DWORD* pdwLeft, DWORD* pdwRight ) { MMRESULT mr; HRESULT hr; DWORD dwVol; if ( !This->m_fWaveOutInit ) return E_UNEXPECTED; mr = waveOutGetVolume( This->m_hWaveOut, &dwVol ); hr = QUARTZ_HRESULT_From_MMRESULT( mr ); if ( FAILED(hr) ) return hr; *pdwLeft = LOWORD(dwVol); *pdwRight = HIWORD(dwVol); return NOERROR; } static HRESULT CAudioRendererImpl_waveOutSetVolume( CAudioRendererImpl* This, DWORD dwLeft, DWORD dwRight ) { MMRESULT mr; DWORD dwVol; if ( !This->m_fWaveOutInit ) return E_UNEXPECTED; dwVol = dwLeft | (dwRight<<16); mr = waveOutSetVolume( This->m_hWaveOut, dwVol ); return QUARTZ_HRESULT_From_MMRESULT( mr ); } #endif /*************************************************************************** * * CAudioRendererImpl methods * */ static HRESULT CAudioRendererImpl_OnActive( CBaseFilterImpl* pImpl ) { CAudioRendererImpl_THIS(pImpl,basefilter); /* HRESULT hr; */ FIXME( "(%p)\n", This ); if ( This->pPin->pin.pmtConn == NULL ) return NOERROR; This->m_fInFlush = FALSE; /* FIXME - don't work correctly. hr = CAudioRendererImpl_waveOutRun(This); if ( FAILED(hr) ) return hr; */ return NOERROR; } static HRESULT CAudioRendererImpl_OnInactive( CBaseFilterImpl* pImpl ) { CAudioRendererImpl_THIS(pImpl,basefilter); WAVEFORMATEX* pwfx; HRESULT hr; FIXME( "(%p)\n", This ); if ( This->pPin->pin.pmtConn == NULL ) return NOERROR; pwfx = (WAVEFORMATEX*)This->pPin->pin.pmtConn->pbFormat; if ( pwfx == NULL ) return E_FAIL; This->m_fInFlush = FALSE; hr = CAudioRendererImpl_waveOutInit(This,pwfx); if ( FAILED(hr) ) return hr; /* FIXME - may cause deadlock. hr = CAudioRendererImpl_waveOutPause(This); if ( FAILED(hr) ) return hr; */ return NOERROR; } static HRESULT CAudioRendererImpl_OnStop( CBaseFilterImpl* pImpl ) { CAudioRendererImpl_THIS(pImpl,basefilter); FIXME( "(%p)\n", This ); CAudioRendererImpl_waveOutUninit(This); This->m_fInFlush = FALSE; TRACE("returned\n" ); return NOERROR; } static const CBaseFilterHandlers filterhandlers = { CAudioRendererImpl_OnActive, /* pOnActive */ CAudioRendererImpl_OnInactive, /* pOnInactive */ CAudioRendererImpl_OnStop, /* pOnStop */ }; /*************************************************************************** * * CAudioRendererPinImpl methods * */ static HRESULT CAudioRendererPinImpl_OnDisconnect( CPinBaseImpl* pImpl ) { CAudioRendererPinImpl_THIS(pImpl,pin); TRACE("(%p)\n",This); if ( This->meminput.pAllocator != NULL ) { IMemAllocator_Decommit(This->meminput.pAllocator); IMemAllocator_Release(This->meminput.pAllocator); This->meminput.pAllocator = NULL; } return NOERROR; } static HRESULT CAudioRendererPinImpl_CheckMediaType( CPinBaseImpl* pImpl, const AM_MEDIA_TYPE* pmt ) { CAudioRendererPinImpl_THIS(pImpl,pin); const WAVEFORMATEX* pwfx; TRACE("(%p,%p)\n",This,pmt); if ( !IsEqualGUID( &pmt->majortype, &MEDIATYPE_Audio ) ) { TRACE("not audio\n"); return E_FAIL; } if ( !IsEqualGUID( &pmt->subtype, &MEDIASUBTYPE_NULL ) && !IsEqualGUID( &pmt->subtype, &MEDIASUBTYPE_PCM ) ) { TRACE("not PCM\n"); return E_FAIL; } if ( !IsEqualGUID( &pmt->formattype, &FORMAT_WaveFormatEx ) ) { TRACE("not WAVE\n"); return E_FAIL; } TRACE("testing WAVE header\n"); if ( pmt->cbFormat < (sizeof(WAVEFORMATEX)-sizeof(WORD)) ) return E_FAIL; pwfx = (const WAVEFORMATEX*)pmt->pbFormat; if ( pwfx == NULL ) return E_FAIL; if ( pwfx->wFormatTag != 1 ) return E_FAIL; TRACE("returned successfully.\n"); return NOERROR; } static HRESULT CAudioRendererPinImpl_Receive( CPinBaseImpl* pImpl, IMediaSample* pSample ) { CAudioRendererPinImpl_THIS(pImpl,pin); HRESULT hr; BYTE* pData = NULL; DWORD dwDataLength; DWORD dwWritten; FIXME( "(%p,%p)\n",This,pSample ); if ( !This->pRender->m_fWaveOutInit ) return E_UNEXPECTED; if ( This->pRender->m_fInFlush ) return S_FALSE; if ( pSample == NULL ) return E_POINTER; hr = IMediaSample_GetPointer( pSample, &pData ); if ( FAILED(hr) ) return hr; dwDataLength = (DWORD)IMediaSample_GetActualDataLength( pSample ); while ( 1 ) { TRACE("trying to write %lu bytes\n",dwDataLength); ResetEvent( This->pRender->m_hEventRender ); hr = CAudioRendererImpl_waveOutWriteData( This->pRender,pData,dwDataLength,&dwWritten); if ( FAILED(hr) ) break; if ( hr == S_FALSE ) { WaitForSingleObject( This->pRender->m_hEventRender, INFINITE ); continue; } pData += dwWritten; dwDataLength -= dwWritten; hr = CAudioRendererImpl_waveOutFlush(This->pRender); if ( FAILED(hr) ) break; if ( dwDataLength == 0 ) break; } return hr; } static HRESULT CAudioRendererPinImpl_ReceiveCanBlock( CPinBaseImpl* pImpl ) { CAudioRendererPinImpl_THIS(pImpl,pin); TRACE( "(%p)\n", This ); /* might block. */ return S_OK; } static HRESULT CAudioRendererPinImpl_EndOfStream( CPinBaseImpl* pImpl ) { CAudioRendererPinImpl_THIS(pImpl,pin); FIXME( "(%p)\n", This ); This->pRender->m_fInFlush = FALSE; /* FIXME - don't notify twice until stopped or seeked. */ return CBaseFilterImpl_MediaEventNotify( &This->pRender->basefilter, EC_COMPLETE, (LONG_PTR)S_OK, (LONG_PTR)(IBaseFilter*)(This->pRender) ); } static HRESULT CAudioRendererPinImpl_BeginFlush( CPinBaseImpl* pImpl ) { CAudioRendererPinImpl_THIS(pImpl,pin); FIXME( "(%p)\n", This ); This->pRender->m_fInFlush = TRUE; CAudioRendererImpl_waveOutReset(This->pRender); return NOERROR; } static HRESULT CAudioRendererPinImpl_EndFlush( CPinBaseImpl* pImpl ) { CAudioRendererPinImpl_THIS(pImpl,pin); FIXME( "(%p)\n", This ); This->pRender->m_fInFlush = FALSE; return NOERROR; } static HRESULT CAudioRendererPinImpl_NewSegment( CPinBaseImpl* pImpl, REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, double rate ) { CAudioRendererPinImpl_THIS(pImpl,pin); FIXME( "(%p)\n", This ); This->pRender->m_fInFlush = FALSE; return NOERROR; } static const CBasePinHandlers pinhandlers = { NULL, /* pOnPreConnect */ NULL, /* pOnPostConnect */ CAudioRendererPinImpl_OnDisconnect, /* pOnDisconnect */ CAudioRendererPinImpl_CheckMediaType, /* pCheckMediaType */ NULL, /* pQualityNotify */ CAudioRendererPinImpl_Receive, /* pReceive */ CAudioRendererPinImpl_ReceiveCanBlock, /* pReceiveCanBlock */ CAudioRendererPinImpl_EndOfStream, /* pEndOfStream */ CAudioRendererPinImpl_BeginFlush, /* pBeginFlush */ CAudioRendererPinImpl_EndFlush, /* pEndFlush */ CAudioRendererPinImpl_NewSegment, /* pNewSegment */ }; /*************************************************************************** * * new/delete CAudioRendererImpl * */ /* can I use offsetof safely? - FIXME? */ static QUARTZ_IFEntry FilterIFEntries[] = { { &IID_IPersist, offsetof(CAudioRendererImpl,basefilter)-offsetof(CAudioRendererImpl,unk) }, { &IID_IMediaFilter, offsetof(CAudioRendererImpl,basefilter)-offsetof(CAudioRendererImpl,unk) }, { &IID_IBaseFilter, offsetof(CAudioRendererImpl,basefilter)-offsetof(CAudioRendererImpl,unk) }, { &IID_IBasicAudio, offsetof(CAudioRendererImpl,basaud)-offsetof(CAudioRendererImpl,unk) }, }; static HRESULT CAudioRendererImpl_OnQueryInterface( IUnknown* punk, const IID* piid, void** ppobj ) { CAudioRendererImpl_THIS(punk,unk); if ( This->pSeekPass == NULL ) return E_NOINTERFACE; if ( IsEqualGUID( &IID_IMediaPosition, piid ) || IsEqualGUID( &IID_IMediaSeeking, piid ) ) { TRACE( "IMediaSeeking(or IMediaPosition) is queried\n" ); return IUnknown_QueryInterface( (IUnknown*)(&This->pSeekPass->unk), piid, ppobj ); } return E_NOINTERFACE; } static void QUARTZ_DestroyAudioRenderer(IUnknown* punk) { CAudioRendererImpl_THIS(punk,unk); TRACE( "(%p)\n", This ); if ( This->pPin != NULL ) { IUnknown_Release(This->pPin->unk.punkControl); This->pPin = NULL; } if ( This->pSeekPass != NULL ) { IUnknown_Release((IUnknown*)&This->pSeekPass->unk); This->pSeekPass = NULL; } CAudioRendererImpl_UninitIBasicAudio(This); CBaseFilterImpl_UninitIBaseFilter(&This->basefilter); } HRESULT QUARTZ_CreateAudioRenderer(IUnknown* punkOuter,void** ppobj) { CAudioRendererImpl* This = NULL; HRESULT hr; TRACE("(%p,%p)\n",punkOuter,ppobj); This = (CAudioRendererImpl*) QUARTZ_AllocObj( sizeof(CAudioRendererImpl) ); if ( This == NULL ) return E_OUTOFMEMORY; This->pSeekPass = NULL; This->pPin = NULL; This->m_fInFlush = FALSE; This->m_fWaveOutInit = FALSE; This->m_hEventRender = (HANDLE)NULL; QUARTZ_IUnkInit( &This->unk, punkOuter ); This->qiext.pNext = NULL; This->qiext.pOnQueryInterface = &CAudioRendererImpl_OnQueryInterface; QUARTZ_IUnkAddDelegation( &This->unk, &This->qiext ); hr = CBaseFilterImpl_InitIBaseFilter( &This->basefilter, This->unk.punkControl, &CLSID_AudioRender, QUARTZ_AudioRender_Name, &filterhandlers ); if ( SUCCEEDED(hr) ) { hr = CAudioRendererImpl_InitIBasicAudio(This); if ( FAILED(hr) ) { CBaseFilterImpl_UninitIBaseFilter(&This->basefilter); } } if ( FAILED(hr) ) { QUARTZ_FreeObj(This); return hr; } This->unk.pEntries = FilterIFEntries; This->unk.dwEntries = sizeof(FilterIFEntries)/sizeof(FilterIFEntries[0]); This->unk.pOnFinalRelease = QUARTZ_DestroyAudioRenderer; hr = QUARTZ_CreateAudioRendererPin( This, &This->basefilter.csFilter, &This->pPin ); if ( SUCCEEDED(hr) ) hr = QUARTZ_CompList_AddComp( This->basefilter.pInPins, (IUnknown*)&This->pPin->pin, NULL, 0 ); if ( SUCCEEDED(hr) ) hr = QUARTZ_CreateSeekingPassThruInternal( (IUnknown*)&(This->unk), &This->pSeekPass, TRUE, (IPin*)&(This->pPin->pin) ); if ( FAILED(hr) ) { IUnknown_Release( This->unk.punkControl ); return hr; } *ppobj = (void*)&(This->unk); return S_OK; } /*************************************************************************** * * new/delete CAudioRendererPinImpl * */ /* can I use offsetof safely? - FIXME? */ static QUARTZ_IFEntry PinIFEntries[] = { { &IID_IPin, offsetof(CAudioRendererPinImpl,pin)-offsetof(CAudioRendererPinImpl,unk) }, { &IID_IMemInputPin, offsetof(CAudioRendererPinImpl,meminput)-offsetof(CAudioRendererPinImpl,unk) }, }; static void QUARTZ_DestroyAudioRendererPin(IUnknown* punk) { CAudioRendererPinImpl_THIS(punk,unk); TRACE( "(%p)\n", This ); CPinBaseImpl_UninitIPin( &This->pin ); CMemInputPinBaseImpl_UninitIMemInputPin( &This->meminput ); } HRESULT QUARTZ_CreateAudioRendererPin( CAudioRendererImpl* pFilter, CRITICAL_SECTION* pcsPin, CAudioRendererPinImpl** ppPin) { CAudioRendererPinImpl* This = NULL; HRESULT hr; TRACE("(%p,%p,%p)\n",pFilter,pcsPin,ppPin); This = (CAudioRendererPinImpl*) QUARTZ_AllocObj( sizeof(CAudioRendererPinImpl) ); if ( This == NULL ) return E_OUTOFMEMORY; QUARTZ_IUnkInit( &This->unk, NULL ); This->pRender = pFilter; hr = CPinBaseImpl_InitIPin( &This->pin, This->unk.punkControl, pcsPin, &pFilter->basefilter, QUARTZ_AudioRenderPin_Name, FALSE, &pinhandlers ); if ( SUCCEEDED(hr) ) { hr = CMemInputPinBaseImpl_InitIMemInputPin( &This->meminput, This->unk.punkControl, &This->pin ); if ( FAILED(hr) ) { CPinBaseImpl_UninitIPin( &This->pin ); } } if ( FAILED(hr) ) { QUARTZ_FreeObj(This); return hr; } This->unk.pEntries = PinIFEntries; This->unk.dwEntries = sizeof(PinIFEntries)/sizeof(PinIFEntries[0]); This->unk.pOnFinalRelease = QUARTZ_DestroyAudioRendererPin; *ppPin = This; TRACE("returned successfully.\n"); return S_OK; } /*************************************************************************** * * CAudioRendererImpl::IBasicAudio * */ static HRESULT WINAPI IBasicAudio_fnQueryInterface(IBasicAudio* iface,REFIID riid,void** ppobj) { CAudioRendererImpl_THIS(iface,basaud); TRACE("(%p)->()\n",This); return IUnknown_QueryInterface(This->unk.punkControl,riid,ppobj); } static ULONG WINAPI IBasicAudio_fnAddRef(IBasicAudio* iface) { CAudioRendererImpl_THIS(iface,basaud); TRACE("(%p)->()\n",This); return IUnknown_AddRef(This->unk.punkControl); } static ULONG WINAPI IBasicAudio_fnRelease(IBasicAudio* iface) { CAudioRendererImpl_THIS(iface,basaud); TRACE("(%p)->()\n",This); return IUnknown_Release(This->unk.punkControl); } static HRESULT WINAPI IBasicAudio_fnGetTypeInfoCount(IBasicAudio* iface,UINT* pcTypeInfo) { CAudioRendererImpl_THIS(iface,basaud); FIXME("(%p)->()\n",This); return E_NOTIMPL; } static HRESULT WINAPI IBasicAudio_fnGetTypeInfo(IBasicAudio* iface,UINT iTypeInfo, LCID lcid, ITypeInfo** ppobj) { CAudioRendererImpl_THIS(iface,basaud); FIXME("(%p)->()\n",This); return E_NOTIMPL; } static HRESULT WINAPI IBasicAudio_fnGetIDsOfNames(IBasicAudio* iface,REFIID riid, LPOLESTR* ppwszName, UINT cNames, LCID lcid, DISPID* pDispId) { CAudioRendererImpl_THIS(iface,basaud); FIXME("(%p)->()\n",This); return E_NOTIMPL; } static HRESULT WINAPI IBasicAudio_fnInvoke(IBasicAudio* iface,DISPID DispId, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarRes, EXCEPINFO* pExcepInfo, UINT* puArgErr) { CAudioRendererImpl_THIS(iface,basaud); FIXME("(%p)->()\n",This); return E_NOTIMPL; } static HRESULT WINAPI IBasicAudio_fnput_Volume(IBasicAudio* iface,long lVol) { CAudioRendererImpl_THIS(iface,basaud); FIXME("(%p)->()\n",This); return E_NOTIMPL; } static HRESULT WINAPI IBasicAudio_fnget_Volume(IBasicAudio* iface,long* plVol) { CAudioRendererImpl_THIS(iface,basaud); FIXME("(%p)->()\n",This); return E_NOTIMPL; } static HRESULT WINAPI IBasicAudio_fnput_Balance(IBasicAudio* iface,long lBalance) { CAudioRendererImpl_THIS(iface,basaud); FIXME("(%p)->()\n",This); return E_NOTIMPL; } static HRESULT WINAPI IBasicAudio_fnget_Balance(IBasicAudio* iface,long* plBalance) { CAudioRendererImpl_THIS(iface,basaud); FIXME("(%p)->()\n",This); return E_NOTIMPL; } static ICOM_VTABLE(IBasicAudio) ibasicaudio = { ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE /* IUnknown fields */ IBasicAudio_fnQueryInterface, IBasicAudio_fnAddRef, IBasicAudio_fnRelease, /* IDispatch fields */ IBasicAudio_fnGetTypeInfoCount, IBasicAudio_fnGetTypeInfo, IBasicAudio_fnGetIDsOfNames, IBasicAudio_fnInvoke, /* IBasicAudio fields */ IBasicAudio_fnput_Volume, IBasicAudio_fnget_Volume, IBasicAudio_fnput_Balance, IBasicAudio_fnget_Balance, }; HRESULT CAudioRendererImpl_InitIBasicAudio( CAudioRendererImpl* This ) { TRACE("(%p)\n",This); ICOM_VTBL(&This->basaud) = &ibasicaudio; return NOERROR; } void CAudioRendererImpl_UninitIBasicAudio( CAudioRendererImpl* This ) { TRACE("(%p)\n",This); }