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

Symbian

开发平台:

C/C++

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