hxaudstr.cpp
上传用户:dangjiwu
上传日期:2013-07-19
资源大小:42019k
文件大小:121k
源码类别:

Symbian

开发平台:

Visual C++

  1. /* ***** BEGIN LICENSE BLOCK *****
  2.  * Source last modified: $Id: hxaudstr.cpp,v 1.17.2.1.2.1 2005/07/08 18:12:41 gwright Exp $
  3.  * 
  4.  * Portions Copyright (c) 1995-2004 RealNetworks, Inc. All Rights Reserved.
  5.  * 
  6.  * The contents of this file, and the files included with this file,
  7.  * are subject to the current version of the RealNetworks Public
  8.  * Source License (the "RPSL") available at
  9.  * http://www.helixcommunity.org/content/rpsl unless you have licensed
  10.  * the file under the current version of the RealNetworks Community
  11.  * Source License (the "RCSL") available at
  12.  * http://www.helixcommunity.org/content/rcsl, in which case the RCSL
  13.  * will apply. You may also obtain the license terms directly from
  14.  * RealNetworks.  You may not use this file except in compliance with
  15.  * the RPSL or, if you have a valid RCSL with RealNetworks applicable
  16.  * to this file, the RCSL.  Please see the applicable RPSL or RCSL for
  17.  * the rights, obligations and limitations governing use of the
  18.  * contents of the file.
  19.  * 
  20.  * Alternatively, the contents of this file may be used under the
  21.  * terms of the GNU General Public License Version 2 or later (the
  22.  * "GPL") in which case the provisions of the GPL are applicable
  23.  * instead of those above. If you wish to allow use of your version of
  24.  * this file only under the terms of the GPL, and not to allow others
  25.  * to use your version of this file under the terms of either the RPSL
  26.  * or RCSL, indicate your decision by deleting the provisions above
  27.  * and replace them with the notice and other provisions required by
  28.  * the GPL. If you do not delete the provisions above, a recipient may
  29.  * use your version of this file under the terms of any one of the
  30.  * RPSL, the RCSL or the GPL.
  31.  * 
  32.  * This file is part of the Helix DNA Technology. RealNetworks is the
  33.  * developer of the Original Code and owns the copyrights in the
  34.  * portions it created.
  35.  * 
  36.  * This file, and the files included with this file, is distributed
  37.  * and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
  38.  * KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
  39.  * ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
  40.  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
  41.  * ENJOYMENT OR NON-INFRINGEMENT.
  42.  * 
  43.  * Technology Compatibility Kit Test Suite(s) Location:
  44.  *    http://www.helixcommunity.org/content/tck
  45.  * 
  46.  * Contributor(s):
  47.  * 
  48.  * ***** END LICENSE BLOCK ***** */
  49. #include "hlxclib/stdio.h"
  50. #include "hlxclib/string.h"
  51. #include "hxresult.h"
  52. #include "hxtypes.h"
  53. #include "hxcom.h"
  54. #include "hxengin.h"
  55. #include "ihxpckts.h"
  56. #include "hxausvc.h"
  57. #include "hxrasyn.h"
  58. #include "hxprefs.h"
  59. #include "hxerror.h"
  60. #include "errdbg.h"
  61. #include "chxpckts.h"
  62. #include "hxaudply.h"
  63. #include "hxaudstr.h"
  64. #include "hxaudses.h"
  65. #include "hxmixer.h"
  66. #include "hxaudvol.h"   
  67. #include "hxslist.h"
  68. #include "hxmap.h"
  69. #include "auderrs.h"
  70. #include "hxtick.h"
  71. //#include "rmarsmp.h"
  72. #ifdef _WINDOWS
  73. #include "hxrsmp2.h"
  74. #endif /* _WINDOWS */
  75. //#include "resample.h"   
  76. //#include "interp.h"   
  77. #include "crosfade.h"
  78. #include "hxheap.h"
  79. #ifdef _DEBUG
  80. #undef HX_THIS_FILE             
  81. static const char HX_THIS_FILE[] = __FILE__;
  82. #endif
  83. #define CACHE_INCREMENT_SIZE    2
  84. //#define _TESTING    1
  85. #ifdef _TESTING
  86. #include <fcntl.h>
  87. #include <sys/types.h>
  88. #include <sys/stat.h>
  89. #if defined (_WINDOWS) || defined (_WIN32)
  90. #include <io.h>
  91. #endif
  92. int g_log = -1;
  93. #endif
  94. /************************************************************************
  95.  *  Method:
  96.  *              IHXAudioStream::CHXAudioStream()
  97.  *      Purpose:
  98.  *              Constructor. 
  99.  */
  100. CHXAudioStream::CHXAudioStream(CHXAudioPlayer* owner, IUnknown* pContext)
  101. :       m_lRefCount(0)
  102. ,       m_wLastError(HXR_OK)
  103. ,       m_pResampler(NULL)
  104. ,       m_pValues(0)
  105. ,       m_bDisableWrite(FALSE)
  106. ,       m_ulGranularity(0)
  107. ,       m_ulInputBytesPerGran(0)
  108. ,       m_ulOutputBytesPerGran(0)
  109. ,       m_ulExcessInterpBufferSize(0)
  110. ,       m_ulPreviousExcessInterpBufferSize(0)
  111. ,       m_pDataList(0)
  112. ,       m_pInstantaneousList(0)
  113. ,       m_pRAByToTsInList(0)
  114. ,       m_pRAByToTsAdjustedList(0)
  115. ,       m_bFirstWrite(TRUE)
  116. ,       m_bHooksInitialized(FALSE)
  117. ,       m_bInited(FALSE)
  118. ,       m_bSetupDone(FALSE)
  119. ,       m_bAudioFormatKnown(FALSE)
  120. ,       m_ulMaxBlockSize(0)
  121. ,       m_pResampleBuf(0)
  122. ,       m_pTmpResBuf(0)
  123. ,       m_pCrossFader(0)
  124. ,       m_pCrossFadeBuffer(0)
  125. ,       m_pExcessInterpBuffer(NULL)
  126. ,       m_pTempInterpBuffer(NULL)
  127. ,       m_fVolume((float)1.0)
  128. ,       m_bChannelConvert(FALSE)
  129. ,       m_pStreamVolume(0)
  130. ,       m_uVolume(HX_MAX_VOLUME)
  131. ,       m_bMute(FALSE)
  132. ,       m_bGotHooks(FALSE)
  133. ,       m_llLastWriteTime(0)
  134. ,       m_ulFudge(5)
  135. ,       m_pInDataPtr(0)
  136. ,       m_pOutDataPtr(0)
  137. ,       m_pVolumeAdviseSink(0)
  138. ,       m_bTobeTimed(TRUE)
  139. ,       m_bIsFirstPacket(TRUE)
  140. ,       m_bIsLive(FALSE)
  141. ,       m_ulBaseTime(0)
  142. ,       m_ulLiveDelay(0)
  143. ,       m_bSetupToBeDone(FALSE)
  144. ,       m_bCrossFadingToBeDone(FALSE)
  145. ,       m_pCrossFadeStream(NULL)
  146. ,       m_llCrossFadeStartTime(0)
  147. ,       m_ulCrossFadeDuration(0)
  148. ,       m_bFadeToThisStream(FALSE)
  149. ,       m_bFadeAlreadyDone(FALSE)
  150. ,       m_bRealAudioStream(FALSE)
  151. ,       m_ulLastInputStartTime(0)
  152. ,       m_ulLastInputEndTime(0)
  153. ,       m_llLastStartTimePlayed(0)
  154. ,       m_ulTSRollOver(0)
  155. ,       m_bLastWriteTimeUpdated(FALSE)
  156. ,       m_pCommonClassFactory(NULL)
  157. ,       m_pAvailableBuffers(NULL)
  158. ,       m_uCacheSize(CACHE_INCREMENT_SIZE)
  159. ,       m_bCacheMayBeGrown(FALSE)
  160. ,       m_bDeterminedInitialCacheSize(FALSE)
  161. ,       m_bLastNMilliSecsToBeSaved(FALSE)
  162. ,       m_ulLastNMilliSeconds(MINIMUM_INITIAL_PUSHDOWN)
  163. ,       m_pLastNMilliSecsList(NULL)
  164. ,       m_ulLastNHeadTime(0)
  165. ,       m_ulLastNTailTime(0)
  166. ,       m_eState(E_STOPPED)
  167. ,       m_bCanBeRewound(FALSE)
  168. ,       m_bAudioDeviceReflushHint(FALSE)
  169. ,       m_bIsResumed(FALSE)
  170. ,       m_bPlayerPause(FALSE)
  171. ,       m_pPreferences(NULL)
  172. ,       m_bMayNeedToRollbackTimestamp(FALSE)
  173. {
  174. /*
  175.  *  Left around for future debugging
  176.     static int fnum = 0;
  177.     char fname[80];
  178.  
  179.     sprintf(fname, "c:\temp\before.%d", fnum);
  180.     fdbefore = fopen(fname, "ab+");
  181.     sprintf(fname, "c:\temp\before.%d.txt", fnum);
  182.     fdbeforetxt = fopen(fname, "w+");
  183.     sprintf(fname, "c:\temp\after.%d", fnum);
  184.     fdafter = fopen(fname, "ab+");
  185.     sprintf(fname, "c:\temp\after.%d.txt", fnum);
  186.     fdaftertxt = fopen(fname, "w+");
  187.     sprintf(fname, "c:\temp\in.%d", fnum);
  188.     fdin = fopen(fname, "ab+");
  189.     
  190.     fnum++;
  191. */
  192.     m_Owner         = owner;
  193.     if (m_Owner)
  194.     {
  195.         m_Owner->AddRef();
  196.     }
  197.     if (pContext)
  198.     {
  199.         HX_VERIFY(HXR_OK == pContext->QueryInterface(IID_IHXCommonClassFactory, 
  200.                                             (void**) &m_pCommonClassFactory));
  201.     }
  202. #if defined(HELIX_FEATURE_PREFERENCES)
  203.     if (pContext)
  204.     {
  205.         HX_VERIFY(HXR_OK == pContext->QueryInterface(IID_IHXPreferences, (void**) &m_pPreferences));
  206.     }
  207. #endif /* HELIX_FEATURE_PREFERENCES */
  208.     m_pInDataPtr    = new HXAudioData;
  209.     m_pOutDataPtr   = new HXAudioData;
  210. };
  211. /************************************************************************
  212.  *  Method:
  213.  *              IHXAudioStream::~CHXAudioStream()
  214.  *      Purpose:
  215.  *              Destructor. Clean up and set free.
  216.  */
  217. CHXAudioStream::~CHXAudioStream()
  218. {
  219.     ResetStream();
  220. /*
  221.  *  Left around for future debugging
  222.     if (fdbefore)
  223.     {
  224.         fclose(fdbefore);
  225.     }
  226.     if (fdbeforetxt)
  227.     {
  228.         fclose(fdbeforetxt);
  229.     }
  230.     if (fdafter)
  231.     {
  232.         fclose(fdafter);
  233.     }
  234.     if (fdaftertxt)
  235.     {
  236.         fclose(fdaftertxt);
  237.     }
  238.     if (fdin)
  239.     {
  240.         fclose(fdin);
  241.     }
  242. */
  243. }
  244. /////////////////////////////////////////////////////////////////////////
  245. //  Method:
  246. //      IUnknown::QueryInterface
  247. //  Purpose:
  248. //      Implement this to export the interfaces supported by your
  249. //      object.
  250. //
  251. STDMETHODIMP CHXAudioStream::QueryInterface(REFIID riid, void** ppvObj)
  252. {
  253. QInterfaceList qiList[] =
  254. {
  255. { GET_IIDHANDLE(IID_IHXAudioStream), (IHXAudioStream*) this },
  256. { GET_IIDHANDLE(IID_IHXRealAudioSync), (IHXRealAudioSync*) this },
  257. { GET_IIDHANDLE(IID_IHXAudioStream2), (IHXAudioStream2*) this },
  258. { GET_IIDHANDLE(IID_IHXCommonClassFactory), (IHXCommonClassFactory*) this },
  259. { GET_IIDHANDLE(IID_IHXUpdateProperties), (IHXUpdateProperties*) this },
  260. };
  261.     return QIFind(qiList, QILISTSIZE(qiList), riid, ppvObj);
  262. }
  263. /////////////////////////////////////////////////////////////////////////
  264. //  Method:
  265. //      IUnknown::AddRef
  266. //  Purpose:
  267. //      Everyone usually implements this the same... feel free to use
  268. //      this implementation.
  269. //
  270. STDMETHODIMP_(ULONG32) CHXAudioStream::AddRef()
  271. {
  272.     return InterlockedIncrement(&m_lRefCount);
  273. }
  274. /////////////////////////////////////////////////////////////////////////
  275. //  Method:
  276. //      IUnknown::Release
  277. //  Purpose:
  278. //      Everyone usually implements this the same... feel free to use
  279. //      this implementation.
  280. //
  281. STDMETHODIMP_(ULONG32) CHXAudioStream::Release()
  282. {
  283.     if (InterlockedDecrement(&m_lRefCount) > 0)
  284.     {
  285.         return m_lRefCount;
  286.     }
  287.     delete this;
  288.     return 0;
  289. }
  290. /*
  291.  *  IHXAudioStream methods
  292.  */
  293. /************************************************************************
  294.  *  Method:
  295.  *              IHXAudioStream::Init
  296.  *      Purpose:
  297.  *              Init the audio stream.
  298.  */
  299. STDMETHODIMP CHXAudioStream::Init
  300. (
  301.     const HXAudioFormat*        pAudioFormat,
  302.           IHXValues*            pValues
  303. )
  304. {
  305.     if (m_bAudioFormatKnown)
  306.     {
  307.         return HXR_OK;
  308.     }
  309.     HX_RESULT theErr = HXR_OK;
  310.     m_pValues = pValues;
  311.     if (m_pValues)
  312.     {
  313.         m_pValues->AddRef();
  314.         UINT32 ulVal = 0;
  315.         m_pValues->GetPropertyULONG32("audioDeviceReflushHint", ulVal);
  316.         if (ulVal == 1)
  317.         {
  318.             SetAudioDeviceReflushHint(TRUE);
  319.             m_Owner->m_Owner->CheckIfLastNMilliSecsToBeStored();
  320.         }
  321.     }
  322.     memcpy( &m_AudioFmt, pAudioFormat, sizeof(HXAudioFormat) ); /* Flawfinder: ignore */
  323.     // Create the audio data list 
  324.     m_pDataList = new CHXSimpleList;
  325.     if ( !m_pDataList )
  326.         theErr = HXR_OUTOFMEMORY;
  327.     if(!theErr) // check if list constructor really succeeded
  328.     {
  329.         if(!m_pDataList->IsPtrListValid())
  330.             theErr = HXR_OUTOFMEMORY;
  331.     }
  332.     m_pInstantaneousList = new CHXSimpleList;
  333.     if ( !m_pInstantaneousList || !m_pInstantaneousList->IsPtrListValid())
  334.         theErr = HXR_OUTOFMEMORY;
  335.     // Reset this so that we init the hooks
  336.     m_bFirstWrite       = TRUE;
  337.     m_bHooksInitialized = FALSE;
  338. #if defined(HELIX_FEATURE_VOLUME)
  339.     // Create a volume object.
  340.     if ( !theErr )
  341.     {
  342.         m_pVolumeAdviseSink = new HXStreamVolumeAdviseSink;
  343.         if (!m_pVolumeAdviseSink)
  344.         {
  345.             theErr = HXR_OUTOFMEMORY;
  346.         }
  347.         else
  348.         {
  349.             m_pVolumeAdviseSink->AddRef();
  350.             m_pVolumeAdviseSink->m_pCHXAudioStream = this;
  351.         }
  352.         m_pStreamVolume = (IHXVolume*) new CHXVolume;
  353.         if ( !m_pStreamVolume )
  354.             theErr = HXR_OUTOFMEMORY;
  355.         else
  356.         {
  357.             m_pStreamVolume->AddRef();
  358.             m_pStreamVolume->AddAdviseSink(m_pVolumeAdviseSink);
  359.             m_pStreamVolume->SetVolume(HX_MAX_VOLUME);
  360.         }
  361.     }
  362. #endif /* HELIX_FEATURE_VOLUME */
  363. #ifdef _TESTING
  364.     g_log =  open("c:\log\stream.raw", O_WRONLY | O_CREAT
  365.                   | O_BINARY | _O_SEQUENTIAL);
  366. #endif
  367.     m_bAudioFormatKnown = TRUE;
  368.     if (m_bSetupToBeDone)
  369.     {
  370.         m_bSetupToBeDone    = FALSE;
  371.         m_Owner->AudioFormatNowKnown();
  372.     }
  373.     if (!theErr && m_bSetupDone && !m_bInited)
  374.     {
  375.         theErr = ProcessInfo();
  376.     }
  377.     return theErr;
  378. }
  379. /************************************************************************
  380.  *  Method:
  381.  *              IHXAudioStream::Write
  382.  *  Purpose:
  383.  *      Write audio data to Audio Services. 
  384.  *
  385.  *      NOTE: If the renderer loses packets and there is no loss
  386.  *      correction, then the renderer should write the next packet 
  387.  *      using a meaningful start time.  Audio Services will play 
  388.  *      silence where packets are missing.
  389.  */
  390. STDMETHODIMP CHXAudioStream::Write
  391.     HXAudioData*        pInData
  392. )
  393. {
  394.     HX_RESULT theErr = HXR_OK;
  395.     if (!pInData)
  396.     {
  397.         return HXR_INVALID_PARAMETER;
  398.     }
  399.     if (!m_bInited)
  400.     {
  401.         return HXR_NOT_INITIALIZED;
  402.     }
  403.     // Init pre-mix hooks. Call this once to set up hook info. 
  404.     if ( !m_bHooksInitialized )
  405.     {
  406.         InitHooks();
  407.     }
  408.     // Process any "hooks"; Add the data to the data list.
  409.     /* If buffer is NULL, it means that the user just 
  410.      * wants to know what timestamp should be placed in the next 
  411.      * STREAMED/TIMED audio data
  412.      */
  413.     if ( !m_bGotHooks || !pInData->pData)
  414.     {
  415.         theErr = AddData( pInData );
  416.     }
  417.     else
  418.     {
  419.         HXAudioData outData;
  420.         
  421.         outData.pData       = 0;
  422.         outData.ulAudioTime = 0;
  423.         theErr = ProcessHooks( pInData, &outData );
  424.         if (!theErr && !m_bDisableWrite )
  425.         {
  426.             theErr = AddData( &outData );
  427.         }
  428.         if (outData.pData)
  429.         {
  430.             outData.pData->Release();
  431.         }
  432.     }
  433.     return theErr;
  434. }
  435. /************************************************************************
  436.  *  Method:
  437.  *              IHXAudioStream::AddPreMixHook
  438.  *      Purpose:
  439.  *      Use this method to add a pre-mix audio data hook.
  440.  */
  441. STDMETHODIMP CHXAudioStream::AddPreMixHook
  442.           IHXAudioHook*    pHook,
  443.     const BOOL              bDisableWrite
  444. )
  445. {
  446. #if defined(HELIX_FEATURE_AUDIO_PREMIXHOOK)
  447.     void* pTmp = 0;
  448.     
  449.     /* Does one already exists */
  450.     if (m_PreMixHookMap.Lookup((void*)pHook, pTmp))
  451.     {
  452.         return HXR_INVALID_PARAMETER;
  453.     }
  454.     HXAudioHookInfo* pPreMixHookInfo = (HXAudioHookInfo*) new HXAudioHookInfo;
  455.     if(!pPreMixHookInfo)
  456.     {
  457.         return HXR_OUTOFMEMORY;
  458.     }
  459.     pPreMixHookInfo->pHook        = pHook;
  460.     pPreMixHookInfo->bDisableWrite  = bDisableWrite;
  461.     pPreMixHookInfo->bIgnoreAudioData = FALSE;
  462.     IHXValues* pValues = NULL;
  463.     if (pHook && pHook->QueryInterface(IID_IHXValues, (void**) &pValues) == HXR_OK)
  464.     {
  465.         UINT32 ulValue = 0;
  466.         pValues->GetPropertyULONG32("IgnoreAudioData", ulValue);
  467.         pPreMixHookInfo->bIgnoreAudioData = (ulValue == 1);
  468.         HX_RELEASE(pValues);
  469.     }
  470.     pHook->AddRef();            // Released in destructor
  471.     m_PreMixHookMap.SetAt(pHook, pPreMixHookInfo);
  472.     m_bGotHooks = TRUE;
  473.     /* If any one of them is Disabled, we do not write */
  474.     if (bDisableWrite)
  475.     {
  476.         m_bDisableWrite = TRUE;
  477.     }
  478.     ProcessAudioHook(ACTION_ADD, pHook);
  479.     /* If we are already initialized, send the audio format */
  480.     if (m_bHooksInitialized)
  481.     {
  482.         if (pPreMixHookInfo->bIgnoreAudioData ||
  483.             HXR_OK == ProcessAudioHook(ACTION_CHECK, pHook))
  484.         {
  485.             pHook->OnInit( &m_AudioFmt );
  486.         }
  487.     }
  488.     return HXR_OK;
  489. #else
  490.     return HXR_NOTIMPL;
  491. #endif /* HELIX_FEATURE_AUDIO_PREMIXHOOK */
  492. }
  493. /************************************************************************
  494.  *  Method:
  495.  *              IHXAudioStream::RemovePreMixHook
  496.  *      Purpose:
  497.  *      Use this method to remove a pre-mix audio data hook.
  498.  */
  499. STDMETHODIMP CHXAudioStream::RemovePreMixHook
  500.       IHXAudioHook*    pHook
  501. )
  502. {
  503. #if defined(HELIX_FEATURE_AUDIO_PREMIXHOOK)
  504.     HXAudioHookInfo* pPreMixHookInfo = 0;
  505.     BOOL bCheckForDisableWrite        = FALSE;
  506.     if (!m_PreMixHookMap.Lookup((void*)pHook, (void*&) pPreMixHookInfo))
  507.     {
  508.         return HXR_INVALID_PARAMETER;
  509.     }
  510.     m_PreMixHookMap.RemoveKey(pHook);
  511.     /* If we are removing a hook which had disable write, 
  512.      * we need to re-determine if any of the remaining hooks
  513.      * has DisableWrite set to TRUE
  514.      */
  515.     if (pPreMixHookInfo->bDisableWrite)
  516.     {
  517.         bCheckForDisableWrite = TRUE;
  518.         m_bDisableWrite       = FALSE;
  519.     }
  520.     ProcessAudioHook(ACTION_REMOVE, pHook);
  521.     pPreMixHookInfo->pHook->Release();
  522.     delete pPreMixHookInfo;
  523.     if (m_PreMixHookMap.GetCount() == 0)
  524.     {
  525.         m_bGotHooks     = FALSE;
  526.         m_bDisableWrite = FALSE;
  527.     }
  528.     else if (bCheckForDisableWrite)
  529.     {
  530.         CHXMapPtrToPtr::Iterator lIter = m_PreMixHookMap.Begin();
  531.         for (; lIter != m_PreMixHookMap.End(); ++lIter)
  532.         {
  533.             HXAudioHookInfo* pPreMixHook = (HXAudioHookInfo*) (*lIter);
  534.             
  535.             /* atleast one has Disable Write ON */
  536.             if (pPreMixHook->bDisableWrite)
  537.             {
  538.                 m_bDisableWrite = TRUE;
  539.                 break;
  540.             }
  541.         }
  542.     }
  543. #endif /* HELIX_FEATURE_AUDIO_PREMIXHOOK */
  544.     return HXR_OK;
  545. }
  546. /************************************************************************
  547. *  Method:
  548. *       IHXAudioStream::AddDryNotification
  549. *  Purpose:
  550. *       Use this to add a notification response object to get notifications
  551. *       when audio stream is running dry.
  552. */
  553. STDMETHODIMP CHXAudioStream::AddDryNotification
  554.                         (
  555.                             IHXDryNotification* /*IN*/ pNotification
  556.                         )
  557. {
  558.     if (!pNotification)
  559.     {
  560.         return HXR_INVALID_PARAMETER;
  561.     }
  562.     void* pTmp = 0;
  563.     
  564.     /* Does one already exists */
  565.     if (m_DryNotificationMap.Lookup((void*)pNotification, pTmp))
  566.     {
  567.         return HXR_INVALID_PARAMETER;
  568.     }
  569.     pNotification->AddRef();
  570.     m_DryNotificationMap.SetAt((void*)pNotification, (void*)pNotification);
  571.     return HXR_OK;
  572. }
  573. /************************************************************************
  574. *  Method:
  575. *      IHXAudioStream2::RemoveDryNotification
  576. *  Purpose:
  577. *           Use this to remove itself from the notification response object
  578. *           during the stream switching.
  579. */
  580. STDMETHODIMP CHXAudioStream::RemoveDryNotification   
  581.                             (
  582.                                 IHXDryNotification* /*IN*/ pNotification
  583.                             )
  584. {
  585.     HX_RESULT   hr = HXR_OK;
  586.     void* pTmp = 0;
  587.     if (!pNotification)
  588.     {
  589.         hr = HXR_INVALID_PARAMETER;
  590.         goto cleanup;
  591.     }
  592.     // remove only if it is exists
  593.     if (m_DryNotificationMap.Lookup((void*)pNotification, pTmp))
  594.     {
  595.         m_DryNotificationMap.RemoveKey((void*)pNotification);
  596.         HX_RELEASE(pNotification);
  597.     }
  598.     else
  599.     {
  600.         hr = HXR_INVALID_PARAMETER;
  601.         goto cleanup;
  602.     }
  603. cleanup:
  604.     return hr;
  605. }
  606. /************************************************************************
  607. *  Method:
  608. *      IHXAudioStream2::GetAudioFormat
  609. *  Purpose:
  610. *           Returns the input audio format of the data written by the 
  611. *           renderer. This function will fill in the pre-allocated 
  612. *           HXAudioFormat structure passed in.
  613. */
  614. STDMETHODIMP
  615. CHXAudioStream::GetAudioFormat(HXAudioFormat*   /*IN/OUT*/pAudioFormat)
  616. {
  617.     HX_ASSERT(pAudioFormat);
  618.     if (!pAudioFormat)
  619.     {
  620.         return HXR_INVALID_PARAMETER;
  621.     }
  622.     if (!m_bInited)
  623.     {
  624.         return HXR_UNEXPECTED;
  625.     }
  626.     pAudioFormat->uChannels         = m_AudioFmt.uChannels;
  627.     pAudioFormat->uBitsPerSample    = m_AudioFmt.uBitsPerSample;
  628.     pAudioFormat->ulSamplesPerSec   = m_AudioFmt.ulSamplesPerSec;
  629.     pAudioFormat->uMaxBlockSize     = m_AudioFmt.uMaxBlockSize;
  630.     return HXR_OK;
  631. }
  632.  
  633. /************************************************************************
  634.  *  Method:
  635.  *              IHXAudioStream::GetAudioVolume
  636.  *      Purpose:
  637.  *              Return this stream's IRMA volume interface.
  638.  */
  639. STDMETHODIMP_(IHXVolume*) CHXAudioStream::GetAudioVolume()
  640. {
  641.     if ( m_pStreamVolume )
  642.     {
  643.         m_pStreamVolume->AddRef();
  644.         return m_pStreamVolume;
  645.     }
  646.     else
  647.     {
  648.         return 0;
  649.     }
  650. }
  651. #if defined(HELIX_FEATURE_VOLUME)
  652. /*
  653.  *      IHXVolumeAdviseSink methods
  654.  */
  655. STDMETHODIMP CHXAudioStream::OnVolumeChange
  656. (
  657.     const UINT16 uVolume
  658. )
  659. {
  660.     m_uVolume = uVolume;
  661.     return HXR_OK;
  662. }
  663. STDMETHODIMP CHXAudioStream::OnMuteChange
  664. (
  665.     const BOOL bMute
  666. )
  667. {
  668.     m_bMute = bMute;
  669.     return HXR_OK;
  670. }
  671. #endif /* HELIX_FEATURE_VOLUME */
  672. /************************************************************************
  673.  *  Method:
  674.  *              IHXAudioStream::AddData
  675.  *      Purpose:
  676.  *              Add audio data to list.
  677.  *      NOTE: Mark Streamed data also as Timed data IF we don't write a streamed packet
  678.  *       since it was LATE!!!
  679.  */
  680. HX_RESULT CHXAudioStream::AddData
  681. (
  682.     HXAudioData* pAudioData
  683. )
  684. {
  685.     HX_RESULT       theErr = HXR_OK;
  686.     BOOL            bInTSRollOver = FALSE;
  687.     HXAudioInfo*    pAinfo = 0;
  688.     /* If buffer is NULL, it means that the user just 
  689.      * wants to know what timestamp should be placed in the next 
  690.      * STREAMED/TIMED audio data
  691.      */
  692.     if (!pAudioData->pData)
  693.     {
  694.         HXAudioInfo* pInfo = NULL;
  695.         
  696.         if (!m_pDataList->IsEmpty() && 
  697.             NULL != (pInfo = (HXAudioInfo*) m_pDataList->GetTail()))
  698.         {
  699.             pAudioData->ulAudioTime = pInfo->ulStartTime + 
  700.                                       CalcMs(pInfo->pBuffer->GetSize());
  701.         }
  702.         else
  703.         {
  704.             pAudioData->ulAudioTime = INT64_TO_UINT32(m_llLastWriteTime - CAST_TO_INT64 m_ulTSRollOver * CAST_TO_INT64 MAX_UINT32);
  705.         }
  706.         return HXR_OK;
  707.     }
  708.     // make sure the renderer does not pass NULL data!!
  709.     HX_ASSERT(pAudioData->pData->GetBuffer() != NULL &&
  710.               pAudioData->pData->GetSize() != 0);
  711.     if (pAudioData->pData->GetBuffer()  == NULL ||
  712.         pAudioData->pData->GetSize()    == 0)
  713.     {
  714.         return HXR_INVALID_PARAMETER;
  715.     }
  716.     if (m_bIsFirstPacket)
  717.     {
  718.         m_bIsFirstPacket = FALSE;
  719.         
  720.         IHXErrorMessages* pErrMsg = NULL;
  721.         if (HXR_OK == m_Owner->m_pContext->QueryInterface(IID_IHXErrorMessages, (void**)&pErrMsg))
  722.         {
  723.             DEBUG_OUT(pErrMsg, DOL_GENERIC, (s,"AudioFormatIn: %lu channels %lu SamplesPerSec", m_AudioFmt.uChannels, m_AudioFmt.ulSamplesPerSec));
  724.             DEBUG_OUT(pErrMsg, DOL_GENERIC, (s,"AudioFormatOut: %lu channels %lu SamplesPerSec", m_DeviceFmt.uChannels, m_DeviceFmt.ulSamplesPerSec));
  725.         }
  726.         HX_RELEASE(pErrMsg);
  727.         if (m_bIsLive)
  728.         {
  729.             m_Owner->UpdateStreamLastWriteTime();
  730.             UpdateStreamLastWriteTime(TRUE);
  731.         }
  732.     }
  733. //{FILE* f1 = ::fopen("c:\temp\audio.txt", "a+"); ::fprintf(f1, "%lutAddDatat%pt%lun", HX_GET_BETTERTICKCOUNT(), this, pAudioData->ulAudioTime);::fclose(f1);}
  734. //    ::fwrite(pAudioData->pData->GetBuffer(), pAudioData->pData->GetSize(), 1, fdin);
  735.     UINT32 ulDataTime = CalcMs(pAudioData->pData->GetSize());
  736.     UINT32 ulEndTime = pAudioData->ulAudioTime + ulDataTime;
  737.     if (m_pAvailableBuffers && !m_bDeterminedInitialCacheSize && ulDataTime > 0)
  738.     {
  739.         m_bDeterminedInitialCacheSize = TRUE;
  740.         m_uCacheSize = (UINT16) (m_ulGranularity*2/ulDataTime) + 1;
  741.         /* make sure it is atleast CACHE_INCREMENT_SIZE to begin with */
  742.         m_uCacheSize = m_uCacheSize < CACHE_INCREMENT_SIZE ? 
  743.                             CACHE_INCREMENT_SIZE : m_uCacheSize;
  744.     }
  745.     if (m_ulLastInputStartTime > pAudioData->ulAudioTime &&
  746.         ((m_ulLastInputStartTime - pAudioData->ulAudioTime) > MAX_TIMESTAMP_GAP))
  747.     {
  748.         bInTSRollOver = TRUE;
  749.         m_ulTSRollOver++;
  750.     }
  751.     m_ulLastInputStartTime  = pAudioData->ulAudioTime;
  752.     m_ulLastInputEndTime    = ulEndTime;
  753.     /* even in STREAMING_AUDIO case, it might happen, that the packets
  754.      * written are late. e.g. packets received late on the network 
  755.      */
  756.     INT64 llActualTimestamp = CAST_TO_INT64 (pAudioData->ulAudioTime) + CAST_TO_INT64 m_ulTSRollOver * CAST_TO_INT64 MAX_UINT32;
  757.     INT64 llActualEndTime = CAST_TO_INT64 (pAudioData->ulAudioTime) + CAST_TO_INT64 (ulDataTime) +
  758.                             CAST_TO_INT64 m_ulTSRollOver * CAST_TO_INT64 MAX_UINT32;
  759.     if ((pAudioData->uAudioStreamType == STREAMING_AUDIO ||
  760.          pAudioData->uAudioStreamType == TIMED_AUDIO) &&
  761.        !(llActualTimestamp >= m_llLastWriteTime ||
  762.          llActualEndTime > m_llLastWriteTime)) 
  763.     {
  764.         /* Too late*/
  765.         m_bTobeTimed    = TRUE;
  766. //{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);}
  767.         return HXR_LATE_PACKET; 
  768.     }
  769.     pAinfo = new HXAudioInfo;
  770.     if(!pAinfo)
  771.     {
  772.         theErr = HXR_OUTOFMEMORY;
  773.         goto exit;
  774.     }
  775.     pAudioData->pData->AddRef();
  776.     pAinfo->pBuffer             = pAudioData->pData;
  777.     pAinfo->ulStartTime         = pAudioData->ulAudioTime;
  778.     pAinfo->pOffset             = pAudioData->pData->GetBuffer();  
  779.     pAinfo->ulBytesLeft         = pAudioData->pData->GetSize();  
  780.     pAinfo->uAudioStreamType    = pAudioData->uAudioStreamType;
  781.     if (m_bTobeTimed && pAudioData->uAudioStreamType == STREAMING_AUDIO)
  782.     {
  783.         pAinfo->uAudioStreamType = TIMED_AUDIO;
  784.         m_bTobeTimed             = FALSE;
  785.     }
  786.     else if (m_bTobeTimed && pAudioData->uAudioStreamType == TIMED_AUDIO)
  787.     {
  788.         m_bTobeTimed    = FALSE;
  789.     }
  790. //{FILE* f1 = ::fopen("c:\temp\audio.txt", "a+"); ::fprintf(f1, "AddData ulAudioTime: %lun", pAudioData->ulAudioTime);::fclose(f1);}
  791.     if (pAinfo->uAudioStreamType == INSTANTANEOUS_AUDIO)
  792.     {
  793. CHXSimpleList* pList = new CHXSimpleList;
  794.         if(!pList)
  795.         {
  796.             theErr = HXR_OUTOFMEMORY;
  797.             goto exit;
  798.         }
  799. pList->AddHead((void*) pAinfo);
  800. m_pInstantaneousList->AddTail((void*) pList);
  801. m_Owner->m_Owner->ToBeRewound();
  802.     }
  803.     else if (pAinfo->uAudioStreamType == STREAMING_INSTANTANEOUS_AUDIO)
  804.     {
  805. HX_ASSERT(m_pInstantaneousList && m_pInstantaneousList->GetCount() > 0);
  806. CHXSimpleList* pList = NULL;
  807. if (m_pInstantaneousList->GetCount() == 0)
  808. {
  809.     pList = new CHXSimpleList;
  810.             if(!pList)
  811.             {
  812.                 theErr = HXR_OUTOFMEMORY;
  813.                 goto exit;
  814.             }
  815.     m_pInstantaneousList->AddTail((void*) pList);
  816.     // fix for naive users!
  817.     pAinfo->uAudioStreamType = INSTANTANEOUS_AUDIO;
  818.     m_Owner->m_Owner->ToBeRewound();
  819. }
  820.         pList = (CHXSimpleList*) m_pInstantaneousList->GetTail();
  821.         pList->AddTail(pAinfo);
  822.     }
  823.     else if (m_pDataList->IsEmpty())
  824.     {
  825.         m_pDataList->AddTail((void*) pAinfo);
  826.     }
  827.     else
  828.     {
  829.         HXAudioInfo* pInfo = (HXAudioInfo*) m_pDataList->GetTail();
  830.         UINT32  ulActualTSRollOver = m_ulTSRollOver;
  831.         if (bInTSRollOver && ulActualTSRollOver)
  832.         {
  833.             ulActualTSRollOver--;
  834.         }
  835.         INT64 llActualLastEndTime = CAST_TO_INT64 (pInfo->ulStartTime) + CAST_TO_INT64 (CalcMs(pInfo->pBuffer->GetSize())) +
  836.                                     CAST_TO_INT64 ulActualTSRollOver * CAST_TO_INT64 MAX_UINT32;
  837.         INT64 llActualLastStartTime = CAST_TO_INT64 (pInfo->ulStartTime) + CAST_TO_INT64 ulActualTSRollOver * CAST_TO_INT64 MAX_UINT32;
  838.         
  839.         if (llActualTimestamp < llActualLastStartTime)
  840.         {
  841.             /* Not allowed */
  842.             theErr = HXR_OUTOFORDER_PACKET; 
  843.             /* something is wrong... figure out what?*/
  844.             HX_ASSERT(!("Packets written out of order"));
  845.             goto exit;
  846.         }
  847.         if (pAinfo->uAudioStreamType == STREAMING_AUDIO)
  848.         {
  849.             /* is it a resonable packet to add to the list */
  850.             if ((llActualTimestamp <= llActualLastEndTime               &&
  851.                  llActualLastEndTime - llActualTimestamp <= m_ulFudge)  || 
  852.                 (llActualTimestamp >= llActualLastEndTime               &&
  853.                  llActualTimestamp - llActualLastEndTime <= m_ulFudge))
  854.             {
  855.                 m_pDataList->AddTail((void*) pAinfo);
  856.             }
  857.             else
  858.             {
  859.                 theErr = HXR_NONCONTIGUOUS_PACKET; //HX_LATE_PACKET;
  860.                 /* something is wrong... figure out what?*/
  861.                 HX_ASSERT(!("Streaming Audio: Non-Contigous Write"));
  862.                 m_bTobeTimed    = TRUE;
  863.                 goto exit;
  864.             }
  865.         }
  866.         else
  867.         {
  868.             /* see if there is any overlap.. we do not allow any overlap */
  869.             if (llActualTimestamp < llActualLastEndTime &&
  870.                 llActualLastEndTime - llActualTimestamp > m_ulFudge)
  871.             {
  872.                 /* hmmm an overlapped packet */
  873.                 theErr = HXR_OVERLAPPED_PACKET;
  874.                 /* something is wrong... figure out what?*/
  875.                 HX_ASSERT(!("Timed Audio: Overlapping write"));
  876.                 m_bTobeTimed    = TRUE;
  877.                 goto exit;
  878.             }
  879.             else
  880.             {
  881.                 m_pDataList->AddTail((void*) pAinfo);
  882.             }
  883.         }
  884.     }
  885. exit:
  886.     if (theErr != HXR_OK && pAinfo)
  887.     {
  888.         pAinfo->pBuffer->Release();
  889.         delete pAinfo;
  890.     }
  891.     /* Make sure to discard any data that is prior to cross-fade time */
  892.     if (!theErr && m_bCrossFadingToBeDone && m_bFadeToThisStream)
  893.     {
  894.         RemoveExcessCrossFadeData();
  895.     }
  896. //{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);}
  897.     
  898.     return theErr;
  899. }
  900. HX_RESULT CHXAudioStream::ProcessInfo(void)
  901. {
  902.     HX_RESULT theErr = HXR_OK;
  903.     // Calculate the number of bytes per granularity.
  904.     m_ulInputBytesPerGran = (ULONG32) 
  905.                 (((m_AudioFmt.uChannels * ((m_AudioFmt.uBitsPerSample==8)?1:2) *  m_AudioFmt.ulSamplesPerSec) 
  906.                                 / 1000.0) * m_ulGranularity);
  907.     m_ulOutputBytesPerGran  = (ULONG32) 
  908.                 (((m_DeviceFmt.uChannels * ((m_DeviceFmt.uBitsPerSample==8)?1:2) *  m_DeviceFmt.ulSamplesPerSec) 
  909.                                 / 1000.0) * m_ulGranularity);
  910.     /* Number of samples required at output should be a multiple of 8 if 
  911.      * sampling rate is 8K/16K/32K...or a multiple of 11 for 11K/22K...
  912.      * This is needed since the resamplerequires works reliably ONLY if
  913.      * this condition is true. Ken is working on this problem. This is 
  914.      * an interim fix 
  915.      */
  916.     ULONG32 ulExtraGranularity = 1;
  917.     if (m_DeviceFmt.ulSamplesPerSec % 8 == 0)
  918.     {
  919.         ulExtraGranularity = 8;
  920.     }
  921.     else
  922.     {
  923.         ulExtraGranularity = 11;
  924.     }
  925.     // Make sure that number of bytes per granularity is an even number.
  926.     if (m_ulInputBytesPerGran % (2*m_AudioFmt.uChannels*ulExtraGranularity) != 0)
  927.     {
  928.         m_ulInputBytesPerGran -= m_ulInputBytesPerGran % (2*m_AudioFmt.uChannels*ulExtraGranularity);
  929.     }
  930.     if (m_ulOutputBytesPerGran % (2*m_DeviceFmt.uChannels*ulExtraGranularity) != 0)
  931.     {
  932.         m_ulOutputBytesPerGran -= m_ulOutputBytesPerGran % (2*m_DeviceFmt.uChannels*ulExtraGranularity);
  933.     }
  934.     if (!theErr)
  935.     {
  936.         // Setup the resampler
  937.         theErr = SetupResampler();
  938.     }
  939.     if (!theErr)
  940.     {
  941.         m_bInited = TRUE;
  942.         
  943.         if (m_eState == E_STOPPED)
  944.         {
  945.             m_eState = E_INITIALIZED;
  946.         } 
  947.     }
  948.     if (!theErr && m_bInited && m_bCrossFadingToBeDone && 
  949.         m_bFadeToThisStream)
  950.     {
  951.         InitializeCrossFader();
  952.     }
  953.     /* Get the current player time to set the last write audio time 
  954.      * If someone creates a stream mid presentation, we ask the player 
  955.      * object for the current write time.
  956.      */
  957.     // set last write time to be the current playback time since
  958.     // this is what other system components(i.e. renderers) based on 
  959.     // fixed b#69847 - loss of push-down-worth of data =
  960.     // m_Owner->GetLastAudioWriteTime() - m_Owner->GetCurrentPlayBackTime()
  961. //    m_llLastWriteTime = m_Owner->GetCurrentPlayBackTime();
  962.     // XXXRA: It is necessary to use last audio write time for any delayed
  963.     // audio streams to work that do not involve any Pause/Rewind logic.
  964.     // To cover the case where a source (and an audio stream) has been added
  965.     // mid-playback by SMIL renderer which has a delay equivalent to the 
  966.     // current playback time, it should result in a player rewind which should 
  967.     // reset the lastaudiowrite time accordingly...so we should be able
  968.     // to use m_Owner->GetLastAudioWriteTime() value in such a use case as well.
  969.     // this change is required to fix PR 79161 and PR 69780.
  970.     // Henry, PR 69847 (the reason for the earlier change) is still busted. 
  971.     // so I am reverting this code to the original code. you will have 
  972.     // to come up with a different fix for PR 69847 since this was clearly not 
  973.     // the correct fix.
  974.     m_llLastWriteTime = m_Owner->GetLastAudioWriteTime();
  975.     if (!theErr && m_bInited)
  976.     {
  977.         m_Owner->StreamInitialized(this);
  978.     }
  979.     return theErr;
  980. }
  981. /************************************************************************
  982.  *  Method:
  983.  *              IHXAudioStream::SetupResampler
  984.  *      Purpose:
  985.  */
  986. HX_RESULT CHXAudioStream::SetupResampler()
  987. {
  988.     HX_RESULT theErr = HXR_OK;
  989. #if defined(HELIX_FEATURE_RESAMPLER)
  990.     // Create a resampler for this stream if we need one.
  991.     // Current resampler code resamples these sampling rates:
  992.     // 8000,11025,16000,22050,32000,44100.  The resample also
  993.     // converts 8-bit to 16-bit. NOTE: We convert all 8-bit samples
  994.     // to 16-bit before input into the resampler or mixer.
  995.     /* Resampler does the following tasks:
  996.      * 1. Conversion for sampling rates
  997.      * 2. Conversion from 8->16 and will also do 16->8 (XXX TBD)
  998.      * 3. Conversion from stereo to mono
  999.      * We do not use resampler for conversion from mono to stereo. This
  1000.      * takes place in the Mixer.
  1001.      */
  1002. /*
  1003.     fprintf(fdbeforetxt, "Samples: %lu, Channels: %lu, Bits/Sample: %lun",
  1004.          m_AudioFmt.ulSamplesPerSec, m_AudioFmt.uChannels, m_AudioFmt.uBitsPerSample);
  1005.     fprintf(fdaftertxt, "Samples: %lu, Channels: %lu, Bits/Sample: %lun",
  1006.          m_DeviceFmt.ulSamplesPerSec, m_DeviceFmt.uChannels, m_DeviceFmt.uBitsPerSample);
  1007. */
  1008.     if ((m_AudioFmt.ulSamplesPerSec != m_DeviceFmt.ulSamplesPerSec) ||
  1009.         (m_AudioFmt.uBitsPerSample != m_DeviceFmt.uBitsPerSample)   ||
  1010.         (m_AudioFmt.uChannels == 2 && m_DeviceFmt.uChannels == 1))
  1011.     {
  1012. m_AudioFmt.uMaxBlockSize = (UINT16) (m_ulInputBytesPerGran*1.5);
  1013.         if (HXR_OK == m_Owner->GetOwner()->CreateResampler(m_AudioFmt, 
  1014.                                                            m_DeviceFmt, 
  1015.                                                            m_pResampler))
  1016.         {                               
  1017.             /* times 2 since resampler always returns data in 16 bit.
  1018.              * times 2 if i/p or o/p is stereo
  1019.              * May change in future when we do 16->8 conversion in resampler
  1020.              */
  1021.             m_ulMaxBlockSize = (ULONG32) m_DeviceFmt.uMaxBlockSize * 2 * 2;
  1022.             /* This may be TRUE in downsampling */
  1023.             if (m_ulMaxBlockSize < (ULONG32) (m_ulInputBytesPerGran*1.5))
  1024.             {
  1025.                 m_ulMaxBlockSize = (ULONG32) (m_ulInputBytesPerGran*1.5);
  1026.             }
  1027.         }
  1028.         else
  1029.         {
  1030.             HX_RELEASE(m_pResampler);
  1031.             theErr = HX_RESAMPLER_ERROR;
  1032.         }
  1033.         if ( !theErr )
  1034.         {
  1035.             m_pResampleBuf = (UCHAR*) new char [ m_ulMaxBlockSize ];
  1036.             m_pTmpResBuf = (UCHAR*) new char [ m_ulMaxBlockSize ];
  1037.             if (!m_pResampleBuf || !m_pTmpResBuf)
  1038.             {
  1039.                 theErr = HXR_OUTOFMEMORY;
  1040.             }
  1041.         }
  1042.     }
  1043.     else
  1044.     {
  1045.         m_ulMaxBlockSize =  m_DeviceFmt.uMaxBlockSize;
  1046.     }
  1047.     /* Do not rely on max block size specified by the user */
  1048.     if (!theErr)
  1049.     {
  1050.         m_AudioFmt.uMaxBlockSize = (UINT16) m_ulMaxBlockSize;
  1051.     }
  1052.     m_bChannelConvert = (m_AudioFmt.uChannels == 1 && m_DeviceFmt.uChannels == 2);
  1053. #endif /* HELIX_FEATURE_RESAMPLER */
  1054.     // Create the resampler output buffer. Size it to the largest needed.
  1055.     return theErr;
  1056. }
  1057. /************************************************************************
  1058.  *  Method:
  1059.  *              IHXAudioStream::GetFormat
  1060.  *      Purpose:
  1061.  *      Return the stream's audio format.
  1062.  */
  1063. HX_RESULT CHXAudioStream::GetFormat
  1064.     HXAudioFormat*      pAudioFormat
  1065. )
  1066. {
  1067.     if (!m_bAudioFormatKnown)
  1068.     {
  1069.         return HXR_NOT_INITIALIZED;
  1070.     }
  1071.     pAudioFormat->uChannels       = m_AudioFmt.uChannels;
  1072.     pAudioFormat->uBitsPerSample  = m_AudioFmt.uBitsPerSample;
  1073.     pAudioFormat->ulSamplesPerSec = m_AudioFmt.ulSamplesPerSec;
  1074.     pAudioFormat->uMaxBlockSize   = m_AudioFmt.uMaxBlockSize;
  1075.     return HXR_OK;
  1076. }
  1077. /************************************************************************
  1078.  *  Method:
  1079.  *              IHXAudioStream::Setup
  1080.  *      Purpose:
  1081.  *              This is called by the player's Setup method. At this
  1082.  *              time the audio device format is set and we can now
  1083.  *              set up the streams pre-mixing buffer. This buffer
  1084.  *              contains data that has been resampled to match the
  1085.  *              audio device format.
  1086.  */
  1087. HX_RESULT CHXAudioStream::Setup(
  1088.         HXAudioFormat*  pFormat
  1089. ,       ULONG32         ulGranularity
  1090. )
  1091. {
  1092.     HX_RESULT theErr = HXR_OK;
  1093.     m_DeviceFmt.uChannels       = pFormat->uChannels;
  1094.     m_DeviceFmt.uBitsPerSample  = pFormat->uBitsPerSample;
  1095.     m_DeviceFmt.ulSamplesPerSec = pFormat->ulSamplesPerSec;
  1096.     m_DeviceFmt.uMaxBlockSize   = pFormat->uMaxBlockSize;
  1097.     m_ulGranularity = ulGranularity;
  1098.     m_bSetupDone = TRUE;
  1099.     
  1100.     /* we have all the info now.. so setup the resampler */
  1101.     if (m_bAudioFormatKnown && !m_bInited)
  1102.     {
  1103.         theErr = ProcessInfo();
  1104.     }
  1105.     return theErr;
  1106. }
  1107. /************************************************************************
  1108.  *  Method:
  1109.  *              IHXAudioStream::ResetStream
  1110.  *      Purpose:
  1111.  */
  1112. void CHXAudioStream::ResetStream()
  1113. {
  1114.     m_bInited           = FALSE;
  1115.     m_bCanBeRewound     = FALSE;
  1116.     m_bSetupDone        = FALSE;
  1117.     m_bAudioFormatKnown = FALSE;
  1118.     m_bIsResumed        = FALSE;
  1119.     
  1120.     UnRegister();
  1121.     while (m_pAvailableBuffers && m_pAvailableBuffers->GetCount() > 0)
  1122.     {
  1123.         IHXBuffer* pBuffer = (IHXBuffer*) m_pAvailableBuffers->RemoveHead();
  1124.         HX_RELEASE(pBuffer);
  1125.     }
  1126.     HX_DELETE(m_pAvailableBuffers);
  1127.     // Delete all entries in the audio data list
  1128.     FlushBuffers();
  1129.     HX_DELETE(m_pDataList);
  1130.     HX_DELETE(m_pInstantaneousList);
  1131.     CleanupRAByToTs();
  1132.     HX_DELETE(m_pRAByToTsInList);
  1133.     HX_DELETE(m_pRAByToTsAdjustedList);
  1134.     
  1135.     // Delete resample buffer
  1136.     HX_VECTOR_DELETE(m_pResampleBuf);
  1137.     // Delete tmp resample buffer
  1138.     HX_VECTOR_DELETE(m_pTmpResBuf);
  1139.     HX_VECTOR_DELETE(m_pCrossFadeBuffer);
  1140.     HX_VECTOR_DELETE(m_pExcessInterpBuffer);
  1141.     HX_VECTOR_DELETE(m_pTempInterpBuffer);
  1142.     m_ulExcessInterpBufferSize = m_ulPreviousExcessInterpBufferSize = 0;
  1143.     
  1144. #if defined(HELIX_FEATURE_CROSSFADE)
  1145.     HX_DELETE(m_pCrossFader);
  1146. #endif /* HELIX_FEATURE_CROSSFADE */
  1147.     // Free the resampler
  1148.     HX_RELEASE(m_pResampler);
  1149.     m_bGotHooks = FALSE;
  1150.     m_llLastWriteTime = 0;
  1151.     m_ulTSRollOver = 0;
  1152. #ifdef _TESTING
  1153.     if ( g_log > 0 )
  1154.         close(g_log);
  1155.     g_log = -1;
  1156. #endif
  1157.     HX_RELEASE(m_pValues);
  1158. #if defined(HELIX_FEATURE_AUDIO_PREMIXHOOK)
  1159.     // Delete all entries in the pre-mix hook list.
  1160.     if ( m_PreMixHookMap.GetCount() > 0)
  1161.     {
  1162.         HXAudioHookInfo* h = 0;
  1163.         CHXMapPtrToPtr::Iterator lIter = m_PreMixHookMap.Begin();
  1164.         for (; lIter != m_PreMixHookMap.End(); ++lIter)
  1165.         {
  1166.             h = (HXAudioHookInfo*) (*lIter);
  1167.             ProcessAudioHook(ACTION_REMOVE, h->pHook);
  1168.             h->pHook->Release();
  1169.             delete h;
  1170.         }
  1171.         
  1172.         m_PreMixHookMap.RemoveAll();
  1173.     }
  1174. #endif /* HELIX_FEATURE_AUDIO_PREMIXHOOK */
  1175. #if defined(HELIX_FEATURE_VOLUME)
  1176.     // Delete IRMA volume object.
  1177.     if (m_pStreamVolume && m_pVolumeAdviseSink)
  1178.     {
  1179.         m_pStreamVolume->RemoveAdviseSink(m_pVolumeAdviseSink);
  1180.         m_pVolumeAdviseSink->m_pCHXAudioStream = 0;
  1181.     }
  1182.     HX_RELEASE(m_pVolumeAdviseSink);
  1183. #endif /* HELIX_FEATURE_VOLUME */
  1184.     HX_RELEASE(m_pStreamVolume);
  1185.     HX_DELETE(m_pInDataPtr);
  1186.     HX_DELETE(m_pOutDataPtr);
  1187.     if (m_DryNotificationMap.GetCount() > 0)
  1188.     {
  1189.         IHXDryNotification* pDryNotification = 0;
  1190.         CHXMapPtrToPtr::Iterator lIter = m_DryNotificationMap.Begin();
  1191.         for (; lIter != m_DryNotificationMap.End(); ++lIter)
  1192.         {
  1193.             pDryNotification = (IHXDryNotification*) (*lIter);
  1194.             pDryNotification->Release();
  1195.         }
  1196.         
  1197.         m_DryNotificationMap.RemoveAll();
  1198.     }
  1199.     HX_RELEASE(m_pCrossFadeStream);
  1200.     HX_RELEASE(m_pCommonClassFactory);
  1201. #if defined(HELIX_FEATURE_PREFERENCES)
  1202.     HX_RELEASE(m_pPreferences);
  1203. #endif /* HELIX_FEATURE_PREFERENCES */
  1204.     HX_RELEASE(m_Owner);
  1205.     return;
  1206. }
  1207. HX_RESULT
  1208. CHXAudioStream::ProcessAudioHook(PROCESS_ACTION action, 
  1209.                                  IHXAudioHook* pAudioHook)
  1210. {
  1211.     return HXR_OK;
  1212. }
  1213. // Dummy version of this method - real version would be in hxaudstr_new.cpp
  1214. BOOL CHXAudioStream::ConvertIntoBuffer(tAudioSample* buffer, UINT32 nSamples, INT64 llStartTimeInSamples)
  1215. {
  1216.     return FALSE;
  1217. }
  1218. /************************************************************************
  1219.  *  Method:
  1220.  *              IHXAudioStream::InitHooks
  1221.  *      Purpose:
  1222.  *      Init any pre-mix hooks. Return TRUE if hooks exist else return
  1223.  *      FALSE.
  1224.  */
  1225. void CHXAudioStream::InitHooks()
  1226. {
  1227. #if defined(HELIX_FEATURE_AUDIO_PREMIXHOOK)
  1228.     /* Iterate thru the hook list and call the hook's OnInit().
  1229.      * If any of the hooks have disabled write set to TRUE, then
  1230.      * we will let this override any set to FALSE.
  1231.      */
  1232.     if ( m_PreMixHookMap.GetCount() > 0 )
  1233.     {
  1234.         HXAudioHookInfo* h = 0;
  1235.         CHXMapPtrToPtr::Iterator lIter = m_PreMixHookMap.Begin();
  1236.         for (; lIter != m_PreMixHookMap.End(); ++lIter)
  1237.         {
  1238.             h = (HXAudioHookInfo*) (*lIter);
  1239.             if (h->bIgnoreAudioData ||
  1240.                 HXR_OK == ProcessAudioHook(ACTION_CHECK, h->pHook))
  1241.             {
  1242.                 h->pHook->OnInit( &m_AudioFmt );
  1243.             }
  1244.         }
  1245.     }
  1246. #endif /* HELIX_FEATURE_AUDIO_PREMIXHOOK */
  1247.     m_bHooksInitialized = TRUE;
  1248. }
  1249. /************************************************************************
  1250.  *  Method:
  1251.  *              IHXAudioStream::ProcessHooks
  1252.  *      Purpose:
  1253.  */
  1254. HX_RESULT CHXAudioStream::ProcessHooks
  1255.     HXAudioData*        pInData,
  1256.     HXAudioData*        pOutData
  1257. )
  1258. {
  1259.     HX_RESULT theErr = HXR_OK;
  1260. #if defined(HELIX_FEATURE_AUDIO_PREMIXHOOK)
  1261.     m_pInDataPtr->pData         = pInData->pData;
  1262.     m_pInDataPtr->pData->AddRef();
  1263.     m_pInDataPtr->ulAudioTime   = pInData->ulAudioTime;
  1264.     
  1265.     m_pOutDataPtr->pData        = NULL;
  1266.     m_pOutDataPtr->ulAudioTime  = pInData->ulAudioTime;
  1267.     m_pInDataPtr->uAudioStreamType    = pInData->uAudioStreamType;
  1268.     m_pOutDataPtr->uAudioStreamType   = pInData->uAudioStreamType;
  1269.     if ( m_PreMixHookMap.GetCount() > 0 )
  1270.     {
  1271.         HXAudioHookInfo* pPreMixHookInfo = 0;
  1272.         CHXMapPtrToPtr::Iterator lIter = m_PreMixHookMap.Begin();
  1273.         for (; !theErr && lIter != m_PreMixHookMap.End(); ++lIter)
  1274.         {
  1275.             pPreMixHookInfo = (HXAudioHookInfo*) (*lIter);
  1276.             if (HXR_OK == ProcessAudioHook(ACTION_CHECK, pPreMixHookInfo->pHook))
  1277.             {
  1278.                 theErr = pPreMixHookInfo->pHook->OnBuffer( m_pInDataPtr, m_pOutDataPtr);
  1279.                 /* Check to see if renderer changed the buffer. If so, then
  1280.                  * make this output as input to the next Hook.
  1281.                  */
  1282.                 if (!theErr && m_pOutDataPtr->pData)
  1283.                 {
  1284.                     m_pInDataPtr->pData->Release();
  1285.                     m_pInDataPtr->pData     = m_pOutDataPtr->pData;
  1286.                     m_pInDataPtr->ulAudioTime   = m_pOutDataPtr->ulAudioTime;
  1287.                     m_pOutDataPtr->pData        = 0;
  1288.                 }
  1289.             }
  1290.             else if (pPreMixHookInfo->bIgnoreAudioData)
  1291.             {
  1292.                 IHXBuffer* pTempBuf = m_pInDataPtr->pData;
  1293.                 m_pInDataPtr->pData = NULL;
  1294.                 theErr = pPreMixHookInfo->pHook->OnBuffer( m_pInDataPtr, m_pOutDataPtr);
  1295.                 m_pInDataPtr->pData = pTempBuf;
  1296.             }
  1297.         }
  1298.     }
  1299.     /* Final output is always in InDataPtr*/
  1300.     pOutData->pData             = m_pInDataPtr->pData;
  1301.     pOutData->ulAudioTime       = m_pInDataPtr->ulAudioTime;
  1302.     pOutData->uAudioStreamType  = m_pInDataPtr->uAudioStreamType;
  1303. #endif /* HELIX_FEATURE_AUDIO_PREMIXHOOK */
  1304.     return theErr;
  1305. }
  1306. /************************************************************************
  1307.  *  Method:
  1308.  *      CHXAudioStream::MixIntoBuffer
  1309.  *  Purpose:
  1310.  *      Mix stream data into this pPlayerBuf.
  1311.  *  Note:
  1312.  *      
  1313.  *      Resampler always works on 16 bit PCM. If the input is
  1314.  *      8 bit, it converts it first to 16 bit before making
  1315.  *      any resampling calculations. 
  1316.  *      We always try to open audio device in 16 bit stereo mode.
  1317.  *      This is because a new player/stream may be instantiated in the
  1318.  *      midst of a presentation and this new stream may be stereo. If we 
  1319.  *      earlier opened the device as mono, we will have to force this stereo
  1320.  *      stream to be played as mono! Not a good idea. Also any mono-streo
  1321.  *      conversion almost comes for free (some extra memory usage and 
  1322.  *      an extra assignment) since it can be done in the mixing loop in
  1323.  *      MixBuffer().
  1324.  *
  1325.  *      Any 8-16 and stereo-mono conversion, if required, SHOULD be done
  1326.  *      before resampling.
  1327.  *      Any mono-stereo conversion should be done after resampling.
  1328.  *
  1329.  *      Stereo-Mono conversion code resides in the resampler. 
  1330.  *      Mono-Stereo conversion code resides in the mixer. 
  1331.  *
  1332.  */
  1333. HX_RESULT CHXAudioStream::MixIntoBuffer
  1334. (
  1335.     UCHAR*   pPlayerBuf,
  1336.     ULONG32  ulBufSize,
  1337.     ULONG32& ulBufTime,
  1338.     BOOL&    bIsMixBufferDirty,
  1339.     BOOL     bGetCrossFadeData
  1340. )
  1341. {
  1342.     BOOL    bCrossFadeThisTime  = FALSE;
  1343.     UINT32  ulTimeActuallyFaded = m_ulGranularity;
  1344.     if (!m_bInited)
  1345.     {
  1346.         return HXR_NOT_INITIALIZED;
  1347.     }
  1348. //{FILE* f1 = ::fopen("c:\temp\rasync.txt", "a+"); ::fprintf(f1, "Call MixIntoBuffer: %lun", m_ulLastWriteTime);::fclose(f1);}
  1349.     /* If this is a *FROM* stream, we may have already mixed
  1350.      * data during cross-fade with *TO* stream
  1351.      */
  1352.     if (m_bFadeAlreadyDone && !m_bFadeToThisStream)
  1353.     {
  1354.         m_bFadeAlreadyDone = FALSE;
  1355.         return HXR_OK;
  1356.     }
  1357.     HX_ASSERT(!bGetCrossFadeData || !m_bFadeToThisStream);
  1358.     /* If we need to mix cross fade data from the *from* stream,
  1359.      * it better be available 
  1360.      */
  1361.     HX_ASSERT(!bGetCrossFadeData || m_pDataList->GetCount() > 0);
  1362.     /* If this stream needs to be cross-faded and is a
  1363.      * NOT a fade-to stream, it would have been already taken
  1364.      * care of by the fade-to stream in an earlier call to 
  1365.      * MixIntoBuffer()
  1366.      */
  1367.     if (m_bCrossFadingToBeDone && m_pDataList->GetCount() > 0)
  1368.     {
  1369.         HXAudioInfo* pInfo = (HXAudioInfo*) m_pDataList->GetHead();
  1370.         INT64 llActualStartTime  = 0;
  1371.         if (pInfo)
  1372.         {
  1373.             llActualStartTime   = CAST_TO_INT64 (pInfo->ulStartTime) + 
  1374.                                   CAST_TO_INT64 (CalcMs(pInfo->pBuffer->GetSize() - pInfo->ulBytesLeft)) +
  1375.                                   CAST_TO_INT64 m_ulTSRollOver * CAST_TO_INT64 MAX_UINT32;
  1376.             if (m_bFadeToThisStream)
  1377.             {
  1378.                 /* Cool! It is time for cross-fading */
  1379.                 if ((m_llLastWriteTime <= m_llCrossFadeStartTime                            &&
  1380.                      m_llCrossFadeStartTime - m_llLastWriteTime <= CAST_TO_INT64 m_ulGranularity)  ||
  1381.                     (m_llLastWriteTime > m_llCrossFadeStartTime                             &&
  1382.                      m_llLastWriteTime - m_llCrossFadeStartTime <= CAST_TO_INT64 m_ulFudge))
  1383.                 {
  1384.                     bCrossFadeThisTime = TRUE;
  1385.                     if (m_llLastWriteTime <= m_llCrossFadeStartTime)
  1386.                     {
  1387.                         ulTimeActuallyFaded = m_ulGranularity - 
  1388.                                               INT64_TO_UINT32(m_llCrossFadeStartTime - m_llLastWriteTime);
  1389.                     }
  1390. //{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);}
  1391.                     HX_ASSERT(
  1392.                         (llActualStartTime >= m_llCrossFadeStartTime &&
  1393.                         (llActualStartTime <= m_llCrossFadeStartTime + 
  1394.                                               m_ulCrossFadeDuration)) ||
  1395.                         (llActualStartTime < m_llCrossFadeStartTime && 
  1396.                         (m_llCrossFadeStartTime - llActualStartTime <= CAST_TO_INT64 m_ulFudge)));
  1397.                 }
  1398.             }
  1399.         }
  1400.     }
  1401.     UINT32  ulLastWriteTime = INT64_TO_UINT32(m_llLastWriteTime - CAST_TO_INT64 m_ulTSRollOver * CAST_TO_INT64 MAX_UINT32);
  1402.     if (!bGetCrossFadeData && ulBufTime < ulLastWriteTime)
  1403.     {
  1404.         ulBufTime = ulLastWriteTime;
  1405.     }
  1406.     /* If there are any DryNotifications and the data list is empty
  1407.      * we need to notify them so that they can write more data.
  1408.      */
  1409.     if (m_DryNotificationMap.GetCount() > 0 || m_Owner->GetAudioStreamCount() == 1)
  1410.     {
  1411.         UINT32 ulNumMsRequired = m_ulGranularity;
  1412.         if (m_pDataList->IsEmpty() || !EnoughDataAvailable(ulLastWriteTime, ulNumMsRequired))
  1413.         {
  1414.             if (!bIsMixBufferDirty && !bGetCrossFadeData && !m_Owner->m_Owner->ReallyNeedData())
  1415.             {
  1416.                 return HXR_WOULD_BLOCK;
  1417.             }
  1418.             if (m_DryNotificationMap.GetCount() > 0)
  1419.             {
  1420.                 IHXDryNotification* pDryNotification = 0;
  1421.                 CHXMapPtrToPtr::Iterator lIter = m_DryNotificationMap.Begin();
  1422.                 for (; lIter != m_DryNotificationMap.End(); ++lIter)
  1423.                 {
  1424.                     pDryNotification = (IHXDryNotification*) (*lIter);
  1425.                     pDryNotification->OnDryNotification(ulLastWriteTime, ulNumMsRequired);
  1426.                 }
  1427.                 if (m_Owner->GetState() != E_PLAYING)
  1428.                 {
  1429.                     return HXR_OK;
  1430.                 }
  1431.             }
  1432.         }
  1433.     }
  1434.     m_Owner->DataInAudioDevice(TRUE);
  1435.     // /////////////////////////////////////////////////////////////
  1436.     // There may be no buffers in the list. No packets? Play silence.
  1437.     // Still need to increment time.
  1438.     if ( m_pDataList->IsEmpty() && m_pInstantaneousList->IsEmpty() )
  1439.     {
  1440.         m_llLastWriteTime += CAST_TO_INT64 m_ulGranularity;
  1441. //{FILE* f1 = ::fopen("e:\MixIntoBuffer.txt", "a+"); ::fprintf(f1, "%lut%pt%lun", HX_GET_BETTERTICKCOUNT(), this, (UINT32)m_llLastWriteTime);::fclose(f1);}
  1442.         return HXR_NO_DATA;
  1443.     }
  1444.     UCHAR*      pSourceBuffer = 0;
  1445.     ULONG32     ulMaxBytes = 0;
  1446.     ULONG32     ulMaxFramesIn = 0;
  1447.     ULONG32     ulMaxFramesOut = 0;
  1448.     ULONG32     ulNumBytesMixed = 0;
  1449.     BOOL        bMonoToStereoMayBeConverted = TRUE;
  1450.     BOOL        bResampleBufferDirty        = FALSE;
  1451.     // /////////////////////////////////////////////////////////////
  1452.     // If no  resampling, mix stream data directly into the player
  1453.     // buffer.
  1454.     if ( !m_pResampler)
  1455.     {
  1456.         pSourceBuffer   = pPlayerBuf;
  1457.         ulMaxBytes      = m_ulInputBytesPerGran;
  1458.         /* For only those sound cards which do not
  1459.          * support stereo - a RARE (non-existent) case 
  1460.          */
  1461.         if (m_AudioFmt.uChannels == 2 && m_DeviceFmt.uChannels == 1)
  1462.         {
  1463.             /* We should never reach here since this case
  1464.              * should be handled by the Resampler
  1465.              * Temporary ASSERT... 
  1466.              */
  1467.             HX_ASSERT(FALSE);
  1468.         }
  1469.         /* Mono->Stereo conversion*/
  1470.         else if (m_bChannelConvert)
  1471.         {
  1472.             HX_ASSERT(ulMaxBytes <= ulBufSize/2);
  1473.             
  1474.             /* Avoid GPF in retail builds! */
  1475.             if (ulMaxBytes > ulBufSize/2)
  1476.             {
  1477.                 ulMaxBytes = ulBufSize/2;
  1478.             }
  1479.         }
  1480.         else
  1481.         {
  1482.             HX_ASSERT(ulMaxBytes <= ulBufSize);
  1483.             
  1484.             /* Avoid GPF in retail builds! */
  1485.             if (ulMaxBytes > ulBufSize)
  1486.             {
  1487.                 ulMaxBytes = ulBufSize;
  1488.             }
  1489.         }
  1490.     }
  1491. #if defined(HELIX_FEATURE_RESAMPLER)
  1492.     // /////////////////////////////////////////////////////////////
  1493.     // If resampling, mix stream data into a tmp buffer. Then
  1494.     // resample this buffer and mix the final resampled buffer into
  1495.     // the player buffer.
  1496.     else
  1497.     {
  1498.         bMonoToStereoMayBeConverted = FALSE;
  1499. //      memset(m_pTmpResBuf, 0, HX_SAFESIZE_T(m_ulMaxBlockSize));
  1500.         pSourceBuffer = m_pTmpResBuf;
  1501.         /* 
  1502.          * Audio Session will always ask for m_ulOutputBytesPerGran bytes to be mixed
  1503.          * in MixIntoBuffer() call. So we need to produce these many number of bytes.
  1504.          * If there is any mono-stereo conversion that happens in the mixing, number
  1505.          * of output bytes required from the resampler are half the number of 
  1506.          * m_ulOutputBytesPerGran bytes.
  1507.          */
  1508.         if (m_pResampler)
  1509.         {
  1510.             ulMaxFramesOut = m_ulOutputBytesPerGran/(m_DeviceFmt.uBitsPerSample==8 ? 1 : 2);
  1511.             if (m_DeviceFmt.uChannels == 2)
  1512.             {
  1513.                 ulMaxFramesOut /= 2;
  1514.             }
  1515.             ulMaxFramesIn = m_pResampler->Requires(ulMaxFramesOut);
  1516.             ulMaxBytes = ulMaxFramesIn *  ((m_AudioFmt.uBitsPerSample==8)? 1 : 2)
  1517.                                             * m_AudioFmt.uChannels;
  1518.         }
  1519.         else
  1520.         {
  1521.             ulMaxBytes = m_ulInputBytesPerGran;
  1522.         }
  1523.         HX_ASSERT(ulMaxBytes <= m_ulMaxBlockSize);
  1524.     }
  1525. #endif /* HELIX_FEATURE_RESAMPLER */
  1526.     // /////////////////////////////////////////////////////////////
  1527.     // Mix n bytes of data into buffer
  1528.     ulNumBytesMixed = MixData(pSourceBuffer, ulMaxBytes, bMonoToStereoMayBeConverted, 
  1529.         (!m_pResampler) ? bIsMixBufferDirty : bResampleBufferDirty);
  1530. /*
  1531.     if (ulNumBytesMixed > 0)
  1532.     {
  1533.         ::fwrite(pSourceBuffer, ulNumBytesMixed, 1, fdbefore);
  1534.     }
  1535. */
  1536. #if defined(HELIX_FEATURE_RESAMPLER)
  1537.     // /////////////////////////////////////////////////////////////
  1538.     // If we need to resample , then do this and then mix data into
  1539.     // the player buffer.
  1540.     // Only resample and mix if volume is *not* zero and there 
  1541.     // are some bytes to mix.
  1542.     if (m_pResampler && ulNumBytesMixed > 0 && m_uVolume > 0 && !m_bMute)
  1543.     {
  1544.         if(ulNumBytesMixed < ulMaxBytes  &&  8==m_AudioFmt.uBitsPerSample)
  1545.         {
  1546.             //fill remainder with 128's (-1), silence:
  1547.             UCHAR* pTmp = &pSourceBuffer[ulNumBytesMixed];
  1548.             ULONG32 ulNumBytesLeftToSilence = ulMaxBytes-ulNumBytesMixed;
  1549.             do
  1550.             {
  1551.                 *pTmp = 128;
  1552.                 pTmp++;
  1553.             } while(--ulNumBytesLeftToSilence);
  1554.         }
  1555.         ULONG32 ulOutBytes      = 0;
  1556.         if (m_pResampler)
  1557.         {
  1558.             ulOutBytes = m_pResampler->Resample((UINT16*)pSourceBuffer,
  1559.                                                 ulMaxBytes,
  1560.                                                 (UINT16*)m_pResampleBuf);
  1561. /*
  1562.             FILE* fp = fopen("c:\temp\audio.txt", "w+");
  1563.             ::fwrite(m_pResampleBuf, ulOutBytes, 1, fp);
  1564.             fclose(fp);
  1565. */
  1566.             /* Resampler will do stereo to mono conversion for us.*/
  1567.             HX_ASSERT(ulMaxFramesOut == (ulOutBytes / 2 / 
  1568.                       (m_AudioFmt.uChannels == 2 && m_DeviceFmt.uChannels == 1 ? 1 : m_AudioFmt.uChannels))) ;
  1569.         }
  1570.         if (m_bChannelConvert)
  1571.         {
  1572.             HX_ASSERT(ulOutBytes*2 <= ulBufSize);
  1573.             if ( ulOutBytes > ulBufSize/2 )
  1574.             {           
  1575.                 ulOutBytes = ulBufSize/2;
  1576.             }
  1577.         }
  1578.         else
  1579.         {
  1580.             HX_ASSERT(ulOutBytes <= ulBufSize);
  1581.             ulOutBytes = ulBufSize;
  1582.         }
  1583.         BOOL bBeforeMixBufferDirty = bIsMixBufferDirty;
  1584.         UINT32 ulMixedNumBytes = 0;
  1585. #if defined(HELIX_FEATURE_MIXER)
  1586.         ulMixedNumBytes = CHXMixer::MixBuffer( m_pResampleBuf, pPlayerBuf, 
  1587.                              ulOutBytes, m_bChannelConvert,
  1588.                              m_uVolume, m_DeviceFmt.uBitsPerSample, bIsMixBufferDirty);
  1589. #else
  1590.         ::memcpy(pPlayerBuf, m_pResampleBuf, ulOutBytes); /* Flawfinder: ignore */
  1591.         bIsMixBufferDirty = TRUE;
  1592.         ulMixedNumBytes = ulOutBytes;
  1593. #endif /* HELIX_FEATURE_MIXER */
  1594.         // If we mixed only a partial buffer, make the remaining buffer silent
  1595.         if (!bBeforeMixBufferDirty && ulMixedNumBytes < ulBufSize)
  1596.         {
  1597.             ::memset(pPlayerBuf+ulMixedNumBytes, 0, ulBufSize-ulMixedNumBytes);
  1598.         }
  1599.     }
  1600. afterMixing:
  1601. #endif /* HELIX_FEATURE_RESAMPLER */
  1602. #ifdef _TESTING
  1603.     if ( g_log > 0 )
  1604.     {
  1605.         write( g_log, pPlayerBuf, ulNumBytesMixed);
  1606.     }
  1607. #endif
  1608.     /* This is for *FROM* stream */
  1609.     if (bGetCrossFadeData)
  1610.     {
  1611.         m_bFadeAlreadyDone = TRUE;
  1612.     }
  1613.     /* If we are cross-fading, we have data from this stream in pPlayerBuf
  1614.      * Now get data to be  cross-faded from *From* stream in 
  1615.      * m_pCrossFadeBuffer
  1616.      */
  1617. #if defined(HELIX_FEATURE_CROSSFADE) && defined(HELIX_FEATURE_MIXER)
  1618.     else if (bCrossFadeThisTime)
  1619.     {
  1620.         /* Allocate CrossFade Buffer */
  1621.         if (!m_pCrossFadeBuffer)
  1622.         {
  1623.             m_ulCrossFadeBufferSize = ulBufSize;
  1624.             m_pCrossFadeBuffer = new UCHAR[m_ulCrossFadeBufferSize];
  1625.         }
  1626.         memset(m_pCrossFadeBuffer, 0, HX_SAFESIZE_T(m_ulCrossFadeBufferSize));
  1627.         UINT32 ulCrossFadeLen = m_ulCrossFadeBufferSize;
  1628.         UINT32 ulTmpBufTime   = 0;
  1629.         BOOL bIsDrity = FALSE;
  1630.         m_pCrossFadeStream->MixIntoBuffer(m_pCrossFadeBuffer,
  1631.                                          ulCrossFadeLen, ulTmpBufTime, bIsDrity, TRUE);
  1632.         /* Now it is time to perform cross-fading between
  1633.          * pPlayerBuf and m_pCrossFadeBuffer
  1634.          */
  1635.         
  1636.         UINT32 ulStartByteToFade            = 0;
  1637.         UINT32 ulNumMsInThisBuffer          = CalcDeviceMs(ulBufSize);
  1638.         UINT32 ulNumBytesToBeCrossFaded = ulBufSize;
  1639.         UINT32 ulSampleSize = ((m_DeviceFmt.uBitsPerSample==8)? 1 : 2)
  1640.                             * m_DeviceFmt.uChannels;
  1641.         /* Make sure we have integral number of samples */
  1642.         HX_ASSERT(ulBufSize == (ulBufSize/ulSampleSize) * ulSampleSize);
  1643.         /* Only partial buffer needs to be cross-faded.
  1644.          *   -------------
  1645.          * ~~_____________|
  1646.          *
  1647.          *       -----------
  1648.          *      |___________~~
  1649.          *
  1650.          *      
  1651.          *     -----
  1652.          *    |_____|  <-- Granularity size block that is mixed.
  1653.          *
  1654.          *       <--> Only partial block needs to be faded
  1655.          */
  1656.         
  1657.         if (ulTimeActuallyFaded < ulNumMsInThisBuffer)
  1658.         {
  1659.             ulNumBytesToBeCrossFaded = (UINT32) (ulBufSize * 
  1660.                 (ulTimeActuallyFaded*1./ulNumMsInThisBuffer)) ;
  1661.             UINT32 ulOutOfPhase = ulNumBytesToBeCrossFaded % ulSampleSize;
  1662.             if (ulOutOfPhase > 0)
  1663.             {
  1664.                 ulNumBytesToBeCrossFaded = 
  1665.                     ulNumBytesToBeCrossFaded - ulOutOfPhase;
  1666.             }
  1667.             ulStartByteToFade = ulBufSize - ulNumBytesToBeCrossFaded;
  1668.         }
  1669.         if (ulTimeActuallyFaded > m_ulCrossFadeDuration)
  1670.         {
  1671.             ulNumBytesToBeCrossFaded = (UINT32) (ulBufSize * 
  1672.                 (m_ulCrossFadeDuration*1./ulNumMsInThisBuffer)) ;
  1673.             UINT32 ulOutOfPhase = ulNumBytesToBeCrossFaded % ulSampleSize;
  1674.             if (ulOutOfPhase > 0)
  1675.             {
  1676.                 ulNumBytesToBeCrossFaded = 
  1677.                     ulNumBytesToBeCrossFaded - ulOutOfPhase;
  1678.             }
  1679.         }
  1680.         UINT16 uNumSamples = (UINT16) (ulNumBytesToBeCrossFaded/
  1681.                                        ulSampleSize);
  1682.         BOOL bWasDirty = bIsMixBufferDirty;
  1683.         /* Mix the initial bytes that are not cross-faded*/
  1684.         if (ulStartByteToFade > 0)
  1685.         {
  1686.             CHXMixer::MixBuffer( m_pCrossFadeBuffer, pPlayerBuf, 
  1687.                         ulStartByteToFade, FALSE, 100, 8, bWasDirty);
  1688.         }
  1689.         m_pCrossFader->CrossFade((INT16*) (m_pCrossFadeBuffer+ulStartByteToFade), 
  1690.                                  (INT16*) (pPlayerBuf+ulStartByteToFade), 
  1691.                                  uNumSamples);
  1692.         /* make sure we have silence in bytes that were not touched */
  1693.         if (!bIsMixBufferDirty &&
  1694.             (ulStartByteToFade + (uNumSamples*ulSampleSize)) < ulBufSize)
  1695.         {
  1696.             ::memset(pPlayerBuf+ulStartByteToFade + (uNumSamples*ulSampleSize), 0, 
  1697.                 ulBufSize - (ulStartByteToFade + (uNumSamples*ulSampleSize)));
  1698.         }
  1699.         bIsMixBufferDirty = TRUE;
  1700.     }
  1701.     if (bGetCrossFadeData || bCrossFadeThisTime)
  1702.     {
  1703.         if (bGetCrossFadeData)
  1704.         {
  1705.             HX_ASSERT(m_llLastWriteTime >= m_llCrossFadeStartTime);
  1706.             if (m_llLastWriteTime >= m_llCrossFadeStartTime)
  1707.             {
  1708.                 HX_ASSERT(m_llLastWriteTime - m_llCrossFadeStartTime < MAX_TIMESTAMP_GAP);
  1709.                 ulTimeActuallyFaded = INT64_TO_UINT32(m_llLastWriteTime - m_llCrossFadeStartTime);
  1710.             }
  1711.         }
  1712.         if (ulTimeActuallyFaded >= m_ulCrossFadeDuration)
  1713.         {
  1714.             m_bCrossFadingToBeDone = FALSE;
  1715.             HX_RELEASE(m_pCrossFadeStream);
  1716.             /* We should release any extra buffers if it is a
  1717.              * *from* stream
  1718.              */
  1719.             if (!m_bFadeToThisStream)
  1720.             {
  1721.                 /* Do not remove any instantaenous buffers */
  1722.                 FlushBuffers(FALSE);
  1723.             }
  1724.         }
  1725.         else
  1726.         {
  1727.             m_ulCrossFadeDuration   -= ulTimeActuallyFaded;
  1728.             m_llCrossFadeStartTime  += CAST_TO_INT64 ulTimeActuallyFaded;
  1729.         }
  1730.     }
  1731.     else if (m_bCrossFadingToBeDone && !m_bFadeToThisStream)
  1732.     {
  1733.         m_pCrossFadeStream->SyncStream(m_llLastWriteTime);
  1734.     }
  1735. #endif /* HELIX_FEATURE_CROSSFADE && HELIX_FEATURE_MIXER */
  1736. //{FILE* f1 = ::fopen("e:\MixIntoBuffer.txt", "a+"); ::fprintf(f1, "%lut%pt%lun", HX_GET_BETTERTICKCOUNT(), this, (UINT32)m_llLastWriteTime);::fclose(f1);}
  1737.     return HXR_OK;
  1738. }
  1739. /************************************************************************
  1740.  *  Method:
  1741.  *      CHXAudioStream::MixData
  1742.  *  Purpose:
  1743.  *      Mix all valid data in my auxilliary list into the buffer.
  1744.  *
  1745.  *  Thoughts:
  1746.  *      while there are buffers available
  1747.  *          if (buffertime is more than endtime) break;
  1748.  *          if (any part of buffer is >startime and < endtime)
  1749.  *              we are in business. 
  1750.  *              mix that part of the buffer, update offset, 
  1751.  *              update max of num bytes written in this round.
  1752.      * Looks like we need to keep LastWrite time and offsets for all buffers
  1753.      * that get written in one pass.
  1754.      * Consider this scenario:
  1755.      *  
  1756.      *
  1757.         ----------------- -----------------
  1758.        |________________| |_______________|  -> Skew  1
  1759.           ________ __________   
  1760.          |_______| |_________|              ->Skew    2  5
  1761.           ____________________________________
  1762.          |__________________|_|_______________| Skew in opposite direction 3
  1763.                _______
  1764.               |_______|                               4
  1765.          ____________
  1766.         |____________|      <- Buffer to be mixed currently
  1767.                
  1768.         
  1769.           Order of buffer processing will be in the order of numbers on the right.
  1770.           Since all the theree buffers have fudge within fudge limit, they need to 
  1771.           be written one after the other. This is possible only if we keep last
  1772.           write times and last written offsets in mixer buffer for each one of them.
  1773.         Is this extra processsing on every write worthed OR do we place limitations
  1774.         on the data that can be written.
  1775.      *  Hmmm... We are now going with STREAMED/INSTANTANEOUS/TIMED model since the
  1776.      *  above case is shows that users can really screw things up and it would be
  1777.      *  very difficult to handle this case. So instead, we do not support over-lapped
  1778.      *  buffers any more. i.e. If a renderer wants to have streamed and instantaneous
  1779.      *  behavior, it needs to use two audio streams.
  1780.  */
  1781. ULONG32 CHXAudioStream::MixData
  1782. (
  1783.         UCHAR*  pDestBuf
  1784. ,       ULONG32 ulBufLen
  1785. ,       BOOL    bMonoToStereoMayBeConverted
  1786. ,       BOOL&   bIsMixBufferDirty
  1787. )
  1788. {
  1789.     HXAudioInfo*    pInfo                       = 0;
  1790.     ULONG32         ulNumBytes                  = 0;
  1791.     LISTPOSITION    lp                          = 0;
  1792.     LISTPOSITION    lastlp                      = 0;
  1793.     LISTPOSITION    lpList                      = 0;
  1794.     LISTPOSITION    lastlpList                  = 0;
  1795.     ULONG32         ulNumBytesWritten           = 0;
  1796.     BOOL            bLastWriteTimeToBeUpdated   = TRUE;
  1797.     ULONG32         ulDestinationOffset         = 0;
  1798.     BOOL            bWasMixBufferDirty          = bIsMixBufferDirty;
  1799.     // /////////////////////////////////////////////////////////////
  1800.     // Go thru the buffer list and mix in valid buffers.
  1801.     /* First all instantaneous buffers
  1802.      * All the instantaneous buffers get written at the start of 
  1803.      * the destination buffer.
  1804.      */
  1805.     lpList = lastlpList = 0;
  1806.     lpList = m_pInstantaneousList->GetHeadPosition();
  1807.     while(lpList)
  1808.     {
  1809.         lastlpList      = lpList;
  1810.         CHXSimpleList* pList = (CHXSimpleList*) m_pInstantaneousList->GetNext(lpList);
  1811.         lp = lastlp = 0;
  1812.         lp = pList->GetHeadPosition();
  1813.         ulDestinationOffset = 0;
  1814.         while( lp )
  1815.         {
  1816.             lastlp      = lp;
  1817.             pInfo       = (HXAudioInfo*) pList->GetNext(lp);
  1818.             /* just place it at the end of the last write position */
  1819.             ULONG32 ulNumMoreBytesToWrite = 0;
  1820.             if (m_bChannelConvert && bMonoToStereoMayBeConverted)
  1821.             {
  1822.                 ulNumMoreBytesToWrite = (ulBufLen*2-ulDestinationOffset)/2;
  1823.             }
  1824.             else
  1825.             {
  1826.                 ulNumMoreBytesToWrite = ulBufLen-ulDestinationOffset;
  1827.             }
  1828.             ulNumBytes = pInfo->ulBytesLeft > ulNumMoreBytesToWrite ? 
  1829.                          ulNumMoreBytesToWrite : pInfo->ulBytesLeft;
  1830.             // /////////////////////////////////////////////////////////////
  1831.             // Mix the data into the stream buffer, with stream volume. Don't 
  1832.             // do volume calculation if volume is 1. If volume is 0, then 
  1833.             // don't mix. Don't mix if there are no bytes to mix.
  1834.             if  (m_uVolume > 0 &&  ulNumBytes > 0)
  1835.             {
  1836.                 if (m_bChannelConvert && bMonoToStereoMayBeConverted)
  1837.                 {
  1838.                     HX_ASSERT(ulDestinationOffset + ulNumBytes*2 <= ulBufLen*2);
  1839.                 }
  1840.                 else
  1841.                 {
  1842.                     HX_ASSERT(ulDestinationOffset + ulNumBytes <= ulBufLen);
  1843.                 }
  1844.                 /* we will actually make bIsMixBufferDirty dirty at the end of this function */
  1845.                 BOOL bLocalDirty = bIsMixBufferDirty;
  1846. #if defined(HELIX_FEATURE_MIXER)
  1847.                 CHXMixer::MixBuffer(pInfo->pOffset, pDestBuf+ulDestinationOffset, 
  1848.                                      ulNumBytes, m_bChannelConvert && bMonoToStereoMayBeConverted,
  1849.                                      m_uVolume, m_AudioFmt.uBitsPerSample, bLocalDirty);
  1850. #else
  1851.                 ::memcpy(pDestBuf+ulDestinationOffset, pInfo->pOffset, ulNumBytes); /* Flawfinder: ignore */
  1852.                 bLocalDirty = TRUE;
  1853. #endif /* HELIX_FEATURE_MIXER */
  1854.             }
  1855.             ULONG32 ulActualBytesWritten = ((m_bChannelConvert && bMonoToStereoMayBeConverted) ? 
  1856.                                         2*ulNumBytes : ulNumBytes);
  1857.             if (ulNumBytesWritten < ulActualBytesWritten)
  1858.             {
  1859.                 ulNumBytesWritten = ulActualBytesWritten;
  1860.             }
  1861.             ulDestinationOffset += ulActualBytesWritten;
  1862.             pInfo->ulBytesLeft  -= ulNumBytes;
  1863.             pInfo->pOffset      += ulNumBytes;
  1864.             if (pInfo->ulBytesLeft == 0)
  1865.             {
  1866.                 FreeInfo(pInfo, TRUE);
  1867.                 pList->RemoveAt(lastlp);
  1868.             }
  1869.             /* Have we written enough for this time? */
  1870.             if (ulBufLen == ulDestinationOffset ||
  1871.                 (m_bChannelConvert && bMonoToStereoMayBeConverted &&
  1872.                 (ulBufLen*2 == ulDestinationOffset)))
  1873.             {
  1874.                 break;
  1875.             }
  1876.         }
  1877.         if (ulNumBytesWritten > 0 && m_uVolume > 0)
  1878.         {
  1879.             bIsMixBufferDirty = TRUE;
  1880.         }
  1881.         if (pList->GetCount() == 0 && m_pInstantaneousList->GetCount() > 1)
  1882.         {
  1883.             m_pInstantaneousList->RemoveAt(lastlpList);
  1884.             HX_DELETE(pList);
  1885.         }
  1886.     }
  1887.     /* now timed buffers */
  1888.     /* We do not support over-lapped buffers any more */
  1889.     ulDestinationOffset = 0;
  1890.     lp = lastlp = 0;
  1891.     lp = m_pDataList->GetHeadPosition();
  1892.     while( lp )
  1893.     {
  1894.         INT64   llActualStartTime = 0;
  1895.         UINT32  ulActualTSRollOver = m_ulTSRollOver;
  1896.         lastlp  = lp;
  1897.         pInfo   = (HXAudioInfo*) m_pDataList->GetNext(lp);
  1898.         if (pInfo->ulStartTime > m_ulLastInputStartTime &&
  1899.             ((pInfo->ulStartTime - m_ulLastInputStartTime) > MAX_TIMESTAMP_GAP))
  1900.         {
  1901.             ulActualTSRollOver--;
  1902.         }
  1903.         llActualStartTime = CAST_TO_INT64 (pInfo->ulStartTime) + CAST_TO_INT64 ulActualTSRollOver * CAST_TO_INT64 MAX_UINT32;
  1904.         HX_ASSERT(llActualStartTime - m_llLastWriteTime < MAX_TIMESTAMP_GAP);
  1905.         /* only at the start of the buffer, we check whether
  1906.          * we are done or not for this round
  1907.          */
  1908.         if (pInfo->uAudioStreamType == STREAMING_AUDIO      &&
  1909.             pInfo->pOffset == pInfo->pBuffer->GetBuffer()   &&
  1910.             llActualStartTime > m_llLastWriteTime           &&
  1911.             llActualStartTime - m_llLastWriteTime > CAST_TO_INT64 m_ulFudge)
  1912.         {
  1913.             break;
  1914.         }
  1915.         if (pInfo->uAudioStreamType == TIMED_AUDIO && 
  1916.             (pInfo->ulBytesLeft == pInfo->pBuffer->GetSize() ||
  1917.              m_bCrossFadingToBeDone))
  1918.         {
  1919.             llActualStartTime = CAST_TO_INT64 (pInfo->ulStartTime) + 
  1920.                                 CAST_TO_INT64 (CalcMs(pInfo->pBuffer->GetSize() - pInfo->ulBytesLeft)) +
  1921.                                 CAST_TO_INT64 ulActualTSRollOver * CAST_TO_INT64 MAX_UINT32;
  1922.             HX_ASSERT(llActualStartTime - m_llLastWriteTime < MAX_TIMESTAMP_GAP);
  1923.             if (llActualStartTime >= m_llLastWriteTime && 
  1924.                 llActualStartTime - m_llLastWriteTime >= CAST_TO_INT64 m_ulGranularity)
  1925.             {
  1926. //{FILE* f1 = ::fopen("e:\MixData.txt", "a+"); ::fprintf(f1, "%lut%pt%lut%lun", HX_GET_BETTERTICKCOUNT(), this, (UINT32)llActualStartTime, (UINT32)m_llLastWriteTime);::fclose(f1);}
  1927.                 break;
  1928.             }
  1929.             /*Calculate the actual time where to write from*/
  1930.             ULONG32 ulBytesDiff = 0;
  1931.             if (llActualStartTime >= m_llLastWriteTime)
  1932.             {
  1933.                 ulBytesDiff = CalcOffset(m_llLastWriteTime, llActualStartTime);
  1934.                 ulBytesDiff = ulBytesDiff - (ulBytesDiff % (2*m_AudioFmt.uChannels));
  1935.                 
  1936.                 if (m_bChannelConvert && bMonoToStereoMayBeConverted)
  1937.                 {
  1938.                     ulBytesDiff *= 2;
  1939.                     /* This check is needed to account for lost packets.
  1940.                      * If there are more than one packet missing in a row,
  1941.                      * we may get multiple packets with TIMED_AUDIO flag
  1942.                      * and they may be far apart in time to be written 
  1943.                      * in this block
  1944.                      */
  1945.                     if (ulDestinationOffset + ulBytesDiff > ulBufLen*2)
  1946.                     {
  1947.                         bLastWriteTimeToBeUpdated = FALSE;
  1948.                         m_llLastWriteTime += 
  1949.                             CalcMs((ulBufLen*2 - ulDestinationOffset)/2);
  1950.                         break;
  1951.                     }
  1952.                 }
  1953.                 else
  1954.                 {
  1955.                     /* This check is needed to account for lost packets.
  1956.                      * If there are more than one packet missing in a row,
  1957.                      * we may get multiple packets with TIMED_AUDIO flag
  1958.                      * and they may be far apart in time to be written 
  1959.                      * in this block
  1960.                      */
  1961.                     if (ulDestinationOffset + ulBytesDiff > ulBufLen)
  1962.                     {
  1963.                         bLastWriteTimeToBeUpdated = FALSE;
  1964.                         m_llLastWriteTime += 
  1965.                             CalcMs(ulBufLen - ulDestinationOffset);
  1966.                         break;
  1967.                     }
  1968.                 }
  1969.                 ulDestinationOffset += ulBytesDiff;
  1970.             }
  1971.             else
  1972.             {
  1973.                 ulBytesDiff = CalcOffset(llActualStartTime, m_llLastWriteTime);
  1974.                 /* Make sure that it is at even byte boundary */
  1975.                 ulBytesDiff     = ulBytesDiff - (ulBytesDiff % (2*m_AudioFmt.uChannels));
  1976.                 if (pInfo->ulBytesLeft >= ulBytesDiff)
  1977.                 {
  1978.                     pInfo->pOffset          += ulBytesDiff;
  1979.                     pInfo->ulBytesLeft  -= ulBytesDiff;
  1980.                 }
  1981.                 else
  1982.                 {
  1983.                     pInfo->pOffset          += pInfo->ulBytesLeft;
  1984.                     pInfo->ulBytesLeft   = 0;
  1985.                 }
  1986.             }
  1987.         }
  1988.         /* just place it at the end of the last write position */
  1989.         ULONG32 ulNumMoreBytesToWrite = 0;
  1990.         if (m_bChannelConvert && bMonoToStereoMayBeConverted)
  1991.         {
  1992.             ulNumMoreBytesToWrite = (ulBufLen*2-ulDestinationOffset)/2;
  1993.         }
  1994.         else
  1995.         {
  1996.             ulNumMoreBytesToWrite = ulBufLen-ulDestinationOffset;
  1997.         }
  1998.         ulNumBytes = pInfo->ulBytesLeft > ulNumMoreBytesToWrite ? 
  1999.                      ulNumMoreBytesToWrite : pInfo->ulBytesLeft;
  2000.         // /////////////////////////////////////////////////////////////
  2001.         // Mix the data into the stream buffer, with stream volume. Don't 
  2002.         // do volume calculation if volume is 1. If volume is 0, then 
  2003.         // don't mix. Don't mix if there are no bytes to mix.
  2004.         if  (m_uVolume > 0 &&  ulNumBytes > 0)
  2005.         {
  2006.             if (m_bChannelConvert && bMonoToStereoMayBeConverted)
  2007.             {
  2008.                 HX_ASSERT(ulDestinationOffset + ulNumBytes*2 <= ulBufLen*2);
  2009.             }
  2010.             else
  2011.             {
  2012.                 HX_ASSERT(ulDestinationOffset + ulNumBytes <= ulBufLen);
  2013.             }
  2014.             /* we will actually make bIsMixBufferDirty dirty at the end of this function */
  2015.             BOOL bLocalDirty = bIsMixBufferDirty;
  2016. #if defined(HELIX_FEATURE_MIXER)
  2017.             CHXMixer::MixBuffer(pInfo->pOffset, pDestBuf+ulDestinationOffset, 
  2018.                                  ulNumBytes, m_bChannelConvert && bMonoToStereoMayBeConverted,
  2019.                                  m_uVolume, m_AudioFmt.uBitsPerSample, bLocalDirty);
  2020. #else
  2021.             ::memcpy(pDestBuf+ulDestinationOffset, pInfo->pOffset, ulNumBytes); /* Flawfinder: ignore */
  2022.             bLocalDirty = TRUE;
  2023. #endif /* HELIX_FEATURE_MIXER */
  2024.         }
  2025.         ULONG32 ulActuallyBytesWritten = ulNumBytes;
  2026.         ulActuallyBytesWritten = ((m_bChannelConvert && bMonoToStereoMayBeConverted) ?
  2027.             ulActuallyBytesWritten*2 : ulActuallyBytesWritten);
  2028.         if (ulNumBytesWritten < ulActuallyBytesWritten + ulDestinationOffset)
  2029.         {
  2030.             ulNumBytesWritten = ulActuallyBytesWritten + ulDestinationOffset;
  2031.         }
  2032.         ulDestinationOffset += ulActuallyBytesWritten;
  2033.         pInfo->ulBytesLeft  -= ulNumBytes;
  2034.         pInfo->pOffset      += ulNumBytes;
  2035.         INT64 llLastWriteTime = 0;
  2036.         
  2037.         llLastWriteTime = CAST_TO_INT64 (pInfo->ulStartTime) + 
  2038.                           CAST_TO_INT64 (CalcMs(pInfo->pBuffer->GetSize() - pInfo->ulBytesLeft)) +
  2039.                           CAST_TO_INT64 ulActualTSRollOver * CAST_TO_INT64 MAX_UINT32;
  2040.         if (bLastWriteTimeToBeUpdated)
  2041.         {
  2042.             m_llLastStartTimePlayed = llLastWriteTime - CalcMs(ulNumBytes);
  2043.         }
  2044.         bLastWriteTimeToBeUpdated = FALSE;
  2045.         if (m_llLastWriteTime < llLastWriteTime)
  2046.         {
  2047.             m_llLastWriteTime = llLastWriteTime;
  2048.         }
  2049.         if (pInfo->ulBytesLeft == 0)
  2050.         {
  2051.             FreeInfo(pInfo);
  2052.             m_pDataList->RemoveAt(lastlp);
  2053.         }
  2054.         /* Have we written enough for this time? */
  2055.         if (ulBufLen == ulDestinationOffset ||
  2056.             (m_bChannelConvert && bMonoToStereoMayBeConverted &&
  2057.             (ulBufLen*2 == ulDestinationOffset)))
  2058.         {
  2059.             break;
  2060.         }
  2061.     }
  2062.     if (bLastWriteTimeToBeUpdated)
  2063.     {
  2064.         m_llLastWriteTime += m_ulGranularity;
  2065.     }
  2066.     else /* We mixed some input bytes */
  2067.     {
  2068.         if (m_bRealAudioStream)
  2069.         {
  2070. //{FILE* f1 = ::fopen("c:\temp\rasync.txt", "a+"); ::fprintf(f1, "Call MapFudgedTimestamps: %lun", m_ulLastStartTimePlayed);::fclose(f1);}
  2071.             MapFudgedTimestamps();
  2072.         }
  2073.     }
  2074.     if (ulNumBytesWritten > 0 && m_uVolume > 0)
  2075.     {
  2076.         bIsMixBufferDirty = TRUE;
  2077.     }
  2078.     if (!bWasMixBufferDirty && ulNumBytesWritten < ulBufLen && bIsMixBufferDirty)
  2079.     {
  2080.         ::memset(pDestBuf+ulNumBytesWritten, 0, ulBufLen-ulNumBytesWritten);
  2081.     }
  2082.     return ulNumBytesWritten;
  2083. }
  2084. /************************************************************************
  2085.  *  Method:
  2086.  *              CHXAudioStream::CalcMs
  2087.  *      Purpose:
  2088.  *              Calculate the duration in millisecs for this number of bytes.
  2089.  */
  2090. ULONG32 CHXAudioStream::CalcMs
  2091. (
  2092.     ULONG32     ulNumBytes
  2093. )
  2094. {
  2095.     return ( (ULONG32) (( 1000.0 
  2096.                 / (m_AudioFmt.uChannels * ((m_AudioFmt.uBitsPerSample==8)?1:2) 
  2097.                 *  m_AudioFmt.ulSamplesPerSec) ) 
  2098.                 *  ulNumBytes) );
  2099. }
  2100. /************************************************************************
  2101.  *  Method:
  2102.  *              CHXAudioStream::CalcDeviceMs
  2103.  *      Purpose:
  2104.  *              Calculate the duration in millisecs for this number of 
  2105.  *              bytes in Device format.
  2106.  */
  2107. ULONG32 CHXAudioStream::CalcDeviceMs
  2108. (
  2109.     ULONG32     ulNumBytes
  2110. )
  2111. {
  2112.     return ( (ULONG32) (( 1000.0 
  2113.                 / (m_DeviceFmt.uChannels * ((m_DeviceFmt.uBitsPerSample==8)?1:2) 
  2114.                 *  m_DeviceFmt.ulSamplesPerSec) ) 
  2115.                 *  ulNumBytes) );
  2116. }
  2117. /************************************************************************
  2118.  *  Method:
  2119.  *              CHXAudioStream::CalcOffset
  2120.  *      Purpose:
  2121.  *              Calculate the offset in bytes given time.
  2122.  */
  2123. UINT32 CHXAudioStream::CalcOffset
  2124. (
  2125.     INT64 llStartTime
  2126. ,   INT64 llEndTime
  2127. )
  2128. {
  2129.     /* Using m_ulBytesPerMs may introduce cumulative error due 
  2130.      * to decimal cutoff 
  2131.      */
  2132.     HX_ASSERT(llEndTime - llStartTime < MAX_TIMESTAMP_GAP);
  2133.     return INT64_TO_UINT32((llEndTime - llStartTime) *  
  2134.                      (m_ulGranularity ? m_ulInputBytesPerGran*1./m_ulGranularity : 0));
  2135. }
  2136. void CHXAudioStream::FlushBuffers(BOOL bInstantaneousAlso)
  2137. {
  2138.     while (m_pDataList && m_pDataList->GetCount() > 0)
  2139.     {
  2140.         HXAudioInfo* pInfo = (HXAudioInfo*) m_pDataList->RemoveHead();
  2141.         FreeInfo(pInfo);
  2142.     }
  2143.     /* throw away any data in excess buffer for interpolator */
  2144.     m_ulPreviousExcessInterpBufferSize = 0;
  2145.     while (bInstantaneousAlso && m_pInstantaneousList && m_pInstantaneousList->GetCount() > 0)
  2146.     {
  2147.         CHXSimpleList* pList = (CHXSimpleList*) m_pInstantaneousList->RemoveHead();
  2148.         while (pList->GetCount() > 0)
  2149.         {
  2150.             HXAudioInfo* pInfo = (HXAudioInfo*) pList->RemoveHead();
  2151.             FreeInfo(pInfo, TRUE);
  2152.         }
  2153.         HX_DELETE(pList);
  2154.     }
  2155.     // reset m_bLastNMilliSecsToBeSaved so that we actually 
  2156.     // delete buffers in FreeInfo
  2157.     BOOL bLastNMilliSecsToBeSaved = m_bLastNMilliSecsToBeSaved;
  2158.     m_bLastNMilliSecsToBeSaved = FALSE;
  2159.     while (m_pLastNMilliSecsList && m_pLastNMilliSecsList->GetCount() > 0)
  2160.     {
  2161.         HXAudioInfo* pInfo = (HXAudioInfo*) m_pLastNMilliSecsList->RemoveHead();
  2162.         FreeInfo(pInfo);
  2163.     }
  2164.     m_bLastNMilliSecsToBeSaved = bLastNMilliSecsToBeSaved;
  2165.     HX_DELETE(m_pLastNMilliSecsList);
  2166. }
  2167. BOOL
  2168. CHXAudioStream::EnoughDataAvailable(ULONG32& ulLastWriteTime, ULONG32& ulNumMsRequired)
  2169. {
  2170.     ULONG32 ulBytesNeeded = 0;
  2171.     BOOL    bAvailable = TRUE;
  2172.         // /////////////////////////////////////////////////////////////
  2173.     // If no  resampling, mix stream data directly into the player
  2174.     // buffer.
  2175.     if ( !m_pResampler)
  2176.     {
  2177.         ulBytesNeeded   = m_ulInputBytesPerGran;
  2178.     }
  2179.     // /////////////////////////////////////////////////////////////
  2180.     // If resampling, mix stream data into a tmp buffer. Then
  2181.     // resample this buffer and mix the final resampled buffer into
  2182.     // the player buffer.
  2183.     else
  2184.     {
  2185.         /* 
  2186.          * Audio Session will always ask for m_ulOutputBytesPerGran bytes to be mixed
  2187.          * in MixIntoBuffer() call. So we need to produce these many number of bytes.
  2188.          * If there is any mono-stereo conversion that happens in the mixing, number
  2189.          * of output bytes required from the resampler are half the number of 
  2190.          * m_ulOutputBytesPerGran bytes.
  2191.          */
  2192.         ULONG32 ulMaxFramesOut = m_ulOutputBytesPerGran/(m_DeviceFmt.uBitsPerSample==8 ? 1 : 2);
  2193.         
  2194.         if (m_DeviceFmt.uChannels == 2)
  2195.         {
  2196.             ulMaxFramesOut /= 2;
  2197.         }
  2198.         ULONG32 ulMaxFramesIn = m_pResampler->Requires(ulMaxFramesOut);
  2199.         ulBytesNeeded = ulMaxFramesIn *  ((m_AudioFmt.uBitsPerSample==8)? 1 : 2)
  2200.                                         * m_AudioFmt.uChannels;
  2201.     }
  2202.     ULONG32         ulBytesAvailable    = 0;
  2203.     LISTPOSITION    lp                  = m_pDataList->GetHeadPosition();
  2204.     while(lp)
  2205.     {
  2206.         HXAudioInfo* pInfo  = (HXAudioInfo*) m_pDataList->GetNext(lp);
  2207.         ulBytesAvailable += pInfo->ulBytesLeft;
  2208.         if ((pInfo->ulStartTime >= INT64_TO_UINT32(m_llLastWriteTime+m_ulGranularity)) ||
  2209.             ulBytesAvailable >= ulBytesNeeded)
  2210.         {
  2211.             return TRUE;
  2212.         }
  2213.     }
  2214.     ulNumMsRequired = CalcMs(ulBytesNeeded - ulBytesAvailable);
  2215.     UINT32  ulAdjustedLastWriteTime = INT64_TO_UINT32(m_llLastWriteTime - CAST_TO_INT64 m_ulTSRollOver * CAST_TO_INT64 MAX_UINT32);
  2216.     HX_ASSERT(ulAdjustedLastWriteTime + m_ulGranularity >= ulNumMsRequired);
  2217.     if (ulAdjustedLastWriteTime + m_ulGranularity >= ulNumMsRequired)
  2218.     {
  2219.         ulLastWriteTime = ulAdjustedLastWriteTime + m_ulGranularity - ulNumMsRequired;
  2220.     }
  2221.     else
  2222.     {
  2223.         ulLastWriteTime = 0;
  2224.     }
  2225.     return FALSE;
  2226. }
  2227. void            
  2228. CHXAudioStream::SetLive(BOOL bIsLive) 
  2229. {   
  2230.     if (m_bIsFirstPacket)
  2231.     {
  2232.         m_bIsLive = bIsLive;
  2233.     }
  2234. }
  2235. HX_RESULT    
  2236. CHXAudioStream::StartCrossFade(CHXAudioStream*  pFromStream, 
  2237.                                UINT32           ulCrossFadeStartTime,
  2238.                                UINT32           ulCrossFadeDuration, 
  2239.                                BOOL             bToStream)
  2240. {
  2241. #if defined(HELIX_FEATURE_CROSSFADE)
  2242.     if (m_bCrossFadingToBeDone)
  2243.     {
  2244.         return HXR_UNEXPECTED;
  2245.     }
  2246.     HX_RELEASE(m_pCrossFadeStream);
  2247.     m_bCrossFadingToBeDone  = TRUE;
  2248.     m_pCrossFadeStream      = pFromStream;
  2249.     m_pCrossFadeStream->AddRef();
  2250.     m_llCrossFadeStartTime  = CAST_TO_INT64 ulCrossFadeStartTime;
  2251.     m_ulCrossFadeDuration   = ulCrossFadeDuration;
  2252.     m_bFadeToThisStream     = bToStream;
  2253.     if (m_bInited && m_bFadeToThisStream)
  2254.     {
  2255.         InitializeCrossFader();
  2256.     }
  2257.     
  2258.     return HXR_OK;
  2259. #else
  2260.     return HXR_NOTIMPL;
  2261. #endif /* HELIX_FEATURE_CROSSFADE */
  2262. }
  2263. void
  2264. CHXAudioStream::InitializeCrossFader(void)
  2265. {
  2266. #if defined(HELIX_FEATURE_CROSSFADE)
  2267.     if (!m_pCrossFader)
  2268.     {
  2269.         m_pCrossFader = new CrossFader;
  2270.     }
  2271.     UINT16 uNumSamplesToFade = (UINT16)
  2272.         (m_DeviceFmt.ulSamplesPerSec * m_ulCrossFadeDuration/1000);
  2273.     /* Make cross-fade duration to land on a sample boundary */
  2274.     m_ulCrossFadeDuration = (uNumSamplesToFade * 1000)/
  2275.                                 m_DeviceFmt.ulSamplesPerSec;
  2276.     HX_ASSERT(m_ulCrossFadeDuration > 0 && uNumSamplesToFade > 0);
  2277.     m_pCrossFader->Initialize(uNumSamplesToFade, m_DeviceFmt.uChannels);
  2278. #endif /* HELIX_FEATURE_CROSSFADE */
  2279. }
  2280. /*
  2281.  *  IHXRealAudioSync methods
  2282.  */
  2283. /************************************************************************
  2284.  *  Method:
  2285.  *      IHXRealAudioSync::Register
  2286.  *  Purpose:
  2287.  */
  2288. STDMETHODIMP
  2289. CHXAudioStream::Register(void)
  2290. {
  2291. #if defined _DEBUG && defined HELIX_FEATURE_AUDIO_MULTIPLAYER_PAUSE 
  2292.     if (HXDebugOptionEnabled("zDoNotUseFudge"))
  2293.     {
  2294.         return HXR_OK;
  2295.     }
  2296. #endif
  2297.     if (m_bRealAudioStream)
  2298.     {
  2299.         return HXR_UNEXPECTED;
  2300.     }
  2301.     m_bRealAudioStream = TRUE;
  2302.     m_Owner->RegisterRealAudioStream(this);
  2303.     if (!m_pRAByToTsInList)
  2304.     {
  2305.         m_pRAByToTsInList       = new CHXSimpleList;
  2306.         m_pRAByToTsAdjustedList = new CHXSimpleList;
  2307.     }
  2308.     return HXR_OK;
  2309. }
  2310. /************************************************************************
  2311.  *  Method:
  2312.  *      IHXRealAudioSync::UnRegister
  2313.  *  Purpose:
  2314.  */
  2315. STDMETHODIMP
  2316. CHXAudioStream::UnRegister(void)
  2317. {
  2318. #if defined _DEBUG && defined HELIX_FEATURE_AUDIO_MULTIPLAYER_PAUSE 
  2319.     if (HXDebugOptionEnabled("zDoNotUseFudge"))
  2320.     {
  2321.         return HXR_OK;
  2322.     }
  2323. #endif
  2324.     if (!m_bRealAudioStream)
  2325.     {
  2326.         return HXR_UNEXPECTED;
  2327.     }
  2328.     m_bRealAudioStream = FALSE;
  2329.     m_Owner->UnRegisterRealAudioStream(this);
  2330.     CleanupRAByToTs();
  2331.     return HXR_OK;
  2332. }
  2333. /************************************************************************
  2334.  *  Method:
  2335.  *      IHXRealAudioSync::FudgeTimestamp
  2336.  *  Purpose:
  2337.  *      Tell the audio stream about the relationship between the number 
  2338.  *      of bytes written to the actual timestamp.
  2339.  *          
  2340.  */
  2341. STDMETHODIMP
  2342. CHXAudioStream::FudgeTimestamp(UINT32 /*IN*/ ulNumberofBytes,
  2343.                                UINT32 /*IN*/ ulTimestamp)
  2344. {
  2345. #if defined _DEBUG && defined HELIX_FEATURE_AUDIO_MULTIPLAYER_PAUSE 
  2346.     if (HXDebugOptionEnabled("zDoNotUseFudge"))
  2347.     {
  2348.         return HXR_OK;
  2349.     }
  2350. #endif
  2351.     RealAudioBytesToTimeStamp* pByToTs = 
  2352.         new RealAudioBytesToTimeStamp;
  2353.     pByToTs->m_ulTimestamp      = ulTimestamp;
  2354.     pByToTs->m_ulInTimestamp    = m_ulLastInputStartTime;
  2355.     pByToTs->m_ulInEndTime      = m_ulLastInputEndTime;
  2356.     if (m_bIsLive && m_ulBaseTime > 0)
  2357.     {
  2358.         pByToTs->m_ulTimestamp  += m_ulLiveDelay;
  2359.         if (pByToTs->m_ulTimestamp > m_ulBaseTime)
  2360.         {
  2361.             pByToTs->m_ulTimestamp -= m_ulBaseTime;
  2362.         }
  2363.         else
  2364.         {
  2365.             pByToTs->m_ulTimestamp  = 0;
  2366.         }
  2367.     }
  2368.     pByToTs->m_ulOrigTimestamp  = pByToTs->m_ulTimestamp;
  2369.     m_pRAByToTsInList->AddTail((void*) pByToTs);
  2370. //{FILE* f1 = ::fopen("d:\temp\audio.txt", "a+"); ::fprintf(f1, "Fudge:t%lut%lun", ulTimestamp, m_ulLastInputStartTime);::fclose(f1);}
  2371.     return HXR_OK;
  2372. }
  2373. void
  2374. CHXAudioStream::CleanupRAByToTs(void)
  2375. {
  2376.     if (!m_pRAByToTsInList)
  2377.     {
  2378.         return;
  2379.     }
  2380.     CHXSimpleList::Iterator ndx = m_pRAByToTsInList->Begin();
  2381.     for (; ndx != m_pRAByToTsInList->End(); ++ndx)
  2382.     {
  2383.         RealAudioBytesToTimeStamp* pByToTs = 
  2384.             (RealAudioBytesToTimeStamp*) (*ndx);
  2385.         delete pByToTs;
  2386.     }
  2387.     m_pRAByToTsInList->RemoveAll();
  2388.     ndx = m_pRAByToTsAdjustedList->Begin();
  2389.     for (; ndx != m_pRAByToTsAdjustedList->End(); ++ndx)
  2390.     {
  2391.         RealAudioBytesToTimeStamp* pByToTs = 
  2392.             (RealAudioBytesToTimeStamp*) (*ndx);
  2393.         delete pByToTs;
  2394.     }
  2395.     m_pRAByToTsAdjustedList->RemoveAll();
  2396. }
  2397. HX_RESULT
  2398. CHXAudioStream::ConvertCurrentTime(double dBytesPlayed, 
  2399.                                    UINT32 ulCurrentTime, 
  2400.                                    UINT32& ulAdjustedTime)
  2401. {
  2402. //    return HXR_FAIL;
  2403.     HX_ASSERT(m_bRealAudioStream);
  2404.     ulAdjustedTime  = ulCurrentTime;
  2405.     LISTPOSITION posRABytes = m_pRAByToTsAdjustedList->GetHeadPosition();
  2406.     BOOL         bIsDone    = FALSE;
  2407.     RealAudioBytesToTimeStamp* pByToTsLower = NULL;
  2408.     RealAudioBytesToTimeStamp* pByToTsHigher = NULL;
  2409.     INT64   llActualByToTsHigherTimestamp = 0;
  2410.     INT64   llActualByToTsLowerTimestamp =0;
  2411.     while(posRABytes)
  2412.     {
  2413.         RealAudioBytesToTimeStamp* pByToTs = (RealAudioBytesToTimeStamp*) 
  2414.                             m_pRAByToTsAdjustedList->GetAt(posRABytes);
  2415.         if (dBytesPlayed >= pByToTs->m_ulOutNumBytes)
  2416.         {
  2417.             pByToTsLower = pByToTs;
  2418.         }
  2419.         else
  2420.         {
  2421.             if (pByToTsLower)
  2422.             {
  2423.                 pByToTsHigher = pByToTs;
  2424.             }
  2425.             else
  2426.             {
  2427.                 /* It means that this stream was added mid-presentation and we have not yet 
  2428.                  * played any bits from this stream. Maintain the current time and do not
  2429.                  * fudge it.
  2430.                  */
  2431.                 return HXR_OK;
  2432.             }
  2433.         }
  2434.         if (pByToTsLower && pByToTsHigher)
  2435.         {
  2436.             break;
  2437.         }
  2438.         m_pRAByToTsAdjustedList->GetNext(posRABytes);
  2439.     }
  2440.     /* We got a range, interpolate */
  2441.     if (pByToTsLower && pByToTsHigher)
  2442.     {
  2443. //{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);}
  2444.         /* Need to re-visit this ASSERT. A check will do for now */
  2445. #if 0
  2446.         HX_ASSERT((pByToTsHigher->m_ulTimestamp >= 
  2447.                    pByToTsLower->m_ulTimestamp) &&
  2448.                   (pByToTsHigher->m_ulOutNumBytes >= 
  2449.                    pByToTsLower->m_ulOutNumBytes));
  2450. #endif
  2451.         llActualByToTsHigherTimestamp = CAST_TO_INT64 (pByToTsHigher->m_ulTimestamp) + CAST_TO_INT64 m_ulTSRollOver * CAST_TO_INT64 MAX_UINT32;
  2452.         llActualByToTsLowerTimestamp = CAST_TO_INT64 (pByToTsLower->m_ulTimestamp) + CAST_TO_INT64 m_ulTSRollOver * CAST_TO_INT64 MAX_UINT32;
  2453.         if ((llActualByToTsHigherTimestamp >= llActualByToTsLowerTimestamp) &&
  2454.             (pByToTsHigher->m_ulOutNumBytes >= pByToTsLower->m_ulOutNumBytes))
  2455.         {
  2456.             ulAdjustedTime = pByToTsLower->m_ulTimestamp +
  2457.                          (UINT32) (((dBytesPlayed - pByToTsLower->m_ulOutNumBytes)*1./
  2458.                          (pByToTsHigher->m_ulOutNumBytes - 
  2459.                           pByToTsLower->m_ulOutNumBytes)) *
  2460.                           INT64_TO_UINT32(llActualByToTsHigherTimestamp - 
  2461.                           llActualByToTsLowerTimestamp));
  2462. //{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);}
  2463.         }
  2464.         else 
  2465.         {
  2466.             ulAdjustedTime = pByToTsLower->m_ulTimestamp;
  2467. //{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);}
  2468.         }
  2469. //{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);}
  2470.     }
  2471.     /* The best we can do is return the time of the nearest map */
  2472.     else if (pByToTsLower)
  2473.     {
  2474.         ulAdjustedTime = pByToTsLower->m_ulTimestamp;
  2475.         double dBytesDiff = dBytesPlayed - pByToTsLower->m_ulOutNumBytes;
  2476.         if (dBytesDiff > 0)
  2477.         {
  2478.             double dNumBytes = m_Owner->ConvertMsToBytes(pByToTsLower->m_ulDuration);
  2479.             if (dBytesDiff >= dNumBytes)
  2480.             {
  2481.                 ulAdjustedTime += pByToTsLower->m_ulDuration;
  2482.             }
  2483.             else
  2484.             {
  2485.                 ulAdjustedTime += (UINT32) (pByToTsLower->m_ulDuration * dBytesDiff *1./dNumBytes);
  2486.             }
  2487.         }
  2488. //{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);}
  2489.     }
  2490.     /* Remove all maps before pByToTsLower */
  2491.     posRABytes = m_pRAByToTsAdjustedList->GetHeadPosition();
  2492.     while(posRABytes)
  2493.     {
  2494.         RealAudioBytesToTimeStamp* pByToTs = 
  2495.             (RealAudioBytesToTimeStamp*) m_pRAByToTsAdjustedList->GetAt(posRABytes);
  2496.         if (pByToTs != pByToTsLower)
  2497.         {
  2498. //{FILE* f1 = ::fopen("d:\temp\rasync.txt", "a+"); ::fprintf(f1, "Delete: OutBytes: %f OutTS: %lun", pByToTs->m_ulOutNumBytes, pByToTs->m_ulTimestamp);::fclose(f1);}
  2499.             delete pByToTs;
  2500.             posRABytes = m_pRAByToTsAdjustedList->RemoveAt(posRABytes);
  2501.         }
  2502.         else
  2503.         {
  2504.             break;
  2505.         }
  2506.     }
  2507. //{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);}
  2508.     return HXR_OK;
  2509. }
  2510. void
  2511. CHXAudioStream::MapFudgedTimestamps(void)
  2512. {
  2513.     LISTPOSITION    posRABytes = m_pRAByToTsInList->GetHeadPosition();
  2514.     INT64           llActualByToTsInEndTime = 0;
  2515.     INT64           llActualByToTsInStartTime = 0;
  2516.     while(posRABytes)
  2517.     {
  2518.         RealAudioBytesToTimeStamp* pByToTs = 
  2519.             (RealAudioBytesToTimeStamp*) m_pRAByToTsInList->GetAt(posRABytes);
  2520.         llActualByToTsInStartTime = CAST_TO_INT64 (pByToTs->m_ulInTimestamp) + CAST_TO_INT64 m_ulTSRollOver * CAST_TO_INT64 MAX_UINT32;
  2521.         llActualByToTsInEndTime = CAST_TO_INT64 (pByToTs->m_ulInEndTime) + CAST_TO_INT64 m_ulTSRollOver * CAST_TO_INT64 MAX_UINT32;
  2522.         /* Too late */
  2523.         if (llActualByToTsInEndTime < m_llLastStartTimePlayed)
  2524.         {
  2525.             posRABytes = m_pRAByToTsInList->RemoveAt(posRABytes);
  2526.             delete pByToTs;
  2527.         }
  2528.         else if (llActualByToTsInStartTime <= m_llLastStartTimePlayed
  2529.                 /*&& pByToTs->m_ulInEndTime >= m_ulLastStartTimePlayed*/)
  2530.         {
  2531.             /* These two values will be used in determining what time it is */
  2532.             // Number of bytes that have been written to the audio device till now*/
  2533.             pByToTs->m_ulOutNumBytes = m_Owner->NumberOfBytesWritten();
  2534.             HX_ASSERT(m_llLastStartTimePlayed - llActualByToTsInStartTime < MAX_TIMESTAMP_GAP);
  2535.             /* Interpolate */
  2536.             UINT32 ulTimeDiff = INT64_TO_UINT32(m_llLastStartTimePlayed - llActualByToTsInStartTime);
  2537.             pByToTs->m_ulTimestamp += ulTimeDiff;
  2538.             
  2539.             pByToTs->m_ulDuration   = INT64_TO_UINT32((llActualByToTsInEndTime - 
  2540.                                        llActualByToTsInStartTime) - CAST_TO_INT64 ulTimeDiff);
  2541.                                       
  2542.             posRABytes = m_pRAByToTsInList->RemoveAt(posRABytes);
  2543.             m_pRAByToTsAdjustedList->AddTail(pByToTs);
  2544. //{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);}
  2545.         }
  2546.         else
  2547.         {
  2548.             break;
  2549.         }
  2550.     }
  2551. }
  2552. void
  2553. CHXAudioStream::RemoveExcessCrossFadeData()
  2554. {
  2555. #if defined(HELIX_FEATURE_CROSSFADE)
  2556.     HXAudioInfo*    pInfo = (HXAudioInfo*) m_pDataList->GetHead();
  2557.     INT64           llStartTime  = 0;
  2558.     INT64           llEndTime    = 0;
  2559.     LISTPOSITION lp = m_pDataList->GetHeadPosition();
  2560.     while(lp)
  2561.     {
  2562.         UINT32  ulActualTSRollOver = m_ulTSRollOver;
  2563.         pInfo = (HXAudioInfo*) m_pDataList->GetAt(lp);
  2564.         if (pInfo->ulStartTime > m_ulLastInputStartTime &&
  2565.             ((pInfo->ulStartTime - m_ulLastInputStartTime) > MAX_TIMESTAMP_GAP))
  2566.         {
  2567.             ulActualTSRollOver--;
  2568.         }
  2569.         llStartTime     = CAST_TO_INT64 (pInfo->ulStartTime) + 
  2570.                           CAST_TO_INT64 (CalcMs(pInfo->pBuffer->GetSize() - pInfo->ulBytesLeft)) +
  2571.                           CAST_TO_INT64 ulActualTSRollOver * CAST_TO_INT64 MAX_UINT32;
  2572.         llEndTime       = CAST_TO_INT64 (pInfo->ulStartTime) + 
  2573.                           CAST_TO_INT64 (CalcMs(pInfo->pBuffer->GetSize())) +
  2574.                           CAST_TO_INT64 ulActualTSRollOver * CAST_TO_INT64 MAX_UINT32;
  2575.         /* Do we have to remove this block completely */
  2576.         if (llEndTime < m_llCrossFadeStartTime)
  2577.         {
  2578.             lp = m_pDataList->RemoveAt(lp);
  2579.             FreeInfo(pInfo);
  2580.         }
  2581.         /* Remove some part of the block internally */
  2582.         else if (llStartTime <= m_llCrossFadeStartTime 
  2583.                  /* && ulEndTime >= m_ulCrossFadeStartTime */)
  2584.         {
  2585.             UINT32 ulBytesToDiscard = 
  2586.                     CalcOffset(llStartTime, m_llCrossFadeStartTime);
  2587.             /* Make sure that it is at even byte boundary */
  2588.             ulBytesToDiscard    -= (ulBytesToDiscard % (2*m_AudioFmt.uChannels));
  2589.             if (pInfo->ulBytesLeft > ulBytesToDiscard)
  2590.             {
  2591.                 pInfo->ulBytesLeft -= ulBytesToDiscard;
  2592.                 pInfo->pOffset     += ulBytesToDiscard;
  2593.                 
  2594.                 /* Make it TIME_AUDIO since this would be the first block 
  2595.                  * written during cross-fade for *TO* stream.
  2596.                  */
  2597.                 if (m_bFadeToThisStream)
  2598.                 {
  2599.                     pInfo->uAudioStreamType = TIMED_AUDIO;
  2600.                 }
  2601.                 break;
  2602.             }
  2603.             else
  2604.             {
  2605.                 /* It is legal to happen with a *to* stream */
  2606.                 if (!m_bFadeToThisStream)
  2607.                 {
  2608.                     /* Something is screwed up here */
  2609.                     HX_ASSERT(FALSE);
  2610.                 }
  2611.                 pInfo->ulBytesLeft = 0;
  2612.                 lp = m_pDataList->RemoveAt(lp);
  2613.                 FreeInfo(pInfo);
  2614.             }
  2615.         }
  2616.         else
  2617.         {
  2618.             /* Not enough data */
  2619.             /* It is legal to happen with a *to* stream */
  2620.             if (!m_bFadeToThisStream)
  2621.             {
  2622.                 /* Something is screwed up here */
  2623.                 HX_ASSERT(FALSE);
  2624.             }
  2625.             break;
  2626.         }
  2627.     }
  2628. #endif /* HELIX_FEATURE_CROSSFADE */
  2629. }
  2630. void    
  2631. CHXAudioStream::SyncStream(INT64 llSyncTime)
  2632. {
  2633.     m_llLastWriteTime = llSyncTime;
  2634. }
  2635. void
  2636. CHXAudioStream::UpdateStreamLastWriteTime(BOOL bForceUpdate /*= FALSE*/)
  2637. {
  2638.     if (m_bLastWriteTimeUpdated)
  2639.     {
  2640.         return;
  2641.     }
  2642.     m_bLastWriteTimeUpdated = TRUE;
  2643.     if (m_bIsLive)
  2644.     {
  2645.         if (!m_pValues || m_pValues->GetPropertyULONG32("LiveSyncStartTime", m_ulBaseTime) != HXR_OK)
  2646.         {
  2647.             if (bForceUpdate)
  2648.             {
  2649.                 m_bIsLive = FALSE;
  2650.                 m_ulBaseTime = 0;
  2651.                 m_llLastWriteTime = m_Owner->GetLastAudioWriteTime();
  2652.             }
  2653.             else
  2654.             {
  2655.                 /* 
  2656.                  * do not set it yet.. we will wait till the first
  2657.                  * AddData call 
  2658.                  */
  2659.                 m_bLastWriteTimeUpdated = FALSE;
  2660.             }
  2661.         }
  2662.         else
  2663.         {
  2664.             m_pValues->GetPropertyULONG32("Delay", m_ulLiveDelay);
  2665.             INT64 llLastPlayerWriteTime = m_Owner->GetLastAudioWriteTime();
  2666.             if (m_ulLiveDelay > 0 && 
  2667.                 CAST_TO_INT64  m_ulLiveDelay > llLastPlayerWriteTime &&
  2668.                 m_ulBaseTime > INT64_TO_UINT32(CAST_TO_INT64  m_ulLiveDelay-llLastPlayerWriteTime))
  2669.             {
  2670.                 m_llLastWriteTime   = CAST_TO_INT64 (m_ulBaseTime - 
  2671.                                         INT64_TO_UINT32(CAST_TO_INT64  m_ulLiveDelay-llLastPlayerWriteTime));
  2672.             }
  2673.             else
  2674.             {
  2675.                 m_llLastWriteTime   = CAST_TO_INT64  m_ulBaseTime;
  2676.             }
  2677.         }
  2678.     }
  2679.     else
  2680.     {
  2681.         // XXX HP
  2682.         //
  2683.         // Prolbem: 
  2684.         // when rewinding audio data upon resume, the audio-push-down worth of data
  2685.         // would be missing when the stream's first resume is at the middle of playback,
  2686.         // 
  2687.         // Solution: 
  2688.         // we need to adjust the m_llLastWriteTime to the last audio player write time
  2689.         if (m_Owner->IsResumed() && !m_bIsResumed)
  2690.         {
  2691.             m_llLastWriteTime = m_Owner->GetLastAudioWriteTime();
  2692.         }
  2693.     }
  2694. }
  2695. void
  2696. CHXAudioStream::SaveLastNMilliSeconds(BOOL bSave, UINT32 ulNMilliSeconds)
  2697. {
  2698.     m_bLastNMilliSecsToBeSaved  = bSave; // TRUE;       //
  2699.     m_ulLastNMilliSeconds       = ulNMilliSeconds; // 2000;//
  2700.     HX_ASSERT(!m_bLastNMilliSecsToBeSaved || m_ulLastNMilliSeconds > 0);
  2701.     // ensure we need to save for atleast 1 sec
  2702.     if (m_bLastNMilliSecsToBeSaved && m_ulLastNMilliSeconds < 1000)
  2703.     {
  2704.         m_ulLastNMilliSeconds = 1000;
  2705.     }
  2706.     if (!m_bLastNMilliSecsToBeSaved)
  2707.     {
  2708.         while (m_pLastNMilliSecsList && m_pLastNMilliSecsList->GetCount() > 0)
  2709.         {
  2710.             HXAudioInfo* pInfo = (HXAudioInfo*) m_pLastNMilliSecsList->RemoveHead();
  2711.             FreeInfo(pInfo);
  2712.         }
  2713.         HX_DELETE(m_pLastNMilliSecsList);
  2714.     }
  2715. }
  2716. void
  2717. CHXAudioStream::RewindStream(UINT32 ulTimeToRewind)
  2718. {
  2719.     HX_ASSERT(m_bLastNMilliSecsToBeSaved);
  2720.     if (!m_bCanBeRewound)
  2721.     {
  2722.         return;
  2723.     }
  2724.     if (m_bLastNMilliSecsToBeSaved && m_pLastNMilliSecsList)
  2725.     {
  2726.         HX_ASSERT(m_llLastWriteTime >= ulTimeToRewind);
  2727.         if (m_llLastWriteTime >= ulTimeToRewind)
  2728.         {
  2729.             m_llLastWriteTime -= ulTimeToRewind;
  2730.         }
  2731.         else
  2732.         {
  2733.             m_llLastWriteTime = 0;
  2734.         }
  2735.         HXAudioInfo* pInfo = NULL;
  2736.         // reset any pInfo's in data list that may have been partially used.
  2737.         CHXSimpleList::Iterator ndx = m_pDataList->Begin();
  2738.         for (; ndx != m_pDataList->End(); ++ndx)
  2739.         {
  2740.             pInfo = (HXAudioInfo*) (*ndx);
  2741.             if (pInfo->ulBytesLeft  != pInfo->pBuffer->GetSize())
  2742.             {
  2743.                 pInfo->pOffset      = pInfo->pBuffer->GetBuffer();
  2744.                 pInfo->ulBytesLeft  = pInfo->pBuffer->GetSize();
  2745.             }
  2746.             else
  2747.             {
  2748.                 break;
  2749.             }
  2750.         }
  2751.         UINT32 ulLastWriteTime = INT64_TO_UINT32(m_llLastWriteTime - CAST_TO_INT64 m_ulTSRollOver * CAST_TO_INT64 MAX_UINT32);
  2752.         BOOL bTimedToBeSet = (m_pLastNMilliSecsList->GetCount() > 0);
  2753.         while (m_pLastNMilliSecsList->GetCount() > 0)
  2754.         {
  2755.             pInfo = (HXAudioInfo*) m_pLastNMilliSecsList->RemoveTail();
  2756.             m_pDataList->AddHead(pInfo);
  2757.             if (pInfo->ulStartTime <= ulLastWriteTime)
  2758.             {
  2759.                 break;
  2760.             }
  2761.         }
  2762.         if (bTimedToBeSet)
  2763.         {
  2764.             pInfo = (HXAudioInfo*) m_pDataList->GetHead();
  2765.             pInfo->uAudioStreamType = TIMED_AUDIO;
  2766.         }
  2767.         // remove remaining elements from the list
  2768.         while (m_pLastNMilliSecsList->GetCount() > 0)
  2769.         {
  2770.             pInfo = (HXAudioInfo*) m_pLastNMilliSecsList->RemoveHead();
  2771.             // delete the stored one
  2772.             HX_RELEASE(pInfo->pBuffer);
  2773.             HX_DELETE(pInfo);
  2774.         }
  2775. //{FILE* f1 = ::fopen("d:\temp\multi.txt", "a+"); ::fprintf(f1, "%p %p RewindStream %lu %lun", this, m_Owner, ulFirstAudioTime, m_llLastWriteTime);::fclose(f1);}
  2776.         // put back stuff from adjusted list to in list
  2777.         while (m_pRAByToTsAdjustedList && m_pRAByToTsAdjustedList->GetCount() > 0)
  2778.         {
  2779.             RealAudioBytesToTimeStamp* pByToTs = 
  2780.                 (RealAudioBytesToTimeStamp*) m_pRAByToTsAdjustedList->RemoveTail();
  2781.             // restore original fudge timestamp
  2782.             pByToTs->m_ulTimestamp = pByToTs->m_ulOrigTimestamp;
  2783.             m_pRAByToTsInList->AddHead(pByToTs);
  2784.         }
  2785.     }
  2786. }
  2787. void
  2788. CHXAudioStream::Pause(BOOL bPlayerPause)
  2789. {
  2790.     if (m_eState == E_PAUSED)
  2791.     {
  2792.         return;
  2793.     }
  2794.     m_eState = E_PAUSED;
  2795.     m_bCanBeRewound = FALSE;
  2796.     m_bPlayerPause = bPlayerPause;
  2797.     return;
  2798. }
  2799. void
  2800. CHXAudioStream::Resume(BOOL bPlayerResume)
  2801. {
  2802.     if (!m_bInited ||
  2803.         m_eState == E_PLAYING)
  2804.     {
  2805.         return;
  2806.     }
  2807.     UpdateStreamLastWriteTime();
  2808.     // add/resume audio stream on the fly
  2809.     if( m_Owner->IsResumed() )
  2810.     {
  2811.         
  2812.         if (m_eState != E_PAUSED        &&
  2813.             !m_bIsResumed               && 
  2814.             (!m_pDataList->IsEmpty() || !m_pInstantaneousList->IsEmpty()))
  2815.         {
  2816.             m_Owner->AudioStreamStateChanged(E_PLAYING);
  2817.             m_eState = E_PLAYING;
  2818.         }
  2819.         // whoever pause the stream is responsible for resuming the same
  2820.         // stream, the stream can either be paused specifically by the SMIL renderer
  2821.         // without pausing the playback or be paused by the AudioPlayer which
  2822.         // pauses the playback
  2823.         else if (!bPlayerResume || m_bPlayerPause)
  2824.         {
  2825.             m_eState = E_PLAYING;
  2826.         }
  2827.     }
  2828.     else
  2829.     {
  2830.         m_eState = E_PLAYING;
  2831.     }
  2832.     
  2833.     if (m_eState == E_PLAYING)
  2834.     {
  2835.         m_bCanBeRewound = TRUE;       
  2836.         m_bIsResumed = TRUE;
  2837.     }
  2838.  
  2839.     return;
  2840. }
  2841. void
  2842. CHXAudioStream::Seek(UINT32 ulSeekTime)
  2843. {
  2844.     m_llLastWriteTime   = CAST_TO_INT64 (m_ulBaseTime + ulSeekTime);
  2845.     m_bFirstWrite       = TRUE;
  2846.     m_bTobeTimed        = TRUE;
  2847.     m_ulTSRollOver      = 0;
  2848.     m_ulLastInputStartTime  = 0;
  2849.     m_ulLastInputEndTime    = 0;
  2850.     // Remove all buffers from auxlliary list. This means that a 
  2851.     // renderer must send all buffers again including those buffers
  2852.     // that start at time t way out there in the future.
  2853.     FlushBuffers();
  2854.     CleanupRAByToTs();
  2855.     
  2856.     /* Remove any cross-fading */
  2857.     m_bCrossFadingToBeDone  = FALSE;
  2858.     HX_RELEASE(m_pCrossFadeStream);
  2859.     // XXX HP what happen if this is called from the client core on
  2860.     //        IHXTrack::Seek()
  2861.     return;
  2862. }
  2863. void
  2864. CHXAudioStream::Stop(void)
  2865. {
  2866.     if (m_eState == E_STOPPED)
  2867.     {
  2868.         return;
  2869.     }
  2870.     m_eState = E_STOPPED;
  2871.     ResetStream();
  2872.     return;
  2873. }
  2874. void    
  2875. CHXAudioStream::SetAudioDeviceReflushHint(BOOL bSupported)
  2876. {
  2877.     m_bAudioDeviceReflushHint = bSupported;
  2878.     return;
  2879. }
  2880. void
  2881. CHXAudioStream::FreeInfo(HXAudioInfo* pInfo, BOOL bInstantaneous /* = FALSE */)
  2882. {
  2883.     if (m_bLastNMilliSecsToBeSaved && !bInstantaneous)
  2884.     {
  2885.         if (!m_pLastNMilliSecsList)
  2886.         {
  2887.             m_pLastNMilliSecsList       = new CHXSimpleList;
  2888.             m_ulLastNHeadTime   = pInfo->ulStartTime;
  2889.             m_ulLastNTailTime   = pInfo->ulStartTime;
  2890.         }
  2891.         // reset members
  2892.         pInfo->pOffset      = pInfo->pBuffer->GetBuffer();
  2893.         pInfo->ulBytesLeft  = pInfo->pBuffer->GetSize();
  2894.         // add it to the tail
  2895.         m_pLastNMilliSecsList->AddTail(pInfo);
  2896.         // Last m_ulLastNTailTime could have been invalidated by a rewind:
  2897.         // check it again here:
  2898.         m_ulLastNHeadTime = ((HXAudioInfo*) m_pLastNMilliSecsList->GetHead())->ulStartTime;
  2899.         m_ulLastNTailTime = pInfo->ulStartTime;
  2900.         // time to expire certain blocks?
  2901.         if (CALCULATE_ELAPSED_TICKS(m_ulLastNHeadTime, m_ulLastNTailTime) > m_ulLastNMilliSeconds)
  2902.         {
  2903.             // override pInfo. we will delete this block at the bottom
  2904.             pInfo = (HXAudioInfo*) m_pLastNMilliSecsList->RemoveHead();
  2905.             // update head time
  2906.             HXAudioInfo* pHeadInfo = (HXAudioInfo*) m_pLastNMilliSecsList->GetHead();
  2907.             // we should always have ATLEAST one nore in the list
  2908.             HX_ASSERT(pHeadInfo);
  2909.             m_ulLastNHeadTime = pHeadInfo->ulStartTime;
  2910.         }
  2911.         else
  2912.         {
  2913.             // early exit to save this block
  2914.             return;
  2915.         }
  2916.     }
  2917.     FreeBuffer(pInfo->pBuffer);
  2918.     delete pInfo;
  2919. }
  2920. void
  2921. CHXAudioStream::FreeBuffer(IHXBuffer* pBuffer)
  2922. {
  2923.     /* do we need to keep it around for reuse? */
  2924.     if (!m_pAvailableBuffers || m_pAvailableBuffers->GetCount() >= m_uCacheSize)
  2925.     {
  2926. //{FILE* f1 = ::fopen("d:\temp\cache.txt", "a+"); ::fprintf(f1, "Discard n");::fclose(f1);}
  2927.         /* 
  2928.          * now that we are full, we should grow the cache size, if we ever have
  2929.          * a cache miss
  2930.          */
  2931.         m_bCacheMayBeGrown = TRUE;
  2932.         pBuffer->Release();
  2933.         return;
  2934.     }
  2935.     /* 
  2936.      * check if we have the only reference, if so reuse it
  2937.      * else release our reference
  2938.      */
  2939.     pBuffer->AddRef();
  2940.     if (pBuffer->Release() > 1)
  2941.     {
  2942.         pBuffer->Release();
  2943.         return;
  2944.     }
  2945. #ifdef _MACINTOSH
  2946.     m_pAvailableBuffers->AddTail((void*) pBuffer);
  2947. #else
  2948.     BOOL bAddToTail = (HX_GET_BETTERTICKCOUNT() & 0x01) ? TRUE : FALSE;
  2949.     if (bAddToTail)
  2950.     {
  2951.         m_pAvailableBuffers->AddTail((void*) pBuffer);
  2952.     }
  2953.     else
  2954.     {
  2955.         m_pAvailableBuffers->AddHead((void*) pBuffer);
  2956.     }
  2957. #endif
  2958. //{FILE* f1 = ::fopen("d:\temp\cache.txt", "a+"); ::fprintf(f1, "Added %dn", m_pAvailableBuffers->GetCount());::fclose(f1);}
  2959.     return;
  2960. }
  2961. /************************************************************************
  2962.  *  Method:
  2963.  *      IHXCommonClassFactory::CreateInstance
  2964.  */
  2965. STDMETHODIMP 
  2966. CHXAudioStream::CreateInstance
  2967. (
  2968.     REFCLSID    /*IN*/          rclsid,
  2969.     void**      /*OUT*/         ppUnknown
  2970. )
  2971. {
  2972.     HX_RESULT theErr = HXR_OK;
  2973.     if (IsEqualCLSID(rclsid, CLSID_IHXBuffer))
  2974.     {
  2975.         if (!m_pAvailableBuffers)
  2976.         {
  2977. #ifdef _MACINTOSH
  2978.             m_pAvailableBuffers = new HXAudioMacQueue;
  2979. #else
  2980.             m_pAvailableBuffers = new CHXSimpleList;
  2981. #endif
  2982.         }
  2983.         if (m_pAvailableBuffers->GetCount() > 0)
  2984.         {
  2985. #ifdef _MACINTOSH
  2986.             *ppUnknown = (IUnknown*) (IHXBuffer*) m_pAvailableBuffers->RemoveHead();
  2987.             if (!*ppUnknown) goto justincase;
  2988. #else
  2989.             BOOL bRemoveFromHead = (HX_GET_BETTERTICKCOUNT() & 0x01) ? TRUE : FALSE;
  2990.             if (bRemoveFromHead)
  2991.             {
  2992.                 *ppUnknown = (IUnknown*) (IHXBuffer*) m_pAvailableBuffers->RemoveHead();
  2993.             }
  2994.             else
  2995.             {
  2996.                 *ppUnknown = (IUnknown*) (IHXBuffer*) m_pAvailableBuffers->RemoveTail();
  2997.             }
  2998. #endif
  2999. //{FILE* f1 = ::fopen("d:\temp\cache.txt", "a+"); ::fprintf(f1, "Cache Hit %dn", m_pAvailableBuffers->GetCount());::fclose(f1);}
  3000.             goto exit;
  3001.         }
  3002.         else
  3003.         {
  3004. #ifdef _MACINTOSH
  3005. justincase:
  3006. #endif
  3007.             if (m_bCacheMayBeGrown)
  3008.             {
  3009.                 m_bCacheMayBeGrown  = FALSE;
  3010.                 m_uCacheSize        += CACHE_INCREMENT_SIZE;
  3011. //{FILE* f1 = ::fopen("d:\temp\cache.txt", "a+"); ::fprintf(f1, "Cache increased to: %u n", m_uCacheSize);::fclose(f1);}
  3012.             }
  3013.         }
  3014.         /* 
  3015.          * fall down to using the comonclass factory to allocate this buiffer since 
  3016.          * we do not have it in the cache
  3017.          */
  3018.     }
  3019. //{FILE* f1 = ::fopen("d:\temp\cache.txt", "a+"); ::fprintf(f1, "Cache Miss buffered blocks: %dn", m_pDataList->GetCount());::fclose(f1);}
  3020.     theErr = m_pCommonClassFactory->CreateInstance(rclsid, ppUnknown);
  3021. exit:
  3022.     return theErr;
  3023. }
  3024. /************************************************************************
  3025.  *  Method:
  3026.  *      IHXCommonClassFactory::CreateInstanceAggregatable
  3027.  */
  3028. STDMETHODIMP 
  3029. CHXAudioStream::CreateInstanceAggregatable
  3030. (
  3031.     REFCLSID        /*IN*/      rclsid,
  3032.     REF(IUnknown*)  /*OUT*/     pUnknown,
  3033.     IUnknown*       /*IN*/      pUnkOuter
  3034. )
  3035. {
  3036.     return m_pCommonClassFactory->CreateInstanceAggregatable(rclsid, pUnknown, pUnkOuter);
  3037. }
  3038. /************************************************************************
  3039.  *      Method:
  3040.  *          IHXUpdateProperties::UpdatePacketTimeOffset
  3041.  *      Purpose:
  3042.  *          Call this method to update the timestamp offset of cached packets
  3043.  */
  3044. STDMETHODIMP
  3045. CHXAudioStream::UpdatePacketTimeOffset(INT32 lTimeOffset)
  3046. {
  3047.     HX_RESULT       rc = HXR_OK;
  3048.     HXAudioInfo*    pInfo = NULL;
  3049.     // adjust the start time 
  3050.     CHXSimpleList::Iterator ndx = m_pDataList->Begin();
  3051.     for (; ndx != m_pDataList->End(); ++ndx)
  3052.     {
  3053.         pInfo = (HXAudioInfo*) (*ndx);
  3054.         pInfo->ulStartTime += lTimeOffset;
  3055.     }
  3056.   
  3057.     if (m_pLastNMilliSecsList)
  3058.     {
  3059.         ndx = m_pLastNMilliSecsList->Begin();
  3060.         for (; ndx != m_pLastNMilliSecsList->End(); ++ndx)
  3061.         {
  3062.             pInfo = (HXAudioInfo*) (*ndx);
  3063.             pInfo->ulStartTime += lTimeOffset;
  3064.         }
  3065.     }
  3066.     // Adjust more state:
  3067.     m_ulLastInputStartTime += lTimeOffset;
  3068.     m_ulLastInputEndTime += lTimeOffset;  
  3069.     m_llLastWriteTime += lTimeOffset;
  3070.     m_ulLastNHeadTime += lTimeOffset;  
  3071.     m_ulLastNTailTime += lTimeOffset;  
  3072.     m_llLastStartTimePlayed += lTimeOffset;
  3073.     return rc;
  3074. }
  3075. /************************************************************************
  3076.  *      Method:
  3077.  *          IHXUpdateProperties::UpdatePlayTimes
  3078.  *      Purpose:
  3079.  *          Call this method to update the playtime attributes
  3080.  */
  3081. STDMETHODIMP
  3082. CHXAudioStream::UpdatePlayTimes(IHXValues* pProps)
  3083. {
  3084.     return HXR_OK;
  3085. }
  3086. void
  3087. CHXAudioStream::RollBackTimestamp()
  3088. {
  3089.     if (m_llLastWriteTime > CAST_TO_INT64 m_ulGranularity)
  3090.     {
  3091.         m_llLastWriteTime -= CAST_TO_INT64 m_ulGranularity;
  3092.     }
  3093. }
  3094.  
  3095. #if defined(HELIX_FEATURE_VOLUME)  
  3096. /////////////////////////////////////////////////////////////////////////
  3097. // CHXAudioStream::HXVolumeAdviseSink
  3098. //
  3099. CHXAudioStream::HXStreamVolumeAdviseSink::HXStreamVolumeAdviseSink() :
  3100.      m_lRefCount (0)
  3101. ,    m_pCHXAudioStream (0)
  3102. {
  3103. }
  3104. CHXAudioStream::HXStreamVolumeAdviseSink::~HXStreamVolumeAdviseSink()
  3105. {
  3106. }
  3107. /*
  3108.  * IUnknown methods
  3109.  */
  3110. /////////////////////////////////////////////////////////////////////////
  3111. //      Method:
  3112. //              IUnknown::QueryInterface
  3113. //      Purpose:
  3114. //              Implement this to export the interfaces supported by your 
  3115. //              object.
  3116. //
  3117. STDMETHODIMP CHXAudioStream::HXStreamVolumeAdviseSink::QueryInterface(REFIID riid, void** ppvObj)
  3118. {
  3119.     if (IsEqualIID(riid, IID_IHXVolumeAdviseSink))
  3120.     {
  3121.         AddRef();
  3122.         *ppvObj = (IHXVolumeAdviseSink*)this;
  3123.         return HXR_OK;
  3124.     }
  3125.     else if (IsEqualIID(riid, IID_IUnknown))
  3126.     {
  3127.         AddRef();
  3128.         *ppvObj = this;
  3129.         return HXR_OK;
  3130.     }
  3131.     *ppvObj = NULL;
  3132.     return HXR_NOINTERFACE;
  3133. }
  3134. /////////////////////////////////////////////////////////////////////////
  3135. //      Method:
  3136. //              IUnknown::AddRef
  3137. //      Purpose:
  3138. //              Everyone usually implements this the same... feel free to use
  3139. //              this implementation.
  3140. //
  3141. STDMETHODIMP_(ULONG32) CHXAudioStream::HXStreamVolumeAdviseSink::AddRef()
  3142. {
  3143.     return InterlockedIncrement(&m_lRefCount);
  3144. }
  3145. /////////////////////////////////////////////////////////////////////////
  3146. //      Method:
  3147. //              IUnknown::Release
  3148. //      Purpose:
  3149. //              Everyone usually implements this the same... feel free to use
  3150. //              this implementation.
  3151. //
  3152. STDMETHODIMP_(ULONG32) CHXAudioStream::HXStreamVolumeAdviseSink::Release()
  3153. {
  3154.     if (InterlockedDecrement(&m_lRefCount) > 0)
  3155.     {
  3156.         return m_lRefCount;
  3157.     }
  3158.     delete this;
  3159.     return 0;
  3160. }
  3161. /*
  3162.  *      IHXVolumeAdviseSink methods
  3163.  */
  3164. STDMETHODIMP CHXAudioStream::HXStreamVolumeAdviseSink::OnVolumeChange
  3165. (
  3166.     const UINT16        uVolume
  3167. )
  3168. {
  3169.     if (m_pCHXAudioStream)
  3170.     {
  3171.         // Set the audio device volume
  3172.         m_pCHXAudioStream->OnVolumeChange(uVolume);
  3173.     }
  3174.     return HXR_OK;
  3175. }
  3176. STDMETHODIMP CHXAudioStream::HXStreamVolumeAdviseSink::OnMuteChange
  3177. (
  3178.     const BOOL          bMute
  3179. )
  3180. {
  3181.     if (m_pCHXAudioStream)
  3182.     {
  3183.         m_pCHXAudioStream->OnMuteChange(bMute);
  3184.     }
  3185.     return HXR_OK;
  3186. }
  3187. #endif /* HELIX_FEATURE_VOLUME */
  3188. #ifdef _MACINTOSH
  3189. /////////////////////////////////////////////////////////////////////////
  3190. //      
  3191. //      HXAudioMacQueue
  3192. //      
  3193. //      For passing data between an interrupt and anything else (mac only).
  3194. //
  3195. HXAudioMacQueue::HXAudioMacQueue()
  3196. {
  3197.         mQueueHeader.qFlags=0;  
  3198.         mQueueHeader.qHead=0;
  3199.         mQueueHeader.qTail=0;
  3200.         mDestructing = FALSE; // just a safety check
  3201.         m_nCount = 0;
  3202. }
  3203. /////////////////////////////////////////////////////////////////////////
  3204. //
  3205. HX_RESULT HXAudioMacQueue::AddTail(void* pObject)
  3206. {
  3207.         if (pObject && !mDestructing)
  3208.         {
  3209.             HXAudioMacQueueElement * theElement = new HXAudioMacQueueElement();  
  3210.             
  3211.             if (theElement)
  3212.             {  
  3213.                     theElement->mNextElementInQueue = NULL;
  3214.                     theElement->mObject = pObject;    
  3215.                     ::Enqueue((QElem *)theElement, &mQueueHeader);
  3216.                     
  3217.                     m_nCount++;
  3218.                     
  3219.                     //
  3220.                     // If someone interrupts and enters the destructor while we're in here,
  3221.                     // then the pObject and the new node will be leaked.  This shouldn't 
  3222.                     // happen since we should have shut down all interrupts that would
  3223.                     // be adding items to the queue long before we start destructing it.
  3224.                     //
  3225.                     
  3226.                     HX_ASSERT(!mDestructing); // if we DID enter the destructor, let the programmer know...
  3227.             }
  3228.                     
  3229.             return HXR_OK;
  3230.     }
  3231.         
  3232.     return HXR_FAILED;
  3233. }
  3234. /////////////////////////////////////////////////////////////////////////
  3235. //
  3236. void * HXAudioMacQueue::RemoveHead()
  3237. {
  3238.         //
  3239.     // POINT A
  3240.     // 
  3241.     // You can look at the qHead anytime you want, but you can't USE a 
  3242.     // pointer unless it's OFF of the queue.  Basically you do a Dequeue,
  3243.     // and if it succeeds then you know nobody else has it.  If it fails,
  3244.     // an error is returned and you don't mess with it.
  3245.     //
  3246.     
  3247.         if (mQueueHeader.qHead)
  3248.     {
  3249.                 HXAudioMacQueueElement * theElement = (HXAudioMacQueueElement *) mQueueHeader.qHead;
  3250.                 if (theElement)
  3251.                 {                       
  3252.                         OSErr e = ::Dequeue( (QElemPtr) theElement, &mQueueHeader );
  3253.                         
  3254.                         //
  3255.                         // Between points A and D, we can't be guaranteed that the queue header and theElement are valid.  But
  3256.                         // Dequeue will TELL us if that pointer is still valid by its return code.  If it can't remove the item
  3257.                         // from the queue, then somebody else did and the pointer is no longer ours.  If no error was returned
  3258.                         // from dequeue, then it's ours to mess with.
  3259.                         //
  3260.                                                 
  3261.                         if (e == noErr)
  3262.                         {
  3263.                                 // at this point we know that we can do whatever we need to with the object.  
  3264.                                 void* theObj = theElement->mObject;
  3265.                                 delete theElement; // delete the node
  3266.                                 m_nCount--;
  3267.                                 HX_ASSERT(m_nCount >= 0);
  3268.                                 return theObj;
  3269.                         }
  3270.                 }
  3271.    }
  3272.    
  3273.    return NULL;
  3274. }
  3275. /////////////////////////////////////////////////////////////////////////
  3276. //
  3277. UINT32 HXAudioMacQueue::GetCount()
  3278. {
  3279.     return m_nCount;
  3280. }
  3281. /////////////////////////////////////////////////////////////////////////
  3282. //
  3283. HXAudioMacQueue::~HXAudioMacQueue()
  3284. {
  3285.         mDestructing = TRUE; // don't add anything else to the queue
  3286.         
  3287.         void * theObject;
  3288.         while ((theObject = RemoveHead()) != 0)
  3289.         {
  3290.         }
  3291.     
  3292.     // and just to be safe...
  3293.         mQueueHeader.qHead=0;
  3294.         mQueueHeader.qTail=0;
  3295. }
  3296. #endif