?? hxaudstr.cpp
字號:
* Return the stream's audio format.
*/
HX_RESULT CHXAudioStream::GetFormat
(
HXAudioFormat* pAudioFormat
)
{
if (!m_bAudioFormatKnown)
{
return HXR_NOT_INITIALIZED;
}
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::Setup
* Purpose:
* This is called by the player's Setup method. At this
* time the audio device format is set and we can now
* set up the streams pre-mixing buffer. This buffer
* contains data that has been resampled to match the
* audio device format.
*/
HX_RESULT CHXAudioStream::Setup(
HXAudioFormat* pFormat
, ULONG32 ulGranularity
)
{
HX_RESULT theErr = HXR_OK;
m_DeviceFmt.uChannels = pFormat->uChannels;
m_DeviceFmt.uBitsPerSample = pFormat->uBitsPerSample;
m_DeviceFmt.ulSamplesPerSec = pFormat->ulSamplesPerSec;
m_DeviceFmt.uMaxBlockSize = pFormat->uMaxBlockSize;
m_ulGranularity = ulGranularity;
m_bSetupDone = TRUE;
/* we have all the info now.. so setup the resampler */
if (m_bAudioFormatKnown && !m_bInited)
{
theErr = ProcessInfo();
}
return theErr;
}
/************************************************************************
* Method:
* IHXAudioStream::ResetStream
* Purpose:
*/
void CHXAudioStream::ResetStream()
{
m_bInited = FALSE;
m_bCanBeRewound = FALSE;
m_bSetupDone = FALSE;
m_bAudioFormatKnown = FALSE;
m_bIsResumed = FALSE;
UnRegister();
while (m_pAvailableBuffers && m_pAvailableBuffers->GetCount() > 0)
{
IHXBuffer* pBuffer = (IHXBuffer*) m_pAvailableBuffers->RemoveHead();
HX_RELEASE(pBuffer);
}
HX_DELETE(m_pAvailableBuffers);
// Delete all entries in the audio data list
FlushBuffers();
HX_DELETE(m_pDataList);
HX_DELETE(m_pInstantaneousList);
CleanupRAByToTs();
HX_DELETE(m_pRAByToTsInList);
HX_DELETE(m_pRAByToTsAdjustedList);
// Delete resample buffer
HX_VECTOR_DELETE(m_pResampleBuf);
// Delete tmp resample buffer
HX_VECTOR_DELETE(m_pTmpResBuf);
HX_VECTOR_DELETE(m_pCrossFadeBuffer);
HX_VECTOR_DELETE(m_pExcessInterpBuffer);
HX_VECTOR_DELETE(m_pTempInterpBuffer);
m_ulExcessInterpBufferSize = m_ulPreviousExcessInterpBufferSize = 0;
#if defined(HELIX_FEATURE_CROSSFADE)
HX_DELETE(m_pCrossFader);
#endif /* HELIX_FEATURE_CROSSFADE */
// Free the resampler
HX_RELEASE(m_pResampler);
m_bGotHooks = FALSE;
m_llLastWriteTime = 0;
m_ulTSRollOver = 0;
#ifdef _TESTING
if ( g_log > 0 )
close(g_log);
g_log = -1;
#endif
HX_RELEASE(m_pValues);
#if defined(HELIX_FEATURE_AUDIO_PREMIXHOOK)
// Delete all entries in the pre-mix hook list.
if ( m_PreMixHookMap.GetCount() > 0)
{
HXAudioHookInfo* h = 0;
CHXMapPtrToPtr::Iterator lIter = m_PreMixHookMap.Begin();
for (; lIter != m_PreMixHookMap.End(); ++lIter)
{
h = (HXAudioHookInfo*) (*lIter);
ProcessAudioHook(ACTION_REMOVE, h->pHook);
h->pHook->Release();
delete h;
}
m_PreMixHookMap.RemoveAll();
}
#endif /* HELIX_FEATURE_AUDIO_PREMIXHOOK */
#if defined(HELIX_FEATURE_VOLUME)
// Delete IRMA volume object.
if (m_pStreamVolume && m_pVolumeAdviseSink)
{
m_pStreamVolume->RemoveAdviseSink(m_pVolumeAdviseSink);
m_pVolumeAdviseSink->m_pCHXAudioStream = 0;
}
HX_RELEASE(m_pVolumeAdviseSink);
#endif /* HELIX_FEATURE_VOLUME */
HX_RELEASE(m_pStreamVolume);
HX_DELETE(m_pInDataPtr);
HX_DELETE(m_pOutDataPtr);
if (m_DryNotificationMap.GetCount() > 0)
{
IHXDryNotification* pDryNotification = 0;
CHXMapPtrToPtr::Iterator lIter = m_DryNotificationMap.Begin();
for (; lIter != m_DryNotificationMap.End(); ++lIter)
{
pDryNotification = (IHXDryNotification*) (*lIter);
pDryNotification->Release();
}
m_DryNotificationMap.RemoveAll();
}
HX_RELEASE(m_pCrossFadeStream);
HX_RELEASE(m_pCommonClassFactory);
#if defined(HELIX_FEATURE_PREFERENCES)
HX_RELEASE(m_pPreferences);
#endif /* HELIX_FEATURE_PREFERENCES */
HX_RELEASE(m_Owner);
return;
}
HX_RESULT
CHXAudioStream::ProcessAudioHook(PROCESS_ACTION action,
IHXAudioHook* pAudioHook)
{
return HXR_OK;
}
// Dummy version of this method - real version would be in hxaudstr_new.cpp
BOOL CHXAudioStream::ConvertIntoBuffer(tAudioSample* buffer, UINT32 nSamples, INT64 llStartTimeInSamples)
{
return FALSE;
}
/************************************************************************
* Method:
* IHXAudioStream::InitHooks
* Purpose:
* Init any pre-mix hooks. Return TRUE if hooks exist else return
* FALSE.
*/
void CHXAudioStream::InitHooks()
{
#if defined(HELIX_FEATURE_AUDIO_PREMIXHOOK)
/* Iterate thru the hook list and call the hook's OnInit().
* If any of the hooks have disabled write set to TRUE, then
* we will let this override any set to FALSE.
*/
if ( m_PreMixHookMap.GetCount() > 0 )
{
HXAudioHookInfo* h = 0;
CHXMapPtrToPtr::Iterator lIter = m_PreMixHookMap.Begin();
for (; lIter != m_PreMixHookMap.End(); ++lIter)
{
h = (HXAudioHookInfo*) (*lIter);
if (h->bIgnoreAudioData ||
HXR_OK == ProcessAudioHook(ACTION_CHECK, h->pHook))
{
h->pHook->OnInit( &m_AudioFmt );
}
}
}
#endif /* HELIX_FEATURE_AUDIO_PREMIXHOOK */
m_bHooksInitialized = TRUE;
}
/************************************************************************
* Method:
* IHXAudioStream::ProcessHooks
* Purpose:
*/
HX_RESULT CHXAudioStream::ProcessHooks
(
HXAudioData* pInData,
HXAudioData* pOutData
)
{
HX_RESULT theErr = HXR_OK;
#if defined(HELIX_FEATURE_AUDIO_PREMIXHOOK)
m_pInDataPtr->pData = pInData->pData;
m_pInDataPtr->pData->AddRef();
m_pInDataPtr->ulAudioTime = pInData->ulAudioTime;
m_pOutDataPtr->pData = NULL;
m_pOutDataPtr->ulAudioTime = pInData->ulAudioTime;
m_pInDataPtr->uAudioStreamType = pInData->uAudioStreamType;
m_pOutDataPtr->uAudioStreamType = pInData->uAudioStreamType;
if ( m_PreMixHookMap.GetCount() > 0 )
{
HXAudioHookInfo* pPreMixHookInfo = 0;
CHXMapPtrToPtr::Iterator lIter = m_PreMixHookMap.Begin();
for (; !theErr && lIter != m_PreMixHookMap.End(); ++lIter)
{
pPreMixHookInfo = (HXAudioHookInfo*) (*lIter);
if (HXR_OK == ProcessAudioHook(ACTION_CHECK, pPreMixHookInfo->pHook))
{
theErr = pPreMixHookInfo->pHook->OnBuffer( m_pInDataPtr, m_pOutDataPtr);
/* Check to see if renderer changed the buffer. If so, then
* make this output as input to the next Hook.
*/
if (!theErr && m_pOutDataPtr->pData)
{
m_pInDataPtr->pData->Release();
m_pInDataPtr->pData = m_pOutDataPtr->pData;
m_pInDataPtr->ulAudioTime = m_pOutDataPtr->ulAudioTime;
m_pOutDataPtr->pData = 0;
}
}
else if (pPreMixHookInfo->bIgnoreAudioData)
{
IHXBuffer* pTempBuf = m_pInDataPtr->pData;
m_pInDataPtr->pData = NULL;
theErr = pPreMixHookInfo->pHook->OnBuffer( m_pInDataPtr, m_pOutDataPtr);
m_pInDataPtr->pData = pTempBuf;
}
}
}
/* Final output is always in InDataPtr*/
pOutData->pData = m_pInDataPtr->pData;
pOutData->ulAudioTime = m_pInDataPtr->ulAudioTime;
pOutData->uAudioStreamType = m_pInDataPtr->uAudioStreamType;
#endif /* HELIX_FEATURE_AUDIO_PREMIXHOOK */
return theErr;
}
/************************************************************************
* Method:
* CHXAudioStream::MixIntoBuffer
* Purpose:
* Mix stream data into this pPlayerBuf.
* Note:
*
* Resampler always works on 16 bit PCM. If the input is
* 8 bit, it converts it first to 16 bit before making
* any resampling calculations.
* We always try to open audio device in 16 bit stereo mode.
* This is because a new player/stream may be instantiated in the
* midst of a presentation and this new stream may be stereo. If we
* earlier opened the device as mono, we will have to force this stereo
* stream to be played as mono! Not a good idea. Also any mono-streo
* conversion almost comes for free (some extra memory usage and
* an extra assignment) since it can be done in the mixing loop in
* MixBuffer().
*
* Any 8-16 and stereo-mono conversion, if required, SHOULD be done
* before resampling.
* Any mono-stereo conversion should be done after resampling.
*
* Stereo-Mono conversion code resides in the resampler.
* Mono-Stereo conversion code resides in the mixer.
*
*/
HX_RESULT CHXAudioStream::MixIntoBuffer
(
UCHAR* pPlayerBuf,
ULONG32 ulBufSize,
ULONG32& ulBufTime,
BOOL& bIsMixBufferDirty,
BOOL bGetCrossFadeData
)
{
BOOL bCrossFadeThisTime = FALSE;
UINT32 ulTimeActuallyFaded = m_ulGranularity;
if (!m_bInited)
{
return HXR_NOT_INITIALIZED;
}
//{FILE* f1 = ::fopen("c:\\temp\\rasync.txt", "a+"); ::fprintf(f1, "Call MixIntoBuffer: %lu\n", m_ulLastWriteTime);::fclose(f1);}
/* If this is a *FROM* stream, we may have already mixed
* data during cross-fade with *TO* stream
*/
if (m_bFadeAlreadyDone && !m_bFadeToThisStream)
{
m_bFadeAlreadyDone = FALSE;
return HXR_OK;
}
HX_ASSERT(!bGetCrossFadeData || !m_bFadeToThisStream);
/* If we need to mix cross fade data from the *from* stream,
* it better be available
*/
HX_ASSERT(!bGetCrossFadeData || m_pDataList->GetCount() > 0);
/* If this stream needs to be cross-faded and is a
* NOT a fade-to stream, it would have been already taken
* care of by the fade-to stream in an earlier call to
* MixIntoBuffer()
*/
if (m_bCrossFadingToBeDone && m_pDataList->GetCount() > 0)
{
HXAudioInfo* pInfo = (HXAudioInfo*) m_pDataList->GetHead();
INT64 llActualStartTime = 0;
if (pInfo)
{
llActualStartTime = CAST_TO_INT64 (pInfo->ulStartTime) +
CAST_TO_INT64 (CalcMs(pInfo->pBuffer->GetSize() - pInfo->ulBytesLeft)) +
CAST_TO_INT64 m_ulTSRollOver * CAST_TO_INT64 MAX_UINT32;
if (m_bFadeToThisStream)
{
/* Cool! It is time for cross-fading */
if ((m_llLastWriteTime <= m_llCrossFadeStartTime &&
m_llCrossFadeStartTime - m_llLastWriteTime <= CAST_TO_INT64 m_ulGranularity) ||
(m_llLastWriteTime > m_llCrossFadeStartTime &&
m_llLastWriteTime - m_llCrossFadeStartTime <= CAST_TO_INT64 m_ulFudge))
{
bCrossFadeThisTime = TRUE;
if (m_llLastWriteTime <= m_llCrossFadeStartTime)
{
ulTimeActuallyFaded = m_ulGranularity -
INT64_TO_UINT32(m_llCrossFadeStartTime - m_llLastWriteTime);
}
//{FILE* f1 = ::fopen("c:\\raroot\\racross.txt", "a+"); ::fprintf(f1, "m_ulLastWriteTime: %lu ulStartTime: %lu m_ulCrossFadeStartTime: %lu pInfo->ulStartTime: %lu pInfo->pBuffer->GetSize(): %lu pInfo->ulBytesLeft: %lu\n", m_ulLastWriteTime, ulStartTime, m_ulCrossFadeStartTime, pInfo->ulStartTime, pInfo->pBuffer->GetSize(), pInfo->ulBytesLeft);::fclose(f1);}
HX_ASSERT(
(llActualStartTime >= m_llCrossFadeStartTime &&
(llActualStartTime <= m_llCrossFadeStartTime +
m_ulCrossFadeDuration)) ||
(llActualStartTime < m_llCrossFadeStartTime &&
(m_llCrossFadeStartTime - llActualStartTime <= CAST_TO_INT64 m_ulFudge)));
}
}
}
}
UINT32 ulLastWriteTime = INT64_TO_UINT32(m_llLastWriteTime - CAST_TO_INT64 m_ulTSRollOver * CAST_TO_INT64 MAX_UINT32);
if (!bGetCrossFadeData && ulBufTime < ulLastWriteTime)
{
ulBufTime = ulLastWriteTime;
}
/* If there are any DryNotifications and the data list is empty
* we need to notify them so that they can write more data.
*/
if (m_DryNotificationMap.GetCount() > 0 || m_Owner->GetAudioStreamCount() == 1)
{
UINT32 ulNumMsRequired = m_ulGranularity;
if (m_pDataList->IsEmpty() || !EnoughDataAvailable(ulLastWriteTime, ulNumMsRequired))
{
if (!bIsMixBufferDirty && !bGetCrossFadeData && !m_Owner->m_Owner->ReallyNeedData())
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -