?? hxaudstr.cpp
字號:
#ifdef _TESTING
g_log = open("c:\\log\\stream.raw", O_WRONLY | O_CREAT
| O_BINARY | _O_SEQUENTIAL);
#endif
m_bAudioFormatKnown = TRUE;
if (m_bSetupToBeDone)
{
m_bSetupToBeDone = FALSE;
m_Owner->AudioFormatNowKnown();
}
if (!theErr && m_bSetupDone && !m_bInited)
{
theErr = ProcessInfo();
}
return theErr;
}
/************************************************************************
* Method:
* IHXAudioStream::Write
* Purpose:
* Write audio data to Audio Services.
*
* NOTE: If the renderer loses packets and there is no loss
* correction, then the renderer should write the next packet
* using a meaningful start time. Audio Services will play
* silence where packets are missing.
*/
STDMETHODIMP CHXAudioStream::Write
(
HXAudioData* pInData
)
{
HX_RESULT theErr = HXR_OK;
if (!pInData)
{
return HXR_INVALID_PARAMETER;
}
if (!m_bInited)
{
return HXR_NOT_INITIALIZED;
}
// Init pre-mix hooks. Call this once to set up hook info.
if ( !m_bHooksInitialized )
{
InitHooks();
}
// 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;
if(!pPreMixHookInfo)
{
return HXR_OUTOFMEMORY;
}
pPreMixHookInfo->pHook = pHook;
pPreMixHookInfo->bDisableWrite = bDisableWrite;
pPreMixHookInfo->bIgnoreAudioData = 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
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()
{
if ( m_pStreamVolume )
{
m_pStreamVolume->AddRef();
return m_pStreamVolume;
}
else
{
return 0;
}
}
#if defined(HELIX_FEATURE_VOLUME)
/*
* IHXVolumeAdviseSink methods
*/
STDMETHODIMP CHXAudioStream::OnVolumeChange
(
const UINT16 uVolume
)
{
m_uVolume = uVolume;
return HXR_OK;
}
STDMETHODIMP CHXAudioStream::OnMuteChange
(
const BOOL bMute
)
{
m_bMute = bMute;
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)
{
HXAudioInfo* pInfo = NULL;
if (!m_pDataList->IsEmpty() &&
NULL != (pInfo = (HXAudioInfo*) m_pDataList->GetTail()))
{
pAudioData->ulAudioTime = pInfo->ulStartTime +
CalcMs(pInfo->pBuffer->GetSize());
}
else
{
pAudioData->ulAudioTime = INT64_TO_UINT32(m_llLastWriteTime - CAST_TO_INT64 m_ulTSRollOver * CAST_TO_INT64 MAX_UINT32);
}
return HXR_OK;
}
// make sure the renderer does not pass NULL data!!
HX_ASSERT(pAudioData->pData->GetBuffer() != NULL &&
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -