📄 hxaudstr_new.cpp
字号:
HX_DELETE(m_pAvailableBuffers); // Delete all entries in the audio data list FlushBuffers(); HX_DELETE(m_pDataList); HX_DELETE(m_pInstantaneousList); CleanupRAByToTs(); HX_DELETE(m_pRAByToTsInList); HX_DELETE(m_pRAByToTsAdjustedList); HX_DELETE(m_pMixEngine); m_bGotHooks = FALSE; m_llLastWriteTime = 0; m_ulTSRollOver = 0; HX_RELEASE(m_pValues);#if defined(HELIX_FEATURE_AUDIO_PREMIXHOOK) // Delete all entries in the pre-mix hook list. if ( m_PreMixHookMap.GetCount() > 0) { HXAudioHookInfo* h = 0; CHXMapPtrToPtr::Iterator lIter = m_PreMixHookMap.Begin(); for (; lIter != m_PreMixHookMap.End(); ++lIter) { h = (HXAudioHookInfo*) (*lIter); ProcessAudioHook(ACTION_REMOVE, h->pHook); h->pHook->Release(); delete h; } m_PreMixHookMap.RemoveAll(); }#endif /* HELIX_FEATURE_AUDIO_PREMIXHOOK */#ifdef HELIX_FEATURE_VOLUME if( m_pStreamVolume ) { m_pStreamVolume->RemoveAdviseSink(this); m_pStreamVolume->Release(); m_pStreamVolume=NULL; }#endif HX_DELETE(m_pInDataPtr); HX_DELETE(m_pOutDataPtr); if (m_DryNotificationMap && m_DryNotificationMap->GetCount() > 0) { IHXDryNotification* pDryNotification = 0; CHXMapPtrToPtr::Iterator lIter = m_DryNotificationMap->Begin(); for (; lIter != m_DryNotificationMap->End(); ++lIter) { pDryNotification = (IHXDryNotification*) (*lIter); pDryNotification->Release(); } m_DryNotificationMap->RemoveAll(); } HX_RELEASE(m_pCrossFadeStream); HX_RELEASE(m_pCommonClassFactory);#if defined(HELIX_FEATURE_PREFERENCES) HX_RELEASE(m_pPreferences);#endif /* HELIX_FEATURE_PREFERENCES */ HX_RELEASE(m_Owner); return;}HX_RESULTCHXAudioStream::ProcessAudioHook(PROCESS_ACTION action, IHXAudioHook* pAudioHook){ return HXR_OK;}/************************************************************************ * Method: * IHXAudioStream::InitHooks * Purpose: * Init any pre-mix hooks. Return TRUE if hooks exist else return * FALSE. */void CHXAudioStream::InitHooks(){#if defined(HELIX_FEATURE_AUDIO_PREMIXHOOK) /* Iterate thru the hook list and call the hook's OnInit(). * If any of the hooks have disabled write set to TRUE, then * we will let this override any set to FALSE. */ if ( m_PreMixHookMap.GetCount() > 0 ) { HXAudioHookInfo* h = 0; CHXMapPtrToPtr::Iterator lIter = m_PreMixHookMap.Begin(); for (; lIter != m_PreMixHookMap.End(); ++lIter) { h = (HXAudioHookInfo*) (*lIter); if (h->bIgnoreAudioData || HXR_OK == ProcessAudioHook(ACTION_CHECK, h->pHook)) { h->pHook->OnInit( &m_AudioFmt ); } } }#endif /* HELIX_FEATURE_AUDIO_PREMIXHOOK */ m_bHooksInitialized = TRUE;}/************************************************************************ * Method: * IHXAudioStream::ProcessHooks * Purpose: */HX_RESULT CHXAudioStream::ProcessHooks( HXAudioData* pInData, HXAudioData* pOutData){ HX_RESULT theErr = HXR_OK;#if defined(HELIX_FEATURE_AUDIO_PREMIXHOOK) m_pInDataPtr->pData = pInData->pData; m_pInDataPtr->pData->AddRef(); m_pInDataPtr->ulAudioTime = pInData->ulAudioTime; m_pOutDataPtr->pData = NULL; m_pOutDataPtr->ulAudioTime = pInData->ulAudioTime; m_pInDataPtr->uAudioStreamType = pInData->uAudioStreamType; m_pOutDataPtr->uAudioStreamType = pInData->uAudioStreamType; if ( m_PreMixHookMap.GetCount() > 0 ) { HXAudioHookInfo* pPreMixHookInfo = 0; CHXMapPtrToPtr::Iterator lIter = m_PreMixHookMap.Begin(); for (; !theErr && lIter != m_PreMixHookMap.End(); ++lIter) { pPreMixHookInfo = (HXAudioHookInfo*) (*lIter); if (HXR_OK == ProcessAudioHook(ACTION_CHECK, pPreMixHookInfo->pHook)) { // XXXHP, disable hooks when it doesn't support multi-channel if (m_AudioFmt.uChannels <= 2 || pPreMixHookInfo->bMultiChannelSupport) { theErr = pPreMixHookInfo->pHook->OnBuffer( m_pInDataPtr, m_pOutDataPtr); /* Check to see if renderer changed the buffer. If so, then * make this output as input to the next Hook. */ if (!theErr && m_pOutDataPtr->pData) { m_pInDataPtr->pData->Release(); m_pInDataPtr->pData = m_pOutDataPtr->pData; m_pInDataPtr->ulAudioTime = m_pOutDataPtr->ulAudioTime; m_pOutDataPtr->pData = 0; } } } else if (pPreMixHookInfo->bIgnoreAudioData) { IHXBuffer* pTempBuf = m_pInDataPtr->pData; m_pInDataPtr->pData = NULL; theErr = pPreMixHookInfo->pHook->OnBuffer( m_pInDataPtr, m_pOutDataPtr); m_pInDataPtr->pData = pTempBuf; } } } /* Final output is always in InDataPtr*/ pOutData->pData = m_pInDataPtr->pData; pOutData->ulAudioTime = m_pInDataPtr->ulAudioTime; pOutData->uAudioStreamType = m_pInDataPtr->uAudioStreamType;#endif /* HELIX_FEATURE_AUDIO_PREMIXHOOK */ return theErr;}/************************************************************************ * Method: * CHXAudioStream::MixIntoBuffer * Purpose: * Mix stream data into this pPlayerBuf. * */HX_RESULT CHXAudioStream::MixIntoBuffer( UCHAR* pPlayerBuf, ULONG32 ulBufSize, ULONG32& ulBufTime, BOOL& bIsMixBufferDirty, BOOL bGetCrossFadeData){ HX_RESULT res = HXR_OK ; if (!m_bInited) { return HXR_NOT_INITIALIZED; } // bGetCrossFadeData should now be a thing of the past. HX_ASSERT(!bGetCrossFadeData) ;//{FILE* f1 = ::fopen("c:\\temp\\rasync.txt", "a+"); ::fprintf(f1, "Call MixIntoBuffer: %lu\n", m_ulLastWriteTime);::fclose(f1);} /* If this is a *FROM* stream, we may have already mixed * data during cross-fade with *TO* stream */ // update the outside world's sense of time. // XXX wschildbach: how to account for rollover? INT64 llNextMixTime = m_pMixEngine->GetNextMixTimeMillis(); UINT32 ulLastWriteTime = INT64_TO_UINT32(llNextMixTime - CAST_TO_INT64(m_ulTSRollOver) * CAST_TO_INT64(MAX_UINT32)); // In a surestream situation, ulBufTime is 0 on the first stream, and a time corresponding // to the granularity in the second stream. I don't know what this code tries to do. // XXX wschildbach if (ulBufTime < ulLastWriteTime) { ulBufTime = ulLastWriteTime; } /* If there are any DryNotifications and the data list is empty * we need to notify them so that they can write more data. * * If EnoughDataAvailable() returns FALSE, it will have updated * the input values to point at where the buffer needs to be filled. */ INT64 llStartMix, llEndMix; m_pMixEngine->GetMixRange(ulBufSize, llStartMix, llEndMix) ; UINT32 nSamplesNeeded = INT64_TO_UINT32(llEndMix - llStartMix) ; // always fits into UINT32 if (!EnoughDataAvailable(llStartMix, nSamplesNeeded)) { // Check if the audio device is really empty ("ReallyNeedData") or if we are // just over-eagerly filling up the pre-roll. If the latter is the case, // return HXR_WOULD_BLOCK if (!bIsMixBufferDirty && !m_Owner->m_Owner->ReallyNeedData()) { return HXR_WOULD_BLOCK; } // renderer might pause playback if has no packets if (m_DryNotificationMap->GetCount() > 0) { IHXDryNotification* pDryNotification = 0; CHXMapPtrToPtr::Iterator lIter = m_DryNotificationMap->Begin(); for (; lIter != m_DryNotificationMap->End(); ++lIter) { pDryNotification = (IHXDryNotification*) (*lIter); UINT64 streamTime = Samples2Ms(llStartMix, &m_AudioFmt) - CAST_TO_INT64(m_ulTSRollOver)*CAST_TO_INT64(MAX_UINT32); HX_RESULT theErr = pDryNotification->OnDryNotification( INT64_TO_UINT32(streamTime), INT64_TO_UINT32(Samples2Ms(nSamplesNeeded, &m_AudioFmt))) ; if( theErr == HXR_OUTOFMEMORY ) { return theErr; } } if (m_Owner->GetState() != E_PLAYING) { return HXR_OK; } } } // XXX wschildbach what does this do? m_Owner->DataInAudioDevice(TRUE); /* {FILE *f1 = fopen("c:\\temp\\mix.txt","a+"); fprintf(f1,"\ncall MixIntoBuffer(%I64d, id=%ld)\n",(INT64)mixTimeInSamples,m_pMixEngine - (HXAudioSvcMixEngine*)0xdde198); fclose(f1);}*/ // this call does all the mixing. res = m_pMixEngine->MixIntoBuffer(pPlayerBuf, ulBufSize, bIsMixBufferDirty) ; if( m_wLastError == HXR_OUTOFMEMORY ) { return m_wLastError; } if (FAILED(res)) return res ; #if defined(HELIX_FEATURE_AUDIO_INACCURATESAMPLING) if( m_bRealAudioStream ) MapFudgedTimestamps();#endif // update the inside world's sense of time. m_llLastWriteTime = m_pMixEngine->GetNextMixTimeMillis() ;#if 0 {FILE *f = fopen("c:\\temp\\incoming.txt","a+"); fprintf(f,"mix %ld %I64d\n",ulBufTime,m_llLastWriteTime);fclose(f);}#endif return HXR_OK;}/* * This is the callback function that m_pMixEngine->MixIntoBuffer() will call to read * new samples. */BOOL CHXAudioStream::ConvertIntoBuffer(tAudioSample* buffer, UINT32 nSamples, INT64 llStartTimeInSamples){ HXAudioInfo* pInfo = 0; LISTPOSITION lp = 0; INT32 nBytesPerSample = m_AudioFmt.uBitsPerSample>>3 ; BOOL didMix = FALSE ; // set to TRUE if we have packets in this time range BOOL bPacketsAfterRange = FALSE; /* {FILE *f1 = fopen("c:\\temp\\mix.txt","a+"); fprintf(f1," ConvertIntoBuffer(%I64d - %I64d, len=%ld)\n",(INT64)llStartTimeInSamples,(INT64)llStartTimeInSamples+nSamples,nSamples); fclose(f1);} */ // there are two lists of packets here: timed audio and instantaneous audio. // We only look into the list for timed buffers -- Instantaneoue audio is ignored // (it never properly worked anyway, so support is discontinued). /* remove old packets. Old packets are packets that have an end time that is before our current mix time. */ lp = m_pDataList->GetHeadPosition(); while( lp ) { LISTPOSITION lastlp = lp; pInfo = (HXAudioInfo*) m_pDataList->GetNext(lp); if (pInfo->llEndTimeInSamples < llStartTimeInSamples) { /* {FILE *f1 = fopen("c:\\temp\\mix.txt","a+"); fprintf(f1,"-- reaping packet (%I64d,%I64d)\n", pInfo->llStartTimeInSamples,pInfo->llEndTimeInSamples); fclose(f1);} */ FreeInfo(pInfo); m_pDataList->RemoveAt(lastlp); if( m_wLastError == HXR_OUTOFMEMORY ) { return FALSE; } } else // if monotonous and non-overlapping break ; } // now go through the entire list of packets, and look for overlap with the // convert buffer. Any packet with overlap will be at least partially converted // into the buffer. // If packets overlap, one packet will then take precedence over another -- not // much we can do about that. lp = m_pDataList->GetHeadPosition(); while( lp ) { pInfo = (HXAudioInfo*) m_pDataList->GetNext(lp); if (pInfo->llStartTimeInSamples < llStartTimeInSamples + nSamples && pInfo->llEndTimeInSamples > llStartTimeInSamples) { // This packet has some overlap with what we are converting. // if this is the first packet to be mixed into this buffer, // silence out the entire buffer. This is inefficient, but safe if (!didMix) CAudioSvcSampleConverter::silence(buffer, nSamples) ; didMix = TRUE ; INT32 nMixbufferOffset = 0; INT32 pastPacketStart = INT64_TO_INT32(llStartTimeInSamples - pInfo->llStartTimeInSamples) ; if (pastPacketStart < 0) { nMixbufferOffset = -pastPacketStart; pastPacketStart = 0 ; } INT32 nn = Bytes2Samples(pInfo->pBuffer->GetSize(), &m_AudioFmt) ; INT32 nSamplesToUse = nn - pastPacketStart; if (nSamplesToUse > (INT32)(nSamples - nMixbufferOffset)) nSamplesToUse = nSamples - nMixbufferOffset; const unsigned char *cvtin = pInfo->pBuffer->GetBuffer() + pastPacketStart * nBytesPerSample ; tAudioSample *cvtout = buffer + nMixbufferOffset ; /* {FILE *f1 = fopen("c:\\temp\\mix.txt","a+"); fprintf(f1," mix packet (%I64d,%I64d,len=%ld) into buffer(%ld,%ld,len=%ld)\n", pInfo->llStartTimeInSamples,pInfo->llEndTimeInSamples, nn, nMixbufferOffset,nMixbufferOffset+nSamplesToUse,nSamplesToUse); fprintf(f1," pastPacketStart = %I64d, nMixbufferOffset = %ld\n", pastPacketStart,nMixbufferOffset) ; fclose(f1);}*/ 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 ;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -