📄 hxaudstr_new.cpp
字号:
HXAudioData audioData ; audioData.pData = m_piPendingAudioData ; audioData.pData->AddRef() ; // use time of incoming packet -- one sample frame is below the // ms resolution of time stamps. audioData.ulAudioTime = pInData->ulAudioTime; // stream type is incoming stream type audioData.uAudioStreamType = pInData->uAudioStreamType; theErr = Write2(&audioData) ; audioData.pData->Release() ; m_ulPendingAudioBytes = 0 ; // release the slush buffer HX_RELEASE(m_piPendingAudioData) ; if (FAILED(theErr)) return theErr ; } // put partial sample frames from the end of the incoming buffer // into the slush buffer. if (ulInBytes % m_ulSampleFrameSize) { // the slush buffer should be empty here. HX_ASSERT(m_ulPendingAudioBytes == 0); HX_ASSERT(m_piPendingAudioData == 0) ; // reserve a new slush buffer theErr = CreateInstance(IID_IHXBuffer, (void**)&m_piPendingAudioData); if (SUCCEEDED(theErr)) theErr = m_piPendingAudioData->SetSize(m_ulSampleFrameSize) ; if (SUCCEEDED(theErr)) { m_ulPendingAudioBytes = ulInBytes % m_ulSampleFrameSize ; ulInBytes -= m_ulPendingAudioBytes ; memcpy(m_piPendingAudioData->GetBuffer(), pInData->pData->GetBuffer() + ulCutoffBytes + ulInBytes, m_ulPendingAudioBytes) ; } if (FAILED(theErr)) return theErr ; } // send any leftover fragment of the incoming buffer. if (ulInBytes == pInData->pData->GetSize() && !ulCutoffBytes) /* this is the entire buffer, not a fragment. * This is the normal case -- let's handle it efficiently. */ { theErr = Write2(pInData) ; } else if (ulInBytes) /* if anything left in buffer, send it in a fragment */ { HXAudioData audioData ; CHXBufferFragment* pFragment = new CHXBufferFragment( pInData->pData, pInData->pData->GetBuffer() + ulCutoffBytes, ulInBytes); theErr = pFragment->QueryInterface(IID_IUnknown, (void**)&audioData.pData) ; // this must always succeed, since we know it exports a IHXBuffer HX_ASSERT(SUCCEEDED(theErr)) ; // use time of incoming packet -- one sample frame is below the // ms resolution of time stamps. audioData.ulAudioTime = pInData->ulAudioTime; // stream type is incoming stream type if we did not cut anything away, // and STREAMED_AUDIO if we did (because in that case this is a continuation) audioData.uAudioStreamType = ulCutoffBytes ? STREAMING_AUDIO : pInData->uAudioStreamType ; theErr = Write2(&audioData) ; // we release our hold on pFragment here. When MixIntoBuffer() is done with // this fragment, it will also release its hold, and the fragment gets // deleted. audioData.pData->Release() ; }#else theErr = Write2(pInData) ;#endif /* HELIX_FEATURE_AUDIO_INCOMPLETESAMPLE */ return theErr;}/************************************************************************ * Method: * IHXAudioStream::Write2 * Purpose: * Write audio data to Audio Services. This is a companion/backend * function to IHXAudioStream::Write * */HX_RESULT CHXAudioStream::Write2(HXAudioData* pInData){ HX_RESULT theErr = HXR_OK; // Process any "hooks"; Add the data to the data list. /* If buffer is NULL, it means that the user just * wants to know what timestamp should be placed in the next * STREAMED/TIMED audio data */ if ( !m_bGotHooks || !pInData->pData) { theErr = AddData( pInData ); } else { HXAudioData outData; outData.pData = 0; outData.ulAudioTime = 0; theErr = ProcessHooks( pInData, &outData ); if (!theErr && !m_bDisableWrite ) { theErr = AddData( &outData ); } if (outData.pData) { outData.pData->Release(); } } return theErr;}/************************************************************************ * Method: * IHXAudioStream::AddPreMixHook * Purpose: * Use this method to add a pre-mix audio data hook. */STDMETHODIMP CHXAudioStream::AddPreMixHook( IHXAudioHook* pHook, const BOOL bDisableWrite){#if defined(HELIX_FEATURE_AUDIO_PREMIXHOOK) void* pTmp = 0; /* Does one already exists */ if (m_PreMixHookMap.Lookup((void*)pHook, pTmp)) { return HXR_INVALID_PARAMETER; } HXAudioHookInfo* pPreMixHookInfo = (HXAudioHookInfo*) new HXAudioHookInfo; pPreMixHookInfo->pHook = pHook; pPreMixHookInfo->bDisableWrite = bDisableWrite; pPreMixHookInfo->bFinal = FALSE; pPreMixHookInfo->bIgnoreAudioData = FALSE; pPreMixHookInfo->bMultiChannelSupport = FALSE; IHXValues* pValues = NULL; if (pHook && pHook->QueryInterface(IID_IHXValues, (void**) &pValues) == HXR_OK) { UINT32 ulValue = 0; pValues->GetPropertyULONG32("IgnoreAudioData", ulValue); pPreMixHookInfo->bIgnoreAudioData = (ulValue == 1); HX_RELEASE(pValues); } pHook->AddRef(); // Released in destructor IHXAudioMultiChannel* pMultiChannel = NULL; if (pHook && HXR_OK == pHook->QueryInterface(IID_IHXAudioMultiChannel, (void**) &pMultiChannel)) { pPreMixHookInfo->bMultiChannelSupport = pMultiChannel->GetMultiChannelSupport(); } HX_RELEASE(pMultiChannel); m_PreMixHookMap.SetAt(pHook, pPreMixHookInfo); m_bGotHooks = TRUE; /* If any one of them is Disabled, we do not write */ if (bDisableWrite) { m_bDisableWrite = TRUE; } ProcessAudioHook(ACTION_ADD, pHook); /* If we are already initialized, send the audio format */ if (m_bHooksInitialized) { if (pPreMixHookInfo->bIgnoreAudioData || HXR_OK == ProcessAudioHook(ACTION_CHECK, pHook)) { pHook->OnInit( &m_AudioFmt ); } } return HXR_OK;#else return HXR_NOTIMPL;#endif /* HELIX_FEATURE_AUDIO_PREMIXHOOK */}/************************************************************************ * Method: * IHXAudioStream::RemovePreMixHook * Purpose: * Use this method to remove a pre-mix audio data hook. */STDMETHODIMP CHXAudioStream::RemovePreMixHook( IHXAudioHook* pHook){#if defined(HELIX_FEATURE_AUDIO_PREMIXHOOK) HXAudioHookInfo* pPreMixHookInfo = 0; BOOL bCheckForDisableWrite = FALSE; if (!m_PreMixHookMap.Lookup((void*)pHook, (void*&) pPreMixHookInfo)) { return HXR_INVALID_PARAMETER; } m_PreMixHookMap.RemoveKey(pHook); /* If we are removing a hook which had disable write, * we need to re-determine if any of the remaining hooks * has DisableWrite set to TRUE */ if (pPreMixHookInfo->bDisableWrite) { bCheckForDisableWrite = TRUE; m_bDisableWrite = FALSE; } ProcessAudioHook(ACTION_REMOVE, pHook); pPreMixHookInfo->pHook->Release(); delete pPreMixHookInfo; if (m_PreMixHookMap.GetCount() == 0) { m_bGotHooks = FALSE; m_bDisableWrite = FALSE; } else if (bCheckForDisableWrite) { CHXMapPtrToPtr::Iterator lIter = m_PreMixHookMap.Begin(); for (; lIter != m_PreMixHookMap.End(); ++lIter) { HXAudioHookInfo* pPreMixHook = (HXAudioHookInfo*) (*lIter); /* atleast one has Disable Write ON */ if (pPreMixHook->bDisableWrite) { m_bDisableWrite = TRUE; break; } } }#endif /* HELIX_FEATURE_AUDIO_PREMIXHOOK */ return HXR_OK;}/************************************************************************* Method:* IHXAudioStream::AddDryNotification* Purpose:* Use this to add a notification response object to get notifications* when audio stream is running dry.*/STDMETHODIMP CHXAudioStream::AddDryNotification ( IHXDryNotification* /*IN*/ pNotification ){ if (!pNotification) { return HXR_INVALID_PARAMETER; } void* pTmp = 0; /* Does one already exists */ if (m_DryNotificationMap->Lookup((void*)pNotification, pTmp)) { return HXR_INVALID_PARAMETER; } pNotification->AddRef(); m_DryNotificationMap->SetAt((void*)pNotification, (void*)pNotification); return HXR_OK;}/************************************************************************* Method:* IHXAudioStream2::RemoveDryNotification* Purpose:* Use this to remove itself from the notification response object* during the stream switching.*/STDMETHODIMP CHXAudioStream::RemoveDryNotification ( IHXDryNotification* /*IN*/ pNotification ){ HX_RESULT hr = HXR_OK; void* pTmp = 0; if (!pNotification) { hr = HXR_INVALID_PARAMETER; goto cleanup; } // remove only if it is exists if (m_DryNotificationMap->Lookup((void*)pNotification, pTmp)) { m_DryNotificationMap->RemoveKey((void*)pNotification); HX_RELEASE(pNotification); } else { hr = HXR_INVALID_PARAMETER; goto cleanup; }cleanup: return hr;}/************************************************************************* Method:* IHXAudioStream2::GetAudioFormat* Purpose:* Returns the input audio format of the data written by the * renderer. This function will fill in the pre-allocated * HXAudioFormat structure passed in.*/STDMETHODIMPCHXAudioStream::GetAudioFormat(HXAudioFormat* /*IN/OUT*/pAudioFormat){ HX_ASSERT(pAudioFormat); if (!pAudioFormat) { return HXR_INVALID_PARAMETER; } if (!m_bInited) { return HXR_UNEXPECTED; } pAudioFormat->uChannels = m_AudioFmt.uChannels; pAudioFormat->uBitsPerSample = m_AudioFmt.uBitsPerSample; pAudioFormat->ulSamplesPerSec = m_AudioFmt.ulSamplesPerSec; pAudioFormat->uMaxBlockSize = m_AudioFmt.uMaxBlockSize; return HXR_OK;} /************************************************************************ * Method: * IHXAudioStream::GetAudioVolume * Purpose: * Return this stream's IRMA volume interface. */STDMETHODIMP_(IHXVolume*) CHXAudioStream::GetAudioVolume(){ IHXVolume* pRet = NULL; #ifdef HELIX_FEATURE_VOLUME if( m_pStreamVolume ) { m_pStreamVolume->AddRef(); pRet = m_pStreamVolume; }#endif return pRet;}#if defined(HELIX_FEATURE_VOLUME)//// IHXVolume methods//STDMETHODIMP CHXAudioStream::OnVolumeChange(const UINT16 uVolume){ m_uVolume = uVolume;#ifdef HELIX_FEATURE_GAINTOOL if (m_pMixEngine) m_pMixEngine->SetVolume(m_pMixEngine->HXVolume2TenthOfDB(m_uVolume)) ; #endif return HXR_OK;}STDMETHODIMP CHXAudioStream::OnMuteChange(const BOOL bMute){ m_bMute = bMute;#ifdef HELIX_FEATURE_GAINTOOL if (m_pMixEngine) m_pMixEngine->SetVolume(m_pMixEngine->HXVolume2TenthOfDB(bMute ? HX_MIN_VOLUME : m_uVolume)) ;#endif return HXR_OK;}#endif /* HELIX_FEATURE_VOLUME *//************************************************************************ * Method: * IHXAudioStream::AddData * Purpose: * Add audio data to list. * NOTE: Mark Streamed data also as Timed data IF we don't write a streamed packet * since it was LATE!!! */HX_RESULT CHXAudioStream::AddData( HXAudioData* pAudioData){ HX_RESULT theErr = HXR_OK; BOOL bInTSRollOver = FALSE; HXAudioInfo* pAinfo = 0; /* If buffer is NULL, it means that the user just * wants to know what timestamp should be placed in the next * STREAMED/TIMED audio data */ if (!pAudioData->pData)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -