📄 hxaudses.cpp
字号:
while (!theErr && m_pAuxiliaryAudioBuffers->GetCount() > 0)
{
HXAudioData* pAudioData =
(HXAudioData*) m_pAuxiliaryAudioBuffers->GetHead();
// Write session audio data to device.
theErr = m_pAudioDev->Write(pAudioData);
if( theErr == HXR_OUTOFMEMORY )
{
goto exit;
}
if (!theErr)
{
m_ulBlocksWritten++;
m_dNumBytesWritten += pAudioData->pData->GetSize();
m_pAuxiliaryAudioBuffers->RemoveHead();
pAudioData->pData->Release();
delete pAudioData;
}
/*All other error codes are translated into audio driver error*/
else if (theErr != HXR_OUTOFMEMORY && theErr != HXR_WOULD_BLOCK)
{
theErr = HXR_AUDIO_DRIVER;
}
}
}
}
// If we have audio streams then play audio.
if (!theErr && m_bHasStreams)
{
// Push down at least 3 secs of audio.
UINT16 uPush = uNumBlocks;
if (m_bFirstPlayAudio)
{
uPush = (UINT16) m_ulMinBlocksTobeQueued;
}
HXAudioData audioData;
CHXAudioPlayer* pPlayer = 0;
CHXAudioStream* pStream = 0;
CHXSimpleList* pStreamList = 0;
#if defined(HELIX_FEATURE_VOLUME) || defined(HELIX_FEATURE_MIXER)
UINT16 uPlayerVolume = HX_INIT_VOLUME;
#endif
UCHAR* pMixBuffer = 0;
UCHAR* pPlayerBuf = NULL;
UCHAR* pSessionBuf = NULL;
IHXBuffer* pMixIHXBuffer = NULL;
BufType bufType = BUFFER_NONE;
for (UINT16 i = 0; !theErr && i < uPush; i++ )
{
m_uNumToBePushed = uPush - i;
m_bSessionBufferDirty = FALSE; // only used for multi-player case
UINT32 ulNumBytesWritten = m_ulBytesPerGran;
BOOL bAtLeastOnePlayerActive = FALSE;
theErr = m_pSessionBuf->SetSize(m_ulBytesPerGran);
if( theErr == HXR_OUTOFMEMORY )
{
theErr = HXR_OUTOFMEMORY;
goto exit;
}
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();
if (pStreamList)
{
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;
}
}
} //if (pStreamList)
/* 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:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -