hxaudstr.cpp
上传用户:zhongxx05
上传日期:2007-06-06
资源大小:33641k
文件大小:120k
源码类别:

Symbian

开发平台:

C/C++

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