📄 hxaudply.cpp
字号:
/************************************************************************
* Method:
* CHXAudioPlayer::GetStreamCount
* Purpose:
* Get the number of streams associated with this player.
*/
UINT16 CHXAudioPlayer::GetStreamCount()
{
return m_pStreamList->GetCount();
}
/************************************************************************
* Method:
* CHXAudioPlayer::SetStreamInfoResponse
* Purpose:
* Add the stream info response interface to our list.
*/
STDMETHODIMP CHXAudioPlayer::SetStreamInfoResponse
(
IHXAudioStreamInfoResponse* pResponse
)
{
if (!pResponse || !m_pStreamRespList)
{
return HXR_FAILED;
}
/* Add to the stream response list */
LISTPOSITION lPos = m_pStreamRespList->Find(pResponse);
if (lPos)
{
return HXR_FAILED;
}
m_pStreamRespList->AddTail((void*) pResponse);
pResponse->AddRef(); // Released in destructor
return HXR_OK;
}
/************************************************************************
* Method:
* CHXAudioPlayer::RemoveStreamInfoResponse
* Purpose:
* Remove stream info response that was added earlier
*/
STDMETHODIMP CHXAudioPlayer::RemoveStreamInfoResponse
(
IHXAudioStreamInfoResponse* pResponse
)
{
/* Add to the stream response list */
if (pResponse && m_pStreamRespList)
{
LISTPOSITION lPos = m_pStreamRespList->Find(pResponse);
if (lPos)
{
m_pStreamRespList->RemoveAt(lPos);
pResponse->Release(); // Released in destructor
return HXR_OK;
}
}
return HXR_FAILED;
}
UINT16
CHXAudioPlayer::NumberOfResumedStreams(void)
{
UINT16 uNumActive = 0;
if (m_pStreamList && m_pStreamList->GetCount() > 0)
{
CHXAudioStream* pStream = 0;
CHXSimpleList::Iterator lIter = m_pStreamList->Begin();
for (; lIter != m_pStreamList->End(); ++lIter)
{
pStream = (CHXAudioStream*) (*lIter);
if (pStream->GetState() == E_PLAYING)
{
uNumActive++;
}
}
}
return uNumActive;
}
void CHXAudioPlayer::StreamInitialized(CHXAudioStream* pAudioStream)
{
/* If we are already initialized, it means this stream was added mid-
* presentation and gogt initialized later. In this case, report arrival
* of this stream to all StreamInfoResponse objects registered with the
* player
*/
if (m_pStreamRespList && m_bInited)
{
IHXAudioStreamInfoResponse* pAudioStreamInfoResponse = 0;
CHXSimpleList::Iterator lIter = m_pStreamRespList->Begin();
for (; lIter != m_pStreamRespList->End(); ++lIter)
{
pAudioStreamInfoResponse = (IHXAudioStreamInfoResponse*) (*lIter);
pAudioStreamInfoResponse->OnStream(pAudioStream);
}
}
m_bHasStreams = TRUE;
}
ULONG32 CHXAudioPlayer::GetInitialPushdown(BOOL bAtStart /* = FALSE*/)
{
/* If there are any audio streams, initial pushdown is session's
* initial pushdown
*/
if (m_pStreamList->GetCount() > 0)
{
ULONG32 ulRet =
m_Owner->GetInitialPushdown(bAtStart) + m_ulGranularity;
#ifdef HELIX_FEATURE_MIN_HEAP
// The MIN_HEAP code seems to need 1 extra block's worth
// of data to avoid rebuffers during playback. This
// is a low impact temporary solution that fixes the problem.
ulRet += m_ulGranularity;
#endif /* HELIX_FEATURE_MIN_HEAP */
return ulRet;
}
else
{
return 0;
}
}
/************************************************************************
* Method:
* CHXAudioPlayer::OnTimerCallback
* Purpose:
* Timer callback when implementing fake timeline.
*/
void CHXAudioPlayer::OnTimerCallback()
{
ULONG32 ulCurrentTime = HX_GET_TICKCOUNT();
m_ulIncreasingTimer += CALCULATE_ELAPSED_TICKS(m_ulLastFakeCallbackTime, ulCurrentTime);
m_ulLastFakeCallbackTime = ulCurrentTime;
OnTimeSync(m_ulIncreasingTimer);
/* A call to timesync may result in stopping
* playback and we do not want to have any more
* time syncs.
*/
/* Put this back in the scheduler.
*/
if (m_bInited && m_eState == E_PLAYING && !m_ulCallbackID)
{
*m_pFakeAudioCBTime += (int) (m_ulGranularity*1000);
m_ulCallbackID = m_pScheduler->AbsoluteEnter( this,
*((HXTimeval*)m_pFakeAudioCBTime));
}
}
void
CHXAudioPlayer::SetLive(BOOL bIsLive)
{
m_bIsLive = bIsLive;
CHXAudioStream* s = 0;
CHXSimpleList::Iterator lIter = m_pStreamList->Begin();
for (; lIter != m_pStreamList->End(); ++lIter)
{
s = (CHXAudioStream*) (*lIter);
s->SetLive(m_bIsLive);
}
}
void
CHXAudioPlayer::AudioFormatNowKnown(void)
{
HX_ASSERT(m_bInited);
/* When : More than one audio stream created after initialization
* and one of them already called this function earlier
*/
if (m_bHasStreams)
{
return;
}
m_bHasStreams = TRUE;
m_bInited = FALSE;
/* internal setup */
HX_RESULT theErr = Setup(m_ulGranularity);
if (theErr != HXR_OK)
{
IHXErrorMessages* pErrorMessage = NULL;
m_pContext->QueryInterface(IID_IHXErrorMessages, (void**) &pErrorMessage);
if (pErrorMessage)
{
pErrorMessage->Report(HXLOG_ERR, theErr, 0, NULL, NULL);
pErrorMessage->Release();
}
return;
}
HX_ASSERT(m_bInited);
/* If we have not yet resumed, it is simply setting the audio
* player from fake timeline mode to audio timeline mode.
* Instead if we have already been resumed and are acting as a
* fake timeline, we need to kinda pause from being a fake timeline to
* an audio timeline, In this process, we may have to seek the audio
* device to generate right timesyncs.
*/
/* If we are already resumed, we need to call resume again internally */
if (m_bIsResumed)
{
StopFakeTimeline();
Seek(m_ulCurrentTime);
// only resume the owner if we are in a play state...
// otherwise owner will be resumed when the player gets resumed.
if (m_eState == E_PLAYING)
{
m_Owner->Resume();
}
}
else
{
/* Cool! HXPlayer will call resume later */
}
}
void
CHXAudioPlayer::RegisterRealAudioStream(CHXAudioStream* pAudioStream)
{
if (!m_pRealAudioStreamList)
{
m_pRealAudioStreamList = new CHXSimpleList;
}
m_pRealAudioStreamList->AddTail((void*) pAudioStream);
m_bAdjustForRealAudio = TRUE;
}
void
CHXAudioPlayer::UnRegisterRealAudioStream(CHXAudioStream* pAudioStream)
{
if (!m_pRealAudioStreamList)
{
return;
}
LISTPOSITION posStream = m_pRealAudioStreamList->Find((void*) pAudioStream);
if (posStream)
{
m_pRealAudioStreamList->RemoveAt(posStream);
}
/* Check if there are any more RealAudio Streams registered */
if (m_pRealAudioStreamList->GetCount() == 0)
{
m_bAdjustForRealAudio = FALSE;
}
}
BOOL
CHXAudioPlayer::IsAudioOnlyTrue(void)
{
BOOL bRetValue = TRUE;
IHXPlayer* pPlayer = NULL;
m_pContext->QueryInterface(IID_IHXPlayer, (void**)&pPlayer);
HX_ASSERT(pPlayer);
UINT16 uNumSources = pPlayer->GetSourceCount();
IUnknown* pUnknown = NULL;
IHXStreamSource* pStreamSource = NULL;
IHXStream* pStream = NULL;
for (UINT16 i=0; bRetValue && i < uNumSources; i++)
{
pPlayer->GetSource(i, pUnknown);
pUnknown->QueryInterface(IID_IHXStreamSource,
(void**) &pStreamSource);
HX_RELEASE(pUnknown);
HX_ASSERT(pStreamSource);
UINT16 uNumStreams = pStreamSource->GetStreamCount();
for (UINT16 j=0; bRetValue && j < uNumStreams; j++)
{
pStreamSource->GetStream(j, pUnknown);
pUnknown->QueryInterface(IID_IHXStream,
(void**) &pStream);
HX_RELEASE(pUnknown);
HX_ASSERT(pStream);
IHXValues* pHeader = pStream->GetHeader();
if (pHeader)
{
if (!IsThisAudioStream(pHeader))
{
bRetValue = FALSE;
}
pHeader->Release();
}
pStream->Release();
}
HX_RELEASE(pStreamSource);
}
HX_RELEASE(pPlayer);
return bRetValue;
}
BOOL
CHXAudioPlayer::IsThisAudioStream(IHXValues* pHeader)
{
CHXSimpleList::Iterator ndxStream = m_pStreamList->Begin();
for(; ndxStream != m_pStreamList->End(); ++ndxStream)
{
CHXAudioStream* pAudioStream = (CHXAudioStream*) (*ndxStream);
IHXValues* pAudioHeader = pAudioStream->GetStreamInfo();
if (pAudioHeader == pHeader)
{
HX_RELEASE(pAudioHeader);
return TRUE;
}
HX_RELEASE(pAudioHeader);
}
return FALSE;
}
void
CHXAudioPlayer::AdjustForRealAudio()
{
UINT32 ulCurrentDeviceTime = m_ulCurrentTime;
#if defined(HELIX_FEATURE_AUDIO_INACCURATESAMPLING)
if (m_bAdjustForRealAudio)
{
CHXAudioStream* pAudioStream = NULL;
// Only use a playing audio stream for time adjustment:
for (CHXSimpleList::Iterator streamIterator = m_pRealAudioStreamList->Begin();
streamIterator != m_pRealAudioStreamList->End();
++streamIterator)
{
if ( ((CHXAudioStream*) (*streamIterator))->GetState() == E_PLAYING)
{
pAudioStream = (CHXAudioStream*) *streamIterator;
break;
}
}
if (pAudioStream)
{
UINT32 ulAdjustedTime = 0L;
double dBytesPlayed = m_Owner->GetNumBytesPlayed();
if (HXR_OK == pAudioStream->ConvertCurrentTime( dBytesPlayed,
m_ulCurrentTime,
ulAdjustedTime))
{
UINT32 ulTickCount = HX_GET_TICKCOUNT();
/* This is to avoid stall at end of the presentation */
/* The RA stream may have a duration of say 30 seconds
* but the actual data may be only for 29.9
* seconds. In this case, audio stream will never
* return time more than 29.9 seconds and we will get
* stalled. To avoid this, we wait for atmost
* MAX_WAIT_AT_SAME_TIME (== max granularity+50 ms) at
* the same timestamp. If we find that we are pushing
* more data in the audio device but the audio stream
* is reporting the same time for the past
* MAX_WAIT_AT_SAME_TIME, we increment our timestamp
* by the real time elapsed since the last update.
* This code will only trigger when we are near the
* end of presentation.
*/
if (m_bTimeReturned &&
ulAdjustedTime <= m_ulLastCurrentTimeReturned &&
ulCurrentDeviceTime > m_ulLastDeviceTimeAdjusted &&
ulCurrentDeviceTime - m_ulLastDeviceTimeAdjusted > MAX_WAIT_AT_SAME_TIME)
{
UINT32 ulElapsedTime = CALCULATE_ELAPSED_TICKS(m_ulTimeAdjustDoneAt,
ulTickCount);
if (ulElapsedTime >= MAX_WAIT_AT_SAME_TIME)
{
m_ulCurrentTime = m_ulLastCurrentTimeReturned + ulElapsedTime;
m_ulTimeAdjustDoneAt = ulTickCount;
m_ulLastDeviceTimeAdjusted = ulCurrentDeviceTime;
}
else
{
m_ulCurrentTime = ulAdjustedTime;
}
}
else
{
m_ulTimeAdjustDoneAt = ulTickCount;
m_ulCurrentTime = ulAdjustedTime;
}
}
}
}
#endif /* HELIX_FEATURE_AUDIO_INACCURATESAMPLING */
/* Never go back in time */
if (!m_bTimeReturned)
{
m_bTimeReturned = TRUE;
m_ulLastCurrentTimeReturned = m_ulCurrentTime;
m_ulTimeAdjustDoneAt = HX_GET_TICKCOUNT();
m_ulLastDeviceTimeAdjusted = ulCurrentDeviceTime;
}
else if (m_ulCurrentTime <= m_ulLastCurrentTimeReturned)
{
m_ulCurrentTime = m_ulLastCurrentTimeReturned;
}
else
{
m_ulLastDeviceTimeAdjusted = ulCurrentDeviceTime;
m_ulLastCurrentTimeReturned = m_ulCurrentTime;
}
}
HX_RESULT
CHXAudioPlayer::ResumeFakeTimeline(void)
{
HX_RESULT rc = HXR_OK;
HX_ASSERT(!m_bHasStreams);
HXTimeval lTime = m_pScheduler->GetCurrentSchedulerTime();
m_pFakeAudioCBTime->tv_sec = lTime.tv_sec;
m_pFakeAudioCBTime->tv_usec = lTime.tv_usec;
m_ulIncreasingTimer = m_ulCurrentTime;
m_ulLastFakeCallbackTime = HX_GET_TICKCOUNT();
*m_pFakeAudioCBTime += (int) (m_ulGranularity*1000);
m_ulCallbackID = m_pScheduler->AbsoluteEnter(this,
*((HXTimeval*) m_pFakeAudioCBTime));
return rc;
}
HX_RESULT CHXAudioPlayer::Func()
{
m_ulCallbackID = 0;
OnTimerCallback();
return HXR_OK;
}
HX_RESULT CHXAudioPlayer::StopFakeTimeline(void)
{
HX_RESULT rc = HXR_OK;
if(m_ulCallbackID && m_pScheduler)
{
m_pScheduler->Remove(m_ulCallbackID);
}
return rc;
}
double
CHXAudioPlayer::NumberOfBytesWritten()
{
return m_Owner->NumberOfBytesWritten();
}
double
CHXAudioPlayer::ConvertMsToBytes(UINT32 ulTime)
{
return m_Owner->ConvertMsToBytes(ulTime);
}
void
CHXAudioPlayer::UpdateStreamLastWriteTime()
{
// Make each stream seek, too, since they own the resampling buffers.
CHXAudioStream* s = 0;
CHXSimpleList::Iterator lIter = m_pStreamList->Begin();
for (; lIter != m_pStreamList->End(); ++lIter)
{
s = (CHXAudioStream*) (*lIter);
s->UpdateStreamLastWriteTime();
}
}
void
CHXAudioPlayer::SaveLastNMilliSeconds(BOOL bSave, UINT32 ulNMilliSeconds)
{
// Make each stream seek, too, since they own the resampling buffers.
CHXAudioStream* s = 0;
CHXSimpleList::Iterator lIter = m_pStreamList->Begin();
for (; lIter != m_pStreamList->End(); ++lIter)
{
s = (CHXAudioStream*) (*lIter);
s->SaveLastNMilliSeconds(bSave, ulNMilliSeconds);
}
}
void
CHXAudioPlayer::RewindPlayer(UINT32 ulTimeToRewind)
{
if (m_pStreamList->GetCount() == 0 || !m_bCanBeRewound)
{
return;
}
// Make each stream seek, too, since they own the resampling buffers.
CHXAudioStream* s = 0;
CHXSimpleList::Iterator lIter = m_pStreamList->Begin();
for (; lIter != m_pStreamList->End(); ++lIter)
{
s = (CHXAudioStream*) (*lIter);
s->RewindStream(ulTimeToRewind);
}
HX_ASSERT(m_llLastWriteTime >= ulTimeToRewind);
if (m_llLastWriteTime >= ulTimeToRewind)
{
m_llLastWriteTime -= ulTimeToRewind;
}
}
HX_RESULT
CHXAudioPlayer::ProcessAudioHook(PROCESS_ACTION action,
IHXAudioHook* pAudioHook)
{
return HXR_OK;
}
STDMETHODIMP CHXAudioPlayer::SetError( HX_RESULT theErr )
{
if (theErr != HXR_OK)
{
IHXErrorMessages* pErrorMessage = NULL;
m_pContext->QueryInterface(IID_IHXErrorMessages, (void**) &pErrorMessage);
if (pErrorMessage)
{
pErrorMessage->Report(HXLOG_ERR, theErr, 0, NULL, NULL);
pErrorMessage->Release();
}
}
return HXR_OK;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -