📄 hxaudstr_new.cpp
字号:
switch (nBytesPerSample)
{
case 1:
CAudioSvcSampleConverter::cvt8(cvtin, cvtout, nSamplesToUse);
break ;
case 2:
CAudioSvcSampleConverter::cvt16(cvtin, cvtout, nSamplesToUse);
break ;
case 4:
CAudioSvcSampleConverter::cvt32(cvtin, cvtout, nSamplesToUse);
break ;
}
}
else if (pInfo->llStartTimeInSamples >= llStartTimeInSamples + nSamples)
{
/* We've found audio data that is past the
* desired range.
*/
bPacketsAfterRange = TRUE;
}
}
if (!didMix && bPacketsAfterRange)
{
/* We do not have packets for this range, but we
* do have packets after the range.
* Create silence data and make it look like we
* actually had data for this range.
*/
CAudioSvcSampleConverter::silence(buffer, nSamples) ;
didMix = TRUE;
}
return didMix ;
}
/************************************************************************
* Method:
* CHXAudioStream::Bytes2Samples
* Purpose:
* Translate from units of bytes to samples.
*/
UINT32 CHXAudioStream::Bytes2Samples
(
UINT64 ulNumBytes,
const HXAudioFormat *fmt
)
{
ASSERT(ulNumBytes % (fmt->uBitsPerSample >> 3) == 0) ;
return INT64_TO_UINT32(ulNumBytes / (fmt->uBitsPerSample >> 3)) ;
}
/************************************************************************
* Method:
* CHXAudioStream::Samples2Ms
* Purpose:
* Calculate the duration in millisecs for this number of samples.
*/
UINT64 CHXAudioStream::Samples2Ms
(
INT64 nSamples,
const HXAudioFormat *fmt
)
{
UINT32 ulDenom = fmt->uChannels * fmt->ulSamplesPerSec;
UINT64 q = nSamples / ulDenom;
UINT64 r = nSamples - q * ulDenom;
return q * 1000 + (r * 1000) / ulDenom;
}
/************************************************************************
* Method:
* CHXAudioStream::CalcMs
* Purpose:
* Calculate the duration in millisecs for this number of
* bytes in input format.
*/
ULONG32 CHXAudioStream::CalcMs
(
ULONG32 ulNumBytes
)
{
return INT64_TO_ULONG32(Samples2Ms(Bytes2Samples(ulNumBytes, &m_AudioFmt), &m_AudioFmt));
}
/************************************************************************
* Method:
* CHXAudioStream::CalcDeviceMs
* Purpose:
* Calculate the duration in millisecs for this number of
* bytes in Device format.
*/
ULONG32 CHXAudioStream::CalcDeviceMs
(
ULONG32 ulNumBytes
)
{
return INT64_TO_ULONG32(Samples2Ms(Bytes2Samples(ulNumBytes, &m_DeviceFmt), &m_DeviceFmt));
}
/************************************************************************
* Method:
* CHXAudioStream::CalcOffset
* Purpose:
* Calculate the offset in bytes given time.
*/
UINT32 CHXAudioStream::CalcOffset
(
INT64 llStartTime
, INT64 llEndTime
)
{
/* Using m_ulBytesPerMs may introduce cumulative error due
* to decimal cutoff
*/
HX_ASSERT(llEndTime - llStartTime < MAX_TIMESTAMP_GAP);
return m_ulGranularity ?
INT64_TO_UINT32((llEndTime - llStartTime) * m_ulInputBytesPerGran / m_ulGranularity) :
0 ;
}
void CHXAudioStream::FlushBuffers(BOOL bInstantaneousAlso)
{
while (m_pDataList && m_pDataList->GetCount() > 0)
{
HXAudioInfo* pInfo = (HXAudioInfo*) m_pDataList->RemoveHead();
FreeInfo(pInfo);
}
while (bInstantaneousAlso && m_pInstantaneousList && m_pInstantaneousList->GetCount() > 0)
{
CHXSimpleList* pList = (CHXSimpleList*) m_pInstantaneousList->RemoveHead();
while (pList->GetCount() > 0)
{
HXAudioInfo* pInfo = (HXAudioInfo*) pList->RemoveHead();
FreeInfo(pInfo, TRUE);
}
HX_DELETE(pList);
}
// reset m_bLastNMilliSecsToBeSaved so that we actually
// delete buffers in FreeInfo
BOOL bLastNMilliSecsToBeSaved = m_bLastNMilliSecsToBeSaved;
m_bLastNMilliSecsToBeSaved = FALSE;
while (m_pLastNMilliSecsList && m_pLastNMilliSecsList->GetCount() > 0)
{
HXAudioInfo* pInfo = (HXAudioInfo*) m_pLastNMilliSecsList->RemoveHead();
FreeInfo(pInfo);
}
m_bLastNMilliSecsToBeSaved = bLastNMilliSecsToBeSaved;
HX_DELETE(m_pLastNMilliSecsList);
}
/*
this routine checks if there are enough packets waiting in the queue
to be mixed. It will return FALSE if not, or if there are packets missing
in the middle of the queue.
*/
BOOL
CHXAudioStream::EnoughDataAvailable(INT64& llStartTimeInSamples, UINT32& nSamplesRequired)
{
INT64 llEndTimeInSamples = llStartTimeInSamples + nSamplesRequired ;
HXAudioInfo* pInfoOld = 0 ;
HXAudioInfo* pInfo = 0;
LISTPOSITION lp = 0;
// if the list is completely empty, report the whole data range as missing
if (m_pDataList->IsEmpty())
return FALSE ;
nSamplesRequired = 0 ;
/* skip over old packets. Old packets are packets that have an end time that is before
our current mix time. */
lp = m_pDataList->GetHeadPosition();
while( lp )
{
pInfoOld = (HXAudioInfo*) m_pDataList->GetNext(lp);
if (pInfoOld->llEndTimeInSamples >= llStartTimeInSamples)
break ;
}
#if 0 // disabled missing packet detection
// pInfoOld is the first packet to be mixed. To make sure it overlaps with the start
// of the mix buffer, do this (disabled for now):
if (pInfoOld->llStartTimeInSamples > llStartTimeInSamples)
return FALSE ;
#endif
// now go through the rest of packets, and make sure they are contiguous until
// the end of our mix time
// If packets overlap, one packet will then take precedence over another -- not
// much we can do about that.
while( lp )
{
pInfo = (HXAudioInfo*) m_pDataList->GetNext(lp);
// if we see a packet with a timestamp after the mix time ("future packet")
// or one that does not abut with the previous one ("discontinuity"), stop.
if (pInfo->llStartTimeInSamples >= llEndTimeInSamples) // future packet
// pInfo->llStartTimeInSamples != pInfoOld->llEndTimeInSamples) // discontinuity
{
break ;
}
pInfoOld = pInfo ;
}
// pInfoOld is the last packet to be mixed (or the last before a discontinuity).
// Make sure it overlaps with the end of the mix buffer.
if (pInfoOld->llEndTimeInSamples < llEndTimeInSamples)
{
llStartTimeInSamples = pInfoOld->llEndTimeInSamples ;
nSamplesRequired = INT64_TO_UINT32(llEndTimeInSamples - llStartTimeInSamples) ;
return FALSE ;
}
return TRUE ; // Data available!
}
HX_RESULT
CHXAudioStream::StartCrossFade(CHXAudioStream* pFromStream,
UINT32 ulCrossFadeStartTime,
UINT32 ulCrossFadeDuration,
BOOL bToStream)
{
#if defined(HELIX_FEATURE_CROSSFADE)
// XXX wschildbach need to account for rollover.
INT64 llStartTimeInSamples = CAST_TO_INT64(ulCrossFadeStartTime) * m_DeviceFmt.ulSamplesPerSec / 1000 * m_DeviceFmt.uChannels ;
INT64 llEndTimeInSamples = (CAST_TO_INT64(ulCrossFadeStartTime)+ulCrossFadeDuration) * m_DeviceFmt.ulSamplesPerSec / 1000 * m_DeviceFmt.uChannels ;
m_pMixEngine->SetCrossFade(bToStream ? HXAudioSvcMixEngine::FADE_IN : HXAudioSvcMixEngine::FADE_OUT,
llStartTimeInSamples, llEndTimeInSamples) ;
/*
{
FILE *f2 = fopen("c:\\temp\\mix.txt","a+");
fprintf(f2,"** StartCrossFade(%I64d, %I64d, len=%ld, to=%s\n",
llStartTimeInSamples,
llEndTimeInSamples,
(INT32)(-llStartTimeInSamples+llEndTimeInSamples),
bToStream?"yes":"no");
fclose(f2);
}
*/
return HXR_OK;
#else
return HXR_NOTIMPL;
#endif /* HELIX_FEATURE_CROSSFADE */
}
/*
* IHXRealAudioSync methods
*/
/************************************************************************
* Method:
* IHXRealAudioSync::Register
* Purpose:
*/
STDMETHODIMP
CHXAudioStream::Register(void)
{
#if defined _DEBUG && defined HELIX_FEATURE_AUDIO_MULTIPLAYER_PAUSE
if (HXDebugOptionEnabled("zDoNotUseFudge"))
{
return HXR_OK;
}
#endif
if (m_bRealAudioStream)
{
return HXR_UNEXPECTED;
}
m_bRealAudioStream = TRUE;
m_Owner->RegisterRealAudioStream(this);
#if defined(HELIX_FEATURE_AUDIO_INACCURATESAMPLING)
if (!m_pRAByToTsInList)
{
m_pRAByToTsInList = new CHXSimpleList;
m_pRAByToTsAdjustedList = new CHXSimpleList;
}
#endif /* HELIX_FEATURE_AUDIO_INACCURATESAMPLING */
return HXR_OK;
}
/************************************************************************
* Method:
* IHXRealAudioSync::UnRegister
* Purpose:
*/
STDMETHODIMP
CHXAudioStream::UnRegister(void)
{
#if defined _DEBUG && defined HELIX_FEATURE_AUDIO_MULTIPLAYER_PAUSE
if (HXDebugOptionEnabled("zDoNotUseFudge"))
{
return HXR_OK;
}
#endif
if (!m_bRealAudioStream)
{
return HXR_UNEXPECTED;
}
m_bRealAudioStream = FALSE;
m_Owner->UnRegisterRealAudioStream(this);
CleanupRAByToTs();
return HXR_OK;
}
/************************************************************************
* Method:
* IHXRealAudioSync::FudgeTimestamp
* Purpose:
* Tell the audio stream about the relationship between the number
* of bytes written to the actual timestamp.
*
*/
STDMETHODIMP
CHXAudioStream::FudgeTimestamp(UINT32 /*IN*/ ulNumberofBytes,
UINT32 /*IN*/ ulTimestamp)
{
#if defined(HELIX_FEATURE_AUDIO_INACCURATESAMPLING)
#if defined _DEBUG && defined HELIX_FEATURE_AUDIO_MULTIPLAYER_PAUSE
if (HXDebugOptionEnabled("zDoNotUseFudge"))
{
return HXR_OK;
}
#endif
RealAudioBytesToTimeStamp* pByToTs =
new RealAudioBytesToTimeStamp;
pByToTs->m_ulTimestamp = ulTimestamp;
pByToTs->m_ulInTimestamp = m_ulLastInputStartTime;
pByToTs->m_ulInEndTime = m_ulLastInputEndTime;
if (m_bIsLive && m_ulBaseTime > 0)
{
pByToTs->m_ulTimestamp += m_ulLiveDelay;
if (pByToTs->m_ulTimestamp > m_ulBaseTime)
{
pByToTs->m_ulTimestamp -= m_ulBaseTime;
}
else
{
pByToTs->m_ulTimestamp = 0;
}
}
pByToTs->m_ulOrigTimestamp = pByToTs->m_ulTimestamp;
m_pRAByToTsInList->AddTail((void*) pByToTs);
#endif /* HELIX_FEATURE_AUDIO_INACCURATESAMPLING */
//{FILE* f1 = ::fopen("d:\\temp\\audio.txt", "a+"); ::fprintf(f1, "Fudge:\t%lu\t%lu\n", ulTimestamp, m_ulLastInputStartTime);::fclose(f1);}
return HXR_OK;
}
void
CHXAudioStream::CleanupRAByToTs(void)
{
#if defined(HELIX_FEATURE_AUDIO_INACCURATESAMPLING)
if (!m_pRAByToTsInList)
{
return;
}
CHXSimpleList::Iterator ndx = m_pRAByToTsInList->Begin();
for (; ndx != m_pRAByToTsInList->End(); ++ndx)
{
RealAudioBytesToTimeStamp* pByToTs =
(RealAudioBytesToTimeStamp*) (*ndx);
delete pByToTs;
}
m_pRAByToTsInList->RemoveAll();
ndx = m_pRAByToTsAdjustedList->Begin();
for (; ndx != m_pRAByToTsAdjustedList->End(); ++ndx)
{
RealAudioBytesToTimeStamp* pByToTs =
(RealAudioBytesToTimeStamp*) (*ndx);
delete pByToTs;
}
m_pRAByToTsAdjustedList->RemoveAll();
#endif /* HELIX_FEATURE_AUDIO_INACCURATESAMPLING */
}
HX_RESULT
CHXAudioStream::ConvertCurrentTime(double dBytesPlayed,
UINT32 ulCurrentTime,
UINT32& ulAdjustedTime)
{
#if defined(HELIX_FEATURE_AUDIO_INACCURATESAMPLING)
HX_ASSERT(m_bRealAudioStream);
ulAdjustedTime = ulCurrentTime;
LISTPOSITION posRABytes = m_pRAByToTsAdjustedList->GetHeadPosition();
RealAudioBytesToTimeStamp* pByToTsLower = NULL;
RealAudioBytesToTimeStamp* pByToTsHigher = NULL;
INT64 llActualByToTsHigherTimestamp = 0;
INT64 llActualByToTsLowerTimestamp =0;
while(posRABytes)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -