📄 hxaudstr_new.cpp
字号:
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.
*/
STDMETHODIMP
CHXAudioStream::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
)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -