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

Symbian

开发平台:

Visual C++

  1. /* ***** BEGIN LICENSE BLOCK *****
  2.  * Source last modified: $Id: hxaudses.cpp,v 1.39.2.3.2.3 2005/01/24 07:55:08 rggammon Exp $
  3.  * 
  4.  * Portions Copyright (c) 1995-2004 RealNetworks, Inc. All Rights Reserved.
  5.  * 
  6.  * The contents of this file, and the files included with this file,
  7.  * are subject to the current version of the RealNetworks Public
  8.  * Source License (the "RPSL") available at
  9.  * http://www.helixcommunity.org/content/rpsl unless you have licensed
  10.  * the file under the current version of the RealNetworks Community
  11.  * Source License (the "RCSL") available at
  12.  * http://www.helixcommunity.org/content/rcsl, in which case the RCSL
  13.  * will apply. You may also obtain the license terms directly from
  14.  * RealNetworks.  You may not use this file except in compliance with
  15.  * the RPSL or, if you have a valid RCSL with RealNetworks applicable
  16.  * to this file, the RCSL.  Please see the applicable RPSL or RCSL for
  17.  * the rights, obligations and limitations governing use of the
  18.  * contents of the file.
  19.  * 
  20.  * Alternatively, the contents of this file may be used under the
  21.  * terms of the GNU General Public License Version 2 or later (the
  22.  * "GPL") in which case the provisions of the GPL are applicable
  23.  * instead of those above. If you wish to allow use of your version of
  24.  * this file only under the terms of the GPL, and not to allow others
  25.  * to use your version of this file under the terms of either the RPSL
  26.  * or RCSL, indicate your decision by deleting the provisions above
  27.  * and replace them with the notice and other provisions required by
  28.  * the GPL. If you do not delete the provisions above, a recipient may
  29.  * use your version of this file under the terms of any one of the
  30.  * RPSL, the RCSL or the GPL.
  31.  * 
  32.  * This file is part of the Helix DNA Technology. RealNetworks is the
  33.  * developer of the Original Code and owns the copyrights in the
  34.  * portions it created.
  35.  * 
  36.  * This file, and the files included with this file, is distributed
  37.  * and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
  38.  * KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
  39.  * ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
  40.  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
  41.  * ENJOYMENT OR NON-INFRINGEMENT.
  42.  * 
  43.  * Technology Compatibility Kit Test Suite(s) Location:
  44.  *    http://www.helixcommunity.org/content/tck
  45.  * 
  46.  * Contributor(s):
  47.  * 
  48.  * ***** END LICENSE BLOCK ***** */
  49. #include "hxtypes.h"
  50. #include "safestring.h"
  51. #include "hlxclib/stdio.h"
  52. #include "hlxclib/string.h"
  53. #include "hlxclib/stdlib.h"
  54. #ifndef WIN32_PLATFORM_PSPC
  55. #include "hlxclib/signal.h"
  56. #else
  57. #include <winbase.h>
  58. #include <dbgapi.h>
  59. #endif
  60. //#define _TESTING    1
  61. #ifdef _TESTING
  62. #include <fcntl.h>
  63. #include <sys/types.h>
  64. #include <sys/stat.h>
  65. #if defined (_WINDOWS) || defined (_WIN32)
  66. #include <io.h>
  67. #endif
  68. #endif
  69. //#include "racodec.h"
  70. #include "hxresult.h"
  71. #include "hxcom.h"
  72. #include "hxshtdn.h"
  73. #include "hxengin.h"
  74. #include "hxausvc.h"
  75. #include "hxrasyn.h"
  76. #include "hxprefs.h"
  77. #include "ihxpckts.h"
  78. #include "chxpckts.h"
  79. #include "auderrs.h"
  80. #include "hxslist.h"
  81. #include "hxtick.h"
  82. #ifdef _SYMBIAN
  83. #include "audsymbian.h"
  84. #else
  85. #include "hxaudev.h"
  86. #endif
  87. #include "hxaudply.h"
  88. #include "hxaudstr.h"
  89. #include "hxaudvol.h"
  90. #include "timeval.h"
  91. #include "hxaudses.h"
  92. #include "hxaudtyp.h"
  93. #include "hxmixer.h"
  94. #include "hxthread.h"
  95. #if defined (HELIX_FEATURE_RESAMPLER) && !defined (HELIX_CONFIG_FIXEDPOINT)
  96. #include "hxrsmp2.h"
  97. #endif /* HELIX_FEATURE_RESAMPLER && !HELIX_CONFIG_FIXEDPOINT */
  98. #include "hxprefs.h"
  99. #include "hxprefutil.h"
  100. class CHXAudioPlayer;
  101. #include "hxheap.h"
  102. #ifdef _DEBUG
  103. #undef HX_THIS_FILE
  104. static const char HX_THIS_FILE[] = __FILE__;
  105. #endif
  106. #if defined(HELIX_CONFIG_MIN_PCM_PUSHDOWN_BYTES)
  107. // The following value was arrived at via trial and error and has been
  108. // demonstrated to give optimal heap usage values for RA8, ATRAC3, & MP3.
  109. #define IDEAL_MINIMAL_INITIAL_PUSHDOWN  500 //ms
  110. #else
  111. #define IDEAL_MINIMAL_INITIAL_PUSHDOWN  1000 // ms
  112. #endif
  113. #define MIN_BLOCKS_TOBEQUEUED   (m_ulMinimumPushdown*1.0/m_ulGranularity)
  114. #define SOME_INSANELY_LARGE_VALUE       3600000 /* 1 hour */
  115. #ifdef _WIN32
  116. #define HXMSG_QUIT              (WM_USER + 200) /* Exit from the thread */
  117. #define HXMSG_RESUME            (WM_USER + 201) /* Resume audio thread */
  118. #define HXMSG_STOP              (WM_USER + 202) /* Stop audio thread */
  119. #else
  120. #define HXMSG_QUIT              200             /* Exit from the thread */
  121. #define HXMSG_RESUME            201             /* Change timer value */
  122. #define HXMSG_STOP              202             /* Stop audio thread */
  123. #endif /*_WIN32*/
  124. #ifdef _MACINTOSH
  125. BOOL    CHXAudioSession::zm_Locked=FALSE;
  126. #endif /* _MACINTOSH */
  127. #ifdef _UNIX
  128. IHXPreferences* z_pIHXPrefs =  NULL;
  129. #endif
  130. //XXXgfw can whatever this SH4 is be moved down into the audio device
  131. //code for this chipset? This is how we don't allow certain sample
  132. //rates in other devices; by returning HXR_FAIL from _imp_checkformat.
  133. #if !defined(SH4)
  134. const unsigned short z_anValidSampleRates[] = { 8000,
  135.                                                 11025,
  136.                                                 16000,
  137.                                                 22050,
  138.                                                 32000,
  139.                                                 44100
  140.                                                 };
  141. #else
  142. const unsigned short z_anValidSampleRates[] = { 11025,
  143.                                                 22050,
  144.                                                 44100
  145.                                                 };
  146. #endif
  147. struct tableEntry
  148. {
  149.     UINT16 usSampleRate;
  150.     UINT8  usChannels;
  151.     UINT8  usBits;
  152.     inline void set(UINT16 sr,
  153.                     UINT8  chan,
  154.                     UINT8  bits
  155.                     )
  156.         {
  157.             usSampleRate = sr;
  158.             usChannels   = chan;
  159.             usBits       = bits;
  160.         }
  161. };
  162. /*
  163.  *  HXAudioSession methods
  164.  */
  165. /************************************************************************
  166.  *  Method:
  167.  *              CHXAudioSession::CHXAudioSession()
  168.  *      Purpose:
  169.  *              Constructor. Create player list.
  170.  */
  171. CHXAudioSession::CHXAudioSession()
  172.     : m_pContext(NULL)
  173.     , m_lRefCount(0)
  174.     , m_pScheduler (0)
  175.     , m_pPreferences(0)
  176.     , m_pInterruptState(0)
  177.     , m_pPlayerBuf (NULL)
  178.     , m_pSessionBuf (NULL)
  179.     , m_ulGranularity(0)
  180.     , m_dGranularity((double) 0.)
  181.     , m_ulMinimumPushdown(MINIMUM_INITIAL_PUSHDOWN)
  182.     , m_ulIdealMinimumPushdown(IDEAL_MINIMAL_INITIAL_PUSHDOWN)
  183.     , m_ulMinBlocksTobeQueued(1)
  184.     , m_ulMinBlocksTobeQueuedAtStart(1)
  185.     , m_ulBytesPerGran(0)
  186.     , m_ulBlocksWritten(0)
  187.     , m_ulCallbackID(0)
  188.     , m_bFakeAudioTimeline(FALSE)
  189.     , m_bShouldOpenOnCoreThread(FALSE)
  190.     , m_bToBeReOpened(FALSE)
  191.     , m_pDeviceCallback(NULL)
  192.     , m_bHasStreams(FALSE)
  193.     , m_ulIncreasingTimer (0)
  194.     , m_ulCurrentTime (0)
  195.     , m_ulLastAudioTime(0)
  196.     , m_ulLastAudioReturnTime(0)
  197.     , m_ulLastSystemTime(0)
  198.     , m_bAtLeastOneTimeReceived(FALSE)
  199.     , m_ulStartTime(0)
  200.     , m_bTimeSyncReceived(FALSE)
  201.     , m_bPaused(TRUE)
  202.     , m_bStoppedDuringPause(FALSE)
  203.     , m_ulLastFakeCallbackTime(0)
  204.     , m_pFakeAudioCBTime(0)
  205.     , m_pInDataPtr(0)
  206.     , m_pOutDataPtr(0)
  207.     , m_pPlayerResponse(0)
  208.     , m_bFirstPlayAudio(TRUE)
  209.     , m_uVolume(HX_INIT_VOLUME)
  210.     , m_bMute(FALSE)
  211.     , m_bAudioDeviceSupportsVolume(TRUE)
  212.     , m_dBufEndTime((double) 0.)
  213.     , m_bDisableWrite(FALSE)
  214.     , m_bInPlayAudio(FALSE)
  215.     , m_bInActualResume(FALSE)
  216.     , m_dNumBytesWritten((double)0)
  217.     , m_dNumBytesPlayed((double)0)
  218.     , m_bInited(FALSE)
  219.     , m_pAudioDev(0)
  220.     , m_pCurrentAudioDev(NULL)
  221.     , m_pReplacedAudioDev(NULL)
  222.     , m_bReplacedDev(FALSE)
  223.     , m_pPlayerList(0)
  224.     , m_pHookList(NULL)
  225.     , m_pAuxiliaryAudioBuffers(0)
  226.     , m_pMutex(NULL)
  227.     , m_pFinalHook(NULL)
  228.     , m_bUseFinalHook(FALSE)
  229.     , m_pCoreMutex(NULL)
  230.     , m_uAskFromAudioDevice(0)
  231.     , m_bDeferActualResume(FALSE)
  232.     , m_pLastPausedPlayer(NULL)
  233.     , m_bUsingReplacedDevice(FALSE)
  234.     , m_bToBeRewound(FALSE)
  235.     , m_ulLastRewindTimestamp(0)
  236.     , m_uNumToBePushed(0)
  237.     , m_bSessionBufferDirty(FALSE)
  238.     , m_bPostMixHooksUpdated(FALSE)
  239.     , m_pMPPSupport(NULL)
  240. #if defined(HELIX_FEATURE_TIMELINE_WATCHER)
  241.     , m_pTimeLineWatchers(NULL)
  242. #endif    
  243. {
  244.     m_pFakeAudioCBTime                  = new Timeval;
  245.     m_pInDataPtr                        = new HXAudioData;
  246.     m_pOutDataPtr                       = new HXAudioData;
  247.     m_pInDataPtr->pData                 = 0;
  248.     m_pInDataPtr->ulAudioTime           = 0;
  249.     m_pInDataPtr->uAudioStreamType      = STREAMING_AUDIO;
  250.     m_pOutDataPtr->ulAudioTime          = 0;
  251.     m_pOutDataPtr->pData                = 0;
  252.     m_pOutDataPtr->uAudioStreamType     = STREAMING_AUDIO;
  253.     /* Default value of Device format */
  254.     m_DeviceFmt.uChannels       = 2;
  255.     m_DeviceFmt.uBitsPerSample  = 16;
  256.     m_DeviceFmt.ulSamplesPerSec = 16000;
  257.     m_DeviceFmt.uMaxBlockSize   = 64000;
  258. #ifdef HELIX_FEATURE_VOLUME
  259.     m_pDeviceVolume = NULL;
  260. #endif
  261. #ifdef THREADS_SUPPORTED
  262.     HXMutex::MakeMutex(m_pMutex);
  263. #else
  264.     HXMutex::MakeStubMutex(m_pMutex);
  265. #endif
  266. };
  267. /************************************************************************
  268.  *  Method:
  269.  *              CHXAudioSession::~CHXAudioSession()
  270.  *      Purpose:
  271.  *              Destructor. Clean up and set free.
  272.  */
  273. CHXAudioSession::~CHXAudioSession()
  274. {
  275.     Close();
  276. }
  277. void
  278. CHXAudioSession::Close(void)
  279. {
  280.     // Delete all player items
  281.     if ( m_pPlayerList )
  282.     {
  283.         CHXAudioPlayer* p = 0;
  284.         CHXSimpleList::Iterator lIter = m_pPlayerList->Begin();
  285.         for (; lIter != m_pPlayerList->End(); ++lIter)
  286.         {
  287.             p = (CHXAudioPlayer*) (*lIter);
  288.             if ( p )
  289.                 p->Release();
  290.         }
  291.         delete m_pPlayerList;
  292.         m_pPlayerList = 0;
  293.     }
  294.     while (m_pHookList && m_pHookList->GetCount() > 0)
  295.     {
  296.         HXAudioHookInfo* pHookInfo = (HXAudioHookInfo*) m_pHookList->RemoveHead();
  297.         pHookInfo->pHook->Release();
  298.         delete pHookInfo;
  299.     }
  300.     HX_DELETE(m_pHookList);
  301.     if (m_pAuxiliaryAudioBuffers)
  302.     {
  303.         while (m_pAuxiliaryAudioBuffers->GetCount() > 0)
  304.         {
  305.             HXAudioData* pAudioData =
  306.                 (HXAudioData*) m_pAuxiliaryAudioBuffers->RemoveHead();
  307.             pAudioData->pData->Release();
  308.             delete pAudioData;
  309.         }
  310.         delete m_pAuxiliaryAudioBuffers;
  311.         m_pAuxiliaryAudioBuffers    = 0;
  312.     }
  313.     ResetSession();
  314.     if( m_ulCallbackID && m_pScheduler)
  315.     {
  316.         m_pScheduler->Remove(m_ulCallbackID);
  317.         m_ulCallbackID = 0;
  318.     }
  319. #ifdef HELIX_FEATURE_VOLUME
  320.     if( m_pDeviceVolume )
  321.     {
  322.         m_pDeviceVolume->RemoveAdviseSink(this);
  323.         HX_RELEASE(m_pDeviceVolume);
  324.     }
  325. #endif
  326.     if (m_pDeviceCallback && m_pDeviceCallback->PendingID())
  327.     {
  328.         m_pScheduler->Remove(m_pDeviceCallback->PendingID());
  329.     }
  330.     HX_RELEASE(m_pDeviceCallback);
  331.     HX_RELEASE(m_pScheduler);
  332.     HX_RELEASE(m_pInterruptState);
  333. #if defined(HELIX_FEATURE_PREFERENCES)
  334.     if (m_pPreferences)
  335.     {
  336.         /* Store the last volume setting */
  337.         IHXBuffer* pBuffer = new CHXBuffer;
  338.         pBuffer->AddRef();
  339.         pBuffer->SetSize(16);
  340.         SafeSprintf((char*) pBuffer->GetBuffer(),16,"%d",(int) m_uVolume); /* Flawfinder: ignore */
  341.         m_pPreferences->WritePref("Volume", pBuffer);
  342.         pBuffer->Release();
  343. #if defined(HELIX_FEATURE_MUTE_PREFERENCE)
  344.         /* Store the last mute setting */
  345.         IHXBuffer* pMuteBuffer = new CHXBuffer;
  346.         pMuteBuffer->AddRef();
  347.         pMuteBuffer->SetSize(16);
  348.         SafeSprintf((char*) pMuteBuffer->GetBuffer(),16,"%d",(int) m_bMute);
  349.         m_pPreferences->WritePref("Mute", pMuteBuffer);
  350.         pMuteBuffer->Release();
  351. #endif /* HELIX_FEATURE_MUTE_PREFERENCE */
  352.         HX_RELEASE(m_pPreferences);
  353. #ifdef _UNIX
  354.         z_pIHXPrefs = NULL;
  355. #endif
  356.     }
  357. #endif /* HELIX_FEATURE_PREFERENCES */
  358. #if defined(HELIX_FEATURE_TIMELINE_WATCHER)
  359.     //IHXTimelineManager
  360.     while( m_pTimeLineWatchers && m_pTimeLineWatchers->GetCount() )
  361.     {
  362.         IHXTimelineWatcher* pWatcher = (IHXTimelineWatcher*)m_pTimeLineWatchers->RemoveHead();
  363.         HX_RELEASE(pWatcher);
  364.     }
  365.     HX_DELETE(m_pTimeLineWatchers);
  366. #endif
  367.     
  368.     HX_DELETE(m_pFakeAudioCBTime);
  369.     HX_DELETE(m_pInDataPtr);
  370.     HX_DELETE(m_pOutDataPtr);
  371.     HX_RELEASE(m_pContext);
  372.     HX_DELETE(m_pMutex);
  373.     HX_RELEASE(m_pFinalHook);
  374.     HX_RELEASE(m_pMPPSupport);
  375. }
  376. /////////////////////////////////////////////////////////////////////////
  377. //  Method:
  378. //      IUnknown::QueryInterface
  379. //  Purpose:
  380. //      Implement this to export the interfaces supported by your
  381. //      object.
  382. //
  383. STDMETHODIMP CHXAudioSession::QueryInterface(REFIID riid, void** ppvObj)
  384. {
  385.     QInterfaceList  qiList[] =
  386.         {
  387.             { GET_IIDHANDLE(IID_IUnknown), (IUnknown*)(IHXAudioDeviceResponse*)this},
  388.             { GET_IIDHANDLE(IID_IHXAudioDeviceResponse), (IHXAudioDeviceResponse*)this  },
  389.             { GET_IIDHANDLE(IID_IHXAudioDeviceManager),  (IHXAudioDeviceManager*)this   },
  390.             { GET_IIDHANDLE(IID_IHXAudioDeviceManager2), (IHXAudioDeviceManager2*)this  },
  391.             { GET_IIDHANDLE(IID_IHXAudioPushdown),       (IHXAudioPushdown*)this        },
  392. #ifdef HELIX_FEATURE_VOLUME
  393.             { GET_IIDHANDLE(IID_IHXVolumeAdviseSink), (IHXVolumeAdviseSink*)this        },
  394. #endif
  395. #if defined(HELIX_FEATURE_AUDIO_POSTMIXHOOK)
  396.             { GET_IIDHANDLE(IID_IHXAudioHookManager),    (IHXAudioHookManager*)this     },
  397. #endif
  398. #if defined(HELIX_FEATURE_RESAMPLER) && !defined (HELIX_CONFIG_FIXEDPOINT)
  399.               { GET_IIDHANDLE(IID_IHXAudioResamplerManager), (IHXAudioResamplerManager*)this },
  400. #endif
  401. #if defined(HELIX_FEATURE_TIMELINE_WATCHER)
  402.             { GET_IIDHANDLE(IID_IHXTimelineManager),      (IHXTimelineManager*)this       },
  403. #endif
  404.             { GET_IIDHANDLE(IID_IHXAudioPushdown2),      (IHXAudioPushdown2*)this       }
  405.         };
  406.     return ::QIFind(qiList, QILISTSIZE(qiList), riid, ppvObj);
  407. }
  408. /////////////////////////////////////////////////////////////////////////
  409. //  Method:
  410. //      IUnknown::AddRef
  411. //  Purpose:
  412. //      Everyone usually implements this the same... feel free to use
  413. //      this implementation.
  414. //
  415. STDMETHODIMP_(ULONG32) CHXAudioSession::AddRef()
  416. {
  417.     return InterlockedIncrement(&m_lRefCount);
  418. }
  419. /////////////////////////////////////////////////////////////////////////
  420. //  Method:
  421. //      IUnknown::Release
  422. //  Purpose:
  423. //      Everyone usually implements this the same... feel free to use
  424. //      this implementation.
  425. //
  426. STDMETHODIMP_(ULONG32) CHXAudioSession::Release()
  427. {
  428.     if (InterlockedDecrement(&m_lRefCount) > 0)
  429.     {
  430.         return m_lRefCount;
  431.     }
  432.     delete this;
  433.     return 0;
  434. }
  435. /************************************************************************
  436.  *  Method:
  437.  *              CHXAudioSession::SetVolume
  438.  *      Purpose:
  439.  *              Set device volume. This is the audio device volume.
  440.  *
  441.  */
  442. void CHXAudioSession::SetVolume( const UINT16 uVolume)
  443. {
  444.     m_uVolume = uVolume;
  445.     // only set the volume of not muted
  446.     if (!m_bMute)
  447.     {
  448.         HX_ASSERT(m_pCurrentAudioDev || !m_bReplacedDev);
  449.         _ConstructIfNeeded();
  450.         if (m_pCurrentAudioDev)
  451.         {
  452.             m_pCurrentAudioDev->SetVolume(uVolume);
  453.         }
  454.     }
  455. }
  456. void CHXAudioSession::_ConstructIfNeeded()
  457. {
  458.     if (!m_pCurrentAudioDev)
  459.     {
  460.         CreateAudioDevice();
  461.         if (!m_bAudioDeviceSupportsVolume)
  462.         {
  463.             ReleaseAudioDevice();
  464.         }
  465.     }
  466. }
  467. /************************************************************************
  468.  *  Method:
  469.  *              CHXAudioSession::GetVolume
  470.  *      Purpose:
  471.  *              Get device volume. This is the audio device volume.
  472.  *
  473.  */
  474. UINT16 CHXAudioSession::GetVolume()
  475. {
  476.     if(!m_bMute)
  477.     {
  478.         HX_ASSERT(m_pCurrentAudioDev || !m_bReplacedDev);
  479.         _ConstructIfNeeded();
  480.         if (m_pCurrentAudioDev)
  481.         {
  482.             m_uVolume = m_pCurrentAudioDev->GetVolume();
  483.         }
  484.     }
  485.     return m_uVolume;
  486. }
  487. /************************************************************************
  488.  *  Method:
  489.  *              CHXAudioSession::SetMute
  490.  *      Purpose:
  491.  *              Mute device volume. This is the audio device volume.
  492.  *
  493.  */
  494. void CHXAudioSession::SetMute( const BOOL bMute)
  495. {
  496.     if (bMute != m_bMute)
  497.     {
  498.         m_bMute = bMute;
  499.         UINT16 volLevel = (m_bMute ? 0 : m_uVolume);
  500.         HX_ASSERT(m_pCurrentAudioDev || !m_bReplacedDev);
  501.         _ConstructIfNeeded();
  502.         if (m_pCurrentAudioDev)
  503.         {
  504.             m_pCurrentAudioDev->SetVolume( volLevel );
  505.         }
  506.     }
  507. }
  508. /************************************************************************
  509.  *  Method:
  510.  *              CHXAudioSession::Init
  511.  *      Purpose:
  512.  *              Setup the Audio Player list.
  513.  */
  514. HX_RESULT CHXAudioSession::Init(IUnknown* pContext)
  515. {
  516.     HX_RESULT   theErr  = HXR_OK;
  517.     IHXBuffer* pBuffer = 0;
  518.     if (!pContext)
  519.     {
  520.         theErr = HXR_INVALID_PARAMETER;
  521.         goto cleanup;
  522.     }
  523.     m_pContext = pContext;
  524.     m_pContext->AddRef();
  525. #if defined(HELIX_FEATURE_PREFERENCES)
  526.     // Get preferences interface and info..
  527.     pContext->QueryInterface(IID_IHXPreferences, (void **) &m_pPreferences);
  528. #ifdef _UNIX
  529.     //Set up a global so we can read the ESDSupport pref
  530.     //when we create the audio device
  531.     z_pIHXPrefs = m_pPreferences;
  532. #endif
  533. #endif /* HELIX_FEATURE_PREFERENCES */
  534.     if (HXR_OK != pContext->QueryInterface(IID_IHXScheduler,
  535.                             (void**) &m_pScheduler))
  536.     {
  537.         theErr = HXR_INVALID_PARAMETER;
  538.         goto cleanup;
  539.     }
  540.     pContext->QueryInterface(IID_IHXInterruptState, (void**) &m_pInterruptState);
  541.     // Create audio player list.
  542.     m_pPlayerList = new CHXSimpleList;
  543.     if (!m_pPlayerList || !m_pPlayerList->IsPtrListValid())
  544.     {
  545.         theErr = HXR_OUTOFMEMORY;
  546.         goto cleanup;
  547.     }
  548. #if defined(HELIX_FEATURE_PREFERENCES)
  549.     if (m_pPreferences)
  550.     {
  551.         ReadPrefINT32(m_pPreferences, "MinimumInitalPushdown", m_ulMinimumPushdown);
  552.         ReadPrefINT32(m_pPreferences, "IdealMinimumInitalPushdown", m_ulIdealMinimumPushdown);
  553.         if (m_ulIdealMinimumPushdown > m_ulMinimumPushdown)
  554.         {
  555.             m_ulMinimumPushdown = m_ulIdealMinimumPushdown;
  556.         }
  557.     }
  558. #endif /* HELIX_FEATURE_PREFERENCES */
  559.     // Create a device volume interface.
  560.     if ( !theErr )
  561.     {
  562. #if defined(HELIX_FEATURE_VOLUME)
  563. #if defined(HELIX_FEATURE_PREFERENCES)
  564.         if (m_pPreferences)
  565.         {
  566.             BOOL bOpenAudioDeviceOnPlayback = TRUE;
  567.             ReadPrefBOOL(m_pPreferences, "OpenAudioDeviceOnPlayback", bOpenAudioDeviceOnPlayback);
  568.             if (!bOpenAudioDeviceOnPlayback)
  569.             {
  570.                 // rgammon 12/17/03
  571.                 // Create audio device on init if OpenAudioDeviceOnPlayback is
  572.                 // false. This means that we will be able to query the volume
  573.                 // successfully on startup. It also means that if there are
  574.                 // errors opening the audio device, they will show up at
  575.                 // startup. Some players (the windows player, for example),
  576.                 // save the system volume at shutdown and use that volume for
  577.                 // the ui on startup.
  578.                 CreateAudioDevice();
  579.                 m_uVolume = GetVolume();
  580.             }
  581.         }
  582.         if (m_pPreferences)
  583.         {
  584.             if (ReadPrefINT16(m_pPreferences, "Volume", m_uVolume) != HXR_OK)
  585.             {
  586.                 BOOL bUseDS = FALSE;
  587.                 ReadPrefBOOL(m_pPreferences, "UseDirectSound", bUseDS);
  588.                 if(bUseDS)
  589.                 {
  590.                     m_uVolume = HX_MAX_VOLUME;
  591.                 }
  592.             }
  593. #if defined(HELIX_FEATURE_MUTE_PREFERENCE )
  594.             ReadPrefBOOL(m_pPreferences, "Mute", m_bMute);
  595. #endif /* HELIX_FEATURE_MUTE_PREFERENCE */
  596.         }
  597. #endif /* HELIX_FEATURE_PREFERENCES */
  598.         m_pDeviceVolume = (IHXVolume*)new CHXVolume;
  599.         if( m_pDeviceVolume )
  600.         {
  601.             m_pDeviceVolume->AddRef();
  602.             m_pDeviceVolume->SetVolume(m_uVolume);
  603. #if defined(HELIX_FEATURE_MUTE_PREFERENCE )
  604.             m_pDeviceVolume->SetMute(m_bMute);
  605. #endif /* HELIX_FEATURE_MUTE_PREFERENCE */
  606.             m_pDeviceVolume->AddAdviseSink((IHXVolumeAdviseSink*)this);
  607.         }
  608.         else
  609.             theErr = HXR_OUTOFMEMORY;
  610. #endif /* HELIX_FEATURE_VOLUME */
  611.     }
  612. cleanup:
  613.     return theErr;
  614. }
  615. /************************************************************************
  616.  *  Method:
  617.  *              CHXAudioSession::CreateAudioPlayer
  618.  *      Purpose:
  619.  *       The RMA session object calls this to create an audio player. Each
  620.  *       audio player represents a unique time-line.
  621.  */
  622. HX_RESULT CHXAudioSession::CreateAudioPlayer
  623. (
  624.     CHXAudioPlayer**  ppAudioPlayer
  625. )
  626. {
  627.     m_pMutex->Lock();
  628.     HX_RESULT theErr = HXR_OK;
  629.     // Create a new audio player.
  630.     *ppAudioPlayer= 0;
  631.     *ppAudioPlayer = new CHXAudioPlayer( this );
  632.     if ( !(*ppAudioPlayer) )
  633.         theErr = HXR_OUTOFMEMORY;
  634.     // Add new player to player list.
  635.     if (!theErr)
  636.     {
  637.         theErr = _CreateAudioPlayer(ppAudioPlayer);
  638.     }
  639.     m_pMutex->Unlock();
  640.     return theErr;
  641. }
  642. HX_RESULT
  643. CHXAudioSession::_CreateAudioPlayer(CHXAudioPlayer** ppAudioPlayer)
  644. {
  645.     HX_RESULT   theErr = HXR_OK;
  646.     // Add new player to player list.
  647.     // Setup internal lists, etc.
  648.     theErr = (*ppAudioPlayer)->InitializeStructures();
  649.     if (!theErr)
  650.     {
  651.         // This one to keep it around.
  652.         (*ppAudioPlayer)->AddRef();
  653.         // This one to return back to the caller of CreateAudioPlayer.
  654.         (*ppAudioPlayer)->AddRef();
  655.     }
  656.     // Add new player to player list.
  657.     if ( !theErr && m_pPlayerList )
  658.     {
  659.         m_pPlayerList->AddTail((void*) *ppAudioPlayer);
  660.     }
  661.     if (theErr && *ppAudioPlayer)
  662.     {
  663.         /* Destructor is private. so this is the only way of destructing it */
  664.         (*ppAudioPlayer)->AddRef();
  665.         (*ppAudioPlayer)->Release();
  666.         *ppAudioPlayer = 0;
  667.     }
  668.     return theErr;
  669. }
  670. /************************************************************************
  671.  *  Method:
  672.  *              CHXAudioSession::CreateAudioPlayer
  673.  *      Purpose:
  674.  *       The RMA session object calls this to create an audio player. Each
  675.  *       audio player represents a unique time-line.
  676.  */
  677. HX_RESULT CHXAudioSession::CloseAudioPlayer
  678. (
  679.     CHXAudioPlayer*  pAudioPlayer
  680. )
  681. {
  682.     m_pMutex->Lock();
  683.     if ( m_pPlayerList )
  684.     {
  685.         LISTPOSITION lPosition = NULL;
  686.         lPosition = m_pPlayerList->Find(pAudioPlayer);
  687.         if (lPosition)
  688.         {
  689.             m_pPlayerList->RemoveAt(lPosition);
  690.             pAudioPlayer->Close();
  691.             _NotifyTimelineWatchers( TLW_CLOSE );
  692.             pAudioPlayer->Release();
  693.         }
  694.     }
  695.     m_pMutex->Unlock();
  696.     return HXR_OK;
  697. }
  698. /* ***********************************************************************
  699.  *  Method:
  700.  *              CHXAudioSession::Setup
  701.  *      Purpose:
  702.  *              Create the audio buffer..
  703.  */
  704. HX_RESULT CHXAudioSession::Setup(BOOL bHasStreams)
  705. {
  706.     HX_RESULT theErr = HXR_OK;
  707.     // A new audio player may start while an existing player is
  708.     // already playing.
  709.     if ( m_bInited )
  710.         return HXR_OK;
  711.     /* Only do all of this if there are audio streams... */
  712.     m_bHasStreams = bHasStreams;
  713.     if (m_bHasStreams)
  714.     {
  715.         // Get the audio device format
  716.         // NOTE: The order of these function calls is important.
  717.         // Specifically, the GetDeviceFormat() must precede any of
  718.         // these calls because GetDeviceFormat() determines the
  719.         // final device audio format.
  720.         if (!theErr)
  721.             theErr = GetDeviceFormat();
  722.         // Create the playback buffers
  723.         /* We still need to create playback buffers since we will use the
  724.          * fake timeline if the presentation has atleast one media type other
  725.          * than audio
  726.          */
  727.         if (!theErr || theErr == HXR_AUDIO_DRIVER)
  728.         {
  729.             CreatePlaybackBuffer();
  730.         }
  731.         // Reset the number of blocks we've written
  732.         m_ulBlocksWritten = 0;
  733.         // Open the audio device only if DisableWrite is OFF
  734.         /* This probably needs to be moved at the top so that
  735.          * when second player comes in and we are already intialized,
  736.          * we check for new value of disablewrite again
  737.          */
  738.         CheckDisableWrite();
  739.         m_bUseFinalHook         = FALSE;
  740.         if (!theErr && !m_bDisableWrite)
  741.         {
  742.             theErr = OpenDevice();
  743.         } /* If disable wirte is ON, release the audio device */
  744.         else if (!theErr)
  745.         {
  746.             m_pAudioDev = 0;
  747.         }
  748.         /* If the audio device is busy, check if we have
  749.          * anything other than audio in the presentation.
  750.          * If TRUE, play silence so that the rest of the
  751.          * presentation can be played.
  752.          */
  753.         if (theErr == HXR_AUDIO_DRIVER && !m_bDisableWrite)
  754.         {
  755.             if (!IsAudioOnlyTrue())
  756.             {
  757.                 m_bDisableWrite = TRUE;
  758.                 m_pAudioDev         = 0;
  759.                 theErr      = HXR_OK;
  760.             }
  761.         }
  762.     }
  763.     m_bInited = (!theErr) ? TRUE : FALSE;
  764.     if (!theErr && m_pAudioDev && m_pHookList)
  765.     {
  766.         InitHooks();
  767.     }
  768.     if (!theErr && m_pAudioDev && m_pFinalHook)
  769.     {
  770.         ProcessAudioHook(ACTION_ADD, m_pFinalHook);
  771.     }
  772.     if(m_pContext)
  773.     {
  774.         HX_RELEASE(m_pMPPSupport);
  775.         m_pContext->QueryInterface(IID_IHXMultiPlayPauseSupport, (void**)&m_pMPPSupport);
  776.     }
  777.     return theErr;
  778. }
  779. HX_RESULT
  780. CHXAudioSession::OpenDevice()
  781. {
  782.     HX_RESULT       theErr = HXR_OK;
  783.     HXAudioFormat  audioFormat;
  784.     if (m_pFinalHook)
  785.     {
  786.         m_bUseFinalHook = TRUE;
  787.         if (HXR_OK != ProcessAudioHook(ACTION_CHECK, m_pFinalHook))
  788.         {
  789.             m_bUseFinalHook = FALSE;
  790.         }
  791.         if (m_bUseFinalHook)
  792.         {
  793.             memcpy( &audioFormat, &m_ActualDeviceFmt, sizeof(HXAudioFormat));
  794.             theErr = m_pFinalHook->OnInit(&audioFormat);
  795.         }
  796.     }
  797.     if (!theErr && m_pFinalHook && m_bUseFinalHook)
  798.     {
  799.         m_bUseFinalHook = TRUE;
  800.         /* Did the hook change the data format? */
  801.         if( 0!=memcmp(&audioFormat, &m_ActualDeviceFmt, sizeof(HXAudioFormat)))
  802.         {
  803.             memcpy( &m_BeforeHookDeviceFmt, &m_ActualDeviceFmt, sizeof(HXAudioFormat));
  804.             memcpy( &m_ActualDeviceFmt, &audioFormat, sizeof(HXAudioFormat));
  805.         }
  806.     }
  807.     else
  808.     {
  809.         m_bUseFinalHook = FALSE;
  810.     }
  811.     theErr = OpenAudio();
  812.     if (theErr && m_pFinalHook && m_bUseFinalHook)
  813.     {
  814.         /* Looks like the audio device does not support the format
  815.          * specified by the final Hook
  816.          * Revert back to the original format and try again
  817.          */
  818.         memcpy( &m_ActualDeviceFmt, &m_BeforeHookDeviceFmt, sizeof(HXAudioFormat));
  819.         m_bUseFinalHook         = FALSE;
  820.         theErr = OpenAudio();
  821.     }
  822.     return theErr;
  823. }
  824. /* ***********************************************************************
  825.  *  Method:
  826.  *              CHXAudioSession::GetDeviceFormat
  827.  *      Purpose:
  828.  *              Determine the device format for this session.
  829.  *              The session object needs to resolve the device format
  830.  *              among multiple players.
  831.  */
  832. HX_RESULT CHXAudioSession::GetDeviceFormat()
  833. {
  834.     HX_RESULT       theErr          = HXR_OK;
  835.     UINT16          uOrigSampleRate = 0;
  836.     CHXAudioPlayer* p               = NULL;
  837.     UINT16          bAutoUpsampling = FALSE;
  838.     HXAudioFormat   audioFmt;
  839.     // We no longer force audio device in stereo mode.  However we
  840.     // still try to open it in 16-bit mode since all of our processing
  841.     // is done in 16 bit.
  842.     m_DeviceFmt.uBitsPerSample  = 16;
  843.     //Just grab the first players stats to use as maximums.
  844.     LISTPOSITION lp = m_pPlayerList->GetHeadPosition();
  845.     while(lp)
  846.     {
  847.         p = (CHXAudioPlayer*) m_pPlayerList->GetNext(lp);
  848.         if(0!=p->GetStreamCount())
  849.         {
  850.             p->GetFormat( &audioFmt );
  851.             m_DeviceFmt.uChannels       = audioFmt.uChannels;
  852.             m_DeviceFmt.ulSamplesPerSec = audioFmt.ulSamplesPerSec;
  853.             m_DeviceFmt.uMaxBlockSize   = audioFmt.uMaxBlockSize;
  854.             break;
  855.         }
  856.     }
  857.     //Now loop through the rest of the players and find all the
  858.     //maximums.
  859.     while(lp)
  860.     {
  861.         p = (CHXAudioPlayer*) m_pPlayerList->GetNext(lp);
  862.         if( 0 != p->GetStreamCount() )
  863.         {
  864.             p->GetFormat( &audioFmt );
  865.             m_DeviceFmt.uChannels       = max(m_DeviceFmt.uChannels,
  866.                                               audioFmt.uChannels);
  867.             m_DeviceFmt.ulSamplesPerSec = max(m_DeviceFmt.ulSamplesPerSec,
  868.                                               audioFmt.ulSamplesPerSec);
  869.             m_DeviceFmt.uMaxBlockSize   = max(m_DeviceFmt.uMaxBlockSize,
  870.                                               audioFmt.uMaxBlockSize);
  871.         }
  872.     }
  873.     // turn on the default upsampling to 44K only on IX86 platforms
  874.     // which support MMX
  875.     // XXXgfw this also uses more memory for each block we push down
  876.     // XXXgfw to the audio device. You might not want it on MIN_HEAP
  877.     // XXXgfw kind of MMX devices, if there are any.
  878. #if defined(_M_IX86)
  879.     ReadPrefINT16(m_pPreferences, "AutoAudioUpsampling", bAutoUpsampling );
  880. #endif
  881.     if(bAutoUpsampling)
  882.     {
  883.         //force 44khz as our first attempt to open audio device
  884.         uOrigSampleRate = (UINT16)m_DeviceFmt.ulSamplesPerSec;
  885.         m_DeviceFmt.ulSamplesPerSec = 44100;
  886.     }
  887. #if defined(HELIX_FEATURE_PREFERENCES)
  888.     else
  889.     {
  890.         UINT16 ulSamplesPerSecPreference = 0;
  891.         ReadPrefINT16(m_pPreferences, "AudioDeviceSamplesPerSec", ulSamplesPerSecPreference );
  892.         if(ulSamplesPerSecPreference)
  893.         {
  894.             uOrigSampleRate = (UINT16)m_DeviceFmt.ulSamplesPerSec;
  895.             m_DeviceFmt.ulSamplesPerSec = ulSamplesPerSecPreference;
  896.         }
  897.     }
  898. #endif /* HELIX_FEATURE_PREFERENCES */
  899.     //Start negotiating with the device. Generate a table that will
  900.     //drive the different formats we want to try.  Start with the
  901.     //native rate (and any mods from the pref stuff above) and go up
  902.     //in samplerate. If that fails, go down in sample rate.
  903.     const int nNumberOfRates = sizeof(z_anValidSampleRates)/sizeof(z_anValidSampleRates[0]);
  904.     //Total number of table entries per sample rate will be:
  905.     //nNumberOfRates*4 (mono/16, mono/8, stereo/16, stereo/8) plus
  906.     //native format + user defined samplerate entry.
  907.     const int      nTmp       = nNumberOfRates*4+2;
  908.     unsigned short nTableSize = 0;
  909.     tableEntry* table = new tableEntry[nTmp];
  910.     HX_ASSERT(table);
  911.     if( NULL == table )
  912.         return HXR_OUTOFMEMORY;
  913.     //First entry is always our native format from above with any
  914.     //samplerate changes the user made via prefs.
  915.     table[nTableSize++].set( (UINT16)m_DeviceFmt.ulSamplesPerSec,
  916.                              (UINT8)m_DeviceFmt.uChannels,
  917.                              (UINT8)m_DeviceFmt.uBitsPerSample
  918.                              );
  919.     //Second entry is always the above with the clip's original
  920.     //sample rate, if we changed it.
  921.     if( uOrigSampleRate )
  922.         table[nTableSize++].set(uOrigSampleRate,
  923.                                 (UINT8)m_DeviceFmt.uChannels,
  924.                                 (UINT8)m_DeviceFmt.uBitsPerSample
  925.                                 );
  926.     //Now generate the rest of the format table....
  927.     const UINT8 usNativeChannel = (UINT8)m_DeviceFmt.uChannels;
  928.     const UINT8 usAltChannel    = (2==m_DeviceFmt.uChannels)?1:2;
  929.     const UINT8 usNativeBits    = (UINT8)m_DeviceFmt.uBitsPerSample;
  930.     const UINT8 usAltBits       = (8==m_DeviceFmt.uBitsPerSample)?16:8;
  931.     //First use all equal or higher sample rates.
  932.     short nIdx = 0;
  933.     while( nIdx<nNumberOfRates )
  934.     {
  935.         UINT16 usRate = z_anValidSampleRates[nIdx];
  936.         if( usRate >= m_DeviceFmt.ulSamplesPerSec )
  937.         {
  938.             table[nTableSize++].set(usRate, usNativeChannel, usNativeBits );
  939.             table[nTableSize++].set(usRate, usAltChannel,    usNativeBits );
  940.             table[nTableSize++].set(usRate, usNativeChannel, usAltBits  );
  941.             table[nTableSize++].set(usRate, usAltChannel,    usAltBits  );
  942.         }
  943.         nIdx++;
  944.     }
  945.     //Now all the samle rates lower then the native rate.
  946.     nIdx = nNumberOfRates-1;
  947.     while( nIdx>=0)
  948.     {
  949.         UINT16 usRate = z_anValidSampleRates[nIdx];
  950.         if( usRate < m_DeviceFmt.ulSamplesPerSec )
  951.         {
  952.             table[nTableSize++].set(usRate, usNativeChannel, usNativeBits );
  953.             table[nTableSize++].set(usRate, usAltChannel,    usNativeBits );
  954.             table[nTableSize++].set(usRate, usNativeChannel, usAltBits  );
  955.             table[nTableSize++].set(usRate, usAltChannel,    usAltBits  );
  956.         }
  957.         nIdx--;
  958.     }
  959.     //Now loop through our table and find a supported format.
  960.     nIdx = 0;
  961.     theErr = HXR_FAIL;
  962.     while( FAILED(theErr) && nIdx<nTableSize)
  963.     {
  964.         m_DeviceFmt.ulSamplesPerSec = table[nIdx].usSampleRate;
  965.         m_DeviceFmt.uChannels       = table[nIdx].usChannels;
  966.         m_DeviceFmt.uBitsPerSample  = table[nIdx].usBits;
  967.         theErr = CheckAudioFormat(&m_DeviceFmt);
  968.         nIdx++;
  969.     }
  970.     //We still need to create playback buffers since we will use the
  971.     //fake timeline if the presentation has atleast one media type
  972.     //other than audio
  973.     //XXXgfw this code below needs to be looked at. I Don't want to
  974.     //touch it now for fear of breaking something that will take
  975.     //a long time to fix.
  976.     if (!theErr || theErr == HXR_AUDIO_DRIVER)
  977.     {
  978.         m_ActualDeviceFmt = m_DeviceFmt;
  979.         //All the calculations are done for 16 bit stereo. There are
  980.         //VERY FEW sound cards out there which do not support 16 bit
  981.         //stereo. They will incur a high performace hit because of
  982.         //possible unnecessary up/down conversion. For now we will
  983.         //live with that.
  984.         //XXXgfw wrong. lots of handhelds/phones don't do 16bit-2
  985.         //channel output.
  986.         m_DeviceFmt.uBitsPerSample  = 16;
  987.         m_BeforeHookDeviceFmt = m_ActualDeviceFmt;
  988.     }
  989.     HX_VECTOR_DELETE(table);
  990.     return theErr;
  991. }
  992. /************************************************************************
  993.  *  Method:
  994.  *              CHXAudioSession::CheckAudioFormat
  995.  *      Purpose:
  996.  *       The audio player calls this to check its audio format with the
  997.  *       the audio device.
  998.  */
  999. HX_RESULT CHXAudioSession::CheckAudioFormat
  1000. (
  1001.     HXAudioFormat*    pAudioFormat
  1002. )
  1003. {
  1004.     HX_RESULT theErr = HXR_OK;
  1005.     if (!m_pAudioDev)
  1006.     {
  1007.         CreateAudioDevice();
  1008.         m_pAudioDev = m_pCurrentAudioDev;
  1009.     }
  1010.     if (m_pAudioDev)
  1011.     {
  1012.         theErr = m_pAudioDev->CheckFormat(pAudioFormat);
  1013.         /* Any error from audio device other than memory error is
  1014.          * returned as HXR_AUDIO_DRIVER
  1015.          */
  1016.         if (theErr != HXR_OK && theErr != HXR_OUTOFMEMORY)
  1017.         {
  1018.             theErr = HXR_AUDIO_DRIVER;
  1019.         }
  1020.     }
  1021.     return theErr;
  1022. }
  1023. /************************************************************************
  1024.  *  Method:
  1025.  *              CHXAudioSession::PlayAudio
  1026.  *      Purpose:
  1027.  *       The player object call this to play audio. This method is called
  1028.  *       again in the playback response function.
  1029.  */
  1030. HX_RESULT CHXAudioSession::PlayAudio(UINT16 uNumBlocks)
  1031. {
  1032.     HX_RESULT theErr        = HXR_OK;
  1033.     BOOL      bDisableWrite = FALSE;
  1034.     if ( !m_bInited )
  1035.         return theErr;
  1036.     if (m_bInPlayAudio)
  1037.     {
  1038.         return HXR_OK;
  1039.     }
  1040.     m_pMutex->Lock();
  1041.     if (m_bToBeRewound)
  1042.     {
  1043.         theErr = Rewind();
  1044.         goto exit;
  1045.     }
  1046.     m_bInPlayAudio = TRUE;
  1047.     if (m_pAuxiliaryAudioBuffers &&
  1048.         m_pAuxiliaryAudioBuffers->GetCount() > 0 && m_pAudioDev && !m_bDisableWrite)
  1049.     {
  1050.         if (HXR_OK == ProcessAudioDevice(ACTION_CHECK, m_pAudioDev))
  1051.         {
  1052.             /* Try to stuff in as much backlog as possible */
  1053.             while (!theErr && m_pAuxiliaryAudioBuffers->GetCount() > 0)
  1054.             {
  1055.                 HXAudioData* pAudioData =
  1056.                     (HXAudioData*) m_pAuxiliaryAudioBuffers->GetHead();
  1057.                 // Write session audio data to device.
  1058.                 theErr = m_pAudioDev->Write(pAudioData);
  1059.                 if( theErr == HXR_OUTOFMEMORY )
  1060.                 {
  1061.                     goto exit;
  1062.                 }
  1063.                 if (!theErr)
  1064.                 {
  1065.                     m_ulBlocksWritten++;
  1066.                     m_dNumBytesWritten  += pAudioData->pData->GetSize();
  1067.                     m_pAuxiliaryAudioBuffers->RemoveHead();
  1068.                     pAudioData->pData->Release();
  1069.                     delete pAudioData;
  1070.                 }
  1071.                 /*All other error codes are translated into audio driver error*/
  1072.                 else if (theErr != HXR_OUTOFMEMORY && theErr != HXR_WOULD_BLOCK)
  1073.                 {
  1074.                     theErr = HXR_AUDIO_DRIVER;
  1075.                 }
  1076.             }
  1077.         }
  1078.     }
  1079.     // If we have audio streams then play audio.
  1080.     if (!theErr && m_bHasStreams)
  1081.     {
  1082.         // Push down at least 3 secs of audio.
  1083.         UINT16 uPush = uNumBlocks;
  1084.         if (m_bFirstPlayAudio)
  1085.         {
  1086.             uPush = (UINT16) m_ulMinBlocksTobeQueued;
  1087.         }
  1088.         HXAudioData audioData;
  1089.         CHXAudioPlayer* pPlayer = 0;
  1090.         CHXAudioStream* pStream = 0;
  1091.         CHXSimpleList*  pStreamList = 0;
  1092. #if defined(HELIX_FEATURE_VOLUME) || defined(HELIX_FEATURE_MIXER)
  1093.         UINT16  uPlayerVolume = HX_INIT_VOLUME;
  1094. #endif
  1095.         UCHAR*  pMixBuffer = 0;
  1096.         UCHAR*  pPlayerBuf = NULL;
  1097.         UCHAR*  pSessionBuf = NULL;
  1098.         IHXBuffer* pMixIHXBuffer = NULL;
  1099.         BufType bufType = BUFFER_NONE;
  1100.         for (UINT16 i = 0; !theErr && i < uPush; i++ )
  1101.         {
  1102.             m_uNumToBePushed = uPush - i;
  1103.             m_bSessionBufferDirty = FALSE; // only used for multi-player case
  1104.             UINT32  ulNumBytesWritten = m_ulBytesPerGran;
  1105.             BOOL    bAtLeastOnePlayerActive = FALSE;
  1106.             theErr = m_pSessionBuf->SetSize(m_ulBytesPerGran);
  1107.             if( theErr == HXR_OUTOFMEMORY )
  1108.             {
  1109.                 theErr = HXR_OUTOFMEMORY;
  1110.                 goto exit;
  1111.             }
  1112.             pSessionBuf = m_pSessionBuf->GetBuffer();
  1113.             // Zero session buffer.
  1114.             //memset(pSessionBuf, 0, HX_SAFESIZE_T(m_ulBytesPerGran));
  1115.             // Get each player
  1116.             pPlayer = 0;
  1117.             CHXSimpleList::Iterator lIter = m_pPlayerList->Begin();
  1118.             for (; lIter != m_pPlayerList->End(); ++lIter)
  1119.             {
  1120.                 BOOL bStalled = FALSE;
  1121.                 pPlayer = (CHXAudioPlayer*) (*lIter);
  1122.                 if (pPlayer->GetStreamCount() == 0 ||
  1123.                     pPlayer->IsDonePlayback() ||
  1124.                     pPlayer->GetState() != E_PLAYING)
  1125.                 {
  1126.                     continue;
  1127.                 }
  1128.                 bAtLeastOnePlayerActive = TRUE;
  1129.                 if (m_pPlayerList->GetCount() == 1)
  1130.                 {
  1131.                     pMixIHXBuffer = m_pSessionBuf;
  1132.                     bufType = BUFFER_SESSION;
  1133.                 }
  1134.                 else
  1135.                 {
  1136.                     if (!m_pPlayerBuf)
  1137.                     {
  1138.                         m_pPlayerBuf = new CHXBuffer;
  1139.                         m_pPlayerBuf->AddRef();
  1140.                     }
  1141.                     m_pPlayerBuf->SetSize(m_ulBytesPerGran);
  1142.                     pPlayerBuf = m_pPlayerBuf->GetBuffer();
  1143.                     // Zero play buffer.
  1144. //                  memset(pPlayerBuf, 0, HX_SAFESIZE_T(m_ulBytesPerGran));
  1145.                     pMixIHXBuffer = m_pPlayerBuf;
  1146.                     bufType = BUFFER_PLAYER;
  1147.                 }
  1148.                 pMixBuffer = pMixIHXBuffer->GetBuffer();
  1149.                 BOOL bIsMixBufferDirty = FALSE;
  1150.                 BOOL bMayNeedToRollbackTimestamp = FALSE;
  1151.                 if (pPlayer->GetState() == E_PLAYING)
  1152.                 {
  1153.                     UINT32  ulBufTime = 0;
  1154.                     // Get each stream associated with this player
  1155.                     pStreamList = pPlayer->GetStreamList();
  1156.                     if (pStreamList)
  1157.                     {
  1158.                     CHXSimpleList::Iterator lIter = pStreamList->Begin();
  1159.                     for (; lIter != pStreamList->End(); ++lIter)
  1160.                     {
  1161.                         pStream = (CHXAudioStream*) (*lIter);
  1162.                         pStream->m_bMayNeedToRollbackTimestamp = FALSE;
  1163.                         // don't mix paused audio streams
  1164.                         if (pStream->GetState() != E_PAUSED)
  1165.                         {
  1166.                             theErr = pStream->MixIntoBuffer( pMixBuffer, m_ulBytesPerGran, ulBufTime, bIsMixBufferDirty);
  1167.                             // so as not to trigger ReallyNeedData
  1168.                             // since one of the streams internal m_llLastwritetime
  1169.                             // has been updated even though this flag is set to FALSE.
  1170. #if 0
  1171.                             if (!bIsMixBufferDirty &&
  1172.                                 (theErr == HXR_OK || theErr == HXR_NO_DATA))
  1173.                             {
  1174.                                 bIsMixBufferDirty = TRUE;
  1175.                                 ::memset(pMixBuffer, 0, HX_SAFESIZE_T(m_ulBytesPerGran));
  1176.                             }
  1177. #endif
  1178.                             if (theErr == HXR_NO_DATA)
  1179.                             {
  1180.                                 pStream->m_bMayNeedToRollbackTimestamp = TRUE;
  1181.                                 bMayNeedToRollbackTimestamp = TRUE;
  1182.                                 theErr = HXR_OK;
  1183.                                 continue;
  1184.                             }
  1185.                             if (theErr == HXR_FAIL)
  1186.                             {
  1187.                                 theErr = HXR_OK;
  1188.                                 goto exit;
  1189.                             }
  1190.                             if (theErr == HXR_OUTOFMEMORY)
  1191.                             {
  1192.                                 goto exit;
  1193.                             }
  1194.                             if (theErr == HXR_WOULD_BLOCK)
  1195.                             {
  1196. #ifdef _RAHULDEBUG
  1197.                                 {
  1198.                                     char str[255]; /* Flawfinder: ignore */
  1199.                                     ::sprintf(str, "Num to be pushed remaining: %lun", m_uNumToBePushed); /* Flawfinder: ignore */
  1200.                                     OutputDebugString(str);
  1201.                                 }
  1202. #endif
  1203.                                 if (bMayNeedToRollbackTimestamp)
  1204.                                 {
  1205.                                     bMayNeedToRollbackTimestamp = FALSE;
  1206.                                     lIter = pStreamList->Begin();
  1207.                                     for (; lIter != pStreamList->End(); ++lIter)
  1208.                                     {
  1209.                                         pStream = (CHXAudioStream*) (*lIter);
  1210.                                         if (pStream->m_bMayNeedToRollbackTimestamp)
  1211.                                         {
  1212.                                             pStream->m_bMayNeedToRollbackTimestamp = FALSE;
  1213.                                             pStream->RollBackTimestamp();
  1214.                                         }
  1215.                                     }
  1216.                                 }
  1217.                                 goto handlewouldblock;
  1218.                             }
  1219.                         }
  1220.                         if (pPlayer->GetState() != E_PLAYING)
  1221.                         {
  1222.                             /* We should keep the last buffer around and the last stream
  1223.                              * to be mixed again...TBD XXX Rahul
  1224.                              */
  1225.                             //pPlayer->SetLastMixedBuffer(pMixBuffer, pStream);
  1226.                             bStalled = TRUE;
  1227.                             break;
  1228.                         }
  1229.                     }
  1230.                     } //if (pStreamList)
  1231.                     /* This pause may have happended due to ondrynotification */
  1232.                     if (m_bPaused || m_bStoppedDuringPause)
  1233.                     {
  1234.                         /* This would happen ONLY IF THERE IS ONE AUDIO PLAYER
  1235.                          * and that has been paused. So simply break
  1236.                          */
  1237.                         goto exit;
  1238.                         //break;
  1239.                     }
  1240.                     /* hmmm... looks like there are more than one audio player.
  1241.                      * continue with the next one
  1242.                      */
  1243.                     if (bStalled)
  1244.                     {
  1245.                         continue;
  1246.                     }
  1247.                     /* If the mixer buffer was not used, make sure it is initialized
  1248.                      * to silence since we pass it to post process hooks
  1249.                      */
  1250.                     if (!bIsMixBufferDirty)
  1251.                     {
  1252. //{FILE* f1 = ::fopen("e:\audioses.txt", "a+"); ::fprintf(f1, "%lut%ptsilence in mix buffern", HX_GET_BETTERTICKCOUNT(), this);::fclose(f1);}
  1253.                         ::memset(pMixBuffer, 0, HX_SAFESIZE_T(m_ulBytesPerGran));
  1254.                     }
  1255. #if defined(HELIX_FEATURE_VOLUME) && defined(HELIX_FEATURE_MIXER)
  1256.                     // Apply Player volume to buffer; do this before we call
  1257.                     // the post mix hooks.
  1258.                     uPlayerVolume = pPlayer->GetVolume();
  1259.                     if (uPlayerVolume != 100 && bIsMixBufferDirty)
  1260.                     {
  1261.                         CHXMixer::ApplyVolume(pMixBuffer, m_ulBytesPerGran, uPlayerVolume, m_DeviceFmt.uBitsPerSample);
  1262.                     }
  1263. #endif /* HELIX_FEATURE_VOLUME && HELIX_FEATURE_MIXER */
  1264.                     // Give data to this AudioPlayer's post mix hooks
  1265.                     // (do they want 8 or 16 bit?)
  1266.                     BOOL bChanged = FALSE;
  1267.                     ProcessPostMixHooks(pPlayer, pMixIHXBuffer, &bDisableWrite, ulBufTime, bChanged);
  1268.                     /*
  1269.                      * If the mixer buffer changed (because of a post mix hook)
  1270.                      * make sure to point the player/session buffer to this
  1271.                      * modified buffer
  1272.                      */
  1273.                     if (bChanged)
  1274.                     {
  1275.                         pMixBuffer = pMixIHXBuffer->GetBuffer();
  1276.                         if (bufType == BUFFER_PLAYER)
  1277.                         {
  1278.                             m_pPlayerBuf = pMixIHXBuffer;
  1279.                             pPlayerBuf = pMixIHXBuffer->GetBuffer();
  1280.                         }
  1281.                         else
  1282.                         {
  1283.                             m_pSessionBuf = pMixIHXBuffer;
  1284.                             pSessionBuf = pMixIHXBuffer->GetBuffer();
  1285.                         }
  1286.                     }
  1287.                 }
  1288. #if defined(HELIX_FEATURE_MIXER)
  1289.                 // Don't mix if volume is 0.
  1290.                 // Don't mix if this player has disabled device write.
  1291.                 // Don't mix if there is only one player since we would have
  1292.                 // written data into session buf instead of player buffer
  1293.                 if (m_pPlayerList->GetCount() > 1 && uPlayerVolume > 0 && !bDisableWrite)
  1294.                 {
  1295.                     /* We always set a volume of 100 since we have already applied volume
  1296.                      * to player buffer
  1297.                      */
  1298.                     CHXMixer::MixBuffer( pPlayerBuf, pSessionBuf,
  1299.                                 m_ulBytesPerGran, FALSE, 100, m_DeviceFmt.uBitsPerSample, m_bSessionBufferDirty);
  1300.                 }
  1301. #endif /* HELIX_FEATURE_MIXER */
  1302.                 pPlayer->UpdateLastWriteTime(m_ulGranularity);
  1303.             }
  1304.             if (!bAtLeastOnePlayerActive)
  1305.             {
  1306.                 goto exit;
  1307.             }
  1308.             /* did we ever write to the session buffer ? */
  1309.             if (m_pPlayerList->GetCount() > 1 && !m_bSessionBufferDirty)
  1310.             {
  1311. //{FILE* f1 = ::fopen("e:\audioses.txt", "a+"); ::fprintf(f1, "%lut%ptsilence in session buffern", HX_GET_BETTERTICKCOUNT(), this);::fclose(f1);}
  1312.                 ::memset(pSessionBuf, 0, HX_SAFESIZE_T(m_ulBytesPerGran));
  1313.             }
  1314.             // This increments with each buffered played.
  1315.             m_dBufEndTime   += m_dGranularity;
  1316.             // Set the session buffer to the IRMA buffer.
  1317.             audioData.pData       = m_pSessionBuf;
  1318.             audioData.ulAudioTime = (ULONG32)m_dBufEndTime;
  1319.             if (m_pAudioDev && !m_bDisableWrite)
  1320.             {
  1321.                 /* are we dealing with a f*%$'ed up sound card */
  1322.                 if ((m_BeforeHookDeviceFmt.uChannels == 1 && m_DeviceFmt.uChannels == 2)||
  1323.                     m_BeforeHookDeviceFmt.uBitsPerSample == 8)
  1324.                 {
  1325.                     ConvertTo8BitAndOrMono(&audioData);
  1326.                 }
  1327.                 if (m_pFinalHook && m_bUseFinalHook)
  1328.                 {
  1329.                     if (HXR_OK == ProcessAudioHook(ACTION_CHECK, m_pFinalHook))
  1330.                     {
  1331.                         m_pOutDataPtr->pData        = NULL;
  1332.                         m_pOutDataPtr->ulAudioTime          = audioData.ulAudioTime;
  1333.                         m_pOutDataPtr->uAudioStreamType = audioData.uAudioStreamType;
  1334.                         m_pFinalHook->OnBuffer(&audioData, m_pOutDataPtr);
  1335.                         HX_ASSERT(m_pOutDataPtr->pData);
  1336.                         if (m_pOutDataPtr->pData)
  1337.                         {
  1338.                             HX_RELEASE(audioData.pData);
  1339.                             m_pSessionBuf = audioData.pData = m_pOutDataPtr->pData;
  1340.                         }
  1341.                         else
  1342.                         {
  1343.                             /* This is a screwed up Hook. Disable it */
  1344.                             m_bUseFinalHook = FALSE;
  1345.                         }
  1346.                     }
  1347.                 }
  1348.                 if (m_pHookList)
  1349.                 {
  1350.                     ProcessHooks(&audioData);
  1351.                 }
  1352.                 ulNumBytesWritten    = audioData.pData->GetSize();
  1353.                 if (HXR_OK == ProcessAudioDevice(ACTION_CHECK, m_pAudioDev))
  1354.                 {
  1355.                     // Write session audio data to device.
  1356.                     theErr = m_pAudioDev->Write(&audioData);
  1357.                     if( theErr == HXR_OUTOFMEMORY )
  1358.                     {
  1359.                         goto exit;
  1360.                     }
  1361.                 }
  1362.                 if (theErr == HXR_WOULD_BLOCK)
  1363.                 {
  1364.                     HXAudioData* pAudioData     = new HXAudioData;
  1365.                     pAudioData->pData           = audioData.pData;
  1366.                     pAudioData->pData->AddRef();
  1367.                     pAudioData->ulAudioTime     = audioData.ulAudioTime;
  1368.                     pAudioData->uAudioStreamType= audioData.uAudioStreamType;
  1369.                     // Create auxiliary buffer list, if one is not already created
  1370.                     if (!m_pAuxiliaryAudioBuffers)
  1371.                     {
  1372.                         m_pAuxiliaryAudioBuffers = new CHXSimpleList;
  1373.                     }
  1374.                     if( NULL == m_pAuxiliaryAudioBuffers->AddTail(pAudioData) )
  1375.                     {
  1376.                         theErr = HXR_OUTOFMEMORY;
  1377.                         goto exit;
  1378.                     }
  1379.                     HX_RELEASE(m_pSessionBuf);
  1380.                 }
  1381.                 /* Any error from audio device other than memory error is
  1382.                  * returned as HXR_AUDIO_DRIVER
  1383.                  */
  1384.                 if (theErr != HXR_OK && theErr != HXR_WOULD_BLOCK &&
  1385.                     theErr != HXR_OUTOFMEMORY)
  1386.                 {
  1387.                     theErr = HXR_AUDIO_DRIVER;
  1388.                 }
  1389.             }
  1390.             if (!theErr)
  1391.             {
  1392.                 m_ulBlocksWritten++;
  1393.                 m_dNumBytesWritten  += ulNumBytesWritten;
  1394.             }
  1395.             // So this function is good in theory, but in practice we find in
  1396.             // heap-optimized mode it is not necessary, and it leads to
  1397.             // unnecessary heap fragmentation.
  1398. #if !defined(HELIX_CONFIG_MIN_HEAP_FRAG)
  1399.             theErr = CheckForBufferReuse();
  1400. #endif
  1401.         }  // for loop
  1402.     }     //  end if we have audio streams
  1403. handlewouldblock:
  1404.     // mask this error
  1405.     if (theErr == HXR_WOULD_BLOCK)
  1406.     {
  1407.         theErr = HXR_OK;
  1408.     }
  1409.     // If we do not have audio.. OR  if we do have audio but
  1410.     // we have disabled writing to the device, then we need to
  1411.     // fake the timeline.
  1412.     if (!theErr && !m_ulCallbackID && (!m_bHasStreams || m_bDisableWrite))
  1413.     {
  1414.         if (m_bFirstPlayAudio)
  1415.         {
  1416.             // First time thru, we initialize callback time.
  1417.             HXTimeval lTime = m_pScheduler->GetCurrentSchedulerTime();
  1418.             m_pFakeAudioCBTime->tv_sec = lTime.tv_sec;
  1419.             m_pFakeAudioCBTime->tv_usec = lTime.tv_usec;
  1420.             m_ulIncreasingTimer = 0;
  1421.             m_ulLastFakeCallbackTime    = HX_GET_TICKCOUNT();
  1422.             *m_pFakeAudioCBTime += (int) (m_ulGranularity*1000);
  1423.         }
  1424.         m_bFakeAudioTimeline =  TRUE;
  1425.         m_ulCallbackID = m_pScheduler->RelativeEnter( this, m_ulGranularity);
  1426.         if (m_bFirstPlayAudio)
  1427.         {
  1428.             OnTimeSync(m_ulIncreasingTimer);
  1429.         }
  1430.     }
  1431.     else if (!theErr && !m_ulCallbackID && m_bHasStreams && !m_bDisableWrite)
  1432.     {
  1433.         m_bFakeAudioTimeline =  FALSE;
  1434.         m_ulCallbackID = m_pScheduler->RelativeEnter(this, m_ulGranularity*9/10);
  1435. #if 0   // XXX HP don't send OnTimeSync() untill we resume the audio device
  1436.         // the following logic caused OnTimeSync() sent to video renderer before the audio
  1437.         // timeline is started after seeking, as a consequence, the A/V could be out of
  1438.         // sync, video could be frozen for short period time in order to wait the audio
  1439.         // timeline to catch up
  1440.         if (m_bFirstPlayAudio)
  1441.         {
  1442.             OnTimeSync(m_ulIncreasingTimer);
  1443.         }
  1444. #endif
  1445.     }
  1446. exit:
  1447.     m_bInPlayAudio      = FALSE;
  1448.     // can only happen in multi-player pause/resume/stop case
  1449.     if (m_bDeferActualResume && theErr != HXR_OUTOFMEMORY)
  1450.     {
  1451.         m_bDeferActualResume = FALSE;
  1452.         theErr = ActualResume();
  1453.     }
  1454.     m_bFirstPlayAudio   = FALSE;
  1455.     m_pMutex->Unlock();
  1456.     return theErr;
  1457. }
  1458. HX_RESULT
  1459. CHXAudioSession::CheckForBufferReuse()
  1460. {
  1461.     if (m_pSessionBuf)
  1462.     {
  1463.         m_pSessionBuf->AddRef();
  1464.         if (m_pSessionBuf->Release() > 1)
  1465.         {
  1466.             /*
  1467.              * Cannot use this buffer the next time
  1468.              * release our reference and  create a new one
  1469.              */
  1470.             m_pSessionBuf->Release();
  1471.             m_pSessionBuf = (IHXBuffer*) new CHXBuffer;
  1472.             if( m_pSessionBuf )
  1473.             {
  1474.             m_pSessionBuf->AddRef();
  1475.         }
  1476.             else
  1477.             {
  1478.                 return HXR_OUTOFMEMORY;
  1479.             }
  1480.         }
  1481.     }
  1482.     else
  1483.     {
  1484.         /* create this buffer */
  1485.         m_pSessionBuf = (IHXBuffer*) new CHXBuffer;
  1486.         if( m_pSessionBuf )
  1487.         {
  1488.         m_pSessionBuf->AddRef();
  1489.     }
  1490.         else
  1491.         {
  1492.             return HXR_OUTOFMEMORY;
  1493.         }
  1494.     }
  1495.     if (m_pPlayerBuf)
  1496.     {
  1497.         m_pPlayerBuf->AddRef();
  1498.         if (m_pPlayerBuf->Release() > 1)
  1499.         {
  1500.             /*
  1501.              * Cannot use this buffer the next time
  1502.              * release our reference and  create a new one
  1503.              */
  1504.             m_pPlayerBuf->Release();
  1505.             m_pPlayerBuf = (IHXBuffer*) new CHXBuffer;
  1506.             if( m_pSessionBuf )
  1507.             {
  1508.             m_pPlayerBuf->AddRef();
  1509.         }
  1510.             else
  1511.             {
  1512.                 return HXR_OUTOFMEMORY;
  1513.             }
  1514.     }
  1515.     }
  1516.     return HXR_OK;
  1517. }
  1518. void CHXAudioSession::ConvertTo8BitAndOrMono(HXAudioData* pAudioData)
  1519. {
  1520.     BOOL bChannelConversion = (m_BeforeHookDeviceFmt.uChannels == 1) &&
  1521.                               (m_DeviceFmt.uChannels == 2);
  1522.     BOOL bBitConversion     = m_BeforeHookDeviceFmt.uBitsPerSample == 8;
  1523.     /* Atleast one of them should be true to be in this function */
  1524.     HX_ASSERT(bChannelConversion || bBitConversion);
  1525.     ULONG32     ulLen           = pAudioData->pData->GetSize();
  1526.     short int*  pShortBuf       = (short int*) pAudioData->pData->GetBuffer();
  1527.     UCHAR*      pOutUCharBuf    = pAudioData->pData->GetBuffer();
  1528.     short int*  pOutShortBuf    = (short int*) pAudioData->pData->GetBuffer();
  1529.     ULONG32     ulLoopCount     = ulLen;
  1530.     if (bBitConversion && bChannelConversion)
  1531.     {
  1532.         ulLen       =  pAudioData->pData->GetSize() / 4;
  1533.         ulLoopCount = pAudioData->pData->GetSize() / 4;
  1534.     }
  1535.     else if (bBitConversion && !bChannelConversion)
  1536.     {
  1537.         ulLen       = pAudioData->pData->GetSize() / 2;
  1538.         ulLoopCount = pAudioData->pData->GetSize() / 2;
  1539.     }
  1540.     else /*if (!bBitConversion && bChannelConversion) */
  1541.     {
  1542.         ulLen       = pAudioData->pData->GetSize() / 2;
  1543.         ulLoopCount = pAudioData->pData->GetSize() / 4;
  1544.     }
  1545.     for(ULONG32 j = 0; j < ulLoopCount; j++)
  1546.     {
  1547.         if (bBitConversion && bChannelConversion)
  1548.         {
  1549.             *pOutUCharBuf++ = (UCHAR)   (
  1550.                                 ((LONG32) ((*pShortBuf++  + 32768L) >> 8) +
  1551.                                  (LONG32) ((*pShortBuf++  + 32768L) >> 8))/2
  1552.                                         );
  1553.         }
  1554.         else if (bBitConversion && !bChannelConversion)
  1555.         {
  1556.             *pOutUCharBuf++ = (UCHAR)((*pShortBuf++  + 32768L) >> 8);
  1557.         }
  1558.         else /*if (!bBitConversion && bChannelConversion) */
  1559.         {
  1560.             *pOutShortBuf++ = (short int) (((LONG32) *pShortBuf++  + (LONG32) *pShortBuf++)/2);
  1561.         }
  1562.     }
  1563.     pAudioData->pData->SetSize(ulLen);
  1564. }
  1565. /************************************************************************
  1566.  *  Method:
  1567.  *              CHXAudioSession::ConvertToEight
  1568.  *      Purpose:
  1569.  */
  1570. void CHXAudioSession::ConvertToEight()
  1571. {
  1572.     UCHAR* pSessionBuf = m_pSessionBuf->GetBuffer();
  1573.     ULONG32 ulLen = m_ulBytesPerGran / sizeof(short);
  1574.     short int* iTmp = (short int*) pSessionBuf;
  1575.     for(ULONG32 j = 0; j < ulLen; j++ )
  1576.     {
  1577.         pSessionBuf[j] = (UCHAR) ((*iTmp++  + 32768L) >> 8);
  1578.     }
  1579. }
  1580. /************************************************************************
  1581.  *  Method:
  1582.  *              CHXAudioSession::TryOpenAudio
  1583.  *      Purpose:
  1584.  *       Try to open the audio device.
  1585.  */
  1586. HX_RESULT CHXAudioSession::TryOpenAudio()
  1587. {
  1588.     HX_RESULT theErr = HXR_OK;
  1589.     BOOL bDeviceOpened = FALSE;
  1590.     // Free the audio device if it is ours so that we can create it on the core thread!
  1591.     if ((!m_bReplacedDev || !m_bUsingReplacedDevice) && m_pCurrentAudioDev)
  1592.     {
  1593.         ReleaseAudioDevice();
  1594.         RestoreReplacedDevice();
  1595.         m_pAudioDev = NULL;
  1596.     }
  1597.     theErr = CreateAudioDevice();
  1598.     if (!theErr && m_pCurrentAudioDev)
  1599.     {
  1600.         m_pAudioDev = m_pCurrentAudioDev;
  1601.         if (!m_bReplacedDev || !m_bUsingReplacedDevice)
  1602.         {
  1603.             ((CHXAudioDevice*)m_pAudioDev)->SetGranularity( m_ulGranularity, m_ulBytesPerGran);
  1604.         }
  1605.         theErr = m_pAudioDev->Open( &m_ActualDeviceFmt, this );
  1606.         bDeviceOpened = TRUE;
  1607.         m_ulBlocksWritten = 0;
  1608.         /* we always open in a PAUSED state */
  1609.         if (!theErr)
  1610.         {
  1611.             theErr = m_pAudioDev->Pause();
  1612.             _NotifyTimelineWatchers(TLW_PAUSE);
  1613.         }
  1614.         if (theErr != HXR_OK)
  1615.         {
  1616.             m_pAudioDev = NULL;
  1617.         }
  1618.         if (!theErr && m_pAudioDev)
  1619.         {
  1620.             /* Set the initial device volume */
  1621.             m_pAudioDev->SetVolume(m_bMute ? 0 : m_uVolume);
  1622.         }
  1623.     }
  1624.     /* Any error from audio device other than memory error is returned
  1625.      * as HXR_AUDIO_DRIVER
  1626.      */
  1627.     if (theErr != HXR_OK && theErr != HXR_OUTOFMEMORY)
  1628.     {
  1629.         theErr = HXR_AUDIO_DRIVER;
  1630.     }
  1631. #ifndef _CARBON
  1632.     if (!theErr && bDeviceOpened && m_bShouldOpenOnCoreThread &&
  1633.         m_pInterruptState && !m_pInterruptState->AtInterruptTime())
  1634.     {
  1635.         // we should re-open on the core thread!!!
  1636.         m_bToBeReOpened = TRUE;
  1637.         if( !m_pDeviceCallback )
  1638.         {
  1639.             m_pDeviceCallback = new HXDeviceSetupCallback(this);
  1640.             m_pDeviceCallback->AddRef();
  1641.         }
  1642.         if (!m_pDeviceCallback->PendingID())
  1643.         {
  1644.             m_pDeviceCallback->PendingID( m_pScheduler->RelativeEnter(m_pDeviceCallback, 0));
  1645.         }
  1646.     }
  1647.     else
  1648. #endif
  1649.     {
  1650.         m_bToBeReOpened = FALSE;
  1651.     }
  1652.     return theErr;
  1653. }
  1654. HX_RESULT
  1655. CHXAudioSession::CreateAudioDevice()
  1656. {
  1657.     HX_RESULT theErr = HXR_OK;
  1658.     if (!m_pCurrentAudioDev)
  1659.     {
  1660.         // create the audioout object
  1661.         CHXAudioDevice* pAudioDev = CHXAudioDevice::Create(m_pPreferences);
  1662.         if (pAudioDev)
  1663.         {
  1664.             pAudioDev->AddRef();
  1665.             pAudioDev->Init(m_pContext);
  1666.             if (pAudioDev->InitVolume(0, 100) == TRUE)
  1667.             {
  1668.                 m_bAudioDeviceSupportsVolume = TRUE;
  1669.             }
  1670.             else
  1671.             {
  1672.                 m_bAudioDeviceSupportsVolume = FALSE;
  1673.             }
  1674.             m_pCurrentAudioDev = (IHXAudioDevice*) pAudioDev;
  1675.         }
  1676.         else
  1677.         {
  1678.             theErr = HXR_OUTOFMEMORY;
  1679.         }
  1680.     }
  1681.     return theErr;
  1682. }
  1683. void
  1684. CHXAudioSession::ReleaseAudioDevice()
  1685. {
  1686.     if (m_pCurrentAudioDev)
  1687.     {
  1688.         ProcessAudioDevice(ACTION_REMOVE, m_pCurrentAudioDev);
  1689.     }
  1690.     m_pCurrentAudioDev->Close(FALSE);
  1691.     _NotifyTimelineWatchers( TLW_CLOSE );
  1692.     HX_RELEASE(m_pCurrentAudioDev);
  1693.     m_bToBeReOpened = FALSE;
  1694.     if (m_pDeviceCallback && m_pDeviceCallback->PendingID())
  1695.     {
  1696.         m_pScheduler->Remove(m_pDeviceCallback->PendingID());
  1697.         m_pDeviceCallback->PendingID(0);
  1698.     }
  1699. }
  1700. void
  1701. CHXAudioSession::RestoreReplacedDevice()
  1702. {
  1703.     if (m_bReplacedDev && !m_bUsingReplacedDevice && !m_pCurrentAudioDev)
  1704.     {
  1705.         m_pCurrentAudioDev = m_pReplacedAudioDev;
  1706.         m_pCurrentAudioDev->AddRef();
  1707.         m_bUsingReplacedDevice = TRUE;
  1708.     }
  1709. }
  1710. /************************************************************************
  1711.  *  Method:
  1712.  *              CHXAudioSession::OpenAudio
  1713.  *      Purpose:
  1714.  *       Open the audio device.
  1715.  */
  1716. HX_RESULT CHXAudioSession::OpenAudio()
  1717. {
  1718.     HX_RESULT theErr = TryOpenAudio();
  1719.     if (theErr == HXR_AUDIO_DRIVER)
  1720.     {
  1721.         StopAllOtherPlayers();
  1722.         theErr = TryOpenAudio();
  1723.     }
  1724.     return theErr;
  1725. }
  1726. /************************************************************************
  1727.  *  Method:
  1728.  *              CHXAudioSession::CreatePlaybackBuffer
  1729.  *      Purpose:
  1730.  *              This is the buffer that we mix all player buffers into
  1731.  *              and the one we write to the audio device.
  1732.  */
  1733. HX_RESULT CHXAudioSession::CreatePlaybackBuffer()
  1734. {
  1735.     // Calculate the number of bytes per granularity.
  1736.     m_ulBytesPerGran = (ULONG32)
  1737.             (((m_DeviceFmt.uChannels * ((m_DeviceFmt.uBitsPerSample==8)?1:2) *  m_DeviceFmt.ulSamplesPerSec)
  1738.                             / 1000.0) * m_ulGranularity);
  1739.     /* Number of samples required at output should be a multiple of 8 if
  1740.      * sampling rate is 8K/16K/32K...or a multiple of 11 for 11K/22K...
  1741.      * This is needed since the resamplerequires works reliably ONLY if
  1742.      * this condition is true. Ken is working on this problem. This is
  1743.      * an interim fix
  1744.      */
  1745.     ULONG32 ulExtraGranularity = 1;
  1746.     if (m_DeviceFmt.ulSamplesPerSec % 8 == 0)
  1747.     {
  1748.         ulExtraGranularity = 8;
  1749.     }
  1750.     else
  1751.     {
  1752.         ulExtraGranularity = 11;
  1753.     }
  1754.     if (m_ulBytesPerGran % (2*m_DeviceFmt.uChannels*ulExtraGranularity) != 0)
  1755.     {
  1756.         m_ulBytesPerGran -= m_ulBytesPerGran % (2*m_DeviceFmt.uChannels*ulExtraGranularity);
  1757.         m_dGranularity = (double) m_ulBytesPerGran / (double) ((double) (m_DeviceFmt.uChannels * ((m_DeviceFmt.uBitsPerSample==8)?1:2) *  m_DeviceFmt.ulSamplesPerSec)
  1758.                                 / 1000.0);
  1759.     }
  1760.     // Readjust the max size of the block
  1761.     m_ActualDeviceFmt.uMaxBlockSize = (UINT16) m_ulBytesPerGran;
  1762.     HX_RELEASE(m_pSessionBuf);
  1763.     HX_RELEASE(m_pPlayerBuf);
  1764.     m_pSessionBuf = new CHXBuffer;
  1765.     m_pSessionBuf->AddRef();
  1766.     m_pSessionBuf->SetSize(m_ulBytesPerGran);
  1767.     m_DeviceFmt.uMaxBlockSize   = (UINT16) m_ulBytesPerGran;
  1768.     m_ActualDeviceFmt.uMaxBlockSize = m_DeviceFmt.uMaxBlockSize;
  1769.     return HXR_OK;
  1770. }
  1771. /************************************************************************
  1772.  *  Method:
  1773.  *              CHXAudioSession::Pause
  1774.  *      Purpose:
  1775.  *       Pause playback of this Player's audio.
  1776.  */
  1777. HX_RESULT CHXAudioSession::Pause( CHXAudioPlayer* p)
  1778. {
  1779.     m_pMutex->Lock();
  1780.     BOOL bUseStopInPause = FALSE;
  1781. #if defined _DEBUG && defined HELIX_FEATURE_AUDIO_MULTIPLAYER_PAUSE
  1782.     bUseStopInPause = HXDebugOptionEnabled("zUseStopInPause");
  1783. #endif
  1784.     if (!bUseStopInPause && NumberOfResumedPlayers() == 0)
  1785.     {
  1786.         m_bPaused = TRUE;
  1787.         if(m_ulCallbackID)
  1788.         {
  1789.             m_pScheduler->Remove(m_ulCallbackID);
  1790.             m_ulCallbackID = 0;
  1791.         }
  1792.         // Check to see if all audio players are paused, then and only
  1793.         // then will we pause the device
  1794.         if ( m_pAudioDev )
  1795.         {
  1796.             m_pAudioDev->Pause();
  1797.             _NotifyTimelineWatchers(TLW_PAUSE);
  1798.         }
  1799.         m_bAtLeastOneTimeReceived = FALSE;
  1800.         m_pLastPausedPlayer = p;
  1801.     }
  1802.     /*
  1803.      * more than one audio player is currently active.
  1804.      * We need to do the following:
  1805.      * 1. get the current time from the device
  1806.      * 2. get the time for data we have already pushed down to the device
  1807.      * 3. flush the audio device
  1808.      * 4. instruct all streams to "rewind" by the "written but not played" duration
  1809.      */
  1810. #ifdef HELIX_FEATURE_AUDIO_MULTIPLAYER_PAUSE
  1811.     else if (!GetDisableMultiPlayPauseSupport() && m_pAudioDev && p->HasDataInAudioDevice())
  1812.     {
  1813.         HX_ASSERT(!m_bPaused && !m_bStoppedDuringPause);
  1814.         RewindSession();
  1815.         // this if is temporary
  1816.         if (NumberOfResumedPlayers() > 0)
  1817.         {
  1818.             ActualResume();
  1819.         }
  1820.     }
  1821. #endif
  1822.     m_pMutex->Unlock();
  1823.     return HXR_OK;
  1824. }
  1825. /************************************************************************
  1826.  *  Method:
  1827.  *              CHXAudioSession::Resume
  1828.  *      Purpose:
  1829.  *       Resume playback of this Player's audio.
  1830.  */
  1831. HX_RESULT CHXAudioSession::Resume(CHXAudioPlayer* pPlayerToExclude)
  1832. {
  1833.     HX_RESULT theErr = HXR_OK;
  1834.     if ((m_bPaused || m_bStoppedDuringPause) &&
  1835.         (!m_pLastPausedPlayer || (m_pLastPausedPlayer == pPlayerToExclude)))
  1836.     {
  1837.         theErr = ActualResume();
  1838.     }
  1839. #ifdef HELIX_FEATURE_AUDIO_MULTIPLAYER_PAUSE
  1840.     /*
  1841.      * we need to re-mix to start the newly resumed player instantly
  1842.      * and not delay it by pushdown
  1843.      */
  1844.     else if (!GetDisableMultiPlayPauseSupport() &&
  1845.              (NumberOfResumedPlayers() > 1 ||
  1846.             (m_pLastPausedPlayer && m_pLastPausedPlayer != pPlayerToExclude)))
  1847.     {
  1848.         RewindSession(pPlayerToExclude);
  1849.         theErr = ActualResume();
  1850.     }
  1851. #endif
  1852.     return theErr;
  1853. }
  1854. HX_RESULT
  1855. CHXAudioSession::ActualResume()
  1856. {
  1857.     HX_RESULT   theErr  = HXR_OK;
  1858.     if (m_bInPlayAudio)
  1859.     {
  1860.         // can only happen in multi-player pause/resume/stop case
  1861.         m_bDeferActualResume = TRUE;
  1862.         return HXR_OK;
  1863.     }
  1864.     m_bPaused = FALSE;
  1865.     m_bStoppedDuringPause = FALSE;
  1866.     if (m_bToBeReOpened)
  1867.     {
  1868.         m_bDeferActualResume = TRUE;
  1869.         goto exit;
  1870.     }
  1871.     if (m_bInActualResume)
  1872.     {
  1873.         return HXR_OK;
  1874.     }
  1875.     m_bInActualResume = TRUE;
  1876.     theErr = PlayAudio();
  1877.     m_bInActualResume = FALSE;
  1878.     /*
  1879.      * we may "re-pause" the player in PlayAudio if we need to buffer more
  1880.      * data to play, if we are paused now, don't resume the audio device now
  1881.      * or we will play data that we don't account for.  Fixes the G2 B2
  1882.      * Live pause video sync bug.  JEFFA & RAHUL 11/4/98
  1883.      */
  1884.     if (theErr || m_bPaused || m_bStoppedDuringPause)
  1885.     {
  1886.         goto exit;
  1887.     }
  1888.     // Get the initial system time.
  1889.     if (m_pAudioDev)
  1890.     {
  1891.         m_pAudioDev->Resume();
  1892.         _NotifyTimelineWatchers(TLW_RESUME);
  1893.     }
  1894.     m_pLastPausedPlayer      = NULL;
  1895.     m_ulLastFakeCallbackTime = HX_GET_TICKCOUNT();
  1896. exit:
  1897.     return theErr;
  1898. }
  1899. /************************************************************************
  1900.  *  Method:
  1901.  *              CHXAudioSession::Seek
  1902.  *      Purpose:
  1903.  *       Seek playback of this Player's audio.   TBD
  1904.  */
  1905. HX_RESULT CHXAudioSession::Seek(CHXAudioPlayer* pPlayerToExclude, const UINT32  ulSeekTime)
  1906. {
  1907.     m_pMutex->Lock();
  1908.     if (NumberOfActivePlayers() <= 1)
  1909.     {
  1910.         m_ulStartTime   = m_ulCurrentTime = 0;
  1911.         m_dBufEndTime   = 0.;
  1912.         if (m_pAudioDev)
  1913.         {
  1914.             m_pAudioDev->Reset();
  1915.         }
  1916.         m_ulBlocksWritten       = 0;
  1917.         m_dNumBytesWritten      = (double) 0;
  1918.         m_dNumBytesPlayed       = (double) 0;
  1919.         while (m_pAuxiliaryAudioBuffers &&
  1920.                m_pAuxiliaryAudioBuffers->GetCount() > 0)
  1921.         {
  1922.             HXAudioData* pAudioData =
  1923.                 (HXAudioData*) m_pAuxiliaryAudioBuffers->RemoveHead();
  1924.             pAudioData->pData->Release();
  1925.             delete pAudioData;
  1926.         }
  1927.         m_bFirstPlayAudio           = TRUE;
  1928.         m_bTimeSyncReceived         = FALSE;
  1929.         m_bAtLeastOneTimeReceived   = FALSE;
  1930.         m_ulLastAudioTime           = 0;
  1931.     }
  1932.     /*
  1933.      * more than one audio player is currently active.
  1934.      * We need to do the following:
  1935.      * 1. get the current time from the device
  1936.      * 2. get the time for data we have already pushed down to the device
  1937.      * 3. flush the audio device
  1938.      * 4. instruct all streams to "rewind" by the "written but not played" duration
  1939.      */
  1940. #ifdef HELIX_FEATURE_AUDIO_MULTIPLAYER_PAUSE
  1941.     else if (!GetDisableMultiPlayPauseSupport() && m_pAudioDev)
  1942.     {
  1943.         /* nothing needs to be done here..
  1944.          * it has already been taken care of udring Pause()!!
  1945.          *
  1946.          * this comment is here for the sake of completeness
  1947.          */
  1948.     }
  1949. #endif
  1950.     m_pMutex->Unlock();
  1951.     return HXR_OK;
  1952. }
  1953. /************************************************************************
  1954.  *  Method:
  1955.  *              CHXAudioSession::Stop
  1956.  *      Purpose:
  1957.  *       Stop playback of this Player's audio.
  1958.  */
  1959. HX_RESULT CHXAudioSession::Stop( CHXAudioPlayer* p, BOOL bFlush )
  1960. {
  1961.     m_pMutex->Lock();
  1962.     if (NumberOfActivePlayers() == 0)
  1963.     {
  1964.         if(m_ulCallbackID)
  1965.         {
  1966.             m_pScheduler->Remove(m_ulCallbackID);
  1967.             m_ulCallbackID = 0;
  1968.         }
  1969.         // Close the audio device only if all players are not playing.
  1970.         if ( !IsPlaying() && m_pAudioDev )
  1971.         {
  1972.             m_pAudioDev->Close(bFlush);
  1973.             _NotifyTimelineWatchers( TLW_CLOSE );
  1974.             m_ulBlocksWritten = 0;
  1975.             m_pAudioDev = NULL;
  1976.         }
  1977.         // Reset the session ...
  1978.         ResetSession();
  1979.     }
  1980.     /*
  1981.      * more than one audio player is currently active.
  1982.      * We need to do the following:
  1983.      * 1. get the current time from the device
  1984.      * 2. get the time for data we have already pushed down to the device
  1985.      * 3. flush the audio device
  1986.      * 4. instruct all streams to "rewind" by the "written but not played" duration
  1987.      */
  1988. #ifdef HELIX_FEATURE_AUDIO_MULTIPLAYER_PAUSE
  1989.     else if (!GetDisableMultiPlayPauseSupport() && m_pAudioDev && p->HasDataInAudioDevice())
  1990.     {
  1991.         RewindSession(p);
  1992.         if (NumberOfResumedPlayers() > 0)
  1993.         {
  1994.             HX_ASSERT(m_bPaused == FALSE);
  1995.             ActualResume();
  1996.         }
  1997.     }
  1998. #endif
  1999.     m_pMutex->Unlock();
  2000.     return HXR_OK;
  2001. }
  2002. /************************************************************************
  2003.  *  Method:
  2004.  *              CHXAudioSession::ResetSession
  2005.  *      Purpose:
  2006.  */
  2007. void CHXAudioSession::ResetSession(void)
  2008. {
  2009.     // We only want to reset session if we are no longer playing anything.
  2010.     if ( IsPlaying() )
  2011.         return;
  2012.     m_bInited       = FALSE;
  2013.     m_bDisableWrite = FALSE;
  2014.     // Free the audio device if it is ours
  2015.     if ((!m_bReplacedDev || !m_bUsingReplacedDevice) && m_pCurrentAudioDev)
  2016.     {
  2017.         ReleaseAudioDevice();
  2018.     }
  2019.     RestoreReplacedDevice();
  2020.     m_pAudioDev = 0;
  2021.     // Delete the player mixer buffer
  2022.     HX_RELEASE(m_pPlayerBuf);
  2023.     // Delete the session mixer buffer
  2024.     HX_RELEASE(m_pSessionBuf);
  2025.     m_ulIncreasingTimer = 0;
  2026.     m_ulStartTime       = 0;
  2027.     m_ulCurrentTime     = 0;
  2028.     m_ulBytesPerGran    = 0;
  2029.     m_bHasStreams       = FALSE;
  2030.     m_bPaused            = TRUE;
  2031.     m_bStoppedDuringPause = FALSE;
  2032.     m_bTimeSyncReceived  = FALSE;
  2033.     m_bAtLeastOneTimeReceived = FALSE;
  2034.     m_ulLastAudioTime         = 0;
  2035.     m_bShouldOpenOnCoreThread = FALSE;
  2036.     if(m_ulCallbackID && m_pScheduler)
  2037.     {
  2038.         m_pScheduler->Remove(m_ulCallbackID);
  2039.         m_ulCallbackID = 0;
  2040.     }
  2041.     if (m_pDeviceCallback && m_pDeviceCallback->PendingID())
  2042.     {
  2043.         m_pScheduler->Remove(m_pDeviceCallback->PendingID());
  2044.         m_pDeviceCallback->PendingID(0);
  2045.     }
  2046.     m_bFirstPlayAudio       = TRUE;
  2047.     m_dBufEndTime = 0.;
  2048.     if (m_pAuxiliaryAudioBuffers)
  2049.     {
  2050.         while (m_pAuxiliaryAudioBuffers->GetCount() > 0)
  2051.         {
  2052.             HXAudioData* pAudioData =
  2053.                 (HXAudioData*) m_pAuxiliaryAudioBuffers->RemoveHead();
  2054.             pAudioData->pData->Release();
  2055.             delete pAudioData;
  2056.         }
  2057.         HX_DELETE(m_pAuxiliaryAudioBuffers);
  2058.     }
  2059.     /* Default value of Device format */
  2060.     m_DeviceFmt.uChannels       = 2;
  2061.     m_DeviceFmt.uBitsPerSample  = 16;
  2062.     m_DeviceFmt.ulSamplesPerSec = 16000;
  2063.     m_DeviceFmt.uMaxBlockSize   = 64000;
  2064.     m_ulBlocksWritten           = 0;
  2065.     m_dNumBytesWritten          = (double) 0;
  2066.     m_dNumBytesPlayed           = (double) 0;
  2067.     m_bDeferActualResume        = FALSE;
  2068.     m_pLastPausedPlayer         = NULL;
  2069.     HX_RELEASE(m_pMPPSupport);
  2070.     return;
  2071. }
  2072. HX_RESULT
  2073. CHXAudioSession::ProcessAudioHook(PROCESS_ACTION action,
  2074.                                   IHXAudioHook* pAudioHook)
  2075. {
  2076.     return HXR_OK;
  2077. }
  2078. HX_RESULT
  2079. CHXAudioSession::ProcessAudioDevice(PROCESS_ACTION    action,
  2080.                                     IHXAudioDevice*  pAudioDevice)
  2081. {
  2082.     return HXR_OK;
  2083. }
  2084. /************************************************************************
  2085.  *  Method:
  2086.  *      CHXAudioSession::Replace
  2087.  *  Purpose:
  2088.  *      Used to replace the default audio device.
  2089.  *      This method will fail if the audio device is in use or it has
  2090.  *      already been replaced.
  2091.  */
  2092. STDMETHODIMP
  2093. CHXAudioSession::Replace(IHXAudioDevice* /*IN*/ pAudioDevice)
  2094. {
  2095.     if (!pAudioDevice)
  2096.     {
  2097.         return HXR_POINTER;
  2098.     }
  2099.     // Have we already replaced the audio device?
  2100.     if (m_bReplacedDev)
  2101.     {
  2102.         return HXR_UNEXPECTED;
  2103.     }
  2104.     // Is the audio device in use?
  2105.     if (m_pAudioDev)
  2106.     {
  2107.         return HXR_FAIL;
  2108.     }
  2109.     // make sure the new audio device is initialized.
  2110.     m_bReplacedDev = TRUE;
  2111.     m_bUsingReplacedDevice = TRUE;
  2112.     if (m_pCurrentAudioDev)
  2113.     {
  2114.         // XXXNH: if we've already created an audio device, then shut it down
  2115.         m_pCurrentAudioDev->Close(TRUE);
  2116.         _NotifyTimelineWatchers( TLW_CLOSE );
  2117.         HX_RELEASE(m_pCurrentAudioDev);
  2118.     }
  2119.     m_pCurrentAudioDev = pAudioDevice;
  2120.     m_pCurrentAudioDev->AddRef();
  2121.     m_pReplacedAudioDev = pAudioDevice;
  2122.     m_pReplacedAudioDev->AddRef();
  2123.     m_bAudioDeviceSupportsVolume = FALSE;
  2124.     if (m_pCurrentAudioDev->InitVolume(HX_MIN_VOLUME, HX_MAX_VOLUME) == TRUE)
  2125.     {
  2126.         m_bAudioDeviceSupportsVolume = TRUE;
  2127.         /* Is our current volume setting different ?*/
  2128.         UINT16 uNewVolume = m_pCurrentAudioDev->GetVolume();
  2129.         if (uNewVolume != m_uVolume)
  2130.         {
  2131.             m_uVolume = uNewVolume;
  2132. #ifdef HELIX_FEATURE_VOLUME
  2133.             if( m_pDeviceVolume )
  2134.             {
  2135.                 m_pDeviceVolume->SetVolume(m_uVolume);
  2136.             }
  2137. #endif
  2138.         }
  2139.     }
  2140.     return HXR_OK;
  2141. }
  2142. /************************************************************************
  2143.  *  Method:
  2144.  *      CHXAudioSession::Remove
  2145.  *  Purpose:
  2146.  *      Used to restore the default audio device.  A pointer to the
  2147.  *      original replacement audio device must be passed in for
  2148.  *      authentication purposes- we can't have just anyone reseting
  2149.  *      the audio device.
  2150.  *      This method will fail if the interface passed in is not the
  2151.  *      current audio device or if the current audio device is in use.
  2152.  */
  2153. STDMETHODIMP
  2154. CHXAudioSession::Remove(IHXAudioDevice* /*IN*/ pAudioDevice)
  2155. {
  2156.     if (!pAudioDevice)
  2157.     {
  2158.         return HXR_POINTER;
  2159.     }
  2160.     // If we're using the audio service fail.
  2161.     if (m_pAudioDev)
  2162.     {
  2163.         return HXR_FAIL;
  2164.     }
  2165.     // Have we not replaced the audio device?
  2166.     if (!m_bReplacedDev)
  2167.     {
  2168.         return HXR_UNEXPECTED;
  2169.     }
  2170.     // make sure the it's the same audio device
  2171.     if (m_pReplacedAudioDev != pAudioDevice)
  2172.     {
  2173.         return HXR_INVALID_PARAMETER;
  2174.     }
  2175.     if (m_pCurrentAudioDev)
  2176.     {
  2177.         ProcessAudioDevice(ACTION_REMOVE, m_pCurrentAudioDev);
  2178.     }
  2179.     if (m_pCurrentAudioDev == m_pReplacedAudioDev)
  2180.     {
  2181.         // Close the audio device
  2182.         HX_RELEASE(m_pCurrentAudioDev);
  2183.     }
  2184.     HX_RELEASE(m_pReplacedAudioDev);
  2185.     m_bReplacedDev = FALSE;
  2186.     return HXR_OK;
  2187. }
  2188. /************************************************************************
  2189. *  Method:
  2190. *   IHXAudioDeviceManager::AddFinalHook
  2191. *  Purpose:
  2192. *       One last chance to modify data being written to the audio device.
  2193. *       This hook allows the user to change the audio format that
  2194. *   is to be written to the audio device. This can be done in call
  2195. *   to OnInit() in IHXAudioHook.
  2196. */
  2197. STDMETHODIMP
  2198. CHXAudioSession::SetFinalHook(IHXAudioHook* /*IN*/ pHook)
  2199. {
  2200.     if (m_pFinalHook || !pHook)
  2201.     {
  2202.         return HXR_UNEXPECTED;
  2203.     }
  2204.     m_pFinalHook = pHook;
  2205.     m_pFinalHook->AddRef();
  2206.     BOOL bIsInterruptSafe = FALSE;
  2207.     IHXInterruptSafe* pInterruptSafe = NULL;
  2208.     if (m_pFinalHook->QueryInterface(IID_IHXInterruptSafe,
  2209.                                     (void**) &pInterruptSafe) == HXR_OK)
  2210.     {
  2211.         bIsInterruptSafe = pInterruptSafe->IsInterruptSafe();
  2212.         pInterruptSafe->Release();
  2213.     }
  2214.     if (!bIsInterruptSafe)
  2215.     {
  2216.         IHXInterruptState* pState = NULL;
  2217.         HX_VERIFY(m_pContext->QueryInterface(IID_IHXInterruptState,
  2218.                             (void**) &pState) == HXR_OK);
  2219.         pState->EnableInterrupt(FALSE);
  2220.         pState->Release();
  2221.     }
  2222.     ProcessAudioHook(ACTION_ADD, m_pFinalHook);
  2223.     return HXR_OK;
  2224. }
  2225. /************************************************************************
  2226. *  Method:
  2227. *   IHXAudioDeviceManager::RemoveFinalHook
  2228. *  Purpose:
  2229. *       Remove final hook
  2230. */
  2231. STDMETHODIMP
  2232. CHXAudioSession::RemoveFinalHook(IHXAudioHook* /*IN*/ pHook)
  2233. {
  2234.     if (!m_pFinalHook || m_pFinalHook != pHook)
  2235.     {
  2236.         return HXR_UNEXPECTED;
  2237.     }
  2238.     ProcessAudioHook(ACTION_REMOVE, m_pFinalHook);
  2239.     HX_RELEASE(m_pFinalHook);
  2240.     return HXR_OK;
  2241. }
  2242. /************************************************************************
  2243. *  Method:
  2244. *      IHXAudioDeviceManager::GetAudioFormat
  2245. *  Purpose:
  2246. *           Returns the audio format in which the audio device is opened.
  2247. *           This function will fill in the pre-allocated HXAudioFormat
  2248. *           structure passed in.
  2249. */
  2250. STDMETHODIMP
  2251. CHXAudioSession::GetAudioFormat(HXAudioFormat*  /*IN/OUT*/pAudioFormat)
  2252. {
  2253.     if (!pAudioFormat)
  2254.     {
  2255.         return HXR_UNEXPECTED;
  2256.     }
  2257.     memcpy( pAudioFormat, &m_ActualDeviceFmt, sizeof( HXAudioFormat ));
  2258.     return HXR_OK;
  2259. }
  2260. /**********************************************************************
  2261.  *  Method:
  2262.  *      IHXAudioDeviceManager2::IsReplacedDevice
  2263.  *  Purpose:
  2264.  *  This is used to determine if the audio device has been replaced.
  2265.  */
  2266. STDMETHODIMP_(BOOL) CHXAudioSession::IsReplacedDevice()
  2267. {
  2268.     if (m_bUsingReplacedDevice && m_pReplacedAudioDev)
  2269.     {
  2270.         return TRUE;
  2271.     }
  2272.     return FALSE;
  2273. }
  2274. /*
  2275.  *  IHXAudioResamplerManager methods
  2276.  *
  2277.  */
  2278. STDMETHODIMP
  2279. CHXAudioSession::CreateResampler(HXAudioFormat              inAudioFormat,
  2280.                                  REF(HXAudioFormat)         outAudioFormat,
  2281.                                  REF(IHXAudioResampler*)   pResampler)
  2282. {
  2283.     HX_RESULT                   rc = HXR_FAILED;
  2284. #if defined(HELIX_FEATURE_RESAMPLER) && !defined(HELIX_CONFIG_FIXEDPOINT)
  2285.     HXCDQualityResampler*       pNewResampler = NULL;
  2286.     pResampler = NULL;
  2287.     pNewResampler = new HXCDQualityResampler();
  2288.     if (pNewResampler &&
  2289.         HXR_OK == pNewResampler->Init(inAudioFormat, outAudioFormat))
  2290.     {
  2291.         rc = pNewResampler->QueryInterface(IID_IHXAudioResampler, (void**)&pResampler);
  2292.     }
  2293.     else
  2294.     {
  2295.         HX_DELETE(pNewResampler);
  2296.         rc = HXR_FAILED;
  2297.     }
  2298. #endif /* HELIX_FEATURE_RESAMPLER && !HELIX_CONFIG_FIXEDPOINT*/
  2299.     return rc;
  2300. }
  2301. /*
  2302.  *  IHXAudioPushdown methods
  2303.  */
  2304. /************************************************************************
  2305. *  Method:
  2306. *      IHXAudioPushdown::SetAudioPushdown
  2307. *  Purpose:
  2308. *           Use this to set the minimum audio pushdown value in ms.
  2309. *           This is the amount of audio data that is being written
  2310. *           to the audio device before starting playback.
  2311. */
  2312. STDMETHODIMP CHXAudioSession::SetAudioPushdown(
  2313.                                         UINT32 /*IN*/ ulMinimumPushdown)
  2314. {
  2315.     m_ulMinimumPushdown = ulMinimumPushdown;
  2316.     UpdateMinimumPushdown();
  2317.     return HXR_OK;
  2318. }
  2319. /************************************************************************
  2320. *  Method:
  2321. *      IHXAudioPushdown2::GetAudioPushdown
  2322. *  Purpose:
  2323. *           Use this to get the minimum audio pushdown value in ms.
  2324. *           This is the amount of audio data that is being written
  2325. *           to the audio device before starting playback.
  2326. */
  2327. STDMETHODIMP
  2328. CHXAudioSession::GetAudioPushdown(REF(UINT32) /*OUT*/ ulAudioPushdown)
  2329. {
  2330.     ulAudioPushdown = m_ulMinimumPushdown;
  2331.     return HXR_OK;
  2332. }
  2333. /************************************************************************
  2334. *  Method:
  2335. *      IHXAudioPushdown2::GetCurrentAudioDevicePushdown
  2336. *  Purpose:
  2337. *           Use this to get the audio pushed down to the audio device and haven't
  2338. *           been played yet
  2339. */
  2340. STDMETHODIMP
  2341. CHXAudioSession::GetCurrentAudioDevicePushdown(REF(UINT32) /*OUT*/ ulAudioPusheddown)
  2342. {
  2343.     HX_RESULT   rc = HXR_OK;
  2344.     UINT16      uNumBlocks = 0;
  2345.     UINT32      ulNumBlocksPlayed = 0;
  2346.     UINT32      ulCurTime = 0;
  2347.     ulAudioPusheddown = 0;
  2348.     if (m_bToBeReOpened || !m_pAudioDev)
  2349.     {
  2350.         goto cleanup;
  2351.     }
  2352.     if ( (!m_bReplacedDev) && (((CHXAudioDevice*)m_pAudioDev)->IsWaveOutDevice()) )
  2353.     {
  2354.         uNumBlocks = ((CHXAudioDevice*)m_pAudioDev)->NumberOfBlocksRemainingToPlay();
  2355.     }
  2356.     else
  2357.     {
  2358.         if (m_pAudioDev->GetCurrentAudioTime(ulCurTime) == HXR_OK)
  2359.         {
  2360.             ulNumBlocksPlayed = (UINT32) ((double) ulCurTime / m_dGranularity);
  2361.             if (m_ulBlocksWritten > ulNumBlocksPlayed)
  2362.             {
  2363.                 uNumBlocks = (UINT16) (m_ulBlocksWritten - ulNumBlocksPlayed);
  2364.             }
  2365.         }
  2366.     }
  2367.     ulAudioPusheddown = (UINT32)(uNumBlocks * m_dGranularity);
  2368. cleanup:
  2369.     return rc;
  2370. }
  2371. /************************************************************************
  2372.  *  Method:
  2373.  *      CHXAudioSession::OnTimeSync
  2374.  *  Purpose:
  2375.  *      Notification interface provided by users of the IHXAudioDevice
  2376.  *      interface. This method is called by the IHXAudioDevice when
  2377.  *      audio playback occurs.
  2378.  */
  2379. STDMETHODIMP CHXAudioSession::OnTimeSync(ULONG32 /*IN*/ ulCurrentTime)
  2380. {
  2381.     HX_RESULT theErr = HXR_OK;
  2382.     if (m_pCoreMutex)
  2383.     {
  2384.         m_pCoreMutex->Lock();
  2385.     }
  2386.      m_bTimeSyncReceived = TRUE;
  2387. #ifdef _MACINTOSH
  2388.      if (zm_Locked)
  2389.      {
  2390.         m_pCoreMutex->Unlock();
  2391.         return HXR_OK;
  2392.      }
  2393.      zm_Locked=TRUE;
  2394. #endif
  2395.     CHXAudioPlayer* pPlayer;
  2396.     CHXSimpleList::Iterator lIter;
  2397.     /*
  2398.      * We may reach here from a WOM_DONE callback from audio thread AFTER
  2399.      * stopping the audio device and resetting our member variables.
  2400.      * This is because we may be waiting on m_pCoreMutex owned by the main
  2401.      * thread (where we stop the audio device).
  2402.      * Do not update any member variables in this case since this may screw
  2403.      * up subsequent playback.
  2404.      */
  2405.     /* On Mac, we may have been paused but have not yet issued
  2406.      * pause on the audio device (due to interrupt time conflicts).
  2407.      * Ignore any more timesyncs and do not pump any more data
  2408.      * to the audio device.
  2409.      */
  2410.     if (!m_bInited || m_bPaused || m_bStoppedDuringPause)
  2411.     {
  2412.         goto exit;
  2413.     }
  2414.     /* This is only set in rewindsession - used in pause/resume for multiple
  2415.      * players. We may be waiting on te core mutex on a timesync callback
  2416.      * from the audio device when we reset/resume the audio device since
  2417.      * someone hit pause/resume. In this case, the time passed into
  2418.      * OnTimeSync is still from previous generation and we need to resync.
  2419.      */
  2420.     if (m_uAskFromAudioDevice > 0 && m_pAudioDev)
  2421.     {
  2422.         m_uAskFromAudioDevice--;
  2423.         m_pAudioDev->GetCurrentAudioTime(ulCurrentTime);
  2424.     }
  2425. #if defined(_WINDOWS) || defined(_WIN32) || defined(_MACINTOSH)
  2426.     ulCurrentTime = AnchorDeviceTime(ulCurrentTime);
  2427. #endif /*defined(_WINDOWS) || defined(_WIN32)*/
  2428.     /* Adjust current time to new larger time. */
  2429.     if (ulCurrentTime+m_ulStartTime > m_ulCurrentTime)
  2430.     {
  2431.         /* Check for a messed up time here...
  2432.          * Sometimes, Audio cards may give out some insane value for
  2433.          * the number of bytes played...
  2434.          */
  2435.         if (CALCULATE_ELAPSED_TICKS(
  2436.                     m_ulCurrentTime, ulCurrentTime+m_ulStartTime) >
  2437.                 SOME_INSANELY_LARGE_VALUE)
  2438.         {
  2439.             /* THIS SOUND CARD IS GOING CRAZY...
  2440.              * ATLEAST FOR A WHILE....
  2441.              * Ignore this timesync...
  2442.              */
  2443. //          HX_ASSERT(FALSE);
  2444.         }
  2445.         else
  2446.         {
  2447.             m_ulCurrentTime = ulCurrentTime+m_ulStartTime;
  2448.         }
  2449.     }
  2450.     m_dNumBytesPlayed = ConvertMsToBytes(m_ulCurrentTime - m_ulStartTime);
  2451.     /* Notify each audio player in the session about the current
  2452.      * time.
  2453.      */
  2454.     lIter = m_pPlayerList->Begin();
  2455.     pPlayer = NULL;
  2456.     for (; lIter != m_pPlayerList->End(); ++lIter)
  2457.     {
  2458.         pPlayer = (CHXAudioPlayer*) (*lIter);
  2459.         /* Only if the player is in *PLAY* state, send a timesync*/
  2460.         if (pPlayer->GetState() == E_PLAYING && pPlayer->GetStreamCount() > 0)
  2461.         {
  2462.             theErr = pPlayer->OnTimeSync(m_ulCurrentTime);
  2463.         }
  2464.     }
  2465.     //Let all the timeline watchers know..
  2466.     _NotifyTimelineWatchers( TLW_TIMESYNC, m_ulCurrentTime);
  2467.     
  2468.     /* Start playback of next buffer.    */
  2469.     if (theErr == HXR_OK && m_bHasStreams)
  2470.     {
  2471.         theErr = CheckToPlayMoreAudio();
  2472.     }
  2473. exit:
  2474. #ifdef _MACINTOSH
  2475.     zm_Locked=FALSE;
  2476. #endif
  2477.     if (m_pCoreMutex)
  2478.     {
  2479.         m_pCoreMutex->Unlock();
  2480.     }
  2481.     lIter = m_pPlayerList->Begin();
  2482.     if( theErr )
  2483.     {
  2484.         for (; lIter != m_pPlayerList->End(); ++lIter)
  2485.         {
  2486.             pPlayer = (CHXAudioPlayer*) (*lIter);
  2487.             if( pPlayer )
  2488.             {
  2489.                 pPlayer->SetError(theErr);
  2490.             }
  2491.         }
  2492.     }
  2493.     return theErr;
  2494. }
  2495. void
  2496. CHXAudioSession::UpdateMinimumPushdown()
  2497. {
  2498.     if (m_ulGranularity)
  2499.     {
  2500.         m_ulMinBlocksTobeQueued = (UINT32) (m_ulMinimumPushdown*1.0/m_ulGranularity);
  2501.         if ((m_ulMinBlocksTobeQueued == 0) ||
  2502.             (m_ulMinBlocksTobeQueued*m_ulGranularity < m_ulMinimumPushdown))
  2503.         {
  2504.             m_ulMinBlocksTobeQueued++;
  2505.         }
  2506.         if ((m_ulMinBlocksTobeQueued * m_ulGranularity) >= m_ulIdealMinimumPushdown)
  2507.         {
  2508.             m_ulMinBlocksTobeQueuedAtStart = (UINT32) (m_ulIdealMinimumPushdown*1.0/m_ulGranularity);
  2509.         }
  2510.         else
  2511.         {
  2512.             m_ulMinBlocksTobeQueuedAtStart = m_ulMinBlocksTobeQueued;
  2513.         }
  2514. #if defined(HELIX_FEATURE_PREFERENCES)
  2515.         IHXBuffer* pBuffer = NULL;
  2516.         if (m_pPreferences &&
  2517.             m_pPreferences->ReadPref("RestoreMinimumPushdown", pBuffer) == HXR_OK &&
  2518.             pBuffer &&
  2519.             ::atoi((char*) pBuffer->GetBuffer()) == 1)
  2520.         {
  2521.             m_ulMinBlocksTobeQueuedAtStart = m_ulMinBlocksTobeQueued;
  2522.         }
  2523.         HX_RELEASE(pBuffer);
  2524. #endif /* HELIX_FEATURE_PREFERENCES */
  2525.     }
  2526. }
  2527. /*
  2528.  *  IHXAudioHookManager methods
  2529.  */
  2530. /************************************************************************
  2531. *  Method:
  2532. *      IHXAudioHookManager::AddHook
  2533. *  Purpose:
  2534. *           Use this to add a hook
  2535. */
  2536. STDMETHODIMP CHXAudioSession::AddHook(IHXAudioHook* /*IN*/ pHook)
  2537. {
  2538. #if defined(HELIX_FEATURE_AUDIO_POSTMIXHOOK)
  2539.     if (!pHook)
  2540.     {
  2541.         return HXR_INVALID_PARAMETER;
  2542.     }
  2543.     if (!m_pHookList)
  2544.     {
  2545.         m_pHookList = new CHXSimpleList;
  2546.     }
  2547.     HXAudioHookInfo* pHookInfo = new HXAudioHookInfo;
  2548.     pHookInfo->pHook = pHook;
  2549.     pHookInfo->pHook->AddRef();
  2550.     pHookInfo->bDisableWrite = FALSE;
  2551.     pHookInfo->bFinal   = FALSE;
  2552.     pHookInfo->bIgnoreAudioData = FALSE;
  2553.     pHookInfo->bMultiChannelSupport = FALSE;
  2554.     IHXValues* pValues = NULL;
  2555.     if (pHook && pHook->QueryInterface(IID_IHXValues, (void**) &pValues) == HXR_OK)
  2556.     {
  2557.         UINT32 ulValue = 0;
  2558.         pValues->GetPropertyULONG32("IgnoreAudioData", ulValue);
  2559.         pHookInfo->bIgnoreAudioData = (ulValue == 1);
  2560.         HX_RELEASE(pValues);
  2561.     }
  2562.     IHXAudioMultiChannel* pMultiChannel = NULL;
  2563.     if (pHook && HXR_OK == pHook->QueryInterface(IID_IHXAudioMultiChannel, (void**) &pMultiChannel))
  2564.     {
  2565.         pHookInfo->bMultiChannelSupport = pMultiChannel->GetMultiChannelSupport();
  2566.     }
  2567.     HX_RELEASE(pMultiChannel);
  2568.     m_pHookList->AddTail(pHookInfo);
  2569.     ProcessAudioHook(ACTION_ADD, pHook);
  2570.     // if have already been initialzied...
  2571.     if (m_bInited && m_pAudioDev)
  2572.     {
  2573.         if (pHookInfo->bIgnoreAudioData ||
  2574.             HXR_OK == ProcessAudioHook(ACTION_CHECK, pHook))
  2575.         {
  2576.             HXAudioFormat audioFormat;
  2577.             memcpy( &audioFormat, &m_ActualDeviceFmt, sizeof(HXAudioFormat) );
  2578.             pHook->OnInit(&audioFormat);
  2579.         }
  2580.     }
  2581. #endif /* HELIX_FEATURE_AUDIO_POSTMIXHOOK */
  2582.     return HXR_OK;
  2583. }
  2584. /************************************************************************
  2585. *  Method:
  2586. *      IHXAudioHookManager::RemoveHook
  2587. *  Purpose:
  2588. *           Use this to remove a hook
  2589. */
  2590. STDMETHODIMP CHXAudioSession::RemoveHook(IHXAudioHook* /*IN*/ pHook)
  2591. {
  2592. #if defined(HELIX_FEATURE_AUDIO_POSTMIXHOOK)
  2593.     if (!pHook || !m_pHookList)
  2594.     {
  2595.         return HXR_UNEXPECTED;
  2596.     }
  2597.     BOOL bFound = FALSE;
  2598.     HXAudioHookInfo* h = 0;
  2599.     LISTPOSITION lp, lastlp;
  2600.     lp = lastlp = 0;
  2601.     lp = m_pHookList->GetHeadPosition();
  2602.     while( lp )
  2603.     {
  2604.         lastlp = lp;
  2605.         h = (HXAudioHookInfo*) m_pHookList->GetNext(lp);
  2606.         if ( pHook == h->pHook )
  2607.         {
  2608.             ProcessAudioHook(ACTION_REMOVE, pHook);
  2609.             h->pHook->Release();
  2610.             delete h;
  2611.             h = 0;
  2612.             m_pHookList->RemoveAt(lastlp);
  2613.             bFound = TRUE;
  2614.             break;
  2615.         }
  2616.     }
  2617.     if (!bFound)
  2618.     {
  2619.         return HXR_FAILED;
  2620.     }
  2621. #endif /* HELIX_FEATURE_AUDIO_POSTMIXHOOK */
  2622.     return HXR_OK;
  2623. }
  2624. /************************************************************************
  2625.  *  Method:
  2626.  *      CHXAudioSession::OnTimerCallback
  2627.  *  Purpose:
  2628.  *      Timer callback when implementing fake timeline.
  2629.  */
  2630. void    CHXAudioSession::OnTimerCallback()
  2631. {
  2632.     // NOTE: we are ignoring an HX_RESULT return value here.
  2633.     OnTimeSync(m_ulIncreasingTimer);
  2634.     /* A call to timesync may result in stopping
  2635.      * playback and we do not want to have any more
  2636.      * time syncs.
  2637.      */
  2638.     if (!m_bInited)
  2639.     {
  2640.         return;
  2641.     }
  2642.     /* Put this back in the scheduler.
  2643.      */
  2644.     if(0==m_ulCallbackID)
  2645.     {
  2646.         *m_pFakeAudioCBTime += (int) (m_ulGranularity*1000);
  2647.         m_ulCallbackID = m_pScheduler->RelativeEnter( this, m_ulGranularity);
  2648.     }
  2649.    ULONG32 ulCurrentTime = HX_GET_TICKCOUNT();
  2650.     m_ulIncreasingTimer         += (ulCurrentTime - m_ulLastFakeCallbackTime);
  2651.     m_ulLastFakeCallbackTime     = ulCurrentTime;
  2652. }
  2653. /************************************************************************
  2654.  *  Method:
  2655.  *      CHXAudioSession::GetCurrentPlaybackTime
  2656.  *  Purpose:
  2657.  */
  2658. ULONG32 CHXAudioSession::GetCurrentPlayBackTime(void)
  2659. {
  2660.     m_pMutex->Lock();
  2661.     //#ifndef _LINUX
  2662.     if (!m_bPaused && !m_bStoppedDuringPause)
  2663.     {
  2664.         ULONG32 ulCurTime = 0;
  2665.         /* Get audio device time. */
  2666.         if ( m_pAudioDev )
  2667.         {
  2668. //#if !defined(_WINDOWS) && !defined(_WIN32)
  2669. #if !defined(_WINDOWS) && !defined(_WIN32) && !defined(_MACINTOSH)
  2670.             if (m_bTimeSyncReceived)
  2671.             {
  2672.                 m_pAudioDev->GetCurrentAudioTime(ulCurTime);
  2673.                 if (m_ulCurrentTime < ulCurTime+m_ulStartTime)
  2674.                 {
  2675.                     /* Check for a messed up time here...
  2676.                      * Sometimes, Audio cards may give out some insane value for
  2677.                      * the number of bytes played...
  2678.                      */
  2679.                     if (CALCULATE_ELAPSED_TICKS(
  2680.                                 m_ulCurrentTime, ulCurTime+m_ulStartTime) >
  2681.                             SOME_INSANELY_LARGE_VALUE)
  2682.                     {
  2683.                         /* THIS SOUND CARD IS GOING CRAZY...
  2684.                          * ATLEAST FOR A WHILE....
  2685.                          * Ignore this timesync...
  2686.                          */
  2687.                         //HX_ASSERT(FALSE);
  2688.                     }
  2689.                     else
  2690.                     {
  2691.                         m_ulCurrentTime = ulCurTime+m_ulStartTime;
  2692.                     }
  2693.                 }
  2694.             }
  2695. #else
  2696.             AdjustInRealTime();
  2697. #endif /*!defined(_WINDOWS) && !defined(_WIN32)*/
  2698.         }
  2699.         else
  2700.         {
  2701.             /* Get current system time. */
  2702.             ULONG32 ulCurrentSysTime = HX_GET_TICKCOUNT();
  2703.             m_ulIncreasingTimer         += CALCULATE_ELAPSED_TICKS(m_ulLastFakeCallbackTime, ulCurrentSysTime);
  2704.             m_ulLastFakeCallbackTime    = ulCurrentSysTime;
  2705.             m_ulCurrentTime             = m_ulIncreasingTimer+m_ulStartTime;
  2706.         }
  2707.     }
  2708.     //#endif
  2709.     m_dNumBytesPlayed = ConvertMsToBytes(m_ulCurrentTime - m_ulStartTime);
  2710.     m_pMutex->Unlock();
  2711.     return m_ulCurrentTime;
  2712. }
  2713. UINT32
  2714. CHXAudioSession::AnchorDeviceTime(UINT32 ulCurTime)
  2715. {
  2716.     UINT32  ulAdjustTime            = ulCurTime;
  2717.     UINT32  ulCurrentSystemTime     = HX_GET_TICKCOUNT();
  2718.     if (CALCULATE_ELAPSED_TICKS(m_ulLastAudioTime, ulCurTime) >
  2719.                 SOME_INSANELY_LARGE_VALUE)
  2720.     {
  2721.         goto exit;
  2722.     }
  2723.     if (m_bAtLeastOneTimeReceived)
  2724.     {
  2725.         if (m_ulLastAudioTime == ulCurTime)
  2726.         {
  2727.             UINT32 ulElapsedTime = CALCULATE_ELAPSED_TICKS(m_ulLastSystemTime, ulCurrentSystemTime);
  2728.             ulAdjustTime        += ulElapsedTime;
  2729.         }
  2730.         if (ulAdjustTime < m_ulLastAudioReturnTime)
  2731.         {
  2732.             ulAdjustTime = m_ulLastAudioReturnTime;
  2733.         }
  2734.     }
  2735.     m_ulLastAudioTime           = ulCurTime;
  2736.     m_ulLastSystemTime          = ulCurrentSystemTime;
  2737.     m_ulLastAudioReturnTime     = ulAdjustTime;
  2738.     m_bAtLeastOneTimeReceived   = TRUE;
  2739. //{FILE* f1 = ::fopen("c:\audio.txt", "a+"); ::fprintf(f1, "%lut%lut%lun", m_ulLastSystemTime, ulCurTime, ulAdjustTime);::fclose(f1);}
  2740. exit:
  2741.     return ulAdjustTime;
  2742. }
  2743. void
  2744. CHXAudioSession::AdjustInRealTime()
  2745. {
  2746.     if (m_bAtLeastOneTimeReceived)
  2747.     {
  2748.         UINT32  ulCurrentSystemTime = HX_GET_TICKCOUNT();
  2749.         UINT32 ulElapsedTime = CALCULATE_ELAPSED_TICKS(m_ulLastSystemTime, ulCurrentSystemTime);
  2750.         ulElapsedTime   = m_ulLastAudioTime + ulElapsedTime + m_ulStartTime;
  2751.         if (m_ulCurrentTime < ulElapsedTime)
  2752.         {
  2753.             m_ulCurrentTime     = ulElapsedTime;
  2754.         }
  2755.     }
  2756. }
  2757. /************************************************************************
  2758.  *  Method:
  2759.  *      CHXAudioSession::IsPlaying()
  2760.  *  Purpose:
  2761.  *      Returns TRUE if any audio player is playing.
  2762.  */
  2763. BOOL CHXAudioSession::IsPlaying()
  2764. {
  2765.     if (m_pPlayerList)
  2766.     {
  2767.         CHXAudioPlayer* pPlayer = 0;
  2768.         CHXSimpleList::Iterator lIter = m_pPlayerList->Begin();
  2769.         for (; lIter != m_pPlayerList->End(); ++lIter)
  2770.         {
  2771.             pPlayer = (CHXAudioPlayer*) (*lIter);
  2772.             if (pPlayer->GetState() == E_PLAYING && pPlayer->GetStreamCount() > 0)
  2773.                 return TRUE;
  2774.         }
  2775.     }
  2776.     return FALSE;
  2777. }
  2778. /************************************************************************
  2779.  *  Method:
  2780.  *      CHXAudioSession::NumberOfActivePlayers()
  2781.  *  Purpose:
  2782.  *      Returns number of active players (which are not is a STOP state).
  2783.  */
  2784. UINT16 CHXAudioSession::NumberOfActivePlayers()
  2785. {
  2786.     UINT16 uNumActive = 0;
  2787.     if (m_pPlayerList && m_pPlayerList->GetCount() > 0)
  2788.     {
  2789.         CHXAudioPlayer* pPlayer = 0;
  2790.         CHXSimpleList::Iterator lIter = m_pPlayerList->Begin();
  2791.         for (; lIter != m_pPlayerList->End(); ++lIter)
  2792.         {
  2793.             pPlayer = (CHXAudioPlayer*) (*lIter);
  2794.             if (pPlayer->GetState() != E_STOPPED && pPlayer->GetStreamCount() > 0)
  2795.             {
  2796.                 uNumActive++;
  2797.             }
  2798.         }
  2799.     }
  2800.     return uNumActive;
  2801. }
  2802. /************************************************************************
  2803.  *  Method:
  2804.  *      CHXAudioSession::NumberOfResumedPlayers()
  2805.  *  Purpose:
  2806.  *      Returns number of resumed players (which are in a PLAY state).
  2807.  */
  2808. UINT16 CHXAudioSession::NumberOfResumedPlayers()
  2809. {
  2810.     UINT16 uNumActive = 0;
  2811.     if (m_pPlayerList && m_pPlayerList->GetCount() > 0)
  2812.     {
  2813.         CHXAudioPlayer* pPlayer = 0;
  2814.         CHXSimpleList::Iterator lIter = m_pPlayerList->Begin();
  2815.         for (; lIter != m_pPlayerList->End(); ++lIter)
  2816.         {
  2817.             pPlayer = (CHXAudioPlayer*) (*lIter);
  2818.             if (pPlayer->GetState() == E_PLAYING && pPlayer->GetStreamCount() > 0)
  2819.             {
  2820.                 uNumActive++;
  2821.             }
  2822.         }
  2823.     }
  2824.     return uNumActive;
  2825. }
  2826. /************************************************************************
  2827.  *  Method:
  2828.  *      CHXAudioSession::CheckDisableWrite()
  2829.  *  Purpose:
  2830.  *      TRUE:  If ALL of the players have PostProcessHook with
  2831.  *             DisableWrite flag ON.
  2832.  *      FALSE: Otherwise
  2833.  */
  2834. BOOL CHXAudioSession::CheckDisableWrite()
  2835. {
  2836.     BOOL bDisableWrite = FALSE;
  2837.     if ( m_pPlayerList && m_pPlayerList->GetCount() > 0)
  2838.     {
  2839.         CHXAudioPlayer* pPlayer = 0;
  2840.         CHXSimpleList::Iterator lIter = m_pPlayerList->Begin();
  2841.         for (; lIter != m_pPlayerList->End(); ++lIter)
  2842.         {
  2843.             pPlayer = (CHXAudioPlayer*) (*lIter);
  2844.             if (pPlayer->GetStreamCount() == 0)
  2845.             {
  2846.                 continue;
  2847.             }
  2848.             /* If ANY ONE of them is not disabled, return FALSE */
  2849.             if (!pPlayer->IsDisableWrite())
  2850.             {
  2851.                 bDisableWrite = FALSE;
  2852.                 break;
  2853.             }
  2854.             else
  2855.             {
  2856.                 bDisableWrite = TRUE;
  2857.             }
  2858.         }
  2859.     }
  2860.     m_bDisableWrite = bDisableWrite;
  2861.     return bDisableWrite;
  2862. }
  2863. HX_RESULT
  2864. CHXAudioSession::CheckToPlayMoreAudio()
  2865. {
  2866.     HX_RESULT theErr = HXR_OK;
  2867.     if (m_bToBeReOpened)
  2868.     {
  2869.         return HXR_OK;
  2870.     }
  2871.     BOOL bPlay = FALSE;
  2872.     UINT16 uNumBlocks = 0;
  2873.     if (!m_pAudioDev)
  2874.     {
  2875.         bPlay = TRUE;
  2876.     }
  2877.     else
  2878.     {
  2879.         if ( (!m_bReplacedDev) && (((CHXAudioDevice*)m_pAudioDev)->IsWaveOutDevice()) )
  2880.         {
  2881.             uNumBlocks = ((CHXAudioDevice*)m_pAudioDev)->NumberOfBlocksRemainingToPlay();
  2882.             /* Now that m_ulMinimumPushdown can be set by the user, it is possible
  2883.              * for MIN_BLOCKS_TOBEQUEUED to be 0.
  2884.              */
  2885.             if (uNumBlocks == 0 ||
  2886.                 uNumBlocks < m_ulMinBlocksTobeQueued)
  2887.             {
  2888.                 bPlay = TRUE;
  2889.             }
  2890.         }
  2891.         else
  2892.         {
  2893.             ULONG32 ulCurTime;
  2894.             if (m_pAudioDev->GetCurrentAudioTime(ulCurTime) == HXR_OK)
  2895.             {
  2896.                 UINT32 ulNumBlocksPlayed = (UINT32) ((double) ulCurTime / m_dGranularity);
  2897.                 if (m_ulBlocksWritten > ulNumBlocksPlayed)
  2898.                 {
  2899.                     uNumBlocks = (UINT16) (m_ulBlocksWritten - ulNumBlocksPlayed);
  2900.                 }
  2901.                 /* Now that m_ulMinimumPushdown can be set by the user, it is possible
  2902.                  * for MIN_BLOCKS_TOBEQUEUED to be 0.
  2903.                  */
  2904.                 if (uNumBlocks == 0 ||
  2905.                     uNumBlocks < m_ulMinBlocksTobeQueued)
  2906.                 {
  2907.                     bPlay = TRUE;
  2908.                 }
  2909.             }
  2910.             else
  2911.             {
  2912.                 bPlay = FALSE;
  2913.             }
  2914.         }
  2915.     }
  2916. //{FILE* f1 = ::fopen("c:\temp\play.txt", "a+"); ::fprintf(f1, "%s::CheckToPlayMoreAudio: TickCount: %lu m_ulCurrentTime: %lu Played: %dn",
  2917. //                                                         bCalledFromAudioThread ? "AudioThread" : "MainThread", HX_GET_TICKCOUNT(), m_ulCurrentTime, (int) bPlay);::fclose(f1);}
  2918.     if (bPlay)
  2919.     {
  2920.         HX_ASSERT(!m_pAudioDev || m_ulMinBlocksTobeQueued > uNumBlocks);
  2921.         /* Currently we break transcoding feature of jukwbox because:
  2922.          * - overriden audio device plays much faster than realtime
  2923.          * - mp3 datatype does not implement drynotification interface.
  2924.          * - we therefore play silence instead of halting the timeline
  2925.          *   when we run out of data.
  2926.          *
  2927.          * Patch: revert back to old behavior: i.e. push only one
  2928.          * block at a time for replaced audio device
  2929.          *
  2930.          * correct fix: We should fix mp3 renderer to support drynotification
  2931.          *
  2932.          * XXXRA
  2933.          *
  2934.          * Update Removing this hack for replaced devices since MP3 renderer
  2935.          * now supports dry notification. -- RA 07/18/01:
  2936.          */
  2937.         if (m_pAudioDev && m_ulMinBlocksTobeQueued > uNumBlocks)
  2938.         {
  2939.             uNumBlocks = (UINT16) m_ulMinBlocksTobeQueued - uNumBlocks;
  2940.         }
  2941.         else
  2942.         {
  2943.             uNumBlocks = 1;
  2944.         }
  2945.         theErr = PlayAudio(uNumBlocks);
  2946.     }
  2947.     /* Put this back in the scheduler only if audio streams are present AND disable write
  2948.      * is OFF. If disable write is ON, audio data is written in fake timer callbacks
  2949.      */
  2950.     if (!m_ulCallbackID && m_bHasStreams && !m_bDisableWrite)
  2951.     {
  2952.         m_bFakeAudioTimeline = FALSE;
  2953.         m_ulCallbackID = m_pScheduler->RelativeEnter(this, m_ulGranularity*9/10);
  2954.     }
  2955.     return theErr;
  2956. }
  2957. ULONG32 CHXAudioSession::GetInitialPushdown(BOOL bAtStart /* = FALSE*/)
  2958. {
  2959.     UINT32 uPush = 0;
  2960.     if (m_ulGranularity == 0)
  2961.     {
  2962.         return 0;
  2963.     }
  2964.     if (bAtStart)
  2965.     {
  2966.         uPush = m_ulMinBlocksTobeQueuedAtStart;
  2967.     }
  2968.     else
  2969.     {
  2970.         uPush = m_ulMinBlocksTobeQueued;
  2971.     }
  2972.     return (ULONG32) (uPush * m_ulGranularity);
  2973. }
  2974. STDMETHODIMP CHXAudioSession::Func(void)
  2975. {
  2976.     HX_RESULT theErr    = HXR_OK;
  2977.     m_ulCallbackID = 0;
  2978.     if( m_bFakeAudioTimeline )
  2979.     {
  2980.         OnTimerCallback();
  2981.     }
  2982.     else
  2983.     {
  2984.         theErr = CheckToPlayMoreAudio();
  2985.         if( theErr != HXR_OK )
  2986.         {
  2987.             CHXSimpleList::Iterator lIter = m_pPlayerList->Begin();
  2988.             CHXAudioPlayer* pPlayer = NULL;
  2989.             for (; lIter != m_pPlayerList->End(); ++lIter)
  2990.             {
  2991.                 pPlayer = (CHXAudioPlayer*) (*lIter);
  2992.                 if( pPlayer )
  2993.                 {
  2994.                     pPlayer->SetError(theErr);
  2995.                 }
  2996.             }
  2997.         }
  2998.     }
  2999.     return theErr;
  3000. }
  3001. ULONG32
  3002. CHXAudioSession::SetGranularity(ULONG32 ulGranularity)
  3003. {
  3004.     /* DO NOT change Granularity in the midst of a presentation*/
  3005.     if (!m_bInited)
  3006.     {
  3007.         m_ulGranularity = ulGranularity;
  3008.         m_dGranularity = m_ulGranularity;
  3009.         UpdateMinimumPushdown();
  3010.     }
  3011.     return m_ulGranularity;
  3012. }
  3013. /************************************************************************
  3014.  *  Method:
  3015.  *              CHXAudioSession::GetFormat
  3016.  *      Purpose:
  3017.  *              Return the session's audio device format.
  3018.  */
  3019. void CHXAudioSession::GetFormat
  3020. (
  3021.         HXAudioFormat*   pAudioFormat
  3022. )
  3023. {
  3024.     memcpy(pAudioFormat, &m_DeviceFmt, sizeof( HXAudioFormat) );
  3025. }
  3026. /************************************************************************
  3027.  *  Method:
  3028.  *              CHXAudioSession::ProcessPostMixHooks
  3029.  *      Purpose:
  3030.  *              Send audio data to this player's post mix data hook.
  3031.  *
  3032.  */
  3033. HX_RESULT CHXAudioSession::ProcessPostMixHooks
  3034. (
  3035.     CHXAudioPlayer* pAudioPlayer,
  3036.     IHXBuffer*&    pInBuffer,
  3037.     BOOL*           bDisableWrite,
  3038.     UINT32          ulBufTime,
  3039.     BOOL&           bChanged
  3040. )
  3041. {
  3042. #if defined(HELIX_FEATURE_AUDIO_POSTMIXHOOK)
  3043.     HX_RESULT           theErr      = HXR_OK;
  3044.     CHXSimpleList*      pHookList   = 0;
  3045.     HXAudioHookInfo*     h           = 0;
  3046.     UCHAR*              pInData     = pInBuffer->GetBuffer();
  3047.     bChanged        = FALSE;
  3048.     *bDisableWrite  = FALSE;
  3049.     pHookList = pAudioPlayer->GetPostMixHookList();
  3050.     if ( pHookList && pHookList->GetCount() > 0)
  3051.     {
  3052.         pInBuffer->AddRef();
  3053.         m_pInDataPtr->pData             = pInBuffer;
  3054.         m_pInDataPtr->ulAudioTime       = ulBufTime;
  3055.         m_pOutDataPtr->pData            = NULL;
  3056.         m_bPostMixHooksUpdated = FALSE;
  3057.         // Each hook associated with this player gets the data.
  3058.         CHXSimpleList::Iterator lIter = pHookList->Begin();
  3059.         for (; !theErr && lIter != pHookList->End(); ++lIter)
  3060.         {
  3061.             h = (HXAudioHookInfo*) (*lIter);
  3062.             if (HXR_OK == ProcessAudioHook(ACTION_CHECK, h->pHook))
  3063.             {
  3064.                 // XXXHP, disable hooks when it doesn't support multi-channel
  3065.                 if (m_ActualDeviceFmt.uChannels <= 2 || h->bMultiChannelSupport)
  3066.                 {
  3067.                     if ( h->bDisableWrite )
  3068.                     {
  3069.                         *bDisableWrite = TRUE;
  3070.                     }
  3071.                     theErr = h->pHook->OnBuffer( m_pInDataPtr, m_pOutDataPtr );
  3072.         /*
  3073.          // Testing code to simulate post hook
  3074.                     static int copy = 1;
  3075.                     if (copy == 1)
  3076.                     {
  3077.                         m_pOutDataPtr->pData = m_pInDataPtr->pData;
  3078.                         m_pOutDataPtr->pData->AddRef();
  3079.                         m_pOutDataPtr->ulAudioTime  = m_pInDataPtr->ulAudioTime;
  3080.                     }
  3081.                     else if (copy ==2)
  3082.                     {
  3083.                         m_pOutDataPtr->pData = new CHXBuffer;
  3084.                         m_pOutDataPtr->pData->AddRef();
  3085.                         m_pOutDataPtr->pData->Set(m_pInDataPtr->pData->GetBuffer(), m_pInDataPtr->pData->GetSize());
  3086.                         m_pOutDataPtr->ulAudioTime  = m_pInDataPtr->ulAudioTime;
  3087.                     }
  3088.         */
  3089.                     /* Check to see if post hook changed the buffer. If so, then
  3090.                      * make this output as input to the next Hook.
  3091.                      */
  3092.                     if (!theErr && m_pOutDataPtr->pData)
  3093.                     {
  3094.                         /* HACK HACK HACK!!!!!
  3095.                          *
  3096.                          * RealJukeBox Beta Release 1 has a bug in equalizer
  3097.                          * where it passes a buffer without addrefing it....
  3098.                          * i.e. refcount of 0.
  3099.                          *
  3100.                          * We detect this and do this work for them
  3101.                          *
  3102.                          * This code will be removed post RealPlayer Beta 2
  3103.                          * (that is when RealJukeBox Beta 1 expires)
  3104.                          *
  3105.                          * - XXXRA
  3106.                          */
  3107.                         m_pOutDataPtr->pData->AddRef();
  3108.                         m_pOutDataPtr->pData->AddRef();
  3109.                         if (m_pOutDataPtr->pData->Release() > 1)
  3110.                         {
  3111.                             m_pOutDataPtr->pData->Release();
  3112.                         }
  3113.                         m_pInDataPtr->pData->Release();
  3114.                         m_pInDataPtr->pData         = m_pOutDataPtr->pData;
  3115.                         m_pInDataPtr->ulAudioTime   = m_pOutDataPtr->ulAudioTime;
  3116.                         m_pOutDataPtr->pData        = 0;
  3117.                         bChanged = TRUE;
  3118.                     }
  3119.                 }
  3120.             }
  3121.             else if (h->bIgnoreAudioData)
  3122.             {
  3123.                 IHXBuffer* pTempBuf = m_pInDataPtr->pData;
  3124.                 m_pInDataPtr->pData = NULL;
  3125.                 theErr = h->pHook->OnBuffer( m_pInDataPtr, m_pOutDataPtr);
  3126.                 m_pInDataPtr->pData = pTempBuf;
  3127.             }
  3128.             // the PostMixHook list could be altered in OnBuffer() call
  3129.             // during SoundAnimation
  3130.             if (m_bPostMixHooksUpdated)
  3131.             {
  3132.                 break;
  3133.             }
  3134.         }
  3135.     }
  3136.     // Copy the data back to the input structure.
  3137.     if (!theErr && bChanged && m_pInDataPtr->pData)
  3138.     {
  3139.         ULONG32 ulSize = m_pInDataPtr->pData->GetSize();
  3140.         HX_ASSERT(ulSize <= m_ulBytesPerGran);
  3141.         HX_RELEASE(pInBuffer);
  3142.         /* limit size of the buffer to granularity */
  3143.         if (ulSize > m_ulBytesPerGran)
  3144.         {
  3145.             pInBuffer = new CHXBuffer;
  3146.             pInBuffer->AddRef();
  3147.             pInBuffer->Set(m_pInDataPtr->pData->GetBuffer(), m_ulBytesPerGran);
  3148.         }
  3149.         else
  3150.         {
  3151.             m_pInDataPtr->pData->AddRef();
  3152.             pInBuffer = m_pInDataPtr->pData;
  3153.         }
  3154.     }
  3155.     HX_RELEASE(m_pInDataPtr->pData);
  3156.     return theErr;
  3157. #else
  3158.     return HXR_NOTIMPL;
  3159. #endif /* HELIX_FEATURE_AUDIO_POSTMIXHOOK */
  3160. }
  3161. void
  3162. CHXAudioSession::InitHooks()
  3163. {
  3164.     CHXSimpleList::Iterator ndx = m_pHookList->Begin();
  3165.     for (; ndx != m_pHookList->End(); ++ndx)
  3166.     {
  3167.         HXAudioHookInfo* pHookInfo = (HXAudioHookInfo*) (*ndx);
  3168.         if (pHookInfo->bIgnoreAudioData ||
  3169.             HXR_OK == ProcessAudioHook(ACTION_CHECK, pHookInfo->pHook))
  3170.         {
  3171.             HXAudioFormat audioFormat;
  3172.             memcpy( &audioFormat, &m_ActualDeviceFmt, sizeof( HXAudioFormat ));
  3173.             pHookInfo->pHook->OnInit(&audioFormat);
  3174.             // we do not allow these hooks to change the format on us
  3175.             HX_ASSERT(audioFormat.uChannels             == m_ActualDeviceFmt.uChannels &&
  3176.                      audioFormat.uBitsPerSample == m_ActualDeviceFmt.uBitsPerSample &&
  3177.                      audioFormat.ulSamplesPerSec        == m_ActualDeviceFmt.ulSamplesPerSec &&
  3178.                      audioFormat.uMaxBlockSize  == m_ActualDeviceFmt.uMaxBlockSize);
  3179.         }
  3180.     }
  3181. }
  3182. void
  3183. CHXAudioSession::ProcessHooks(HXAudioData* pAudioData)
  3184. {
  3185. #if defined(HELIX_FEATURE_AUDIO_POSTMIXHOOK)
  3186.     HX_RESULT theErr = HXR_OK;
  3187.     CHXSimpleList::Iterator ndx = m_pHookList->Begin();
  3188.     for (; ndx != m_pHookList->End(); ++ndx)
  3189.     {
  3190.         HXAudioHookInfo* pHookInfo = (HXAudioHookInfo*) (*ndx);
  3191.         if (HXR_OK == ProcessAudioHook(ACTION_CHECK, pHookInfo->pHook))
  3192.         {
  3193.             // XXXHP, disable hooks when it doesn't support multi-channel
  3194.             if (m_ActualDeviceFmt.uChannels <= 2 || pHookInfo->bMultiChannelSupport)
  3195.             {
  3196.                 m_pOutDataPtr->pData        = NULL;
  3197.                 m_pOutDataPtr->ulAudioTime  = pAudioData->ulAudioTime;
  3198.                 m_pOutDataPtr->uAudioStreamType = pAudioData->uAudioStreamType;
  3199.                 theErr = pHookInfo->pHook->OnBuffer(pAudioData, m_pOutDataPtr);
  3200.                 if (!theErr && m_pOutDataPtr->pData)
  3201.                 {
  3202.                     HX_RELEASE(pAudioData->pData);
  3203.                     m_pSessionBuf = pAudioData->pData = m_pOutDataPtr->pData;
  3204.                 }
  3205.             }
  3206.         }
  3207.         else if (pHookInfo->bIgnoreAudioData)
  3208.         {
  3209.             m_pOutDataPtr->pData        = NULL;
  3210.             m_pOutDataPtr->ulAudioTime  = pAudioData->ulAudioTime;
  3211.             m_pOutDataPtr->uAudioStreamType = pAudioData->uAudioStreamType;
  3212.             IHXBuffer* pTmpBuffer = pAudioData->pData;
  3213.             pAudioData->pData = NULL;
  3214.             theErr = pHookInfo->pHook->OnBuffer(pAudioData, m_pOutDataPtr);
  3215.             pAudioData->pData = pTmpBuffer;
  3216.         }
  3217.     }
  3218. #endif /* HELIX_FEATURE_AUDIO_POSTMIXHOOK */
  3219. }
  3220. double
  3221. CHXAudioSession::ConvertMsToBytes(UINT32 ulCurrentTime)
  3222. {
  3223.     UINT32 ulBytesPerSecond = m_ActualDeviceFmt.uChannels *
  3224.                              (m_ActualDeviceFmt.uBitsPerSample / 8) *
  3225.                              m_ActualDeviceFmt.ulSamplesPerSec;
  3226.     return (double)((ulCurrentTime * 1.0 / 1000) * ulBytesPerSecond);
  3227. }
  3228. BOOL
  3229. CHXAudioSession::IsAudioOnlyTrue(void)
  3230. {
  3231.     CHXSimpleList::Iterator lIter = m_pPlayerList->Begin();
  3232.     for (; lIter != m_pPlayerList->End(); ++lIter)
  3233.     {
  3234.         CHXAudioPlayer* pPlayer = (CHXAudioPlayer*) (*lIter);
  3235.         /* If anyone of them is TRUE, return TRUE */
  3236.         if (pPlayer->IsAudioOnlyTrue())
  3237.         {
  3238.             return TRUE;
  3239.         }
  3240.     }
  3241.     return FALSE;
  3242. }
  3243. void
  3244. CHXAudioSession::StopAllOtherPlayers()
  3245. {
  3246.     if (m_pContext)
  3247.     {
  3248.         IHXShutDownEverything* pShutdown;
  3249.         if (m_pContext->QueryInterface(IID_IHXShutDownEverything, (void**)&pShutdown) == HXR_OK)
  3250.         {
  3251.             HX_ASSERT(pShutdown);
  3252.             pShutdown->StopAllOtherPlayers();
  3253.             pShutdown->Release();
  3254.         }
  3255.     }
  3256. }
  3257. void
  3258. CHXAudioSession::CheckIfLastNMilliSecsToBeStored()
  3259. {
  3260.     if (!m_pPlayerList)
  3261.     {
  3262.         return;
  3263.     }
  3264.     BOOL bToBeStored = FALSE;
  3265. #ifdef HELIX_FEATURE_AUDIO_MULTIPLAYER_PAUSE
  3266.     UINT16 uNumPlayersWithStreams = 0;
  3267. #endif
  3268.     CHXSimpleList::Iterator ndx = m_pPlayerList->Begin();
  3269.     for (; ndx != m_pPlayerList->End(); ++ndx)
  3270.     {
  3271.         CHXAudioPlayer* pPlayer = (CHXAudioPlayer*) (*ndx);
  3272.         if (pPlayer->IsLastNMilliSecsToBeStored())
  3273.         {
  3274.             bToBeStored = TRUE;
  3275.             break;
  3276.         }
  3277. #ifdef HELIX_FEATURE_AUDIO_MULTIPLAYER_PAUSE
  3278.         if (!GetDisableMultiPlayPauseSupport() &&
  3279.             pPlayer->GetStreamCount() > 0)
  3280.         {
  3281.             uNumPlayersWithStreams++;
  3282.             if (uNumPlayersWithStreams > 1)
  3283.             {
  3284.                 bToBeStored = TRUE;
  3285.                 break;
  3286.             }
  3287.         }
  3288. #endif
  3289.     }
  3290.     ndx = m_pPlayerList->Begin();
  3291.     for (; ndx != m_pPlayerList->End(); ++ndx)
  3292.     {
  3293.         CHXAudioPlayer* pPlayer = (CHXAudioPlayer*) (*ndx);
  3294.         // pushdown + additional 500 ms...why? i don't know! ;)
  3295.         pPlayer->SaveLastNMilliSeconds(bToBeStored, m_ulMinimumPushdown+500);
  3296.     }
  3297. }
  3298. void
  3299. CHXAudioSession::RewindSession(CHXAudioPlayer* pPlayerToExclude)
  3300. {
  3301.     UINT32 ulCurTime        = m_ulCurrentTime;
  3302.     UINT32 ulTimeToRewind   = 0;
  3303.     m_ulLastRewindTimestamp = HX_GET_TICKCOUNT();
  3304.     // Close the audio device only if all players are not playing.
  3305.     if (m_pAudioDev)
  3306.     {
  3307.         m_pAudioDev->Reset();
  3308.     }
  3309.     m_uAskFromAudioDevice   = 5;
  3310.     /* We should have always be writing AHEAD*/
  3311.     HX_ASSERT((ULONG32) m_dBufEndTime >= ulCurTime);
  3312.     m_bStoppedDuringPause = TRUE;
  3313.     if ((ULONG32) m_dBufEndTime > ulCurTime)
  3314.     {
  3315.         ulTimeToRewind = (ULONG32) m_dBufEndTime - ulCurTime;
  3316.         RewindAllPlayers(ulCurTime, ulTimeToRewind, pPlayerToExclude);
  3317.     }
  3318.     if(m_ulCallbackID )
  3319.     {
  3320.         m_pScheduler->Remove(m_ulCallbackID);
  3321.         m_ulCallbackID = 0;
  3322.     }
  3323.     m_bFirstPlayAudio       = TRUE;
  3324.     m_bTimeSyncReceived     = FALSE;
  3325.     m_bAtLeastOneTimeReceived   = FALSE;
  3326.     m_dBufEndTime           = m_ulCurrentTime;
  3327.     m_ulStartTime           = m_ulCurrentTime;
  3328.     m_dNumBytesPlayed       = (double) 0;
  3329.     m_ulBlocksWritten       = 0;
  3330.     m_dNumBytesWritten      = 0;
  3331.     m_ulLastAudioTime       = 0;
  3332. //{FILE* f1 = ::fopen("d:\temp\multi.txt", "a+"); ::fprintf(f1, "RewindSession %lun", m_ulStartTime);::fclose(f1);}
  3333. }
  3334. void
  3335. CHXAudioSession::RewindAllPlayers(UINT32 ulCurTime, UINT32 ulTimeToRewind, CHXAudioPlayer* pPlayerToExclude)
  3336. {
  3337.     CHXSimpleList::Iterator ndx = m_pPlayerList->Begin();
  3338.     for (; ndx != m_pPlayerList->End(); ++ndx)
  3339.     {
  3340.         CHXAudioPlayer* pPlayer = (CHXAudioPlayer*) (*ndx);
  3341.         if (pPlayer != pPlayerToExclude)
  3342.         {
  3343.             pPlayer->RewindPlayer(ulTimeToRewind);
  3344.         }
  3345.     }
  3346. }
  3347. HX_RESULT
  3348. CHXAudioSession::Rewind()
  3349. {
  3350.     HX_RESULT theErr = HXR_OK;
  3351.     m_bToBeRewound = FALSE;
  3352. #ifdef HELIX_FEATURE_AUDIO_MULTIPLAYER_PAUSE
  3353.     /*
  3354.      * we need to re-mix to start the newly resumed player instantly
  3355.      * and not delay it by pushdown
  3356.      */
  3357.     if (!GetDisableMultiPlayPauseSupport())
  3358.     {
  3359.         RewindSession();
  3360.         if (NumberOfResumedPlayers() > 0)
  3361.         {
  3362.             theErr = ActualResume();
  3363.         }
  3364.     }
  3365. #endif
  3366.     return theErr;
  3367. }
  3368. BOOL
  3369. CHXAudioSession::ReallyNeedData()
  3370. {
  3371.     return (m_bSessionBufferDirty ||
  3372.             (m_uNumToBePushed > (m_ulMinBlocksTobeQueued-m_ulMinBlocksTobeQueuedAtStart))) ? TRUE : FALSE;
  3373. }
  3374. BOOL CHXAudioSession::GetDisableMultiPlayPauseSupport()
  3375. {
  3376.     if(!m_pMPPSupport)
  3377.         return FALSE;
  3378.     return m_pMPPSupport->GetDisableMultiPlayPauseSupport();
  3379. }
  3380. void
  3381. CHXAudioSession::ReopenDevice()
  3382. {
  3383. #ifndef _CARBON
  3384.     if (m_bToBeReOpened &&
  3385.         m_pInterruptState && !m_pInterruptState->AtInterruptTime())
  3386.     {
  3387.         m_pDeviceCallback->PendingID(m_pScheduler->RelativeEnter(m_pDeviceCallback, 0));
  3388.         return;
  3389.     }
  3390. #endif
  3391.     if (m_bToBeReOpened)
  3392.     {
  3393.         TryOpenAudio();
  3394.         if (!m_bToBeReOpened && m_pAudioDev && m_bDeferActualResume)
  3395.         {
  3396.             ActualResume();
  3397.         }
  3398.     }
  3399. }
  3400. //
  3401. // HXDeviceSetupCallback
  3402. CHXAudioSession::HXDeviceSetupCallback::HXDeviceSetupCallback(CHXAudioSession* it) :
  3403.      m_lRefCount (0)
  3404.     ,m_pAudioSessionObject(it)
  3405.     ,m_ulCallbackID(0)
  3406. {
  3407. }
  3408. CHXAudioSession::HXDeviceSetupCallback::~HXDeviceSetupCallback()
  3409. {
  3410.     HX_ASSERT(m_ulCallbackID==0);
  3411.     m_pAudioSessionObject = NULL;
  3412. }
  3413. STDMETHODIMP CHXAudioSession::HXDeviceSetupCallback::QueryInterface(REFIID riid, void** ppvObj)
  3414. {
  3415.     QInterfaceList  qiList[] =
  3416.         {
  3417.             { GET_IIDHANDLE(IID_IUnknown), (IUnknown*)(IHXAudioDeviceResponse*)this},
  3418.             { GET_IIDHANDLE(IID_IHXInterruptSafe), (IHXInterruptSafe*)this  },
  3419.             { GET_IIDHANDLE(IID_IHXCallback),  (IHXCallback*)this   }
  3420.         };
  3421.     return ::QIFind(qiList, QILISTSIZE(qiList), riid, ppvObj);
  3422. }
  3423. STDMETHODIMP_(ULONG32) CHXAudioSession::HXDeviceSetupCallback::AddRef()
  3424. {
  3425.     return InterlockedIncrement(&m_lRefCount);
  3426. }
  3427. STDMETHODIMP_(ULONG32) CHXAudioSession::HXDeviceSetupCallback::Release()
  3428. {
  3429.     if (InterlockedDecrement(&m_lRefCount) > 0)
  3430.     {
  3431.         return m_lRefCount;
  3432.     }
  3433.     delete this;
  3434.     return 0;
  3435. }
  3436. STDMETHODIMP CHXAudioSession::HXDeviceSetupCallback::Func(void)
  3437. {
  3438.     m_ulCallbackID = 0;
  3439.     if(m_pAudioSessionObject)
  3440.     {
  3441.         m_pAudioSessionObject->ReopenDevice();
  3442.     }
  3443.     return HXR_OK;
  3444. }
  3445. STDMETHODIMP_(BOOL) CHXAudioSession::HXDeviceSetupCallback::IsInterruptSafe()
  3446. {
  3447.     return TRUE;
  3448. }
  3449. #if defined(HELIX_FEATURE_TIMELINE_WATCHER)
  3450. HX_RESULT CHXAudioSession::AddTimelineWatcher( IHXTimelineWatcher* pWatcher )
  3451. {
  3452.     HX_RESULT res = HXR_FAIL;
  3453.     if( !m_pTimeLineWatchers )
  3454.     {
  3455.         m_pTimeLineWatchers = new CHXSimpleList();
  3456.         if( !m_pTimeLineWatchers )
  3457.         {
  3458.             return HXR_OUTOFMEMORY;
  3459.         }
  3460.     }
  3461.     
  3462.     
  3463.     LISTPOSITION lPosition = m_pTimeLineWatchers->Find(pWatcher);
  3464.     if(!lPosition)
  3465.     {
  3466.         res = HXR_OUTOFMEMORY;
  3467.         if( m_pTimeLineWatchers->AddTail(pWatcher) )
  3468.         {
  3469.             pWatcher->AddRef();
  3470.             res = HXR_OK;
  3471.         }
  3472.     }
  3473.     
  3474.     return res;
  3475. }
  3476. HX_RESULT CHXAudioSession::RemoveTimelineWatcher( IHXTimelineWatcher* pWatcher )
  3477. {
  3478.     HX_RESULT res = HXR_FAIL;
  3479.     if( m_pTimeLineWatchers )
  3480.     {
  3481.         LISTPOSITION lPosition = m_pTimeLineWatchers->Find(pWatcher);
  3482.         if(lPosition)
  3483.         {
  3484.             m_pTimeLineWatchers->RemoveAt(lPosition);
  3485.             HX_RELEASE(pWatcher);
  3486.             res = HXR_OK;
  3487.         }
  3488.     }
  3489.     return res;
  3490. }
  3491. void CHXAudioSession::_NotifyTimelineWatchers( const int nWhich, const UINT32 ulNow)
  3492. {
  3493.     if( m_pTimeLineWatchers )
  3494.     {
  3495.         
  3496.         LISTPOSITION pos = m_pTimeLineWatchers->GetHeadPosition();
  3497.         while( pos )
  3498.         {
  3499.             IHXTimelineWatcher* pWatcher = (IHXTimelineWatcher*)m_pTimeLineWatchers->GetNext(pos);
  3500.             switch( nWhich )
  3501.             {
  3502.                case TLW_PAUSE:
  3503.                    pWatcher->OnPause();
  3504.                    break;
  3505.                case TLW_RESUME:
  3506.                    pWatcher->OnResume();
  3507.                    break;
  3508.                case TLW_CLOSE:
  3509.                    pWatcher->OnClose();
  3510.                    break;
  3511.                case TLW_TIMESYNC:
  3512.                    pWatcher->OnTimeSync(ulNow);
  3513.                    break;
  3514.                default:
  3515.                    HX_ASSERT("Unknown timeline watcher action."==NULL);
  3516.             }
  3517.         }
  3518.     }
  3519. }
  3520. #endif