📄 hxaudstr.cpp
字号:
if (HXR_OK == m_Owner->m_pContext->QueryInterface(IID_IHXErrorMessages, (void**)&pErrMsg))
{
DEBUG_OUT(pErrMsg, DOL_GENERIC, (s,"AudioFormatIn: %lu channels %lu SamplesPerSec", m_AudioFmt.uChannels, m_AudioFmt.ulSamplesPerSec));
DEBUG_OUT(pErrMsg, DOL_GENERIC, (s,"AudioFormatOut: %lu channels %lu SamplesPerSec", m_DeviceFmt.uChannels, m_DeviceFmt.ulSamplesPerSec));
}
HX_RELEASE(pErrMsg);
if (m_bIsLive)
{
m_Owner->UpdateStreamLastWriteTime();
UpdateStreamLastWriteTime(TRUE);
}
}
//{FILE* f1 = ::fopen("c:\\temp\\audio.txt", "a+"); ::fprintf(f1, "%lu\tAddData\t%p\t%lu\n", HX_GET_BETTERTICKCOUNT(), this, pAudioData->ulAudioTime);::fclose(f1);}
// ::fwrite(pAudioData->pData->GetBuffer(), pAudioData->pData->GetSize(), 1, fdin);
UINT32 ulDataTime = CalcMs(pAudioData->pData->GetSize());
UINT32 ulEndTime = pAudioData->ulAudioTime + ulDataTime;
if (m_pAvailableBuffers && !m_bDeterminedInitialCacheSize && ulDataTime > 0)
{
m_bDeterminedInitialCacheSize = TRUE;
m_uCacheSize = (UINT16) (m_ulGranularity*2/ulDataTime) + 1;
/* make sure it is atleast CACHE_INCREMENT_SIZE to begin with */
m_uCacheSize = m_uCacheSize < CACHE_INCREMENT_SIZE ?
CACHE_INCREMENT_SIZE : m_uCacheSize;
}
if (m_ulLastInputStartTime > pAudioData->ulAudioTime &&
((m_ulLastInputStartTime - pAudioData->ulAudioTime) > MAX_TIMESTAMP_GAP))
{
bInTSRollOver = TRUE;
m_ulTSRollOver++;
}
m_ulLastInputStartTime = pAudioData->ulAudioTime;
m_ulLastInputEndTime = ulEndTime;
/* even in STREAMING_AUDIO case, it might happen, that the packets
* written are late. e.g. packets received late on the network
*/
INT64 llActualTimestamp = CAST_TO_INT64 (pAudioData->ulAudioTime) + CAST_TO_INT64 m_ulTSRollOver * CAST_TO_INT64 MAX_UINT32;
INT64 llActualEndTime = CAST_TO_INT64 (pAudioData->ulAudioTime) + CAST_TO_INT64 (ulDataTime) +
CAST_TO_INT64 m_ulTSRollOver * CAST_TO_INT64 MAX_UINT32;
if ((pAudioData->uAudioStreamType == STREAMING_AUDIO ||
pAudioData->uAudioStreamType == TIMED_AUDIO) &&
!(llActualTimestamp >= m_llLastWriteTime ||
llActualEndTime > m_llLastWriteTime))
{
/* Too late*/
m_bTobeTimed = TRUE;
//{FILE* f1 = ::fopen("e:\\audio.txt", "a+"); ::fprintf(f1, "%lu\t%p\t%d\t%lu\t%lu\tLATE\n", HX_GET_BETTERTICKCOUNT(), this, m_pDataList->GetCount(), pAudioData->ulAudioTime, (INT32)m_llLastWriteTime);::fclose(f1);}
return HXR_LATE_PACKET;
}
pAinfo = new HXAudioInfo;
if(!pAinfo)
{
theErr = HXR_OUTOFMEMORY;
goto exit;
}
pAudioData->pData->AddRef();
pAinfo->pBuffer = pAudioData->pData;
pAinfo->ulStartTime = pAudioData->ulAudioTime;
pAinfo->pOffset = pAudioData->pData->GetBuffer();
pAinfo->ulBytesLeft = pAudioData->pData->GetSize();
pAinfo->uAudioStreamType = pAudioData->uAudioStreamType;
if (m_bTobeTimed && pAudioData->uAudioStreamType == STREAMING_AUDIO)
{
pAinfo->uAudioStreamType = TIMED_AUDIO;
m_bTobeTimed = FALSE;
}
else if (m_bTobeTimed && pAudioData->uAudioStreamType == TIMED_AUDIO)
{
m_bTobeTimed = FALSE;
}
//{FILE* f1 = ::fopen("c:\\temp\\audio.txt", "a+"); ::fprintf(f1, "AddData ulAudioTime: %lu\n", pAudioData->ulAudioTime);::fclose(f1);}
if (pAinfo->uAudioStreamType == INSTANTANEOUS_AUDIO)
{
CHXSimpleList* pList = new CHXSimpleList;
if(!pList)
{
theErr = HXR_OUTOFMEMORY;
goto exit;
}
pList->AddHead((void*) pAinfo);
m_pInstantaneousList->AddTail((void*) pList);
m_Owner->m_Owner->ToBeRewound();
}
else if (pAinfo->uAudioStreamType == STREAMING_INSTANTANEOUS_AUDIO)
{
HX_ASSERT(m_pInstantaneousList && m_pInstantaneousList->GetCount() > 0);
CHXSimpleList* pList = NULL;
if (m_pInstantaneousList->GetCount() == 0)
{
pList = new CHXSimpleList;
if(!pList)
{
theErr = HXR_OUTOFMEMORY;
goto exit;
}
m_pInstantaneousList->AddTail((void*) pList);
// fix for naive users!
pAinfo->uAudioStreamType = INSTANTANEOUS_AUDIO;
m_Owner->m_Owner->ToBeRewound();
}
pList = (CHXSimpleList*) m_pInstantaneousList->GetTail();
pList->AddTail(pAinfo);
}
else if (m_pDataList->IsEmpty())
{
m_pDataList->AddTail((void*) pAinfo);
}
else
{
HXAudioInfo* pInfo = (HXAudioInfo*) m_pDataList->GetTail();
UINT32 ulActualTSRollOver = m_ulTSRollOver;
if (bInTSRollOver && ulActualTSRollOver)
{
ulActualTSRollOver--;
}
INT64 llActualLastEndTime = CAST_TO_INT64 (pInfo->ulStartTime) + CAST_TO_INT64 (CalcMs(pInfo->pBuffer->GetSize())) +
CAST_TO_INT64 ulActualTSRollOver * CAST_TO_INT64 MAX_UINT32;
INT64 llActualLastStartTime = CAST_TO_INT64 (pInfo->ulStartTime) + CAST_TO_INT64 ulActualTSRollOver * CAST_TO_INT64 MAX_UINT32;
if (llActualTimestamp < llActualLastStartTime)
{
/* Not allowed */
theErr = HXR_OUTOFORDER_PACKET;
/* something is fu*#$#up... figure out what?*/
HX_ASSERT(!("Packets written out of order"));
goto exit;
}
if (pAinfo->uAudioStreamType == STREAMING_AUDIO)
{
/* is it a resonable packet to add to the list */
if ((llActualTimestamp <= llActualLastEndTime &&
llActualLastEndTime - llActualTimestamp <= m_ulFudge) ||
(llActualTimestamp >= llActualLastEndTime &&
llActualTimestamp - llActualLastEndTime <= m_ulFudge))
{
m_pDataList->AddTail((void*) pAinfo);
}
else
{
theErr = HXR_NONCONTIGUOUS_PACKET; //HX_LATE_PACKET;
/* something is fu*#$#up... figure out what?*/
HX_ASSERT(!("Streaming Audio: Non-Contigous Write"));
m_bTobeTimed = TRUE;
goto exit;
}
}
else
{
/* see if there is any overlap.. we do not allow any overlap */
if (llActualTimestamp < llActualLastEndTime &&
llActualLastEndTime - llActualTimestamp > m_ulFudge)
{
/* hmmm an overlapped packet */
theErr = HXR_OVERLAPPED_PACKET;
/* something is fu*#$#up... figure out what?*/
HX_ASSERT(!("Timed Audio: Overlapping write"));
m_bTobeTimed = TRUE;
goto exit;
}
else
{
m_pDataList->AddTail((void*) pAinfo);
}
}
}
exit:
if (theErr != HXR_OK && pAinfo)
{
pAinfo->pBuffer->Release();
delete pAinfo;
}
/* Make sure to discard any data that is prior to cross-fade time */
if (!theErr && m_bCrossFadingToBeDone && m_bFadeToThisStream)
{
RemoveExcessCrossFadeData();
}
//{FILE* f1 = ::fopen("e:\\audio.txt", "a+"); ::fprintf(f1, "%lu\t%p\t%d\t%lu\t%lu\n", HX_GET_BETTERTICKCOUNT(), this, m_pDataList->GetCount(), pAudioData->ulAudioTime, (UINT32)m_llLastWriteTime);::fclose(f1);}
return theErr;
}
HX_RESULT CHXAudioStream::ProcessInfo(void)
{
HX_RESULT theErr = HXR_OK;
// Calculate the number of bytes per granularity.
m_ulInputBytesPerGran = (ULONG32)
(((m_AudioFmt.uChannels * ((m_AudioFmt.uBitsPerSample==8)?1:2) * m_AudioFmt.ulSamplesPerSec)
/ 1000.0) * m_ulGranularity);
m_ulOutputBytesPerGran = (ULONG32)
(((m_DeviceFmt.uChannels * ((m_DeviceFmt.uBitsPerSample==8)?1:2) * m_DeviceFmt.ulSamplesPerSec)
/ 1000.0) * m_ulGranularity);
/* Number of samples required at output should be a multiple of 8 if
* sampling rate is 8K/16K/32K...or a multiple of 11 for 11K/22K...
* This is needed since the resamplerequires works reliably ONLY if
* this condition is true. Ken is working on this problem. This is
* an interim fix
*/
ULONG32 ulExtraGranularity = 1;
if (m_DeviceFmt.ulSamplesPerSec % 8 == 0)
{
ulExtraGranularity = 8;
}
else
{
ulExtraGranularity = 11;
}
// Make sure that number of bytes per granularity is an even number.
if (m_ulInputBytesPerGran % (2*m_AudioFmt.uChannels*ulExtraGranularity) != 0)
{
m_ulInputBytesPerGran -= m_ulInputBytesPerGran % (2*m_AudioFmt.uChannels*ulExtraGranularity);
}
if (m_ulOutputBytesPerGran % (2*m_DeviceFmt.uChannels*ulExtraGranularity) != 0)
{
m_ulOutputBytesPerGran -= m_ulOutputBytesPerGran % (2*m_DeviceFmt.uChannels*ulExtraGranularity);
}
if (!theErr)
{
// Setup the resampler
theErr = SetupResampler();
}
if (!theErr)
{
m_bInited = TRUE;
if (m_eState == E_STOPPED)
{
m_eState = E_INITIALIZED;
}
}
if (!theErr && m_bInited && m_bCrossFadingToBeDone &&
m_bFadeToThisStream)
{
InitializeCrossFader();
}
/* Get the current player time to set the last write audio time
* If someone creates a stream mid presentation, we ask the player
* object for the current write time.
*/
// set last write time to be the current playback time since
// this is what other system components(i.e. renderers) based on
// fixed b#69847 - loss of push-down-worth of data =
// m_Owner->GetLastAudioWriteTime() - m_Owner->GetCurrentPlayBackTime()
// m_llLastWriteTime = m_Owner->GetCurrentPlayBackTime();
// XXXRA: It is necessary to use last audio write time for any delayed
// audio streams to work that do not involve any Pause/Rewind logic.
// To cover the case where a source (and an audio stream) has been added
// mid-playback by SMIL renderer which has a delay equivalent to the
// current playback time, it should result in a player rewind which should
// reset the lastaudiowrite time accordingly...so we should be able
// to use m_Owner->GetLastAudioWriteTime() value in such a use case as well.
// this change is required to fix PR 79161 and PR 69780.
// Henry, PR 69847 (the reason for the earlier change) is still busted.
// so I am reverting this code to the original code. you will have
// to come up with a different fix for PR 69847 since this was clearly not
// the correct fix.
m_llLastWriteTime = m_Owner->GetLastAudioWriteTime();
if (!theErr && m_bInited)
{
m_Owner->StreamInitialized(this);
}
return theErr;
}
/************************************************************************
* Method:
* IHXAudioStream::SetupResampler
* Purpose:
*/
HX_RESULT CHXAudioStream::SetupResampler()
{
HX_RESULT theErr = HXR_OK;
#if defined(HELIX_FEATURE_RESAMPLER)
// Create a resampler for this stream if we need one.
// Current resampler code resamples these sampling rates:
// 8000,11025,16000,22050,32000,44100. The resample also
// converts 8-bit to 16-bit. NOTE: We convert all 8-bit samples
// to 16-bit before input into the resampler or mixer.
/* Resampler does the following tasks:
* 1. Conversion for sampling rates
* 2. Conversion from 8->16 and will also do 16->8 (XXX TBD)
* 3. Conversion from stereo to mono
* We do not use resampler for conversion from mono to stereo. This
* takes place in the Mixer.
*/
/*
fprintf(fdbeforetxt, "Samples: %lu, Channels: %lu, Bits/Sample: %lu\n",
m_AudioFmt.ulSamplesPerSec, m_AudioFmt.uChannels, m_AudioFmt.uBitsPerSample);
fprintf(fdaftertxt, "Samples: %lu, Channels: %lu, Bits/Sample: %lu\n",
m_DeviceFmt.ulSamplesPerSec, m_DeviceFmt.uChannels, m_DeviceFmt.uBitsPerSample);
*/
if ((m_AudioFmt.ulSamplesPerSec != m_DeviceFmt.ulSamplesPerSec) ||
(m_AudioFmt.uBitsPerSample != m_DeviceFmt.uBitsPerSample) ||
(m_AudioFmt.uChannels == 2 && m_DeviceFmt.uChannels == 1))
{
m_AudioFmt.uMaxBlockSize = (UINT16) (m_ulInputBytesPerGran*1.5);
if (HXR_OK == m_Owner->GetOwner()->CreateResampler(m_AudioFmt,
m_DeviceFmt,
m_pResampler))
{
/* times 2 since resampler always returns data in 16 bit.
* times 2 if i/p or o/p is stereo
* May change in future when we do 16->8 conversion in resampler
*/
m_ulMaxBlockSize = (ULONG32) m_DeviceFmt.uMaxBlockSize * 2 * 2;
/* This may be TRUE in downsampling */
if (m_ulMaxBlockSize < (ULONG32) (m_ulInputBytesPerGran*1.5))
{
m_ulMaxBlockSize = (ULONG32) (m_ulInputBytesPerGran*1.5);
}
}
else
{
HX_RELEASE(m_pResampler);
theErr = HX_RESAMPLER_ERROR;
}
if ( !theErr )
{
m_pResampleBuf = (UCHAR*) new char [ m_ulMaxBlockSize ];
m_pTmpResBuf = (UCHAR*) new char [ m_ulMaxBlockSize ];
if (!m_pResampleBuf || !m_pTmpResBuf)
{
theErr = HXR_OUTOFMEMORY;
}
}
}
else
{
m_ulMaxBlockSize = m_DeviceFmt.uMaxBlockSize;
}
/* Do not rely on max block size specified by the user */
if (!theErr)
{
m_AudioFmt.uMaxBlockSize = (UINT16) m_ulMaxBlockSize;
}
m_bChannelConvert = (m_AudioFmt.uChannels == 1 && m_DeviceFmt.uChannels == 2);
#endif /* HELIX_FEATURE_RESAMPLER */
// Create the resampler output buffer. Size it to the largest needed.
return theErr;
}
/************************************************************************
* Method:
* IHXAudioStream::GetFormat
* Purpose:
* Return the stream's audio format.
*/
HX_RESULT CHXAudioStream::GetFormat
(
HXAudioFormat* pAudioFormat
)
{
if (!m_bAudioFormatKnown)
{
return HXR_NOT_INITIALIZED;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -