hxaudstr.cpp
上传用户:dangjiwu
上传日期:2013-07-19
资源大小:42019k
文件大小:121k
- /* ***** BEGIN LICENSE BLOCK *****
- * Source last modified: $Id: hxaudstr.cpp,v 1.17.2.1.2.1 2005/07/08 18:12:41 gwright Exp $
- *
- * Portions Copyright (c) 1995-2004 RealNetworks, Inc. All Rights Reserved.
- *
- * The contents of this file, and the files included with this file,
- * are subject to the current version of the RealNetworks Public
- * Source License (the "RPSL") available at
- * http://www.helixcommunity.org/content/rpsl unless you have licensed
- * the file under the current version of the RealNetworks Community
- * Source License (the "RCSL") available at
- * http://www.helixcommunity.org/content/rcsl, in which case the RCSL
- * will apply. You may also obtain the license terms directly from
- * RealNetworks. You may not use this file except in compliance with
- * the RPSL or, if you have a valid RCSL with RealNetworks applicable
- * to this file, the RCSL. Please see the applicable RPSL or RCSL for
- * the rights, obligations and limitations governing use of the
- * contents of the file.
- *
- * Alternatively, the contents of this file may be used under the
- * terms of the GNU General Public License Version 2 or later (the
- * "GPL") in which case the provisions of the GPL are applicable
- * instead of those above. If you wish to allow use of your version of
- * this file only under the terms of the GPL, and not to allow others
- * to use your version of this file under the terms of either the RPSL
- * or RCSL, indicate your decision by deleting the provisions above
- * and replace them with the notice and other provisions required by
- * the GPL. If you do not delete the provisions above, a recipient may
- * use your version of this file under the terms of any one of the
- * RPSL, the RCSL or the GPL.
- *
- * This file is part of the Helix DNA Technology. RealNetworks is the
- * developer of the Original Code and owns the copyrights in the
- * portions it created.
- *
- * This file, and the files included with this file, is distributed
- * and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
- * KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
- * ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
- * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
- * ENJOYMENT OR NON-INFRINGEMENT.
- *
- * Technology Compatibility Kit Test Suite(s) Location:
- * http://www.helixcommunity.org/content/tck
- *
- * Contributor(s):
- *
- * ***** END LICENSE BLOCK ***** */
- #include "hlxclib/stdio.h"
- #include "hlxclib/string.h"
- #include "hxresult.h"
- #include "hxtypes.h"
- #include "hxcom.h"
- #include "hxengin.h"
- #include "ihxpckts.h"
- #include "hxausvc.h"
- #include "hxrasyn.h"
- #include "hxprefs.h"
- #include "hxerror.h"
- #include "errdbg.h"
- #include "chxpckts.h"
- #include "hxaudply.h"
- #include "hxaudstr.h"
- #include "hxaudses.h"
- #include "hxmixer.h"
- #include "hxaudvol.h"
- #include "hxslist.h"
- #include "hxmap.h"
- #include "auderrs.h"
- #include "hxtick.h"
- //#include "rmarsmp.h"
- #ifdef _WINDOWS
- #include "hxrsmp2.h"
- #endif /* _WINDOWS */
- //#include "resample.h"
- //#include "interp.h"
- #include "crosfade.h"
- #include "hxheap.h"
- #ifdef _DEBUG
- #undef HX_THIS_FILE
- static const char HX_THIS_FILE[] = __FILE__;
- #endif
- #define CACHE_INCREMENT_SIZE 2
- //#define _TESTING 1
- #ifdef _TESTING
- #include <fcntl.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #if defined (_WINDOWS) || defined (_WIN32)
- #include <io.h>
- #endif
- int g_log = -1;
- #endif
- /************************************************************************
- * Method:
- * IHXAudioStream::CHXAudioStream()
- * Purpose:
- * Constructor.
- */
- CHXAudioStream::CHXAudioStream(CHXAudioPlayer* owner, IUnknown* pContext)
- : m_lRefCount(0)
- , m_wLastError(HXR_OK)
- , m_pResampler(NULL)
- , m_pValues(0)
- , m_bDisableWrite(FALSE)
- , m_ulGranularity(0)
- , m_ulInputBytesPerGran(0)
- , m_ulOutputBytesPerGran(0)
- , m_ulExcessInterpBufferSize(0)
- , m_ulPreviousExcessInterpBufferSize(0)
- , m_pDataList(0)
- , m_pInstantaneousList(0)
- , m_pRAByToTsInList(0)
- , m_pRAByToTsAdjustedList(0)
- , m_bFirstWrite(TRUE)
- , m_bHooksInitialized(FALSE)
- , m_bInited(FALSE)
- , m_bSetupDone(FALSE)
- , m_bAudioFormatKnown(FALSE)
- , m_ulMaxBlockSize(0)
- , m_pResampleBuf(0)
- , m_pTmpResBuf(0)
- , m_pCrossFader(0)
- , m_pCrossFadeBuffer(0)
- , m_pExcessInterpBuffer(NULL)
- , m_pTempInterpBuffer(NULL)
- , m_fVolume((float)1.0)
- , m_bChannelConvert(FALSE)
- , m_pStreamVolume(0)
- , m_uVolume(HX_MAX_VOLUME)
- , m_bMute(FALSE)
- , m_bGotHooks(FALSE)
- , m_llLastWriteTime(0)
- , m_ulFudge(5)
- , m_pInDataPtr(0)
- , m_pOutDataPtr(0)
- , m_pVolumeAdviseSink(0)
- , m_bTobeTimed(TRUE)
- , m_bIsFirstPacket(TRUE)
- , m_bIsLive(FALSE)
- , m_ulBaseTime(0)
- , m_ulLiveDelay(0)
- , m_bSetupToBeDone(FALSE)
- , m_bCrossFadingToBeDone(FALSE)
- , m_pCrossFadeStream(NULL)
- , m_llCrossFadeStartTime(0)
- , m_ulCrossFadeDuration(0)
- , m_bFadeToThisStream(FALSE)
- , m_bFadeAlreadyDone(FALSE)
- , m_bRealAudioStream(FALSE)
- , m_ulLastInputStartTime(0)
- , m_ulLastInputEndTime(0)
- , m_llLastStartTimePlayed(0)
- , m_ulTSRollOver(0)
- , m_bLastWriteTimeUpdated(FALSE)
- , m_pCommonClassFactory(NULL)
- , m_pAvailableBuffers(NULL)
- , m_uCacheSize(CACHE_INCREMENT_SIZE)
- , m_bCacheMayBeGrown(FALSE)
- , m_bDeterminedInitialCacheSize(FALSE)
- , m_bLastNMilliSecsToBeSaved(FALSE)
- , m_ulLastNMilliSeconds(MINIMUM_INITIAL_PUSHDOWN)
- , m_pLastNMilliSecsList(NULL)
- , m_ulLastNHeadTime(0)
- , m_ulLastNTailTime(0)
- , m_eState(E_STOPPED)
- , m_bCanBeRewound(FALSE)
- , m_bAudioDeviceReflushHint(FALSE)
- , m_bIsResumed(FALSE)
- , m_bPlayerPause(FALSE)
- , m_pPreferences(NULL)
- , m_bMayNeedToRollbackTimestamp(FALSE)
- {
- /*
- * Left around for future debugging
- static int fnum = 0;
- char fname[80];
-
- sprintf(fname, "c:\temp\before.%d", fnum);
- fdbefore = fopen(fname, "ab+");
- sprintf(fname, "c:\temp\before.%d.txt", fnum);
- fdbeforetxt = fopen(fname, "w+");
- sprintf(fname, "c:\temp\after.%d", fnum);
- fdafter = fopen(fname, "ab+");
- sprintf(fname, "c:\temp\after.%d.txt", fnum);
- fdaftertxt = fopen(fname, "w+");
- sprintf(fname, "c:\temp\in.%d", fnum);
- fdin = fopen(fname, "ab+");
-
- fnum++;
- */
- m_Owner = owner;
- if (m_Owner)
- {
- m_Owner->AddRef();
- }
- if (pContext)
- {
- HX_VERIFY(HXR_OK == pContext->QueryInterface(IID_IHXCommonClassFactory,
- (void**) &m_pCommonClassFactory));
- }
- #if defined(HELIX_FEATURE_PREFERENCES)
- if (pContext)
- {
- HX_VERIFY(HXR_OK == pContext->QueryInterface(IID_IHXPreferences, (void**) &m_pPreferences));
- }
- #endif /* HELIX_FEATURE_PREFERENCES */
- m_pInDataPtr = new HXAudioData;
- m_pOutDataPtr = new HXAudioData;
- };
- /************************************************************************
- * Method:
- * IHXAudioStream::~CHXAudioStream()
- * Purpose:
- * Destructor. Clean up and set free.
- */
- CHXAudioStream::~CHXAudioStream()
- {
- ResetStream();
- /*
- * Left around for future debugging
- if (fdbefore)
- {
- fclose(fdbefore);
- }
- if (fdbeforetxt)
- {
- fclose(fdbeforetxt);
- }
- if (fdafter)
- {
- fclose(fdafter);
- }
- if (fdaftertxt)
- {
- fclose(fdaftertxt);
- }
- if (fdin)
- {
- fclose(fdin);
- }
- */
- }
- /////////////////////////////////////////////////////////////////////////
- // Method:
- // IUnknown::QueryInterface
- // Purpose:
- // Implement this to export the interfaces supported by your
- // object.
- //
- STDMETHODIMP CHXAudioStream::QueryInterface(REFIID riid, void** ppvObj)
- {
- QInterfaceList qiList[] =
- {
- { GET_IIDHANDLE(IID_IHXAudioStream), (IHXAudioStream*) this },
- { GET_IIDHANDLE(IID_IHXRealAudioSync), (IHXRealAudioSync*) this },
- { GET_IIDHANDLE(IID_IHXAudioStream2), (IHXAudioStream2*) this },
- { GET_IIDHANDLE(IID_IHXCommonClassFactory), (IHXCommonClassFactory*) this },
- { GET_IIDHANDLE(IID_IHXUpdateProperties), (IHXUpdateProperties*) this },
- };
- return QIFind(qiList, QILISTSIZE(qiList), riid, ppvObj);
- }
- /////////////////////////////////////////////////////////////////////////
- // Method:
- // IUnknown::AddRef
- // Purpose:
- // Everyone usually implements this the same... feel free to use
- // this implementation.
- //
- STDMETHODIMP_(ULONG32) CHXAudioStream::AddRef()
- {
- return InterlockedIncrement(&m_lRefCount);
- }
- /////////////////////////////////////////////////////////////////////////
- // Method:
- // IUnknown::Release
- // Purpose:
- // Everyone usually implements this the same... feel free to use
- // this implementation.
- //
- STDMETHODIMP_(ULONG32) CHXAudioStream::Release()
- {
- if (InterlockedDecrement(&m_lRefCount) > 0)
- {
- return m_lRefCount;
- }
- delete this;
- return 0;
- }
- /*
- * IHXAudioStream methods
- */
- /************************************************************************
- * Method:
- * IHXAudioStream::Init
- * Purpose:
- * Init the audio stream.
- */
- STDMETHODIMP CHXAudioStream::Init
- (
- const HXAudioFormat* pAudioFormat,
- IHXValues* pValues
- )
- {
- if (m_bAudioFormatKnown)
- {
- return HXR_OK;
- }
- HX_RESULT theErr = HXR_OK;
- m_pValues = pValues;
- if (m_pValues)
- {
- m_pValues->AddRef();
- UINT32 ulVal = 0;
- m_pValues->GetPropertyULONG32("audioDeviceReflushHint", ulVal);
- if (ulVal == 1)
- {
- SetAudioDeviceReflushHint(TRUE);
- m_Owner->m_Owner->CheckIfLastNMilliSecsToBeStored();
- }
- }
- memcpy( &m_AudioFmt, pAudioFormat, sizeof(HXAudioFormat) ); /* Flawfinder: ignore */
- // Create the audio data list
- m_pDataList = new CHXSimpleList;
- if ( !m_pDataList )
- theErr = HXR_OUTOFMEMORY;
- if(!theErr) // check if list constructor really succeeded
- {
- if(!m_pDataList->IsPtrListValid())
- theErr = HXR_OUTOFMEMORY;
- }
- m_pInstantaneousList = new CHXSimpleList;
- if ( !m_pInstantaneousList || !m_pInstantaneousList->IsPtrListValid())
- theErr = HXR_OUTOFMEMORY;
- // Reset this so that we init the hooks
- m_bFirstWrite = TRUE;
- m_bHooksInitialized = FALSE;
- #if defined(HELIX_FEATURE_VOLUME)
- // Create a volume object.
- if ( !theErr )
- {
- m_pVolumeAdviseSink = new HXStreamVolumeAdviseSink;
- if (!m_pVolumeAdviseSink)
- {
- theErr = HXR_OUTOFMEMORY;
- }
- else
- {
- m_pVolumeAdviseSink->AddRef();
- m_pVolumeAdviseSink->m_pCHXAudioStream = this;
- }
- m_pStreamVolume = (IHXVolume*) new CHXVolume;
- if ( !m_pStreamVolume )
- theErr = HXR_OUTOFMEMORY;
- else
- {
- m_pStreamVolume->AddRef();
- m_pStreamVolume->AddAdviseSink(m_pVolumeAdviseSink);
- m_pStreamVolume->SetVolume(HX_MAX_VOLUME);
- }
- }
- #endif /* HELIX_FEATURE_VOLUME */
- #ifdef _TESTING
- g_log = open("c:\log\stream.raw", O_WRONLY | O_CREAT
- | O_BINARY | _O_SEQUENTIAL);
- #endif
- m_bAudioFormatKnown = TRUE;
- if (m_bSetupToBeDone)
- {
- m_bSetupToBeDone = FALSE;
- m_Owner->AudioFormatNowKnown();
- }
- if (!theErr && m_bSetupDone && !m_bInited)
- {
- theErr = ProcessInfo();
- }
- return theErr;
- }
- /************************************************************************
- * Method:
- * IHXAudioStream::Write
- * Purpose:
- * Write audio data to Audio Services.
- *
- * NOTE: If the renderer loses packets and there is no loss
- * correction, then the renderer should write the next packet
- * using a meaningful start time. Audio Services will play
- * silence where packets are missing.
- */
- STDMETHODIMP CHXAudioStream::Write
- (
- HXAudioData* pInData
- )
- {
- HX_RESULT theErr = HXR_OK;
- if (!pInData)
- {
- return HXR_INVALID_PARAMETER;
- }
- if (!m_bInited)
- {
- return HXR_NOT_INITIALIZED;
- }
- // Init pre-mix hooks. Call this once to set up hook info.
- if ( !m_bHooksInitialized )
- {
- InitHooks();
- }
- // Process any "hooks"; Add the data to the data list.
- /* If buffer is NULL, it means that the user just
- * wants to know what timestamp should be placed in the next
- * STREAMED/TIMED audio data
- */
- if ( !m_bGotHooks || !pInData->pData)
- {
- theErr = AddData( pInData );
- }
- else
- {
- HXAudioData outData;
-
- outData.pData = 0;
- outData.ulAudioTime = 0;
- theErr = ProcessHooks( pInData, &outData );
- if (!theErr && !m_bDisableWrite )
- {
- theErr = AddData( &outData );
- }
- if (outData.pData)
- {
- outData.pData->Release();
- }
- }
- return theErr;
- }
- /************************************************************************
- * Method:
- * IHXAudioStream::AddPreMixHook
- * Purpose:
- * Use this method to add a pre-mix audio data hook.
- */
- STDMETHODIMP CHXAudioStream::AddPreMixHook
- (
- IHXAudioHook* pHook,
- const BOOL bDisableWrite
- )
- {
- #if defined(HELIX_FEATURE_AUDIO_PREMIXHOOK)
- void* pTmp = 0;
-
- /* Does one already exists */
- if (m_PreMixHookMap.Lookup((void*)pHook, pTmp))
- {
- return HXR_INVALID_PARAMETER;
- }
- HXAudioHookInfo* pPreMixHookInfo = (HXAudioHookInfo*) new HXAudioHookInfo;
- if(!pPreMixHookInfo)
- {
- return HXR_OUTOFMEMORY;
- }
- pPreMixHookInfo->pHook = pHook;
- pPreMixHookInfo->bDisableWrite = bDisableWrite;
- pPreMixHookInfo->bIgnoreAudioData = FALSE;
- IHXValues* pValues = NULL;
- if (pHook && pHook->QueryInterface(IID_IHXValues, (void**) &pValues) == HXR_OK)
- {
- UINT32 ulValue = 0;
- pValues->GetPropertyULONG32("IgnoreAudioData", ulValue);
- pPreMixHookInfo->bIgnoreAudioData = (ulValue == 1);
- HX_RELEASE(pValues);
- }
- pHook->AddRef(); // Released in destructor
- m_PreMixHookMap.SetAt(pHook, pPreMixHookInfo);
- m_bGotHooks = TRUE;
- /* If any one of them is Disabled, we do not write */
- if (bDisableWrite)
- {
- m_bDisableWrite = TRUE;
- }
- ProcessAudioHook(ACTION_ADD, pHook);
- /* If we are already initialized, send the audio format */
- if (m_bHooksInitialized)
- {
- if (pPreMixHookInfo->bIgnoreAudioData ||
- HXR_OK == ProcessAudioHook(ACTION_CHECK, pHook))
- {
- pHook->OnInit( &m_AudioFmt );
- }
- }
- return HXR_OK;
- #else
- return HXR_NOTIMPL;
- #endif /* HELIX_FEATURE_AUDIO_PREMIXHOOK */
- }
- /************************************************************************
- * Method:
- * IHXAudioStream::RemovePreMixHook
- * Purpose:
- * Use this method to remove a pre-mix audio data hook.
- */
- STDMETHODIMP CHXAudioStream::RemovePreMixHook
- (
- IHXAudioHook* pHook
- )
- {
- #if defined(HELIX_FEATURE_AUDIO_PREMIXHOOK)
- HXAudioHookInfo* pPreMixHookInfo = 0;
- BOOL bCheckForDisableWrite = FALSE;
- if (!m_PreMixHookMap.Lookup((void*)pHook, (void*&) pPreMixHookInfo))
- {
- return HXR_INVALID_PARAMETER;
- }
- m_PreMixHookMap.RemoveKey(pHook);
- /* If we are removing a hook which had disable write,
- * we need to re-determine if any of the remaining hooks
- * has DisableWrite set to TRUE
- */
- if (pPreMixHookInfo->bDisableWrite)
- {
- bCheckForDisableWrite = TRUE;
- m_bDisableWrite = FALSE;
- }
- ProcessAudioHook(ACTION_REMOVE, pHook);
- pPreMixHookInfo->pHook->Release();
- delete pPreMixHookInfo;
- if (m_PreMixHookMap.GetCount() == 0)
- {
- m_bGotHooks = FALSE;
- m_bDisableWrite = FALSE;
- }
- else if (bCheckForDisableWrite)
- {
- CHXMapPtrToPtr::Iterator lIter = m_PreMixHookMap.Begin();
- for (; lIter != m_PreMixHookMap.End(); ++lIter)
- {
- HXAudioHookInfo* pPreMixHook = (HXAudioHookInfo*) (*lIter);
-
- /* atleast one has Disable Write ON */
- if (pPreMixHook->bDisableWrite)
- {
- m_bDisableWrite = TRUE;
- break;
- }
- }
- }
- #endif /* HELIX_FEATURE_AUDIO_PREMIXHOOK */
- return HXR_OK;
- }
- /************************************************************************
- * Method:
- * IHXAudioStream::AddDryNotification
- * Purpose:
- * Use this to add a notification response object to get notifications
- * when audio stream is running dry.
- */
- STDMETHODIMP CHXAudioStream::AddDryNotification
- (
- IHXDryNotification* /*IN*/ pNotification
- )
- {
- if (!pNotification)
- {
- return HXR_INVALID_PARAMETER;
- }
- void* pTmp = 0;
-
- /* Does one already exists */
- if (m_DryNotificationMap.Lookup((void*)pNotification, pTmp))
- {
- return HXR_INVALID_PARAMETER;
- }
- pNotification->AddRef();
- m_DryNotificationMap.SetAt((void*)pNotification, (void*)pNotification);
- return HXR_OK;
- }
- /************************************************************************
- * Method:
- * IHXAudioStream2::RemoveDryNotification
- * Purpose:
- * Use this to remove itself from the notification response object
- * during the stream switching.
- */
- STDMETHODIMP CHXAudioStream::RemoveDryNotification
- (
- IHXDryNotification* /*IN*/ pNotification
- )
- {
- HX_RESULT hr = HXR_OK;
- void* pTmp = 0;
- if (!pNotification)
- {
- hr = HXR_INVALID_PARAMETER;
- goto cleanup;
- }
- // remove only if it is exists
- if (m_DryNotificationMap.Lookup((void*)pNotification, pTmp))
- {
- m_DryNotificationMap.RemoveKey((void*)pNotification);
- HX_RELEASE(pNotification);
- }
- else
- {
- hr = HXR_INVALID_PARAMETER;
- goto cleanup;
- }
- cleanup:
- return hr;
- }
- /************************************************************************
- * Method:
- * IHXAudioStream2::GetAudioFormat
- * Purpose:
- * Returns the input audio format of the data written by the
- * renderer. This function will fill in the pre-allocated
- * HXAudioFormat structure passed in.
- */
- STDMETHODIMP
- CHXAudioStream::GetAudioFormat(HXAudioFormat* /*IN/OUT*/pAudioFormat)
- {
- HX_ASSERT(pAudioFormat);
- if (!pAudioFormat)
- {
- return HXR_INVALID_PARAMETER;
- }
- if (!m_bInited)
- {
- return HXR_UNEXPECTED;
- }
- pAudioFormat->uChannels = m_AudioFmt.uChannels;
- pAudioFormat->uBitsPerSample = m_AudioFmt.uBitsPerSample;
- pAudioFormat->ulSamplesPerSec = m_AudioFmt.ulSamplesPerSec;
- pAudioFormat->uMaxBlockSize = m_AudioFmt.uMaxBlockSize;
- return HXR_OK;
- }
-
- /************************************************************************
- * Method:
- * IHXAudioStream::GetAudioVolume
- * Purpose:
- * Return this stream's IRMA volume interface.
- */
- STDMETHODIMP_(IHXVolume*) CHXAudioStream::GetAudioVolume()
- {
- if ( m_pStreamVolume )
- {
- m_pStreamVolume->AddRef();
- return m_pStreamVolume;
- }
- else
- {
- return 0;
- }
- }
- #if defined(HELIX_FEATURE_VOLUME)
- /*
- * IHXVolumeAdviseSink methods
- */
- STDMETHODIMP CHXAudioStream::OnVolumeChange
- (
- const UINT16 uVolume
- )
- {
- m_uVolume = uVolume;
- return HXR_OK;
- }
- STDMETHODIMP CHXAudioStream::OnMuteChange
- (
- const BOOL bMute
- )
- {
- m_bMute = bMute;
- return HXR_OK;
- }
- #endif /* HELIX_FEATURE_VOLUME */
- /************************************************************************
- * Method:
- * IHXAudioStream::AddData
- * Purpose:
- * Add audio data to list.
- * NOTE: Mark Streamed data also as Timed data IF we don't write a streamed packet
- * since it was LATE!!!
- */
- HX_RESULT CHXAudioStream::AddData
- (
- HXAudioData* pAudioData
- )
- {
- HX_RESULT theErr = HXR_OK;
- BOOL bInTSRollOver = FALSE;
- HXAudioInfo* pAinfo = 0;
- /* If buffer is NULL, it means that the user just
- * wants to know what timestamp should be placed in the next
- * STREAMED/TIMED audio data
- */
- if (!pAudioData->pData)
- {
- HXAudioInfo* pInfo = NULL;
-
- if (!m_pDataList->IsEmpty() &&
- NULL != (pInfo = (HXAudioInfo*) m_pDataList->GetTail()))
- {
- pAudioData->ulAudioTime = pInfo->ulStartTime +
- CalcMs(pInfo->pBuffer->GetSize());
- }
- else
- {
- pAudioData->ulAudioTime = INT64_TO_UINT32(m_llLastWriteTime - CAST_TO_INT64 m_ulTSRollOver * CAST_TO_INT64 MAX_UINT32);
- }
- return HXR_OK;
- }
- // make sure the renderer does not pass NULL data!!
- HX_ASSERT(pAudioData->pData->GetBuffer() != NULL &&
- pAudioData->pData->GetSize() != 0);
- if (pAudioData->pData->GetBuffer() == NULL ||
- pAudioData->pData->GetSize() == 0)
- {
- return HXR_INVALID_PARAMETER;
- }
- if (m_bIsFirstPacket)
- {
- m_bIsFirstPacket = FALSE;
-
- IHXErrorMessages* pErrMsg = NULL;
- 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, "%lutAddDatat%pt%lun", 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, "%lut%pt%dt%lut%lutLATEn", 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: %lun", 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 wrong... 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 wrong... 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 wrong... 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, "%lut%pt%dt%lut%lun", 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: %lun",
- m_AudioFmt.ulSamplesPerSec, m_AudioFmt.uChannels, m_AudioFmt.uBitsPerSample);
- fprintf(fdaftertxt, "Samples: %lu, Channels: %lu, Bits/Sample: %lun",
- 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;
- }
- pAudioFormat->uChannels = m_AudioFmt.uChannels;
- pAudioFormat->uBitsPerSample = m_AudioFmt.uBitsPerSample;
- pAudioFormat->ulSamplesPerSec = m_AudioFmt.ulSamplesPerSec;
- pAudioFormat->uMaxBlockSize = m_AudioFmt.uMaxBlockSize;
- return HXR_OK;
- }
- /************************************************************************
- * Method:
- * IHXAudioStream::Setup
- * Purpose:
- * This is called by the player's Setup method. At this
- * time the audio device format is set and we can now
- * set up the streams pre-mixing buffer. This buffer
- * contains data that has been resampled to match the
- * audio device format.
- */
- HX_RESULT CHXAudioStream::Setup(
- HXAudioFormat* pFormat
- , ULONG32 ulGranularity
- )
- {
- HX_RESULT theErr = HXR_OK;
- m_DeviceFmt.uChannels = pFormat->uChannels;
- m_DeviceFmt.uBitsPerSample = pFormat->uBitsPerSample;
- m_DeviceFmt.ulSamplesPerSec = pFormat->ulSamplesPerSec;
- m_DeviceFmt.uMaxBlockSize = pFormat->uMaxBlockSize;
- m_ulGranularity = ulGranularity;
- m_bSetupDone = TRUE;
-
- /* we have all the info now.. so setup the resampler */
- if (m_bAudioFormatKnown && !m_bInited)
- {
- theErr = ProcessInfo();
- }
- return theErr;
- }
- /************************************************************************
- * Method:
- * IHXAudioStream::ResetStream
- * Purpose:
- */
- void CHXAudioStream::ResetStream()
- {
- m_bInited = FALSE;
- m_bCanBeRewound = FALSE;
- m_bSetupDone = FALSE;
- m_bAudioFormatKnown = FALSE;
- m_bIsResumed = FALSE;
-
- UnRegister();
- while (m_pAvailableBuffers && m_pAvailableBuffers->GetCount() > 0)
- {
- IHXBuffer* pBuffer = (IHXBuffer*) m_pAvailableBuffers->RemoveHead();
- HX_RELEASE(pBuffer);
- }
- 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);
-
- // Delete resample buffer
- HX_VECTOR_DELETE(m_pResampleBuf);
- // Delete tmp resample buffer
- HX_VECTOR_DELETE(m_pTmpResBuf);
- HX_VECTOR_DELETE(m_pCrossFadeBuffer);
- HX_VECTOR_DELETE(m_pExcessInterpBuffer);
- HX_VECTOR_DELETE(m_pTempInterpBuffer);
- m_ulExcessInterpBufferSize = m_ulPreviousExcessInterpBufferSize = 0;
-
- #if defined(HELIX_FEATURE_CROSSFADE)
- HX_DELETE(m_pCrossFader);
- #endif /* HELIX_FEATURE_CROSSFADE */
- // Free the resampler
- HX_RELEASE(m_pResampler);
- m_bGotHooks = FALSE;
- m_llLastWriteTime = 0;
- m_ulTSRollOver = 0;
- #ifdef _TESTING
- if ( g_log > 0 )
- close(g_log);
- g_log = -1;
- #endif
- 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 */
- #if defined(HELIX_FEATURE_VOLUME)
- // Delete IRMA volume object.
- if (m_pStreamVolume && m_pVolumeAdviseSink)
- {
- m_pStreamVolume->RemoveAdviseSink(m_pVolumeAdviseSink);
- m_pVolumeAdviseSink->m_pCHXAudioStream = 0;
- }
- HX_RELEASE(m_pVolumeAdviseSink);
- #endif /* HELIX_FEATURE_VOLUME */
- HX_RELEASE(m_pStreamVolume);
- HX_DELETE(m_pInDataPtr);
- HX_DELETE(m_pOutDataPtr);
- if (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_RESULT
- CHXAudioStream::ProcessAudioHook(PROCESS_ACTION action,
- IHXAudioHook* pAudioHook)
- {
- return HXR_OK;
- }
- // Dummy version of this method - real version would be in hxaudstr_new.cpp
- BOOL CHXAudioStream::ConvertIntoBuffer(tAudioSample* buffer, UINT32 nSamples, INT64 llStartTimeInSamples)
- {
- return FALSE;
- }
- /************************************************************************
- * 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))
- {
- 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.
- * Note:
- *
- * Resampler always works on 16 bit PCM. If the input is
- * 8 bit, it converts it first to 16 bit before making
- * any resampling calculations.
- * We always try to open audio device in 16 bit stereo mode.
- * This is because a new player/stream may be instantiated in the
- * midst of a presentation and this new stream may be stereo. If we
- * earlier opened the device as mono, we will have to force this stereo
- * stream to be played as mono! Not a good idea. Also any mono-streo
- * conversion almost comes for free (some extra memory usage and
- * an extra assignment) since it can be done in the mixing loop in
- * MixBuffer().
- *
- * Any 8-16 and stereo-mono conversion, if required, SHOULD be done
- * before resampling.
- * Any mono-stereo conversion should be done after resampling.
- *
- * Stereo-Mono conversion code resides in the resampler.
- * Mono-Stereo conversion code resides in the mixer.
- *
- */
- HX_RESULT CHXAudioStream::MixIntoBuffer
- (
- UCHAR* pPlayerBuf,
- ULONG32 ulBufSize,
- ULONG32& ulBufTime,
- BOOL& bIsMixBufferDirty,
- BOOL bGetCrossFadeData
- )
- {
- BOOL bCrossFadeThisTime = FALSE;
- UINT32 ulTimeActuallyFaded = m_ulGranularity;
- if (!m_bInited)
- {
- return HXR_NOT_INITIALIZED;
- }
- //{FILE* f1 = ::fopen("c:\temp\rasync.txt", "a+"); ::fprintf(f1, "Call MixIntoBuffer: %lun", m_ulLastWriteTime);::fclose(f1);}
- /* If this is a *FROM* stream, we may have already mixed
- * data during cross-fade with *TO* stream
- */
- if (m_bFadeAlreadyDone && !m_bFadeToThisStream)
- {
- m_bFadeAlreadyDone = FALSE;
- return HXR_OK;
- }
- HX_ASSERT(!bGetCrossFadeData || !m_bFadeToThisStream);
- /* If we need to mix cross fade data from the *from* stream,
- * it better be available
- */
- HX_ASSERT(!bGetCrossFadeData || m_pDataList->GetCount() > 0);
- /* If this stream needs to be cross-faded and is a
- * NOT a fade-to stream, it would have been already taken
- * care of by the fade-to stream in an earlier call to
- * MixIntoBuffer()
- */
- if (m_bCrossFadingToBeDone && m_pDataList->GetCount() > 0)
- {
- HXAudioInfo* pInfo = (HXAudioInfo*) m_pDataList->GetHead();
- INT64 llActualStartTime = 0;
- if (pInfo)
- {
- llActualStartTime = CAST_TO_INT64 (pInfo->ulStartTime) +
- CAST_TO_INT64 (CalcMs(pInfo->pBuffer->GetSize() - pInfo->ulBytesLeft)) +
- CAST_TO_INT64 m_ulTSRollOver * CAST_TO_INT64 MAX_UINT32;
- if (m_bFadeToThisStream)
- {
- /* Cool! It is time for cross-fading */
- if ((m_llLastWriteTime <= m_llCrossFadeStartTime &&
- m_llCrossFadeStartTime - m_llLastWriteTime <= CAST_TO_INT64 m_ulGranularity) ||
- (m_llLastWriteTime > m_llCrossFadeStartTime &&
- m_llLastWriteTime - m_llCrossFadeStartTime <= CAST_TO_INT64 m_ulFudge))
- {
- bCrossFadeThisTime = TRUE;
- if (m_llLastWriteTime <= m_llCrossFadeStartTime)
- {
- ulTimeActuallyFaded = m_ulGranularity -
- INT64_TO_UINT32(m_llCrossFadeStartTime - m_llLastWriteTime);
- }
- //{FILE* f1 = ::fopen("c:\raroot\racross.txt", "a+"); ::fprintf(f1, "m_ulLastWriteTime: %lu ulStartTime: %lu m_ulCrossFadeStartTime: %lu pInfo->ulStartTime: %lu pInfo->pBuffer->GetSize(): %lu pInfo->ulBytesLeft: %lun", m_ulLastWriteTime, ulStartTime, m_ulCrossFadeStartTime, pInfo->ulStartTime, pInfo->pBuffer->GetSize(), pInfo->ulBytesLeft);::fclose(f1);}
- HX_ASSERT(
- (llActualStartTime >= m_llCrossFadeStartTime &&
- (llActualStartTime <= m_llCrossFadeStartTime +
- m_ulCrossFadeDuration)) ||
- (llActualStartTime < m_llCrossFadeStartTime &&
- (m_llCrossFadeStartTime - llActualStartTime <= CAST_TO_INT64 m_ulFudge)));
- }
- }
- }
- }
- UINT32 ulLastWriteTime = INT64_TO_UINT32(m_llLastWriteTime - CAST_TO_INT64 m_ulTSRollOver * CAST_TO_INT64 MAX_UINT32);
- if (!bGetCrossFadeData && 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 (m_DryNotificationMap.GetCount() > 0 || m_Owner->GetAudioStreamCount() == 1)
- {
- UINT32 ulNumMsRequired = m_ulGranularity;
- if (m_pDataList->IsEmpty() || !EnoughDataAvailable(ulLastWriteTime, ulNumMsRequired))
- {
- if (!bIsMixBufferDirty && !bGetCrossFadeData && !m_Owner->m_Owner->ReallyNeedData())
- {
- return HXR_WOULD_BLOCK;
- }
- if (m_DryNotificationMap.GetCount() > 0)
- {
- IHXDryNotification* pDryNotification = 0;
- CHXMapPtrToPtr::Iterator lIter = m_DryNotificationMap.Begin();
- for (; lIter != m_DryNotificationMap.End(); ++lIter)
- {
- pDryNotification = (IHXDryNotification*) (*lIter);
- pDryNotification->OnDryNotification(ulLastWriteTime, ulNumMsRequired);
- }
- if (m_Owner->GetState() != E_PLAYING)
- {
- return HXR_OK;
- }
- }
- }
- }
- m_Owner->DataInAudioDevice(TRUE);
- // /////////////////////////////////////////////////////////////
- // There may be no buffers in the list. No packets? Play silence.
- // Still need to increment time.
- if ( m_pDataList->IsEmpty() && m_pInstantaneousList->IsEmpty() )
- {
- m_llLastWriteTime += CAST_TO_INT64 m_ulGranularity;
- //{FILE* f1 = ::fopen("e:\MixIntoBuffer.txt", "a+"); ::fprintf(f1, "%lut%pt%lun", HX_GET_BETTERTICKCOUNT(), this, (UINT32)m_llLastWriteTime);::fclose(f1);}
- return HXR_NO_DATA;
- }
- UCHAR* pSourceBuffer = 0;
- ULONG32 ulMaxBytes = 0;
- ULONG32 ulMaxFramesIn = 0;
- ULONG32 ulMaxFramesOut = 0;
- ULONG32 ulNumBytesMixed = 0;
- BOOL bMonoToStereoMayBeConverted = TRUE;
- BOOL bResampleBufferDirty = FALSE;
- // /////////////////////////////////////////////////////////////
- // If no resampling, mix stream data directly into the player
- // buffer.
- if ( !m_pResampler)
- {
- pSourceBuffer = pPlayerBuf;
- ulMaxBytes = m_ulInputBytesPerGran;
- /* For only those sound cards which do not
- * support stereo - a RARE (non-existent) case
- */
- if (m_AudioFmt.uChannels == 2 && m_DeviceFmt.uChannels == 1)
- {
- /* We should never reach here since this case
- * should be handled by the Resampler
- * Temporary ASSERT...
- */
- HX_ASSERT(FALSE);
- }
- /* Mono->Stereo conversion*/
- else if (m_bChannelConvert)
- {
- HX_ASSERT(ulMaxBytes <= ulBufSize/2);
-
- /* Avoid GPF in retail builds! */
- if (ulMaxBytes > ulBufSize/2)
- {
- ulMaxBytes = ulBufSize/2;
- }
- }
- else
- {
- HX_ASSERT(ulMaxBytes <= ulBufSize);
-
- /* Avoid GPF in retail builds! */
- if (ulMaxBytes > ulBufSize)
- {
- ulMaxBytes = ulBufSize;
- }
- }
- }
- #if defined(HELIX_FEATURE_RESAMPLER)
- // /////////////////////////////////////////////////////////////
- // If resampling, mix stream data into a tmp buffer. Then
- // resample this buffer and mix the final resampled buffer into
- // the player buffer.
- else
- {
- bMonoToStereoMayBeConverted = FALSE;
- // memset(m_pTmpResBuf, 0, HX_SAFESIZE_T(m_ulMaxBlockSize));
- pSourceBuffer = m_pTmpResBuf;
- /*
- * Audio Session will always ask for m_ulOutputBytesPerGran bytes to be mixed
- * in MixIntoBuffer() call. So we need to produce these many number of bytes.
- * If there is any mono-stereo conversion that happens in the mixing, number
- * of output bytes required from the resampler are half the number of
- * m_ulOutputBytesPerGran bytes.
- */
- if (m_pResampler)
- {
- ulMaxFramesOut = m_ulOutputBytesPerGran/(m_DeviceFmt.uBitsPerSample==8 ? 1 : 2);
- if (m_DeviceFmt.uChannels == 2)
- {
- ulMaxFramesOut /= 2;
- }
- ulMaxFramesIn = m_pResampler->Requires(ulMaxFramesOut);
- ulMaxBytes = ulMaxFramesIn * ((m_AudioFmt.uBitsPerSample==8)? 1 : 2)
- * m_AudioFmt.uChannels;
- }
- else
- {
- ulMaxBytes = m_ulInputBytesPerGran;
- }
- HX_ASSERT(ulMaxBytes <= m_ulMaxBlockSize);
- }
- #endif /* HELIX_FEATURE_RESAMPLER */
- // /////////////////////////////////////////////////////////////
- // Mix n bytes of data into buffer
- ulNumBytesMixed = MixData(pSourceBuffer, ulMaxBytes, bMonoToStereoMayBeConverted,
- (!m_pResampler) ? bIsMixBufferDirty : bResampleBufferDirty);
- /*
- if (ulNumBytesMixed > 0)
- {
- ::fwrite(pSourceBuffer, ulNumBytesMixed, 1, fdbefore);
- }
- */
- #if defined(HELIX_FEATURE_RESAMPLER)
- // /////////////////////////////////////////////////////////////
- // If we need to resample , then do this and then mix data into
- // the player buffer.
- // Only resample and mix if volume is *not* zero and there
- // are some bytes to mix.
- if (m_pResampler && ulNumBytesMixed > 0 && m_uVolume > 0 && !m_bMute)
- {
- if(ulNumBytesMixed < ulMaxBytes && 8==m_AudioFmt.uBitsPerSample)
- {
- //fill remainder with 128's (-1), silence:
- UCHAR* pTmp = &pSourceBuffer[ulNumBytesMixed];
- ULONG32 ulNumBytesLeftToSilence = ulMaxBytes-ulNumBytesMixed;
- do
- {
- *pTmp = 128;
- pTmp++;
- } while(--ulNumBytesLeftToSilence);
- }
- ULONG32 ulOutBytes = 0;
- if (m_pResampler)
- {
- ulOutBytes = m_pResampler->Resample((UINT16*)pSourceBuffer,
- ulMaxBytes,
- (UINT16*)m_pResampleBuf);
- /*
- FILE* fp = fopen("c:\temp\audio.txt", "w+");
- ::fwrite(m_pResampleBuf, ulOutBytes, 1, fp);
- fclose(fp);
- */
- /* Resampler will do stereo to mono conversion for us.*/
- HX_ASSERT(ulMaxFramesOut == (ulOutBytes / 2 /
- (m_AudioFmt.uChannels == 2 && m_DeviceFmt.uChannels == 1 ? 1 : m_AudioFmt.uChannels))) ;
- }
- if (m_bChannelConvert)
- {
- HX_ASSERT(ulOutBytes*2 <= ulBufSize);
- if ( ulOutBytes > ulBufSize/2 )
- {
- ulOutBytes = ulBufSize/2;
- }
- }
- else
- {
- HX_ASSERT(ulOutBytes <= ulBufSize);
- ulOutBytes = ulBufSize;
- }
- BOOL bBeforeMixBufferDirty = bIsMixBufferDirty;
- UINT32 ulMixedNumBytes = 0;
- #if defined(HELIX_FEATURE_MIXER)
- ulMixedNumBytes = CHXMixer::MixBuffer( m_pResampleBuf, pPlayerBuf,
- ulOutBytes, m_bChannelConvert,
- m_uVolume, m_DeviceFmt.uBitsPerSample, bIsMixBufferDirty);
- #else
- ::memcpy(pPlayerBuf, m_pResampleBuf, ulOutBytes); /* Flawfinder: ignore */
- bIsMixBufferDirty = TRUE;
- ulMixedNumBytes = ulOutBytes;
- #endif /* HELIX_FEATURE_MIXER */
- // If we mixed only a partial buffer, make the remaining buffer silent
- if (!bBeforeMixBufferDirty && ulMixedNumBytes < ulBufSize)
- {
- ::memset(pPlayerBuf+ulMixedNumBytes, 0, ulBufSize-ulMixedNumBytes);
- }
- }
- afterMixing:
- #endif /* HELIX_FEATURE_RESAMPLER */
- #ifdef _TESTING
- if ( g_log > 0 )
- {
- write( g_log, pPlayerBuf, ulNumBytesMixed);
- }
- #endif
- /* This is for *FROM* stream */
- if (bGetCrossFadeData)
- {
- m_bFadeAlreadyDone = TRUE;
- }
- /* If we are cross-fading, we have data from this stream in pPlayerBuf
- * Now get data to be cross-faded from *From* stream in
- * m_pCrossFadeBuffer
- */
- #if defined(HELIX_FEATURE_CROSSFADE) && defined(HELIX_FEATURE_MIXER)
- else if (bCrossFadeThisTime)
- {
- /* Allocate CrossFade Buffer */
- if (!m_pCrossFadeBuffer)
- {
- m_ulCrossFadeBufferSize = ulBufSize;
- m_pCrossFadeBuffer = new UCHAR[m_ulCrossFadeBufferSize];
- }
- memset(m_pCrossFadeBuffer, 0, HX_SAFESIZE_T(m_ulCrossFadeBufferSize));
- UINT32 ulCrossFadeLen = m_ulCrossFadeBufferSize;
- UINT32 ulTmpBufTime = 0;
- BOOL bIsDrity = FALSE;
- m_pCrossFadeStream->MixIntoBuffer(m_pCrossFadeBuffer,
- ulCrossFadeLen, ulTmpBufTime, bIsDrity, TRUE);
- /* Now it is time to perform cross-fading between
- * pPlayerBuf and m_pCrossFadeBuffer
- */
-
- UINT32 ulStartByteToFade = 0;
- UINT32 ulNumMsInThisBuffer = CalcDeviceMs(ulBufSize);
- UINT32 ulNumBytesToBeCrossFaded = ulBufSize;
- UINT32 ulSampleSize = ((m_DeviceFmt.uBitsPerSample==8)? 1 : 2)
- * m_DeviceFmt.uChannels;
- /* Make sure we have integral number of samples */
- HX_ASSERT(ulBufSize == (ulBufSize/ulSampleSize) * ulSampleSize);
- /* Only partial buffer needs to be cross-faded.
- * -------------
- * ~~_____________|
- *
- * -----------
- * |___________~~
- *
- *
- * -----
- * |_____| <-- Granularity size block that is mixed.
- *
- * <--> Only partial block needs to be faded
- */
-
- if (ulTimeActuallyFaded < ulNumMsInThisBuffer)
- {
- ulNumBytesToBeCrossFaded = (UINT32) (ulBufSize *
- (ulTimeActuallyFaded*1./ulNumMsInThisBuffer)) ;
- UINT32 ulOutOfPhase = ulNumBytesToBeCrossFaded % ulSampleSize;
- if (ulOutOfPhase > 0)
- {
- ulNumBytesToBeCrossFaded =
- ulNumBytesToBeCrossFaded - ulOutOfPhase;
- }
- ulStartByteToFade = ulBufSize - ulNumBytesToBeCrossFaded;
- }
- if (ulTimeActuallyFaded > m_ulCrossFadeDuration)
- {
- ulNumBytesToBeCrossFaded = (UINT32) (ulBufSize *
- (m_ulCrossFadeDuration*1./ulNumMsInThisBuffer)) ;
- UINT32 ulOutOfPhase = ulNumBytesToBeCrossFaded % ulSampleSize;
- if (ulOutOfPhase > 0)
- {
- ulNumBytesToBeCrossFaded =
- ulNumBytesToBeCrossFaded - ulOutOfPhase;
- }
- }
- UINT16 uNumSamples = (UINT16) (ulNumBytesToBeCrossFaded/
- ulSampleSize);
- BOOL bWasDirty = bIsMixBufferDirty;
- /* Mix the initial bytes that are not cross-faded*/
- if (ulStartByteToFade > 0)
- {
- CHXMixer::MixBuffer( m_pCrossFadeBuffer, pPlayerBuf,
- ulStartByteToFade, FALSE, 100, 8, bWasDirty);
- }
- m_pCrossFader->CrossFade((INT16*) (m_pCrossFadeBuffer+ulStartByteToFade),
- (INT16*) (pPlayerBuf+ulStartByteToFade),
- uNumSamples);
- /* make sure we have silence in bytes that were not touched */
- if (!bIsMixBufferDirty &&
- (ulStartByteToFade + (uNumSamples*ulSampleSize)) < ulBufSize)
- {
- ::memset(pPlayerBuf+ulStartByteToFade + (uNumSamples*ulSampleSize), 0,
- ulBufSize - (ulStartByteToFade + (uNumSamples*ulSampleSize)));
- }
- bIsMixBufferDirty = TRUE;
- }
- if (bGetCrossFadeData || bCrossFadeThisTime)
- {
- if (bGetCrossFadeData)
- {
- HX_ASSERT(m_llLastWriteTime >= m_llCrossFadeStartTime);
- if (m_llLastWriteTime >= m_llCrossFadeStartTime)
- {
- HX_ASSERT(m_llLastWriteTime - m_llCrossFadeStartTime < MAX_TIMESTAMP_GAP);
- ulTimeActuallyFaded = INT64_TO_UINT32(m_llLastWriteTime - m_llCrossFadeStartTime);
- }
- }
- if (ulTimeActuallyFaded >= m_ulCrossFadeDuration)
- {
- m_bCrossFadingToBeDone = FALSE;
- HX_RELEASE(m_pCrossFadeStream);
- /* We should release any extra buffers if it is a
- * *from* stream
- */
- if (!m_bFadeToThisStream)
- {
- /* Do not remove any instantaenous buffers */
- FlushBuffers(FALSE);
- }
- }
- else
- {
- m_ulCrossFadeDuration -= ulTimeActuallyFaded;
- m_llCrossFadeStartTime += CAST_TO_INT64 ulTimeActuallyFaded;
- }
- }
- else if (m_bCrossFadingToBeDone && !m_bFadeToThisStream)
- {
- m_pCrossFadeStream->SyncStream(m_llLastWriteTime);
- }
- #endif /* HELIX_FEATURE_CROSSFADE && HELIX_FEATURE_MIXER */
- //{FILE* f1 = ::fopen("e:\MixIntoBuffer.txt", "a+"); ::fprintf(f1, "%lut%pt%lun", HX_GET_BETTERTICKCOUNT(), this, (UINT32)m_llLastWriteTime);::fclose(f1);}
- return HXR_OK;
- }
- /************************************************************************
- * Method:
- * CHXAudioStream::MixData
- * Purpose:
- * Mix all valid data in my auxilliary list into the buffer.
- *
- * Thoughts:
- * while there are buffers available
- * if (buffertime is more than endtime) break;
- * if (any part of buffer is >startime and < endtime)
- * we are in business.
- * mix that part of the buffer, update offset,
- * update max of num bytes written in this round.
- * Looks like we need to keep LastWrite time and offsets for all buffers
- * that get written in one pass.
- * Consider this scenario:
- *
- *
- ----------------- -----------------
- |________________| |_______________| -> Skew 1
- ________ __________
- |_______| |_________| ->Skew 2 5
- ____________________________________
- |__________________|_|_______________| Skew in opposite direction 3
- _______
- |_______| 4
- ____________
- |____________| <- Buffer to be mixed currently
-
-
- Order of buffer processing will be in the order of numbers on the right.
- Since all the theree buffers have fudge within fudge limit, they need to
- be written one after the other. This is possible only if we keep last
- write times and last written offsets in mixer buffer for each one of them.
- Is this extra processsing on every write worthed OR do we place limitations
- on the data that can be written.
- * Hmmm... We are now going with STREAMED/INSTANTANEOUS/TIMED model since the
- * above case is shows that users can really screw things up and it would be
- * very difficult to handle this case. So instead, we do not support over-lapped
- * buffers any more. i.e. If a renderer wants to have streamed and instantaneous
- * behavior, it needs to use two audio streams.
- */
- ULONG32 CHXAudioStream::MixData
- (
- UCHAR* pDestBuf
- , ULONG32 ulBufLen
- , BOOL bMonoToStereoMayBeConverted
- , BOOL& bIsMixBufferDirty
- )
- {
- HXAudioInfo* pInfo = 0;
- ULONG32 ulNumBytes = 0;
- LISTPOSITION lp = 0;
- LISTPOSITION lastlp = 0;
- LISTPOSITION lpList = 0;
- LISTPOSITION lastlpList = 0;
- ULONG32 ulNumBytesWritten = 0;
- BOOL bLastWriteTimeToBeUpdated = TRUE;
- ULONG32 ulDestinationOffset = 0;
- BOOL bWasMixBufferDirty = bIsMixBufferDirty;
- // /////////////////////////////////////////////////////////////
- // Go thru the buffer list and mix in valid buffers.
- /* First all instantaneous buffers
- * All the instantaneous buffers get written at the start of
- * the destination buffer.
- */
- lpList = lastlpList = 0;
- lpList = m_pInstantaneousList->GetHeadPosition();
- while(lpList)
- {
- lastlpList = lpList;
- CHXSimpleList* pList = (CHXSimpleList*) m_pInstantaneousList->GetNext(lpList);
- lp = lastlp = 0;
- lp = pList->GetHeadPosition();
- ulDestinationOffset = 0;
- while( lp )
- {
- lastlp = lp;
- pInfo = (HXAudioInfo*) pList->GetNext(lp);
- /* just place it at the end of the last write position */
- ULONG32 ulNumMoreBytesToWrite = 0;
- if (m_bChannelConvert && bMonoToStereoMayBeConverted)
- {
- ulNumMoreBytesToWrite = (ulBufLen*2-ulDestinationOffset)/2;
- }
- else
- {
- ulNumMoreBytesToWrite = ulBufLen-ulDestinationOffset;
- }
- ulNumBytes = pInfo->ulBytesLeft > ulNumMoreBytesToWrite ?
- ulNumMoreBytesToWrite : pInfo->ulBytesLeft;
- // /////////////////////////////////////////////////////////////
- // Mix the data into the stream buffer, with stream volume. Don't
- // do volume calculation if volume is 1. If volume is 0, then
- // don't mix. Don't mix if there are no bytes to mix.
- if (m_uVolume > 0 && ulNumBytes > 0)
- {
- if (m_bChannelConvert && bMonoToStereoMayBeConverted)
- {
- HX_ASSERT(ulDestinationOffset + ulNumBytes*2 <= ulBufLen*2);
- }
- else
- {
- HX_ASSERT(ulDestinationOffset + ulNumBytes <= ulBufLen);
- }
- /* we will actually make bIsMixBufferDirty dirty at the end of this function */
- BOOL bLocalDirty = bIsMixBufferDirty;
- #if defined(HELIX_FEATURE_MIXER)
- CHXMixer::MixBuffer(pInfo->pOffset, pDestBuf+ulDestinationOffset,
- ulNumBytes, m_bChannelConvert && bMonoToStereoMayBeConverted,
- m_uVolume, m_AudioFmt.uBitsPerSample, bLocalDirty);
- #else
- ::memcpy(pDestBuf+ulDestinationOffset, pInfo->pOffset, ulNumBytes); /* Flawfinder: ignore */
- bLocalDirty = TRUE;
- #endif /* HELIX_FEATURE_MIXER */
- }
- ULONG32 ulActualBytesWritten = ((m_bChannelConvert && bMonoToStereoMayBeConverted) ?
- 2*ulNumBytes : ulNumBytes);
- if (ulNumBytesWritten < ulActualBytesWritten)
- {
- ulNumBytesWritten = ulActualBytesWritten;
- }
- ulDestinationOffset += ulActualBytesWritten;
- pInfo->ulBytesLeft -= ulNumBytes;
- pInfo->pOffset += ulNumBytes;
- if (pInfo->ulBytesLeft == 0)
- {
- FreeInfo(pInfo, TRUE);
- pList->RemoveAt(lastlp);
- }
- /* Have we written enough for this time? */
- if (ulBufLen == ulDestinationOffset ||
- (m_bChannelConvert && bMonoToStereoMayBeConverted &&
- (ulBufLen*2 == ulDestinationOffset)))
- {
- break;
- }
- }
- if (ulNumBytesWritten > 0 && m_uVolume > 0)
- {
- bIsMixBufferDirty = TRUE;
- }
- if (pList->GetCount() == 0 && m_pInstantaneousList->GetCount() > 1)
- {
- m_pInstantaneousList->RemoveAt(lastlpList);
- HX_DELETE(pList);
- }
- }
- /* now timed buffers */
- /* We do not support over-lapped buffers any more */
- ulDestinationOffset = 0;
- lp = lastlp = 0;
- lp = m_pDataList->GetHeadPosition();
- while( lp )
- {
- INT64 llActualStartTime = 0;
- UINT32 ulActualTSRollOver = m_ulTSRollOver;
- lastlp = lp;
- pInfo = (HXAudioInfo*) m_pDataList->GetNext(lp);
- if (pInfo->ulStartTime > m_ulLastInputStartTime &&
- ((pInfo->ulStartTime - m_ulLastInputStartTime) > MAX_TIMESTAMP_GAP))
- {
- ulActualTSRollOver--;
- }
- llActualStartTime = CAST_TO_INT64 (pInfo->ulStartTime) + CAST_TO_INT64 ulActualTSRollOver * CAST_TO_INT64 MAX_UINT32;
- HX_ASSERT(llActualStartTime - m_llLastWriteTime < MAX_TIMESTAMP_GAP);
- /* only at the start of the buffer, we check whether
- * we are done or not for this round
- */
- if (pInfo->uAudioStreamType == STREAMING_AUDIO &&
- pInfo->pOffset == pInfo->pBuffer->GetBuffer() &&
- llActualStartTime > m_llLastWriteTime &&
- llActualStartTime - m_llLastWriteTime > CAST_TO_INT64 m_ulFudge)
- {
- break;
- }
- if (pInfo->uAudioStreamType == TIMED_AUDIO &&
- (pInfo->ulBytesLeft == pInfo->pBuffer->GetSize() ||
- m_bCrossFadingToBeDone))
- {
- llActualStartTime = CAST_TO_INT64 (pInfo->ulStartTime) +
- CAST_TO_INT64 (CalcMs(pInfo->pBuffer->GetSize() - pInfo->ulBytesLeft)) +
- CAST_TO_INT64 ulActualTSRollOver * CAST_TO_INT64 MAX_UINT32;
- HX_ASSERT(llActualStartTime - m_llLastWriteTime < MAX_TIMESTAMP_GAP);
- if (llActualStartTime >= m_llLastWriteTime &&
- llActualStartTime - m_llLastWriteTime >= CAST_TO_INT64 m_ulGranularity)
- {
- //{FILE* f1 = ::fopen("e:\MixData.txt", "a+"); ::fprintf(f1, "%lut%pt%lut%lun", HX_GET_BETTERTICKCOUNT(), this, (UINT32)llActualStartTime, (UINT32)m_llLastWriteTime);::fclose(f1);}
- break;
- }
- /*Calculate the actual time where to write from*/
- ULONG32 ulBytesDiff = 0;
- if (llActualStartTime >= m_llLastWriteTime)
- {
- ulBytesDiff = CalcOffset(m_llLastWriteTime, llActualStartTime);
- ulBytesDiff = ulBytesDiff - (ulBytesDiff % (2*m_AudioFmt.uChannels));
-
- if (m_bChannelConvert && bMonoToStereoMayBeConverted)
- {
- ulBytesDiff *= 2;
- /* This check is needed to account for lost packets.
- * If there are more than one packet missing in a row,
- * we may get multiple packets with TIMED_AUDIO flag
- * and they may be far apart in time to be written
- * in this block
- */
- if (ulDestinationOffset + ulBytesDiff > ulBufLen*2)
- {
- bLastWriteTimeToBeUpdated = FALSE;
- m_llLastWriteTime +=
- CalcMs((ulBufLen*2 - ulDestinationOffset)/2);
- break;
- }
- }
- else
- {
- /* This check is needed to account for lost packets.
- * If there are more than one packet missing in a row,
- * we may get multiple packets with TIMED_AUDIO flag
- * and they may be far apart in time to be written
- * in this block
- */
- if (ulDestinationOffset + ulBytesDiff > ulBufLen)
- {
- bLastWriteTimeToBeUpdated = FALSE;
- m_llLastWriteTime +=
- CalcMs(ulBufLen - ulDestinationOffset);
- break;
- }
- }
- ulDestinationOffset += ulBytesDiff;
- }
- else
- {
- ulBytesDiff = CalcOffset(llActualStartTime, m_llLastWriteTime);
- /* Make sure that it is at even byte boundary */
- ulBytesDiff = ulBytesDiff - (ulBytesDiff % (2*m_AudioFmt.uChannels));
- if (pInfo->ulBytesLeft >= ulBytesDiff)
- {
- pInfo->pOffset += ulBytesDiff;
- pInfo->ulBytesLeft -= ulBytesDiff;
- }
- else
- {
- pInfo->pOffset += pInfo->ulBytesLeft;
- pInfo->ulBytesLeft = 0;
- }
- }
- }
- /* just place it at the end of the last write position */
- ULONG32 ulNumMoreBytesToWrite = 0;
- if (m_bChannelConvert && bMonoToStereoMayBeConverted)
- {
- ulNumMoreBytesToWrite = (ulBufLen*2-ulDestinationOffset)/2;
- }
- else
- {
- ulNumMoreBytesToWrite = ulBufLen-ulDestinationOffset;
- }
- ulNumBytes = pInfo->ulBytesLeft > ulNumMoreBytesToWrite ?
- ulNumMoreBytesToWrite : pInfo->ulBytesLeft;
- // /////////////////////////////////////////////////////////////
- // Mix the data into the stream buffer, with stream volume. Don't
- // do volume calculation if volume is 1. If volume is 0, then
- // don't mix. Don't mix if there are no bytes to mix.
- if (m_uVolume > 0 && ulNumBytes > 0)
- {
- if (m_bChannelConvert && bMonoToStereoMayBeConverted)
- {
- HX_ASSERT(ulDestinationOffset + ulNumBytes*2 <= ulBufLen*2);
- }
- else
- {
- HX_ASSERT(ulDestinationOffset + ulNumBytes <= ulBufLen);
- }
- /* we will actually make bIsMixBufferDirty dirty at the end of this function */
- BOOL bLocalDirty = bIsMixBufferDirty;
- #if defined(HELIX_FEATURE_MIXER)
- CHXMixer::MixBuffer(pInfo->pOffset, pDestBuf+ulDestinationOffset,
- ulNumBytes, m_bChannelConvert && bMonoToStereoMayBeConverted,
- m_uVolume, m_AudioFmt.uBitsPerSample, bLocalDirty);
- #else
- ::memcpy(pDestBuf+ulDestinationOffset, pInfo->pOffset, ulNumBytes); /* Flawfinder: ignore */
- bLocalDirty = TRUE;
- #endif /* HELIX_FEATURE_MIXER */
- }
- ULONG32 ulActuallyBytesWritten = ulNumBytes;
- ulActuallyBytesWritten = ((m_bChannelConvert && bMonoToStereoMayBeConverted) ?
- ulActuallyBytesWritten*2 : ulActuallyBytesWritten);
- if (ulNumBytesWritten < ulActuallyBytesWritten + ulDestinationOffset)
- {
- ulNumBytesWritten = ulActuallyBytesWritten + ulDestinationOffset;
- }
- ulDestinationOffset += ulActuallyBytesWritten;
- pInfo->ulBytesLeft -= ulNumBytes;
- pInfo->pOffset += ulNumBytes;
- INT64 llLastWriteTime = 0;
-
- llLastWriteTime = CAST_TO_INT64 (pInfo->ulStartTime) +
- CAST_TO_INT64 (CalcMs(pInfo->pBuffer->GetSize() - pInfo->ulBytesLeft)) +
- CAST_TO_INT64 ulActualTSRollOver * CAST_TO_INT64 MAX_UINT32;
- if (bLastWriteTimeToBeUpdated)
- {
- m_llLastStartTimePlayed = llLastWriteTime - CalcMs(ulNumBytes);
- }
- bLastWriteTimeToBeUpdated = FALSE;
- if (m_llLastWriteTime < llLastWriteTime)
- {
- m_llLastWriteTime = llLastWriteTime;
- }
- if (pInfo->ulBytesLeft == 0)
- {
- FreeInfo(pInfo);
- m_pDataList->RemoveAt(lastlp);
- }
- /* Have we written enough for this time? */
- if (ulBufLen == ulDestinationOffset ||
- (m_bChannelConvert && bMonoToStereoMayBeConverted &&
- (ulBufLen*2 == ulDestinationOffset)))
- {
- break;
- }
- }
- if (bLastWriteTimeToBeUpdated)
- {
- m_llLastWriteTime += m_ulGranularity;
- }
- else /* We mixed some input bytes */
- {
- if (m_bRealAudioStream)
- {
- //{FILE* f1 = ::fopen("c:\temp\rasync.txt", "a+"); ::fprintf(f1, "Call MapFudgedTimestamps: %lun", m_ulLastStartTimePlayed);::fclose(f1);}
- MapFudgedTimestamps();
- }
- }
- if (ulNumBytesWritten > 0 && m_uVolume > 0)
- {
- bIsMixBufferDirty = TRUE;
- }
- if (!bWasMixBufferDirty && ulNumBytesWritten < ulBufLen && bIsMixBufferDirty)
- {
- ::memset(pDestBuf+ulNumBytesWritten, 0, ulBufLen-ulNumBytesWritten);
- }
- return ulNumBytesWritten;
- }
- /************************************************************************
- * Method:
- * CHXAudioStream::CalcMs
- * Purpose:
- * Calculate the duration in millisecs for this number of bytes.
- */
- ULONG32 CHXAudioStream::CalcMs
- (
- ULONG32 ulNumBytes
- )
- {
- return ( (ULONG32) (( 1000.0
- / (m_AudioFmt.uChannels * ((m_AudioFmt.uBitsPerSample==8)?1:2)
- * m_AudioFmt.ulSamplesPerSec) )
- * ulNumBytes) );
- }
- /************************************************************************
- * Method:
- * CHXAudioStream::CalcDeviceMs
- * Purpose:
- * Calculate the duration in millisecs for this number of
- * bytes in Device format.
- */
- ULONG32 CHXAudioStream::CalcDeviceMs
- (
- ULONG32 ulNumBytes
- )
- {
- return ( (ULONG32) (( 1000.0
- / (m_DeviceFmt.uChannels * ((m_DeviceFmt.uBitsPerSample==8)?1:2)
- * m_DeviceFmt.ulSamplesPerSec) )
- * ulNumBytes) );
- }
- /************************************************************************
- * 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 INT64_TO_UINT32((llEndTime - llStartTime) *
- (m_ulGranularity ? m_ulInputBytesPerGran*1./m_ulGranularity : 0));
- }
- void CHXAudioStream::FlushBuffers(BOOL bInstantaneousAlso)
- {
- while (m_pDataList && m_pDataList->GetCount() > 0)
- {
- HXAudioInfo* pInfo = (HXAudioInfo*) m_pDataList->RemoveHead();
- FreeInfo(pInfo);
- }
- /* throw away any data in excess buffer for interpolator */
- m_ulPreviousExcessInterpBufferSize = 0;
- 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);
- }
- BOOL
- CHXAudioStream::EnoughDataAvailable(ULONG32& ulLastWriteTime, ULONG32& ulNumMsRequired)
- {
- ULONG32 ulBytesNeeded = 0;
- BOOL bAvailable = TRUE;
- // /////////////////////////////////////////////////////////////
- // If no resampling, mix stream data directly into the player
- // buffer.
- if ( !m_pResampler)
- {
- ulBytesNeeded = m_ulInputBytesPerGran;
- }
- // /////////////////////////////////////////////////////////////
- // If resampling, mix stream data into a tmp buffer. Then
- // resample this buffer and mix the final resampled buffer into
- // the player buffer.
- else
- {
- /*
- * Audio Session will always ask for m_ulOutputBytesPerGran bytes to be mixed
- * in MixIntoBuffer() call. So we need to produce these many number of bytes.
- * If there is any mono-stereo conversion that happens in the mixing, number
- * of output bytes required from the resampler are half the number of
- * m_ulOutputBytesPerGran bytes.
- */
- ULONG32 ulMaxFramesOut = m_ulOutputBytesPerGran/(m_DeviceFmt.uBitsPerSample==8 ? 1 : 2);
-
- if (m_DeviceFmt.uChannels == 2)
- {
- ulMaxFramesOut /= 2;
- }
- ULONG32 ulMaxFramesIn = m_pResampler->Requires(ulMaxFramesOut);
- ulBytesNeeded = ulMaxFramesIn * ((m_AudioFmt.uBitsPerSample==8)? 1 : 2)
- * m_AudioFmt.uChannels;
- }
- ULONG32 ulBytesAvailable = 0;
- LISTPOSITION lp = m_pDataList->GetHeadPosition();
- while(lp)
- {
- HXAudioInfo* pInfo = (HXAudioInfo*) m_pDataList->GetNext(lp);
- ulBytesAvailable += pInfo->ulBytesLeft;
- if ((pInfo->ulStartTime >= INT64_TO_UINT32(m_llLastWriteTime+m_ulGranularity)) ||
- ulBytesAvailable >= ulBytesNeeded)
- {
- return TRUE;
- }
- }
- ulNumMsRequired = CalcMs(ulBytesNeeded - ulBytesAvailable);
- UINT32 ulAdjustedLastWriteTime = INT64_TO_UINT32(m_llLastWriteTime - CAST_TO_INT64 m_ulTSRollOver * CAST_TO_INT64 MAX_UINT32);
- HX_ASSERT(ulAdjustedLastWriteTime + m_ulGranularity >= ulNumMsRequired);
- if (ulAdjustedLastWriteTime + m_ulGranularity >= ulNumMsRequired)
- {
- ulLastWriteTime = ulAdjustedLastWriteTime + m_ulGranularity - ulNumMsRequired;
- }
- else
- {
- ulLastWriteTime = 0;
- }
- return FALSE;
- }
- void
- CHXAudioStream::SetLive(BOOL bIsLive)
- {
- if (m_bIsFirstPacket)
- {
- m_bIsLive = bIsLive;
- }
- }
- HX_RESULT
- CHXAudioStream::StartCrossFade(CHXAudioStream* pFromStream,
- UINT32 ulCrossFadeStartTime,
- UINT32 ulCrossFadeDuration,
- BOOL bToStream)
- {
- #if defined(HELIX_FEATURE_CROSSFADE)
- if (m_bCrossFadingToBeDone)
- {
- return HXR_UNEXPECTED;
- }
- HX_RELEASE(m_pCrossFadeStream);
- m_bCrossFadingToBeDone = TRUE;
- m_pCrossFadeStream = pFromStream;
- m_pCrossFadeStream->AddRef();
- m_llCrossFadeStartTime = CAST_TO_INT64 ulCrossFadeStartTime;
- m_ulCrossFadeDuration = ulCrossFadeDuration;
- m_bFadeToThisStream = bToStream;
- if (m_bInited && m_bFadeToThisStream)
- {
- InitializeCrossFader();
- }
-
- return HXR_OK;
- #else
- return HXR_NOTIMPL;
- #endif /* HELIX_FEATURE_CROSSFADE */
- }
- void
- CHXAudioStream::InitializeCrossFader(void)
- {
- #if defined(HELIX_FEATURE_CROSSFADE)
- if (!m_pCrossFader)
- {
- m_pCrossFader = new CrossFader;
- }
- UINT16 uNumSamplesToFade = (UINT16)
- (m_DeviceFmt.ulSamplesPerSec * m_ulCrossFadeDuration/1000);
- /* Make cross-fade duration to land on a sample boundary */
- m_ulCrossFadeDuration = (uNumSamplesToFade * 1000)/
- m_DeviceFmt.ulSamplesPerSec;
- HX_ASSERT(m_ulCrossFadeDuration > 0 && uNumSamplesToFade > 0);
- m_pCrossFader->Initialize(uNumSamplesToFade, m_DeviceFmt.uChannels);
- #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 (!m_pRAByToTsInList)
- {
- m_pRAByToTsInList = new CHXSimpleList;
- m_pRAByToTsAdjustedList = new CHXSimpleList;
- }
- 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 _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);
- //{FILE* f1 = ::fopen("d:\temp\audio.txt", "a+"); ::fprintf(f1, "Fudge:t%lut%lun", ulTimestamp, m_ulLastInputStartTime);::fclose(f1);}
- return HXR_OK;
- }
- void
- CHXAudioStream::CleanupRAByToTs(void)
- {
- 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();
- }
- HX_RESULT
- CHXAudioStream::ConvertCurrentTime(double dBytesPlayed,
- UINT32 ulCurrentTime,
- UINT32& ulAdjustedTime)
- {
- // return HXR_FAIL;
- HX_ASSERT(m_bRealAudioStream);
- ulAdjustedTime = ulCurrentTime;
- LISTPOSITION posRABytes = m_pRAByToTsAdjustedList->GetHeadPosition();
- BOOL bIsDone = FALSE;
- RealAudioBytesToTimeStamp* pByToTsLower = NULL;
- RealAudioBytesToTimeStamp* pByToTsHigher = NULL;
- INT64 llActualByToTsHigherTimestamp = 0;
- INT64 llActualByToTsLowerTimestamp =0;
- while(posRABytes)
- {
- RealAudioBytesToTimeStamp* pByToTs = (RealAudioBytesToTimeStamp*)
- m_pRAByToTsAdjustedList->GetAt(posRABytes);
- if (dBytesPlayed >= pByToTs->m_ulOutNumBytes)
- {
- pByToTsLower = pByToTs;
- }
- else
- {
- if (pByToTsLower)
- {
- pByToTsHigher = pByToTs;
- }
- else
- {
- /* It means that this stream was added mid-presentation and we have not yet
- * played any bits from this stream. Maintain the current time and do not
- * fudge it.
- */
- return HXR_OK;
- }
- }
- if (pByToTsLower && pByToTsHigher)
- {
- break;
- }
- m_pRAByToTsAdjustedList->GetNext(posRABytes);
- }
- /* We got a range, interpolate */
- if (pByToTsLower && pByToTsHigher)
- {
- //{FILE* f1 = ::fopen("d:\temp\rasync.txt", "a+"); ::fprintf(f1, "ConvertLowHigh: dBytesPlayed: %f LowTS: %lu HighTS: %lu LowBytes: %f HighBytes: %fn", dBytesPlayed,pByToTsLower->m_ulTimestamp,pByToTsHigher->m_ulTimestamp, pByToTsLower->m_ulOutNumBytes,pByToTsHigher->m_ulOutNumBytes);::fclose(f1);}
- /* Need to re-visit this ASSERT. A check will do for now */
- #if 0
- HX_ASSERT((pByToTsHigher->m_ulTimestamp >=
- pByToTsLower->m_ulTimestamp) &&
- (pByToTsHigher->m_ulOutNumBytes >=
- pByToTsLower->m_ulOutNumBytes));
- #endif
- llActualByToTsHigherTimestamp = CAST_TO_INT64 (pByToTsHigher->m_ulTimestamp) + CAST_TO_INT64 m_ulTSRollOver * CAST_TO_INT64 MAX_UINT32;
- llActualByToTsLowerTimestamp = CAST_TO_INT64 (pByToTsLower->m_ulTimestamp) + CAST_TO_INT64 m_ulTSRollOver * CAST_TO_INT64 MAX_UINT32;
- if ((llActualByToTsHigherTimestamp >= llActualByToTsLowerTimestamp) &&
- (pByToTsHigher->m_ulOutNumBytes >= pByToTsLower->m_ulOutNumBytes))
- {
- ulAdjustedTime = pByToTsLower->m_ulTimestamp +
- (UINT32) (((dBytesPlayed - pByToTsLower->m_ulOutNumBytes)*1./
- (pByToTsHigher->m_ulOutNumBytes -
- pByToTsLower->m_ulOutNumBytes)) *
- INT64_TO_UINT32(llActualByToTsHigherTimestamp -
- llActualByToTsLowerTimestamp));
- //{FILE* f1 = ::fopen("d:\temp\multi.txt", "a+"); ::fprintf(f1, "ConvertLHINTER: %p %pt%lut%lut%lutt%lut%lut%lut%lun", this, m_Owner, (UINT32) dBytesPlayed, ulCurrentTime, ulAdjustedTime, pByToTsLower->m_ulTimestamp, (UINT32) pByToTsLower->m_ulOutNumBytes, pByToTsHigher->m_ulTimestamp, (UINT32) pByToTsHigher->m_ulOutNumBytes);::fclose(f1);}
- }
- else
- {
- ulAdjustedTime = pByToTsLower->m_ulTimestamp;
- //{FILE* f1 = ::fopen("d:\temp\multi.txt", "a+"); ::fprintf(f1, "ConvertLH: %p %pt%lut%lut%lun", this, m_Owner, (UINT32) dBytesPlayed, ulCurrentTime, ulAdjustedTime);::fclose(f1);}
- }
- //{FILE* f1 = ::fopen("d:\temp\rasync.txt", "a+"); ::fprintf(f1, "ConvertLowHigh: ulCurrentTime: %lu ulAdjustedTime: %lu dBytesPlayed: %f LowTS: %lu HighTS: %lun", ulCurrentTime, ulAdjustedTime, dBytesPlayed,pByToTsLower->m_ulTimestamp,pByToTsHigher->m_ulTimestamp);::fclose(f1);}
- }
- /* The best we can do is return the time of the nearest map */
- else if (pByToTsLower)
- {
- ulAdjustedTime = pByToTsLower->m_ulTimestamp;
- double dBytesDiff = dBytesPlayed - pByToTsLower->m_ulOutNumBytes;
- if (dBytesDiff > 0)
- {
- double dNumBytes = m_Owner->ConvertMsToBytes(pByToTsLower->m_ulDuration);
- if (dBytesDiff >= dNumBytes)
- {
- ulAdjustedTime += pByToTsLower->m_ulDuration;
- }
- else
- {
- ulAdjustedTime += (UINT32) (pByToTsLower->m_ulDuration * dBytesDiff *1./dNumBytes);
- }
- }
- //{FILE* f1 = ::fopen("d:\temp\rasync.txt", "a+"); ::fprintf(f1, "ConvertLower: ulCurrentTime: %lu ulAdjustedTime: %lu dBytesPlayed: %f LowTS: %lu m_ulOutNumBytes: %fn", ulCurrentTime, ulAdjustedTime, dBytesPlayed,pByToTsLower->m_ulTimestamp, pByToTsLower->m_ulOutNumBytes);::fclose(f1);}
- }
- /* Remove all maps before pByToTsLower */
- posRABytes = m_pRAByToTsAdjustedList->GetHeadPosition();
- while(posRABytes)
- {
- RealAudioBytesToTimeStamp* pByToTs =
- (RealAudioBytesToTimeStamp*) m_pRAByToTsAdjustedList->GetAt(posRABytes);
- if (pByToTs != pByToTsLower)
- {
- //{FILE* f1 = ::fopen("d:\temp\rasync.txt", "a+"); ::fprintf(f1, "Delete: OutBytes: %f OutTS: %lun", pByToTs->m_ulOutNumBytes, pByToTs->m_ulTimestamp);::fclose(f1);}
- delete pByToTs;
- posRABytes = m_pRAByToTsAdjustedList->RemoveAt(posRABytes);
- }
- else
- {
- break;
- }
- }
- //{FILE* f1 = ::fopen("d:\temp\multi.txt", "a+"); ::fprintf(f1, "Convert: %p %pt%lut%lut%lun", this, m_Owner, (UINT32) dBytesPlayed, ulCurrentTime, ulAdjustedTime);::fclose(f1);}
- return HXR_OK;
- }
- void
- CHXAudioStream::MapFudgedTimestamps(void)
- {
- LISTPOSITION posRABytes = m_pRAByToTsInList->GetHeadPosition();
- INT64 llActualByToTsInEndTime = 0;
- INT64 llActualByToTsInStartTime = 0;
- while(posRABytes)
- {
- RealAudioBytesToTimeStamp* pByToTs =
- (RealAudioBytesToTimeStamp*) m_pRAByToTsInList->GetAt(posRABytes);
- llActualByToTsInStartTime = CAST_TO_INT64 (pByToTs->m_ulInTimestamp) + CAST_TO_INT64 m_ulTSRollOver * CAST_TO_INT64 MAX_UINT32;
- llActualByToTsInEndTime = CAST_TO_INT64 (pByToTs->m_ulInEndTime) + CAST_TO_INT64 m_ulTSRollOver * CAST_TO_INT64 MAX_UINT32;
- /* Too late */
- if (llActualByToTsInEndTime < m_llLastStartTimePlayed)
- {
- posRABytes = m_pRAByToTsInList->RemoveAt(posRABytes);
- delete pByToTs;
- }
- else if (llActualByToTsInStartTime <= m_llLastStartTimePlayed
- /*&& pByToTs->m_ulInEndTime >= m_ulLastStartTimePlayed*/)
- {
- /* These two values will be used in determining what time it is */
- // Number of bytes that have been written to the audio device till now*/
- pByToTs->m_ulOutNumBytes = m_Owner->NumberOfBytesWritten();
- HX_ASSERT(m_llLastStartTimePlayed - llActualByToTsInStartTime < MAX_TIMESTAMP_GAP);
- /* Interpolate */
- UINT32 ulTimeDiff = INT64_TO_UINT32(m_llLastStartTimePlayed - llActualByToTsInStartTime);
- pByToTs->m_ulTimestamp += ulTimeDiff;
-
- pByToTs->m_ulDuration = INT64_TO_UINT32((llActualByToTsInEndTime -
- llActualByToTsInStartTime) - CAST_TO_INT64 ulTimeDiff);
-
- posRABytes = m_pRAByToTsInList->RemoveAt(posRABytes);
- m_pRAByToTsAdjustedList->AddTail(pByToTs);
- //{FILE* f1 = ::fopen("d:\temp\multi.txt", "a+"); ::fprintf(f1, "Map: %p %pt%lut%lut%lut%lut%lutt%lun", this, m_Owner, (UINT32) pByToTs->m_ulOutNumBytes, pByToTs->m_ulInTimestamp, pByToTs->m_ulInEndTime, pByToTs->m_ulTimestamp, pByToTs->m_ulOrigTimestamp, m_llLastStartTimePlayed);::fclose(f1);}
- }
- else
- {
- break;
- }
- }
- }
- void
- CHXAudioStream::RemoveExcessCrossFadeData()
- {
- #if defined(HELIX_FEATURE_CROSSFADE)
- HXAudioInfo* pInfo = (HXAudioInfo*) m_pDataList->GetHead();
- INT64 llStartTime = 0;
- INT64 llEndTime = 0;
- LISTPOSITION lp = m_pDataList->GetHeadPosition();
- while(lp)
- {
- UINT32 ulActualTSRollOver = m_ulTSRollOver;
- pInfo = (HXAudioInfo*) m_pDataList->GetAt(lp);
- if (pInfo->ulStartTime > m_ulLastInputStartTime &&
- ((pInfo->ulStartTime - m_ulLastInputStartTime) > MAX_TIMESTAMP_GAP))
- {
- ulActualTSRollOver--;
- }
- llStartTime = CAST_TO_INT64 (pInfo->ulStartTime) +
- CAST_TO_INT64 (CalcMs(pInfo->pBuffer->GetSize() - pInfo->ulBytesLeft)) +
- CAST_TO_INT64 ulActualTSRollOver * CAST_TO_INT64 MAX_UINT32;
- llEndTime = CAST_TO_INT64 (pInfo->ulStartTime) +
- CAST_TO_INT64 (CalcMs(pInfo->pBuffer->GetSize())) +
- CAST_TO_INT64 ulActualTSRollOver * CAST_TO_INT64 MAX_UINT32;
- /* Do we have to remove this block completely */
- if (llEndTime < m_llCrossFadeStartTime)
- {
- lp = m_pDataList->RemoveAt(lp);
- FreeInfo(pInfo);
- }
- /* Remove some part of the block internally */
- else if (llStartTime <= m_llCrossFadeStartTime
- /* && ulEndTime >= m_ulCrossFadeStartTime */)
- {
- UINT32 ulBytesToDiscard =
- CalcOffset(llStartTime, m_llCrossFadeStartTime);
- /* Make sure that it is at even byte boundary */
- ulBytesToDiscard -= (ulBytesToDiscard % (2*m_AudioFmt.uChannels));
- if (pInfo->ulBytesLeft > ulBytesToDiscard)
- {
- pInfo->ulBytesLeft -= ulBytesToDiscard;
- pInfo->pOffset += ulBytesToDiscard;
-
- /* Make it TIME_AUDIO since this would be the first block
- * written during cross-fade for *TO* stream.
- */
- if (m_bFadeToThisStream)
- {
- pInfo->uAudioStreamType = TIMED_AUDIO;
- }
- break;
- }
- else
- {
- /* It is legal to happen with a *to* stream */
- if (!m_bFadeToThisStream)
- {
- /* Something is screwed up here */
- HX_ASSERT(FALSE);
- }
- pInfo->ulBytesLeft = 0;
- lp = m_pDataList->RemoveAt(lp);
- FreeInfo(pInfo);
- }
- }
- else
- {
- /* Not enough data */
- /* It is legal to happen with a *to* stream */
- if (!m_bFadeToThisStream)
- {
- /* Something is screwed up here */
- HX_ASSERT(FALSE);
- }
- break;
- }
- }
- #endif /* HELIX_FEATURE_CROSSFADE */
- }
- void
- CHXAudioStream::SyncStream(INT64 llSyncTime)
- {
- m_llLastWriteTime = llSyncTime;
- }
- void
- CHXAudioStream::UpdateStreamLastWriteTime(BOOL bForceUpdate /*= FALSE*/)
- {
- if (m_bLastWriteTimeUpdated)
- {
- return;
- }
- m_bLastWriteTimeUpdated = TRUE;
- if (m_bIsLive)
- {
- if (!m_pValues || m_pValues->GetPropertyULONG32("LiveSyncStartTime", m_ulBaseTime) != HXR_OK)
- {
- if (bForceUpdate)
- {
- m_bIsLive = FALSE;
- m_ulBaseTime = 0;
- m_llLastWriteTime = m_Owner->GetLastAudioWriteTime();
- }
- else
- {
- /*
- * do not set it yet.. we will wait till the first
- * AddData call
- */
- m_bLastWriteTimeUpdated = FALSE;
- }
- }
- else
- {
- m_pValues->GetPropertyULONG32("Delay", m_ulLiveDelay);
- INT64 llLastPlayerWriteTime = m_Owner->GetLastAudioWriteTime();
- if (m_ulLiveDelay > 0 &&
- CAST_TO_INT64 m_ulLiveDelay > llLastPlayerWriteTime &&
- m_ulBaseTime > INT64_TO_UINT32(CAST_TO_INT64 m_ulLiveDelay-llLastPlayerWriteTime))
- {
- m_llLastWriteTime = CAST_TO_INT64 (m_ulBaseTime -
- INT64_TO_UINT32(CAST_TO_INT64 m_ulLiveDelay-llLastPlayerWriteTime));
- }
- else
- {
- m_llLastWriteTime = CAST_TO_INT64 m_ulBaseTime;
- }
- }
- }
- else
- {
- // XXX HP
- //
- // Prolbem:
- // when rewinding audio data upon resume, the audio-push-down worth of data
- // would be missing when the stream's first resume is at the middle of playback,
- //
- // Solution:
- // we need to adjust the m_llLastWriteTime to the last audio player write time
- if (m_Owner->IsResumed() && !m_bIsResumed)
- {
- m_llLastWriteTime = m_Owner->GetLastAudioWriteTime();
- }
- }
- }
- void
- CHXAudioStream::SaveLastNMilliSeconds(BOOL bSave, UINT32 ulNMilliSeconds)
- {
- m_bLastNMilliSecsToBeSaved = bSave; // TRUE; //
- m_ulLastNMilliSeconds = ulNMilliSeconds; // 2000;//
- HX_ASSERT(!m_bLastNMilliSecsToBeSaved || m_ulLastNMilliSeconds > 0);
- // ensure we need to save for atleast 1 sec
- if (m_bLastNMilliSecsToBeSaved && m_ulLastNMilliSeconds < 1000)
- {
- m_ulLastNMilliSeconds = 1000;
- }
- if (!m_bLastNMilliSecsToBeSaved)
- {
- while (m_pLastNMilliSecsList && m_pLastNMilliSecsList->GetCount() > 0)
- {
- HXAudioInfo* pInfo = (HXAudioInfo*) m_pLastNMilliSecsList->RemoveHead();
- FreeInfo(pInfo);
- }
- HX_DELETE(m_pLastNMilliSecsList);
- }
- }
- void
- CHXAudioStream::RewindStream(UINT32 ulTimeToRewind)
- {
- HX_ASSERT(m_bLastNMilliSecsToBeSaved);
- if (!m_bCanBeRewound)
- {
- return;
- }
- if (m_bLastNMilliSecsToBeSaved && m_pLastNMilliSecsList)
- {
- HX_ASSERT(m_llLastWriteTime >= ulTimeToRewind);
- if (m_llLastWriteTime >= ulTimeToRewind)
- {
- m_llLastWriteTime -= ulTimeToRewind;
- }
- else
- {
- m_llLastWriteTime = 0;
- }
- HXAudioInfo* pInfo = NULL;
- // reset any pInfo's in data list that may have been partially used.
- CHXSimpleList::Iterator ndx = m_pDataList->Begin();
- for (; ndx != m_pDataList->End(); ++ndx)
- {
- pInfo = (HXAudioInfo*) (*ndx);
- if (pInfo->ulBytesLeft != pInfo->pBuffer->GetSize())
- {
- pInfo->pOffset = pInfo->pBuffer->GetBuffer();
- pInfo->ulBytesLeft = pInfo->pBuffer->GetSize();
- }
- else
- {
- break;
- }
- }
- UINT32 ulLastWriteTime = INT64_TO_UINT32(m_llLastWriteTime - CAST_TO_INT64 m_ulTSRollOver * CAST_TO_INT64 MAX_UINT32);
- BOOL bTimedToBeSet = (m_pLastNMilliSecsList->GetCount() > 0);
- while (m_pLastNMilliSecsList->GetCount() > 0)
- {
- pInfo = (HXAudioInfo*) m_pLastNMilliSecsList->RemoveTail();
- m_pDataList->AddHead(pInfo);
- if (pInfo->ulStartTime <= ulLastWriteTime)
- {
- break;
- }
- }
- if (bTimedToBeSet)
- {
- pInfo = (HXAudioInfo*) m_pDataList->GetHead();
- pInfo->uAudioStreamType = TIMED_AUDIO;
- }
- // remove remaining elements from the list
- while (m_pLastNMilliSecsList->GetCount() > 0)
- {
- pInfo = (HXAudioInfo*) m_pLastNMilliSecsList->RemoveHead();
- // delete the stored one
- HX_RELEASE(pInfo->pBuffer);
- HX_DELETE(pInfo);
- }
- //{FILE* f1 = ::fopen("d:\temp\multi.txt", "a+"); ::fprintf(f1, "%p %p RewindStream %lu %lun", this, m_Owner, ulFirstAudioTime, m_llLastWriteTime);::fclose(f1);}
- // put back stuff from adjusted list to in list
- while (m_pRAByToTsAdjustedList && m_pRAByToTsAdjustedList->GetCount() > 0)
- {
- RealAudioBytesToTimeStamp* pByToTs =
- (RealAudioBytesToTimeStamp*) m_pRAByToTsAdjustedList->RemoveTail();
- // restore original fudge timestamp
- pByToTs->m_ulTimestamp = pByToTs->m_ulOrigTimestamp;
- m_pRAByToTsInList->AddHead(pByToTs);
- }
- }
- }
- void
- CHXAudioStream::Pause(BOOL bPlayerPause)
- {
- if (m_eState == E_PAUSED)
- {
- return;
- }
- m_eState = E_PAUSED;
- m_bCanBeRewound = FALSE;
- m_bPlayerPause = bPlayerPause;
- return;
- }
- void
- CHXAudioStream::Resume(BOOL bPlayerResume)
- {
- if (!m_bInited ||
- m_eState == E_PLAYING)
- {
- return;
- }
- UpdateStreamLastWriteTime();
- // add/resume audio stream on the fly
- if( m_Owner->IsResumed() )
- {
-
- if (m_eState != E_PAUSED &&
- !m_bIsResumed &&
- (!m_pDataList->IsEmpty() || !m_pInstantaneousList->IsEmpty()))
- {
- m_Owner->AudioStreamStateChanged(E_PLAYING);
- m_eState = E_PLAYING;
- }
- // whoever pause the stream is responsible for resuming the same
- // stream, the stream can either be paused specifically by the SMIL renderer
- // without pausing the playback or be paused by the AudioPlayer which
- // pauses the playback
- else if (!bPlayerResume || m_bPlayerPause)
- {
- m_eState = E_PLAYING;
- }
- }
- else
- {
- m_eState = E_PLAYING;
- }
-
- if (m_eState == E_PLAYING)
- {
- m_bCanBeRewound = TRUE;
- m_bIsResumed = TRUE;
- }
-
- return;
- }
- void
- CHXAudioStream::Seek(UINT32 ulSeekTime)
- {
- m_llLastWriteTime = CAST_TO_INT64 (m_ulBaseTime + ulSeekTime);
- m_bFirstWrite = TRUE;
- m_bTobeTimed = TRUE;
- m_ulTSRollOver = 0;
- m_ulLastInputStartTime = 0;
- m_ulLastInputEndTime = 0;
- // Remove all buffers from auxlliary list. This means that a
- // renderer must send all buffers again including those buffers
- // that start at time t way out there in the future.
- FlushBuffers();
- CleanupRAByToTs();
-
- /* Remove any cross-fading */
- m_bCrossFadingToBeDone = FALSE;
- HX_RELEASE(m_pCrossFadeStream);
- // XXX HP what happen if this is called from the client core on
- // IHXTrack::Seek()
- return;
- }
- void
- CHXAudioStream::Stop(void)
- {
- if (m_eState == E_STOPPED)
- {
- return;
- }
- m_eState = E_STOPPED;
- ResetStream();
- return;
- }
- void
- CHXAudioStream::SetAudioDeviceReflushHint(BOOL bSupported)
- {
- m_bAudioDeviceReflushHint = bSupported;
- return;
- }
- void
- CHXAudioStream::FreeInfo(HXAudioInfo* pInfo, BOOL bInstantaneous /* = FALSE */)
- {
- if (m_bLastNMilliSecsToBeSaved && !bInstantaneous)
- {
- if (!m_pLastNMilliSecsList)
- {
- m_pLastNMilliSecsList = new CHXSimpleList;
- m_ulLastNHeadTime = pInfo->ulStartTime;
- m_ulLastNTailTime = pInfo->ulStartTime;
- }
- // reset members
- pInfo->pOffset = pInfo->pBuffer->GetBuffer();
- pInfo->ulBytesLeft = pInfo->pBuffer->GetSize();
- // add it to the tail
- m_pLastNMilliSecsList->AddTail(pInfo);
- // Last m_ulLastNTailTime could have been invalidated by a rewind:
- // check it again here:
- m_ulLastNHeadTime = ((HXAudioInfo*) m_pLastNMilliSecsList->GetHead())->ulStartTime;
- m_ulLastNTailTime = pInfo->ulStartTime;
- // time to expire certain blocks?
- if (CALCULATE_ELAPSED_TICKS(m_ulLastNHeadTime, m_ulLastNTailTime) > m_ulLastNMilliSeconds)
- {
- // override pInfo. we will delete this block at the bottom
- pInfo = (HXAudioInfo*) m_pLastNMilliSecsList->RemoveHead();
- // update head time
- HXAudioInfo* pHeadInfo = (HXAudioInfo*) m_pLastNMilliSecsList->GetHead();
- // we should always have ATLEAST one nore in the list
- HX_ASSERT(pHeadInfo);
- m_ulLastNHeadTime = pHeadInfo->ulStartTime;
- }
- else
- {
- // early exit to save this block
- return;
- }
- }
- FreeBuffer(pInfo->pBuffer);
- delete pInfo;
- }
- void
- CHXAudioStream::FreeBuffer(IHXBuffer* pBuffer)
- {
- /* do we need to keep it around for reuse? */
- if (!m_pAvailableBuffers || m_pAvailableBuffers->GetCount() >= m_uCacheSize)
- {
- //{FILE* f1 = ::fopen("d:\temp\cache.txt", "a+"); ::fprintf(f1, "Discard n");::fclose(f1);}
- /*
- * now that we are full, we should grow the cache size, if we ever have
- * a cache miss
- */
- m_bCacheMayBeGrown = TRUE;
- pBuffer->Release();
- return;
- }
- /*
- * check if we have the only reference, if so reuse it
- * else release our reference
- */
- pBuffer->AddRef();
- if (pBuffer->Release() > 1)
- {
- pBuffer->Release();
- return;
- }
- #ifdef _MACINTOSH
- m_pAvailableBuffers->AddTail((void*) pBuffer);
- #else
- BOOL bAddToTail = (HX_GET_BETTERTICKCOUNT() & 0x01) ? TRUE : FALSE;
- if (bAddToTail)
- {
- m_pAvailableBuffers->AddTail((void*) pBuffer);
- }
- else
- {
- m_pAvailableBuffers->AddHead((void*) pBuffer);
- }
- #endif
- //{FILE* f1 = ::fopen("d:\temp\cache.txt", "a+"); ::fprintf(f1, "Added %dn", m_pAvailableBuffers->GetCount());::fclose(f1);}
- return;
- }
- /************************************************************************
- * Method:
- * IHXCommonClassFactory::CreateInstance
- */
- STDMETHODIMP
- CHXAudioStream::CreateInstance
- (
- REFCLSID /*IN*/ rclsid,
- void** /*OUT*/ ppUnknown
- )
- {
- HX_RESULT theErr = HXR_OK;
- if (IsEqualCLSID(rclsid, CLSID_IHXBuffer))
- {
- if (!m_pAvailableBuffers)
- {
- #ifdef _MACINTOSH
- m_pAvailableBuffers = new HXAudioMacQueue;
- #else
- m_pAvailableBuffers = new CHXSimpleList;
- #endif
- }
- if (m_pAvailableBuffers->GetCount() > 0)
- {
- #ifdef _MACINTOSH
- *ppUnknown = (IUnknown*) (IHXBuffer*) m_pAvailableBuffers->RemoveHead();
- if (!*ppUnknown) goto justincase;
- #else
- BOOL bRemoveFromHead = (HX_GET_BETTERTICKCOUNT() & 0x01) ? TRUE : FALSE;
- if (bRemoveFromHead)
- {
- *ppUnknown = (IUnknown*) (IHXBuffer*) m_pAvailableBuffers->RemoveHead();
- }
- else
- {
- *ppUnknown = (IUnknown*) (IHXBuffer*) m_pAvailableBuffers->RemoveTail();
- }
- #endif
- //{FILE* f1 = ::fopen("d:\temp\cache.txt", "a+"); ::fprintf(f1, "Cache Hit %dn", m_pAvailableBuffers->GetCount());::fclose(f1);}
- goto exit;
- }
- else
- {
- #ifdef _MACINTOSH
- justincase:
- #endif
- if (m_bCacheMayBeGrown)
- {
- m_bCacheMayBeGrown = FALSE;
- m_uCacheSize += CACHE_INCREMENT_SIZE;
- //{FILE* f1 = ::fopen("d:\temp\cache.txt", "a+"); ::fprintf(f1, "Cache increased to: %u n", m_uCacheSize);::fclose(f1);}
- }
- }
- /*
- * fall down to using the comonclass factory to allocate this buiffer since
- * we do not have it in the cache
- */
- }
- //{FILE* f1 = ::fopen("d:\temp\cache.txt", "a+"); ::fprintf(f1, "Cache Miss buffered blocks: %dn", m_pDataList->GetCount());::fclose(f1);}
- theErr = m_pCommonClassFactory->CreateInstance(rclsid, ppUnknown);
- exit:
- return theErr;
- }
- /************************************************************************
- * Method:
- * IHXCommonClassFactory::CreateInstanceAggregatable
- */
- STDMETHODIMP
- CHXAudioStream::CreateInstanceAggregatable
- (
- REFCLSID /*IN*/ rclsid,
- REF(IUnknown*) /*OUT*/ pUnknown,
- IUnknown* /*IN*/ pUnkOuter
- )
- {
- return m_pCommonClassFactory->CreateInstanceAggregatable(rclsid, pUnknown, pUnkOuter);
- }
- /************************************************************************
- * Method:
- * IHXUpdateProperties::UpdatePacketTimeOffset
- * Purpose:
- * Call this method to update the timestamp offset of cached packets
- */
- STDMETHODIMP
- CHXAudioStream::UpdatePacketTimeOffset(INT32 lTimeOffset)
- {
- HX_RESULT rc = HXR_OK;
- HXAudioInfo* pInfo = NULL;
- // adjust the start time
- CHXSimpleList::Iterator ndx = m_pDataList->Begin();
- for (; ndx != m_pDataList->End(); ++ndx)
- {
- pInfo = (HXAudioInfo*) (*ndx);
- pInfo->ulStartTime += lTimeOffset;
- }
-
- if (m_pLastNMilliSecsList)
- {
- ndx = m_pLastNMilliSecsList->Begin();
- for (; ndx != m_pLastNMilliSecsList->End(); ++ndx)
- {
- pInfo = (HXAudioInfo*) (*ndx);
- pInfo->ulStartTime += lTimeOffset;
- }
- }
- // Adjust more state:
- m_ulLastInputStartTime += lTimeOffset;
- m_ulLastInputEndTime += lTimeOffset;
- m_llLastWriteTime += lTimeOffset;
- m_ulLastNHeadTime += lTimeOffset;
- m_ulLastNTailTime += lTimeOffset;
- m_llLastStartTimePlayed += lTimeOffset;
- return rc;
- }
- /************************************************************************
- * Method:
- * IHXUpdateProperties::UpdatePlayTimes
- * Purpose:
- * Call this method to update the playtime attributes
- */
- STDMETHODIMP
- CHXAudioStream::UpdatePlayTimes(IHXValues* pProps)
- {
- return HXR_OK;
- }
- void
- CHXAudioStream::RollBackTimestamp()
- {
- if (m_llLastWriteTime > CAST_TO_INT64 m_ulGranularity)
- {
- m_llLastWriteTime -= CAST_TO_INT64 m_ulGranularity;
- }
- }
-
- #if defined(HELIX_FEATURE_VOLUME)
- /////////////////////////////////////////////////////////////////////////
- // CHXAudioStream::HXVolumeAdviseSink
- //
- CHXAudioStream::HXStreamVolumeAdviseSink::HXStreamVolumeAdviseSink() :
- m_lRefCount (0)
- , m_pCHXAudioStream (0)
- {
- }
- CHXAudioStream::HXStreamVolumeAdviseSink::~HXStreamVolumeAdviseSink()
- {
- }
- /*
- * IUnknown methods
- */
- /////////////////////////////////////////////////////////////////////////
- // Method:
- // IUnknown::QueryInterface
- // Purpose:
- // Implement this to export the interfaces supported by your
- // object.
- //
- STDMETHODIMP CHXAudioStream::HXStreamVolumeAdviseSink::QueryInterface(REFIID riid, void** ppvObj)
- {
- if (IsEqualIID(riid, IID_IHXVolumeAdviseSink))
- {
- AddRef();
- *ppvObj = (IHXVolumeAdviseSink*)this;
- return HXR_OK;
- }
- else if (IsEqualIID(riid, IID_IUnknown))
- {
- AddRef();
- *ppvObj = this;
- return HXR_OK;
- }
- *ppvObj = NULL;
- return HXR_NOINTERFACE;
- }
- /////////////////////////////////////////////////////////////////////////
- // Method:
- // IUnknown::AddRef
- // Purpose:
- // Everyone usually implements this the same... feel free to use
- // this implementation.
- //
- STDMETHODIMP_(ULONG32) CHXAudioStream::HXStreamVolumeAdviseSink::AddRef()
- {
- return InterlockedIncrement(&m_lRefCount);
- }
- /////////////////////////////////////////////////////////////////////////
- // Method:
- // IUnknown::Release
- // Purpose:
- // Everyone usually implements this the same... feel free to use
- // this implementation.
- //
- STDMETHODIMP_(ULONG32) CHXAudioStream::HXStreamVolumeAdviseSink::Release()
- {
- if (InterlockedDecrement(&m_lRefCount) > 0)
- {
- return m_lRefCount;
- }
- delete this;
- return 0;
- }
- /*
- * IHXVolumeAdviseSink methods
- */
- STDMETHODIMP CHXAudioStream::HXStreamVolumeAdviseSink::OnVolumeChange
- (
- const UINT16 uVolume
- )
- {
- if (m_pCHXAudioStream)
- {
- // Set the audio device volume
- m_pCHXAudioStream->OnVolumeChange(uVolume);
- }
- return HXR_OK;
- }
- STDMETHODIMP CHXAudioStream::HXStreamVolumeAdviseSink::OnMuteChange
- (
- const BOOL bMute
- )
- {
- if (m_pCHXAudioStream)
- {
- m_pCHXAudioStream->OnMuteChange(bMute);
- }
- return HXR_OK;
- }
- #endif /* HELIX_FEATURE_VOLUME */
- #ifdef _MACINTOSH
- /////////////////////////////////////////////////////////////////////////
- //
- // HXAudioMacQueue
- //
- // For passing data between an interrupt and anything else (mac only).
- //
- HXAudioMacQueue::HXAudioMacQueue()
- {
- mQueueHeader.qFlags=0;
- mQueueHeader.qHead=0;
- mQueueHeader.qTail=0;
- mDestructing = FALSE; // just a safety check
- m_nCount = 0;
- }
- /////////////////////////////////////////////////////////////////////////
- //
- HX_RESULT HXAudioMacQueue::AddTail(void* pObject)
- {
- if (pObject && !mDestructing)
- {
- HXAudioMacQueueElement * theElement = new HXAudioMacQueueElement();
-
- if (theElement)
- {
- theElement->mNextElementInQueue = NULL;
- theElement->mObject = pObject;
- ::Enqueue((QElem *)theElement, &mQueueHeader);
-
- m_nCount++;
-
- //
- // If someone interrupts and enters the destructor while we're in here,
- // then the pObject and the new node will be leaked. This shouldn't
- // happen since we should have shut down all interrupts that would
- // be adding items to the queue long before we start destructing it.
- //
-
- HX_ASSERT(!mDestructing); // if we DID enter the destructor, let the programmer know...
- }
-
- return HXR_OK;
- }
-
- return HXR_FAILED;
- }
- /////////////////////////////////////////////////////////////////////////
- //
- void * HXAudioMacQueue::RemoveHead()
- {
- //
- // POINT A
- //
- // You can look at the qHead anytime you want, but you can't USE a
- // pointer unless it's OFF of the queue. Basically you do a Dequeue,
- // and if it succeeds then you know nobody else has it. If it fails,
- // an error is returned and you don't mess with it.
- //
-
- if (mQueueHeader.qHead)
- {
- HXAudioMacQueueElement * theElement = (HXAudioMacQueueElement *) mQueueHeader.qHead;
- if (theElement)
- {
- OSErr e = ::Dequeue( (QElemPtr) theElement, &mQueueHeader );
-
- //
- // Between points A and D, we can't be guaranteed that the queue header and theElement are valid. But
- // Dequeue will TELL us if that pointer is still valid by its return code. If it can't remove the item
- // from the queue, then somebody else did and the pointer is no longer ours. If no error was returned
- // from dequeue, then it's ours to mess with.
- //
-
- if (e == noErr)
- {
- // at this point we know that we can do whatever we need to with the object.
- void* theObj = theElement->mObject;
- delete theElement; // delete the node
- m_nCount--;
- HX_ASSERT(m_nCount >= 0);
- return theObj;
- }
- }
- }
-
- return NULL;
- }
- /////////////////////////////////////////////////////////////////////////
- //
- UINT32 HXAudioMacQueue::GetCount()
- {
- return m_nCount;
- }
- /////////////////////////////////////////////////////////////////////////
- //
- HXAudioMacQueue::~HXAudioMacQueue()
- {
- mDestructing = TRUE; // don't add anything else to the queue
-
- void * theObject;
- while ((theObject = RemoveHead()) != 0)
- {
- }
-
- // and just to be safe...
- mQueueHeader.qHead=0;
- mQueueHeader.qTail=0;
- }
- #endif