📄 hxaudses.cpp
字号:
}
pSessionBuf = m_pSessionBuf->GetBuffer();
// Zero session buffer.
//memset(pSessionBuf, 0, HX_SAFESIZE_T(m_ulBytesPerGran));
// Get each player
pPlayer = 0;
CHXSimpleList::Iterator lIter = m_pPlayerList->Begin();
for (; lIter != m_pPlayerList->End(); ++lIter)
{
BOOL bStalled = FALSE;
pPlayer = (CHXAudioPlayer*) (*lIter);
if (pPlayer->GetStreamCount() == 0 ||
pPlayer->IsDonePlayback() ||
pPlayer->GetState() != E_PLAYING)
{
continue;
}
bAtLeastOnePlayerActive = TRUE;
if (m_pPlayerList->GetCount() == 1)
{
pMixIHXBuffer = m_pSessionBuf;
bufType = BUFFER_SESSION;
}
else
{
if (!m_pPlayerBuf)
{
m_pPlayerBuf = new CHXBuffer;
m_pPlayerBuf->AddRef();
}
m_pPlayerBuf->SetSize(m_ulBytesPerGran);
pPlayerBuf = m_pPlayerBuf->GetBuffer();
// Zero play buffer.
// memset(pPlayerBuf, 0, HX_SAFESIZE_T(m_ulBytesPerGran));
pMixIHXBuffer = m_pPlayerBuf;
bufType = BUFFER_PLAYER;
}
pMixBuffer = pMixIHXBuffer->GetBuffer();
BOOL bIsMixBufferDirty = FALSE;
BOOL bMayNeedToRollbackTimestamp = FALSE;
if (pPlayer->GetState() == E_PLAYING)
{
UINT32 ulBufTime = 0;
// Get each stream associated with this player
pStreamList = pPlayer->GetStreamList();
CHXSimpleList::Iterator lIter = pStreamList->Begin();
for (; lIter != pStreamList->End(); ++lIter)
{
pStream = (CHXAudioStream*) (*lIter);
pStream->m_bMayNeedToRollbackTimestamp = FALSE;
// don't mix paused audio streams
if (pStream->GetState() != E_PAUSED)
{
theErr = pStream->MixIntoBuffer( pMixBuffer, m_ulBytesPerGran, ulBufTime, bIsMixBufferDirty);
// so as not to trigger ReallyNeedData
// since one of the streams internal m_llLastwritetime
// has been updated even though this flag is set to FALSE.
#if 0
if (!bIsMixBufferDirty &&
(theErr == HXR_OK || theErr == HXR_NO_DATA))
{
bIsMixBufferDirty = TRUE;
::memset(pMixBuffer, 0, HX_SAFESIZE_T(m_ulBytesPerGran));
}
#endif
if (theErr == HXR_NO_DATA)
{
pStream->m_bMayNeedToRollbackTimestamp = TRUE;
bMayNeedToRollbackTimestamp = TRUE;
theErr = HXR_OK;
continue;
}
if (theErr == HXR_FAIL)
{
theErr = HXR_OK;
goto exit;
}
if (theErr == HXR_OUTOFMEMORY)
{
goto exit;
}
if (theErr == HXR_WOULD_BLOCK)
{
#ifdef _RAHULDEBUG
{
char str[255]; /* Flawfinder: ignore */
::sprintf(str, "Num to be pushed remaining: %lu\n", m_uNumToBePushed); /* Flawfinder: ignore */
OutputDebugString(str);
}
#endif
if (bMayNeedToRollbackTimestamp)
{
bMayNeedToRollbackTimestamp = FALSE;
lIter = pStreamList->Begin();
for (; lIter != pStreamList->End(); ++lIter)
{
pStream = (CHXAudioStream*) (*lIter);
if (pStream->m_bMayNeedToRollbackTimestamp)
{
pStream->m_bMayNeedToRollbackTimestamp = FALSE;
pStream->RollBackTimestamp();
}
}
}
goto handlewouldblock;
}
}
if (pPlayer->GetState() != E_PLAYING)
{
/* We should keep the last buffer around and the last stream
* to be mixed again...TBD XXX Rahul
*/
//pPlayer->SetLastMixedBuffer(pMixBuffer, pStream);
bStalled = TRUE;
break;
}
}
/* This pause may have happended due to ondrynotification */
if (m_bPaused || m_bStoppedDuringPause)
{
/* This would happen ONLY IF THERE IS ONE AUDIO PLAYER
* and that has been paused. So simply break
*/
goto exit;
//break;
}
/* hmmm... looks like there are more than one audio player.
* continue with the next one
*/
if (bStalled)
{
continue;
}
/* If the mixer buffer was not used, make sure it is initialized
* to silence since we pass it to post process hooks
*/
if (!bIsMixBufferDirty)
{
//{FILE* f1 = ::fopen("e:\\audioses.txt", "a+"); ::fprintf(f1, "%lu\t%p\tsilence in mix buffer\n", HX_GET_BETTERTICKCOUNT(), this);::fclose(f1);}
::memset(pMixBuffer, 0, HX_SAFESIZE_T(m_ulBytesPerGran));
}
#if defined(HELIX_FEATURE_VOLUME) && defined(HELIX_FEATURE_MIXER)
// Apply Player volume to buffer; do this before we call
// the post mix hooks.
uPlayerVolume = pPlayer->GetVolume();
if (uPlayerVolume != 100 && bIsMixBufferDirty)
{
CHXMixer::ApplyVolume(pMixBuffer, m_ulBytesPerGran, uPlayerVolume, m_DeviceFmt.uBitsPerSample);
}
#endif /* HELIX_FEATURE_VOLUME && HELIX_FEATURE_MIXER */
// Give data to this AudioPlayer's post mix hooks
// (do they want 8 or 16 bit?)
BOOL bChanged = FALSE;
ProcessPostMixHooks(pPlayer, pMixIHXBuffer, &bDisableWrite, ulBufTime, bChanged);
/*
* If the mixer buffer changed (because of a post mix hook)
* make sure to point the player/session buffer to this
* modified buffer
*/
if (bChanged)
{
pMixBuffer = pMixIHXBuffer->GetBuffer();
if (bufType == BUFFER_PLAYER)
{
m_pPlayerBuf = pMixIHXBuffer;
pPlayerBuf = pMixIHXBuffer->GetBuffer();
}
else
{
m_pSessionBuf = pMixIHXBuffer;
pSessionBuf = pMixIHXBuffer->GetBuffer();
}
}
}
#if defined(HELIX_FEATURE_MIXER)
// Don't mix if volume is 0.
// Don't mix if this player has disabled device write.
// Don't mix if there is only one player since we would have
// written data into session buf instead of player buffer
if (m_pPlayerList->GetCount() > 1 && uPlayerVolume > 0 && !bDisableWrite)
{
/* We always set a volume of 100 since we have already applied volume
* to player buffer
*/
CHXMixer::MixBuffer( pPlayerBuf, pSessionBuf,
m_ulBytesPerGran, FALSE, 100, m_DeviceFmt.uBitsPerSample, m_bSessionBufferDirty);
}
#endif /* HELIX_FEATURE_MIXER */
pPlayer->UpdateLastWriteTime(m_ulGranularity);
}
if (!bAtLeastOnePlayerActive)
{
goto exit;
}
/* did we ever write to the session buffer ? */
if (m_pPlayerList->GetCount() > 1 && !m_bSessionBufferDirty)
{
//{FILE* f1 = ::fopen("e:\\audioses.txt", "a+"); ::fprintf(f1, "%lu\t%p\tsilence in session buffer\n", HX_GET_BETTERTICKCOUNT(), this);::fclose(f1);}
::memset(pSessionBuf, 0, HX_SAFESIZE_T(m_ulBytesPerGran));
}
// This increments with each buffered played.
m_dBufEndTime += m_dGranularity;
// Set the session buffer to the IRMA buffer.
audioData.pData = m_pSessionBuf;
audioData.ulAudioTime = (ULONG32)m_dBufEndTime;
if (m_pAudioDev && !m_bDisableWrite)
{
/* are we dealing with a f*%$'ed up sound card */
if ((m_BeforeHookDeviceFmt.uChannels == 1 && m_DeviceFmt.uChannels == 2)||
m_BeforeHookDeviceFmt.uBitsPerSample == 8)
{
ConvertTo8BitAndOrMono(&audioData);
}
if (m_pFinalHook && m_bUseFinalHook)
{
if (HXR_OK == ProcessAudioHook(ACTION_CHECK, m_pFinalHook))
{
m_pOutDataPtr->pData = NULL;
m_pOutDataPtr->ulAudioTime = audioData.ulAudioTime;
m_pOutDataPtr->uAudioStreamType = audioData.uAudioStreamType;
m_pFinalHook->OnBuffer(&audioData, m_pOutDataPtr);
HX_ASSERT(m_pOutDataPtr->pData);
if (m_pOutDataPtr->pData)
{
HX_RELEASE(audioData.pData);
m_pSessionBuf = audioData.pData = m_pOutDataPtr->pData;
}
else
{
/* This is a screwed up Hook. Disable it */
m_bUseFinalHook = FALSE;
}
}
}
if (m_pHookList)
{
ProcessHooks(&audioData);
}
ulNumBytesWritten = audioData.pData->GetSize();
if (HXR_OK == ProcessAudioDevice(ACTION_CHECK, m_pAudioDev))
{
// Write session audio data to device.
theErr = m_pAudioDev->Write(&audioData);
if( theErr == HXR_OUTOFMEMORY )
{
goto exit;
}
}
if (theErr == HXR_WOULD_BLOCK)
{
HXAudioData* pAudioData = new HXAudioData;
pAudioData->pData = audioData.pData;
pAudioData->pData->AddRef();
pAudioData->ulAudioTime = audioData.ulAudioTime;
pAudioData->uAudioStreamType= audioData.uAudioStreamType;
// Create auxiliary buffer list, if one is not already created
if (!m_pAuxiliaryAudioBuffers)
{
m_pAuxiliaryAudioBuffers = new CHXSimpleList;
}
if( NULL == m_pAuxiliaryAudioBuffers->AddTail(pAudioData) )
{
theErr = HXR_OUTOFMEMORY;
goto exit;
}
HX_RELEASE(m_pSessionBuf);
}
/* Any error from audio device other than memory error is
* returned as HXR_AUDIO_DRIVER
*/
if (theErr != HXR_OK && theErr != HXR_WOULD_BLOCK &&
theErr != HXR_OUTOFMEMORY)
{
theErr = HXR_AUDIO_DRIVER;
}
}
if (!theErr)
{
m_ulBlocksWritten++;
m_dNumBytesWritten += ulNumBytesWritten;
}
// So this function is good in theory, but in practice we find in
// heap-optimized mode it is not necessary, and it leads to
// unnecessary heap fragmentation.
#if !defined(HELIX_CONFIG_MIN_HEAP_FRAG)
theErr = CheckForBufferReuse();
#endif
} // for loop
} // end if we have audio streams
handlewouldblock:
// mask this error
if (theErr == HXR_WOULD_BLOCK)
{
theErr = HXR_OK;
}
// If we do not have audio.. OR if we do have audio but
// we have disabled writing to the device, then we need to
// fake the timeline.
if (!theErr && !m_ulCallbackID && (!m_bHasStreams || m_bDisableWrite))
{
if (m_bFirstPlayAudio)
{
// First time thru, we initialize callback time.
HXTimeval lTime = m_pScheduler->GetCurrentSchedulerTime();
m_pFakeAudioCBTime->tv_sec = lTime.tv_sec;
m_pFakeAudioCBTime->tv_usec = lTime.tv_usec;
m_ulIncreasingTimer = 0;
m_ulLastFakeCallbackTime = HX_GET_TICKCOUNT();
*m_pFakeAudioCBTime += (int) (m_ulGranularity*1000);
}
m_bFakeAudioTimeline = TRUE;
m_ulCallbackID = m_pScheduler->RelativeEnter( this, m_ulGranularity);
if (m_bFirstPlayAudio)
{
OnTimeSync(m_ulIncreasingTimer);
}
}
else if (!theErr && !m_ulCallbackID && m_bHasStreams && !m_bDisableWrite)
{
m_bFakeAudioTimeline = FALSE;
m_ulCallbackID = m_pScheduler->RelativeEnter(this, m_ulGranularity*9/10);
#if 0 // XXX HP don't send OnTimeSync() untill we resume the audio device
// the following logic caused OnTimeSync() sent to video renderer before the audio
// timeline is started after seeking, as a consequence, the A/V could be out of
// sync, video could be frozen for short period time in order to wait the audio
// timeline to catch up
if (m_bFirstPlayAudio)
{
OnTimeSync(m_ulIncreasingTimer);
}
#endif
}
exit:
m_bInPlayAudio = FALSE;
// can only happen in multi-player pause/resume/stop case
if (m_bDeferActualResume && theErr != HXR_OUTOFMEMORY)
{
m_bDeferActualResume = FALSE;
theErr = ActualResume();
}
m_bFirstPlayAudio = FALSE;
m_pMutex->Unlock();
return theErr;
}
HX_RESULT
CHXAudioSession::CheckForBufferReuse()
{
if (m_pSessionBuf)
{
m_pSessionBuf->AddRef();
if (m_pSessionBuf->Release() > 1)
{
/*
* Cannot use this buffer the next time
* release our reference and create a new one
*/
m_pSessionBuf->Release();
m_pSessionBuf = (IHXBuffer*) new CHXBuffer;
if( m_pSessionBuf )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -