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

Symbian

开发平台:

Visual 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. // #define _AUDREND_FLOW_LOG
  36. #define TIME_SYNC_GRANULARITY 100 // in milliseconds
  37. #define MAX_AUDIO_WRITE_TIME 200 // in milliseconds
  38. #define STREAM_MAJOR_VERSION  0
  39. #define STREAM_MINOR_VERSION  0
  40. #define CONTENT_MAJOR_VERSION 0
  41. #define CONTENT_MINOR_VERSION 0
  42. #define TIME_FUDGE 5
  43. #define BASE_AUDIO_RENDERER_NAME    "Basic Audio"
  44. #define MINIMAL_AUDIO_PUSHDOWN 120
  45. #ifdef _AUDREND_FLOW_LOG
  46. #define AUDREND_FLOW_FILE     "C:\audrend.txt"
  47. #else // _AUDREND_FLOW_LOG
  48. #define AUDREND_FLOW_FILE     NULL
  49. #endif // _AUDREND_FLOW_LOG
  50. /****************************************************************************
  51.  *  Includes
  52.  */
  53. #include "hlxclib/stdio.h"
  54. #include "hlxclib/string.h"
  55. #include "audrend.ver"
  56. #include "hxtypes.h"
  57. #include "hxcom.h"
  58. #include "hxcomm.h"
  59. #include "ihxpckts.h"
  60. #include "hxcore.h"
  61. #include "hxrendr.h"
  62. #include "hxplugn.h"
  63. #include "hxasm.h"
  64. #include "hxver.h"
  65. #include "hxupgrd.h"
  66. #include "hxengin.h"
  67. #include "hxprefs.h"
  68. #include "hxerror.h"
  69. #include "hxausvc.h"
  70. #include "hxthread.h"
  71. #include "hxstrutl.h"
  72. #include "hxtick.h"
  73. #include "hxassert.h"
  74. #include "hxbuffer.h"
  75. #include "addupcol.h"
  76. #include "errdbg.h"
  77. #include "adjtime.h"
  78. #include "hxver.h"
  79. #include "audrmlog.h"
  80. #include "audrend.h"
  81. #include "hxheap.h"
  82. #ifdef _DEBUG
  83. #undef HX_THIS_FILE
  84. static const char HX_THIS_FILE[] = __FILE__;
  85. #endif //  HX_THIS_FILE
  86. /****************************************************************************
  87.  *  Constants
  88.  */
  89. const char* const CAudioRenderer::zm_pDescription    = "RealNetworks Audio Renderer Plugin";
  90. const char* const CAudioRenderer::zm_pCopyright      = HXVER_COPYRIGHT;
  91. const char* const CAudioRenderer::zm_pMoreInfoURL    = HXVER_MOREINFO;
  92. const char* const CAudioRenderer::zm_pStreamMimeTypes[] =
  93. {
  94.     "audio/NULL",
  95.     NULL
  96. };
  97. /************************************************************************
  98.  *  CAudioRenderer
  99.  */
  100. /************************************************************************
  101.  *  Constructor/Destructor
  102.  */
  103. CAudioRenderer::CAudioRenderer()
  104. : m_pContext(NULL)
  105. , m_pStream(NULL)
  106. , m_pBackChannel(NULL)
  107. , m_pHeader(NULL)
  108.         , m_pErrorMessages(NULL)
  109. , m_pCommonClassFactory(NULL)
  110. , m_pPreferences(NULL)
  111. , m_pRegistry(NULL)
  112. , m_ulRegistryID(0)
  113. , m_ulPreroll(0)
  114. , m_ulAudioWantedTime(NO_TIME_SET)
  115. , m_ulLastWriteTime(NO_TIME_SET)
  116. , m_pAudioPlayer(NULL)
  117. , m_bEndOfPackets(FALSE)
  118. , m_bDoneWritingPackets(FALSE)
  119. , m_bInSeekMode(FALSE)
  120. , m_ulDuration(0)
  121. , m_bFirstPacket(TRUE)
  122. , m_bDelayOffsetSet(FALSE)
  123. , m_ulDelay(0)
  124. , m_pMutex(NULL)
  125. , m_bProcessingPacket(FALSE)
  126. , m_pAudioFormat(NULL)
  127. , m_PlayState(stopped)
  128. , m_lRefCount(0)
  129.         , m_ppAudioStream(NULL)
  130.         , m_pAudioStats(NULL)
  131.         , m_ulNumAudioStreams(0)
  132.         , m_ulCurAudioStream(0)
  133.         , m_bCanChangeAudioStream(FALSE)
  134.     , m_lTimeOffset(0)
  135.     // Allocate space for an initial number of pointers
  136.     m_ppAudioStream = new IHXAudioStream* [AUDREND_INITIAL_NUMSTREAMPTRS];
  137.     if (m_ppAudioStream)
  138.     {
  139.         memset((void*) m_ppAudioStream, 0, AUDREND_INITIAL_NUMSTREAMPTRS * sizeof(IHXAudioStream*));
  140.         m_ulNumAudioStreams = AUDREND_INITIAL_NUMSTREAMPTRS;
  141.     }
  142. }
  143. CAudioRenderer::~CAudioRenderer()
  144. {
  145.     EndStream();
  146. #if defined(HELIX_FEATURE_STATS)
  147.     HX_DELETE(m_pAudioStats); 
  148. #endif /* HELIX_FEATURE_STATS */
  149.     HX_DELETE(m_pMutex);
  150.     HX_RELEASE(m_pContext);
  151.     HX_RELEASE(m_pHeader);
  152.     HX_RELEASE(m_pErrorMessages);
  153.     HX_RELEASE(m_pCommonClassFactory);
  154.     HX_RELEASE(m_pPreferences);
  155.     HX_RELEASE(m_pRegistry);
  156. }
  157. /************************************************************************
  158.  *  IHXPlugin Methods
  159.  */
  160. /************************************************************************
  161.  *  Method:
  162.  *    IHXPlugin::InitPlugin
  163.  *  Purpose:
  164.  *    Initializes the plugin for use. This interface must always be
  165.  *    called before any other method is called. This is primarily needed
  166.  *    so that the plugin can have access to the context for creation of
  167.  *    IHXBuffers and IMalloc.
  168.  */
  169. STDMETHODIMP CAudioRenderer::InitPlugin(IUnknown* /*IN*/ pContext)
  170. {
  171.     HX_RESULT retVal = HXR_OK;
  172.     HX_ASSERT(pContext);
  173.     m_pContext = pContext;
  174.     m_pContext->AddRef();
  175.     retVal = m_pContext->QueryInterface(IID_IHXCommonClassFactory,
  176. (void**) &m_pCommonClassFactory);
  177.     m_pContext->QueryInterface(IID_IHXPreferences,
  178.                                (void**) &m_pPreferences);
  179.     m_pContext->QueryInterface(IID_IHXRegistry, (void**) &m_pRegistry);
  180.     if (SUCCEEDED(retVal) && !m_pMutex)
  181.     {
  182. #ifdef THREADS_SUPPORTED
  183. retVal = HXMutex::MakeMutex(m_pMutex);
  184. #else  // THREADS_SUPPORTED
  185. retVal = HXMutex::MakeStubMutex(m_pMutex);
  186. #endif  // THREADS_SUPPORTED
  187.     }
  188. #if defined(HELIX_FEATURE_STATS)
  189.     if (SUCCEEDED(retVal))
  190.     {
  191. m_pAudioStats = new CAudioStatistics(m_pContext);
  192. retVal = HXR_OUTOFMEMORY;
  193. if (m_pAudioStats)
  194. {
  195.     retVal = HXR_OK;
  196. }
  197.     }
  198. #endif /* HELIX_FEATURE_STATS */
  199.     // Get the IHXErrorMessages interface. Not an error
  200.     // if it's not supported
  201.     HX_RELEASE(m_pErrorMessages);
  202.     m_pContext->QueryInterface(IID_IHXErrorMessages,
  203.                                (void**) &m_pErrorMessages);
  204.     if (FAILED(retVal))
  205.     {
  206. HX_RELEASE(m_pCommonClassFactory);
  207. HX_RELEASE(m_pPreferences);
  208. HX_RELEASE(m_pRegistry);
  209.     }
  210.     return retVal;
  211. }
  212. /************************************************************************
  213.  *  Method:
  214.  *    IHXPlugin::GetPluginInfo
  215.  *  Purpose:
  216.  *    Returns the basic information about this plugin. Including:
  217.  *
  218.  *    bLoadMultiple whether or not this plugin DLL can be loaded
  219.  * multiple times. All File Formats must set
  220.  * this value to TRUE.
  221.  *    pDescription which is used in about UIs (can be NULL)
  222.  *    pCopyright which is used in about UIs (can be NULL)
  223.  *    pMoreInfoURL which is used in about UIs (can be NULL)
  224.  */
  225. STDMETHODIMP CAudioRenderer::GetPluginInfo
  226. (
  227.    REF(BOOL)        /*OUT*/ bLoadMultiple,
  228.    REF(const char*) /*OUT*/ pDescription,
  229.    REF(const char*) /*OUT*/ pCopyright,
  230.    REF(const char*) /*OUT*/ pMoreInfoURL,
  231.    REF(ULONG32)     /*OUT*/ ulVersionNumber
  232. )
  233. {
  234.     bLoadMultiple = TRUE;   // Must be true for file formats.
  235.     pDescription    = zm_pDescription;
  236.     pCopyright     = zm_pCopyright;
  237.     pMoreInfoURL    = zm_pMoreInfoURL;
  238.     ulVersionNumber = TARVER_ULONG32_VERSION;
  239.     return HXR_OK;
  240. }
  241. /************************************************************************
  242.  *  Method:
  243.  *    IHXPlugin::GetRendererInfo
  244.  *  Purpose:
  245.  *    If this object is a file format object this method returns
  246.  *    information vital to the instantiation of file format plugins.
  247.  *    If this object is not a file format object, it should return
  248.  *    HXR_UNEXPECTED.
  249.  */
  250. STDMETHODIMP CAudioRenderer::GetRendererInfo
  251. (
  252.  REF(const char**) /*OUT*/ pStreamMimeTypes,
  253.  REF(UINT32)      /*OUT*/ unInitialGranularity
  254. )
  255. {
  256.     pStreamMimeTypes = (const char**)zm_pStreamMimeTypes;
  257.     unInitialGranularity = TIME_SYNC_GRANULARITY;
  258.     return HXR_OK;
  259. }
  260. // *** IUnknown methods ***
  261. /****************************************************************************
  262. *  IUnknown::QueryInterface                                    ref:  hxcom.h
  263. *
  264. *  This routine indicates which interfaces this object supports. If a given
  265. *  interface is supported, the object's reference count is incremented, and
  266. *  a reference to that interface is returned. Otherwise a NULL object and
  267. *  error code are returned. This method is called by other objects to
  268. *  discover the functionality of this object.
  269. */
  270. STDMETHODIMP CAudioRenderer::QueryInterface(REFIID riid, void** ppvObj)
  271. {
  272.     QInterfaceList  qiList[] =
  273.     {
  274. { GET_IIDHANDLE(IID_IHXInterruptSafe), (IHXInterruptSafe*)this},
  275. { GET_IIDHANDLE(IID_IHXDryNotification), (IHXDryNotification*)this},
  276. { GET_IIDHANDLE(IID_IUnknown), (IUnknown*)(IHXPlugin*) this},
  277. { GET_IIDHANDLE(IID_IHXPlugin), (IHXPlugin*)this},
  278. { GET_IIDHANDLE(IID_IHXRenderer), (IHXRenderer*)this},
  279. #if defined(HELIX_FEATURE_STATS)
  280. { GET_IIDHANDLE(IID_IHXStatistics), (IHXStatistics*)this},
  281. #endif // HELIX_FEATURE_STATS
  282.     };
  283.     return ::QIFind(qiList, QILISTSIZE(qiList), riid, ppvObj);
  284. }
  285. /****************************************************************************
  286. *  IUnknown::AddRef                                            ref:  hxcom.h
  287. *
  288. *  This routine increases the object reference count in a thread safe
  289. *  manner. The reference count is used to manage the lifetime of an object.
  290. *  This method must be explicitly called by the user whenever a new
  291. *  reference to an object is used.
  292. */
  293. STDMETHODIMP_(ULONG32) CAudioRenderer::AddRef()
  294. {
  295.     return InterlockedIncrement(&m_lRefCount);
  296. }
  297. /****************************************************************************
  298. *  IUnknown::Release                                           ref:  hxcom.h
  299. *
  300. *  This routine decreases the object reference count in a thread safe
  301. *  manner, and deletes the object if no more references to it exist. It must
  302. *  be called explicitly by the user whenever an object is no longer needed.
  303. */
  304. STDMETHODIMP_(ULONG32) CAudioRenderer::Release()
  305. {
  306.     if (InterlockedDecrement(&m_lRefCount) > 0)
  307.     {
  308.         return m_lRefCount;
  309.     }
  310.     delete this;
  311.     return 0;
  312. }
  313. /************************************************************************
  314.  *  IHXRenderer Methods
  315.  */
  316. /////////////////////////////////////////////////////////////////////////
  317. //  Method:
  318. // IHXRenderer::StartStream
  319. //  Purpose:
  320. // Called by client engine to inform the renderer of the stream it
  321. // will be rendering. The stream interface can provide access to
  322. // its source or player. This method also provides access to the
  323. // primary client controller interface.
  324. //
  325. STDMETHODIMP
  326. CAudioRenderer::StartStream
  327. (
  328.     IHXStream*     pStream,
  329.     IHXPlayer*     pPlayer
  330. )
  331. {
  332.     HX_RESULT retVal = HXR_OK;
  333.     m_pStream  = pStream;
  334.     if (m_pStream)
  335.     {
  336. m_pStream->AddRef();
  337. IHXStreamSource* pSource = 0;
  338. if (m_pStream->GetSource(pSource) == HXR_OK)
  339. {
  340.     /* It is OK if the source does not support backchannel. Reasons:
  341.      *
  342.      * 1. This stream may not be coming from h261 fileformat.
  343.      *   It may instead be merged into a container fileformat which
  344.      *   may be does not support BackChannel.
  345.      *
  346.      * 2. The protocol used to serve this stream may not support
  347.      *   BackChannel.
  348.      */
  349.     pSource->QueryInterface(IID_IHXBackChannel, (void**) &m_pBackChannel);
  350.     pSource->Release();
  351. }
  352.     }
  353.     IHXAudioPushdown2 * pAudioPushdown2 = NULL;
  354.     // get interface to audio player
  355.     if (pPlayer)
  356.     {
  357. retVal = pPlayer->QueryInterface(IID_IHXAudioPlayer,
  358.    (void**) &m_pAudioPlayer);
  359. #ifdef HELIX_CONFIG_MIN_PCM_PUSHDOWN_BYTES
  360.         if( m_pAudioPlayer )
  361.         {
  362.             m_pAudioPlayer->QueryInterface(IID_IHXAudioPushdown2, (void**) &pAudioPushdown2);
  363.             if( pAudioPushdown2 )
  364.             {
  365.                 pAudioPushdown2->SetAudioPushdown( MINIMAL_AUDIO_PUSHDOWN );
  366.                 pAudioPushdown2->Release();
  367.             }
  368.         }
  369. #endif // HELIX_CONFIG_MIN_PCM_PUSHDOWN_BYTES
  370.     }
  371.     return retVal;
  372. }
  373. /////////////////////////////////////////////////////////////////////////
  374. //  Method:
  375. // IHXRenderer::EndStream
  376. //  Purpose:
  377. // Called by client engine to inform the renderer that the stream
  378. // is was rendering is closed.
  379. //
  380. STDMETHODIMP CAudioRenderer::EndStream()
  381. {
  382.     if (m_pMutex)
  383.     {
  384. m_pMutex->Lock();
  385.     }
  386.     m_bDoneWritingPackets = TRUE;
  387.     m_PlayState = stopped;
  388.     if (m_pMutex)
  389.     {
  390. m_pMutex->Unlock();
  391.     }
  392.     if (m_pAudioFormat)
  393.     {
  394.         m_pAudioFormat->Release();
  395.         m_pAudioFormat = NULL;
  396.     }
  397.     HX_RELEASE(m_pStream);
  398.     HX_RELEASE(m_pBackChannel);
  399.     HX_RELEASE(m_pAudioPlayer);
  400.     for (UINT32 i = 0; i < m_ulNumAudioStreams; i++)
  401.     {
  402.         HX_RELEASE(m_ppAudioStream[i]);
  403.     }
  404.     HX_VECTOR_DELETE(m_ppAudioStream);
  405.     m_ulNumAudioStreams = 0;
  406.     return HXR_OK;
  407. }
  408. /////////////////////////////////////////////////////////////////////////
  409. //  Method:
  410. // IHXRenderer::OnHeader
  411. //  Purpose:
  412. // Called by client engine when a header for this renderer is
  413. // available. The header will arrive before any packets.
  414. //
  415. STDMETHODIMP
  416. CAudioRenderer::OnHeader(IHXValues* pHeader)
  417. {
  418.     HX_RESULT retVal = HXR_OK;
  419.     UINT32 ulTrackStartTime = NO_TIME_SET;
  420.     UINT32 ulTrackEndTime = NO_TIME_SET;
  421. #if defined(HELIX_FEATURE_AUTOUPGRADE)
  422.     // check the stream versions
  423.     pHeader->AddRef();
  424.     retVal = CheckStreamVersions(pHeader);
  425.     pHeader->Release();
  426. #endif /* #if defined(HELIX_FEATURE_AUTOUPGRADE) */
  427.     if (SUCCEEDED(retVal))
  428.     {
  429. pHeader->GetPropertyULONG32("Preroll", m_ulPreroll);
  430. pHeader->GetPropertyULONG32("Duration", m_ulDuration);
  431. pHeader->GetPropertyULONG32("Delay", m_ulDelay);
  432. pHeader->GetPropertyULONG32("TrackStartTime", ulTrackStartTime);
  433. pHeader->GetPropertyULONG32("TrackEndTime", ulTrackEndTime);
  434.     }
  435.     if (SUCCEEDED(retVal))
  436.     {
  437. m_pAudioFormat = CreateFormatObject(pHeader);
  438. retVal = HXR_OUTOFMEMORY;
  439. if (m_pAudioFormat)
  440. {
  441.     m_pAudioFormat->AddRef();
  442.     retVal = HXR_OK;
  443. }
  444.     }
  445.     if (SUCCEEDED(retVal))
  446.     {
  447. retVal = m_pAudioFormat->Init(pHeader);
  448. #if defined(HELIX_FEATURE_AUTOUPGRADE)
  449.         if (FAILED(retVal) && retVal == HXR_REQUEST_UPGRADE)
  450.         {
  451.             AddToAutoUpgradeCollection(m_pAudioFormat->GetAutoUpgradeString(),
  452.                                        m_pContext);
  453.         }
  454. #endif /* #if defined(HELIX_FEATURE_AUTOUPGRADE) */
  455.     }
  456.     if (SUCCEEDED(retVal))
  457.     {
  458. retVal = InitAudioStream(pHeader, &m_ppAudioStream[m_ulCurAudioStream]);
  459.     }
  460.     // Setup preroll
  461.     if (SUCCEEDED(retVal))
  462.     {
  463.         // check that stream header preroll value is not too big
  464.         ULONG32 ulMaxPreroll = m_pAudioFormat->GetMaximumPreroll(pHeader);
  465.         if (m_ulPreroll > ulMaxPreroll)
  466.         {
  467.     m_ulPreroll = ulMaxPreroll;
  468.         }
  469. else
  470.         // check that stream header preroll value is set
  471.         if (m_ulPreroll == 0)
  472. {
  473.     // preload is not set for this stream - assume default
  474.     m_ulPreroll = m_pAudioFormat->GetDefaultPreroll(pHeader);
  475. }
  476.         // note that we are not enforcing any minimum preroll here
  477. if (m_ulPreroll > 0)
  478. {
  479.             pHeader->SetPropertyULONG32( "Preroll", m_ulPreroll );
  480. }
  481.         // Set the flag saying whether or not the audio
  482.         // stream parameters can change on the fly
  483.         m_bCanChangeAudioStream = m_pAudioFormat->CanChangeAudioStream();
  484.         // Save the stream header
  485.         HX_RELEASE(m_pHeader);
  486.         m_pHeader = pHeader;
  487.         m_pHeader->AddRef();
  488.     }
  489.     return retVal;
  490. }
  491. /////////////////////////////////////////////////////////////////////////////
  492. //  Method:
  493. // CAudioRenderer::CheckStreamVersions
  494. //  copied from CRealAudioRenderer
  495. HX_RESULT CAudioRenderer::CheckStreamVersions(IHXValues* pHeader)
  496. {
  497.     // check stream and content versions so an upgrade can
  498.     // be called if necessary...
  499.     HX_RESULT pnr = HXR_OK;
  500. #if defined(HELIX_FEATURE_AUTOUPGRADE)
  501.     BOOL bVersionOK = TRUE;
  502.     UINT32 ulStreamVersion = 0;
  503.     UINT32 ulContentVersion = 0;
  504.     if(HXR_OK == pHeader->GetPropertyULONG32("StreamVersion",
  505. ulStreamVersion))
  506.     {
  507. UINT32 ulMajorVersion = HX_GET_MAJOR_VERSION(ulStreamVersion);
  508. UINT32 ulMinorVersion = HX_GET_MINOR_VERSION(ulStreamVersion);
  509. ULONG32 ulThisMajorVersion = STREAM_MAJOR_VERSION;
  510. ULONG32 ulThisMinorVersion = STREAM_MINOR_VERSION;
  511. GetStreamVersion(ulThisMajorVersion, ulThisMinorVersion);
  512. if((ulMajorVersion > ulThisMajorVersion) ||
  513.    ((ulMinorVersion > ulThisMinorVersion) &&
  514.     (ulMajorVersion == ulThisMajorVersion)))
  515. {
  516.     bVersionOK = FALSE;
  517. }
  518.     }
  519.     if(bVersionOK &&
  520.        (HXR_OK == pHeader->GetPropertyULONG32("ContentVersion",
  521.       ulContentVersion)))
  522.     {
  523. UINT32 ulMajorVersion = HX_GET_MAJOR_VERSION(ulContentVersion);
  524. UINT32 ulMinorVersion = HX_GET_MINOR_VERSION(ulContentVersion);
  525. ULONG32 ulThisMajorVersion = CONTENT_MAJOR_VERSION;
  526. ULONG32 ulThisMinorVersion = CONTENT_MINOR_VERSION;
  527. GetContentVersion(ulThisMajorVersion, ulThisMinorVersion);
  528. if((ulMajorVersion > ulThisMajorVersion) ||
  529.    ((ulMinorVersion > ulThisMinorVersion) &&
  530.     (ulMajorVersion == ulMajorVersion)))
  531. {
  532.     bVersionOK = FALSE;
  533. }
  534.     }
  535.     if(!bVersionOK)
  536.     {
  537.         AddToAutoUpgradeCollection(GetUpgradeMimeType(), m_pContext);
  538. pnr = HXR_FAIL;
  539.     }
  540. #endif /* #if defined(HELIX_FEATURE_AUTOUPGRADE) */
  541.     return pnr;
  542. }
  543. /////////////////////////////////////////////////////////////////////////
  544. //  Method:
  545. // IHXRenderer::OnPacket
  546. //  Purpose:
  547. // Called by client engine when a packet for this renderer is
  548. // due.
  549. // lTimeOffset is the amount of time that we lag behind the main player time line
  550. // so if the start time of the track is 10 seconds, lTimeOffset will be 10000 (msec)
  551. // (the first packet's time stamp will be 0 but the player will be at time=10sec)
  552. //
  553. STDMETHODIMP
  554. CAudioRenderer::OnPacket(IHXPacket* pPacket, LONG32 lTimeOffset)
  555. {
  556.     HX_RESULT     retVal = HXR_OK;
  557.     UINT16     uStreamForThisPacket = 0;
  558.     /* Ignore any pre-seek packets or NULL packets */
  559.     if (m_bInSeekMode || pPacket == NULL)
  560.     {
  561. return HXR_OK;
  562.     }
  563.     m_lTimeOffset = lTimeOffset;
  564.     m_bProcessingPacket = TRUE;
  565.     m_pMutex->Lock();
  566.     m_bFirstPacket = FALSE;
  567.     m_pAudioFormat->Enqueue(pPacket);
  568.     if (m_PlayState != playing)
  569.     {
  570. // Take this chance to write audio to audio services
  571. UINT32 ulAudioTime;
  572. DoAudio(ulAudioTime);
  573.     }
  574.     m_bProcessingPacket = FALSE;
  575.     m_pMutex->Unlock();
  576.     return retVal;
  577. }
  578. /////////////////////////////////////////////////////////////////////////
  579. //  Method:
  580. // IHXRenderer::OnTimeSync
  581. //  Purpose:
  582. // Called by client engine to inform the renderer of the current
  583. // time relative to the streams synchronized time-line. The
  584. // renderer should use this time value to update its display or
  585. // render it's stream data accordingly.
  586. //
  587. STDMETHODIMP CAudioRenderer::OnTimeSync(ULONG32 ulTime)
  588. {
  589.     MLOG_MISCEX(m_pErrorMessages, "OTS(%lu)n", ulTime);
  590.     // we never enter the play state on Mac so that we write audio
  591.     // in both packet and timesync
  592. #ifndef _MACINTOSH
  593.     // if we get a timesync we must be playing
  594.     m_PlayState = playing;
  595. #endif
  596.     m_pMutex->Lock();
  597. #ifdef _MACINTOSH
  598.     /* On Mac, since we do not have Mutex, we do not want to process
  599.      * data if we are within OnPacket call
  600.      */
  601.     if (m_bProcessingPacket)
  602.     {
  603. goto exit;
  604.     }
  605.     m_bProcessingPacket = TRUE;
  606. #endif /*_MACINTOSH*/
  607. #if !defined(HELIX_CONFIG_MIN_PCM_PUSHDOWN_BYTES)
  608.     // Write to AS
  609.     UINT32 ulAudioTime;
  610.     DoAudio(ulAudioTime);
  611. #endif
  612. #ifdef _MACINTOSH
  613.     m_bProcessingPacket = FALSE;
  614. exit:
  615. #endif /*_MACINTOSH*/
  616.     m_pMutex->Unlock();
  617.     return HXR_OK;
  618. }
  619. /////////////////////////////////////////////////////////////////////////
  620. //  Method:
  621. // IHXRenderer::OnPreSeek
  622. //  Purpose:
  623. // Called by client engine to inform the renderer that a seek is
  624. // about to occur. The render is informed the last time for the
  625. // stream's time line before the seek, as well as the first new
  626. // time for the stream's time line after the seek will be completed.
  627. //
  628. STDMETHODIMP CAudioRenderer::OnPreSeek(ULONG32 ulOldTime,
  629.        ULONG32 ulNewTime)
  630. {
  631.     m_pMutex->Lock();
  632.     m_PlayState = seeking;
  633.     m_bEndOfPackets = FALSE;
  634.     m_bDoneWritingPackets = FALSE;
  635.     m_bInSeekMode = TRUE;
  636.     m_bFirstPacket = TRUE;
  637.     m_ulLastWriteTime = NO_TIME_SET;
  638.     // get out of our buffering state if we are in one
  639.     if (IsRebuffering())
  640.     {
  641.         EndRebuffer();
  642.     }
  643.     m_pAudioFormat->SetStartTime(ulNewTime);
  644.     m_pAudioFormat->Reset();
  645.     m_pMutex->Unlock();
  646.     return HXR_OK;
  647. }
  648. /////////////////////////////////////////////////////////////////////////
  649. //  Method:
  650. // IHXRenderer::OnPostSeek
  651. //  Purpose:
  652. // Called by client engine to inform the renderer that a seek has
  653. // just occured. The render is informed the last time for the
  654. // stream's time line before the seek, as well as the first new
  655. // time for the stream's time line after the seek.
  656. //
  657. STDMETHODIMP CAudioRenderer::OnPostSeek(ULONG32 ulOldTime, ULONG32 ulNewTime)
  658. {
  659.     m_bInSeekMode   = FALSE;
  660.     return HXR_OK;
  661. }
  662. /////////////////////////////////////////////////////////////////////////
  663. //  Method:
  664. // IHXRenderer::OnPause
  665. //  Purpose:
  666. // Called by client engine to inform the renderer that a pause has
  667. // just occured. The render is informed the last time for the
  668. // stream's time line before the pause.
  669. //
  670. STDMETHODIMP CAudioRenderer::OnPause(ULONG32 ulTime)
  671. {
  672.     m_pMutex->Lock();
  673.     m_PlayState = paused;
  674.     m_pMutex->Unlock();
  675.     return HXR_OK;
  676. }
  677. /////////////////////////////////////////////////////////////////////////
  678. //  Method:
  679. // IHXRenderer::OnBegin
  680. //  Purpose:
  681. // Called by client engine to inform the renderer that a begin or
  682. // resume has just occured. The render is informed the first time
  683. // for the stream's time line after the resume.
  684. //
  685. STDMETHODIMP CAudioRenderer::OnBegin(ULONG32 ulTime)
  686. {
  687.     return HXR_OK;
  688. }
  689. /////////////////////////////////////////////////////////////////////////
  690. //  Method:
  691. // IHXRenderer::OnBuffering
  692. //  Purpose:
  693. // Called by client engine to inform the renderer that buffering
  694. // of data is occuring. The render is informed of the reason for
  695. // the buffering (start-up of stream, seek has occured, network
  696. // congestion, etc.), as well as percentage complete of the
  697. // buffering process.
  698. //
  699. STDMETHODIMP CAudioRenderer::OnBuffering(ULONG32 ulFlags, UINT16 unPercentComplete)
  700. {
  701.     m_PlayState = buffering;
  702.     return HXR_OK;
  703. }
  704. /////////////////////////////////////////////////////////////////////////
  705. //  Method:
  706. // IHXRenderer::GetDisplayType
  707. //  Purpose:
  708. // Called by client engine to ask the renderer for it's preferred
  709. // display type. When layout information is not present, the
  710. // renderer will be asked for it's prefered display type. Depending
  711. // on the display type a buffer of additional information may be
  712. // needed. This buffer could contain information about preferred
  713. // window size.
  714. //
  715. STDMETHODIMP CAudioRenderer::GetDisplayType(REF(HX_DISPLAY_TYPE) ulFlags,
  716.     REF(IHXBuffer*) pBuffer)
  717. {
  718.     ulFlags = HX_DISPLAY_NONE;
  719.     return HXR_OK;
  720. }
  721. /************************************************************************
  722.  * Method:
  723.  *     IHXRenderer::OnEndofPackets
  724.  * Purpose:
  725.  *     Called by client engine to inform the renderer that all the
  726.  *     packets have been delivered. However, if the user seeks before
  727.  *     EndStream() is called, renderer may start getting packets again
  728.  *     and the client engine will eventually call this function again.
  729.  */
  730. STDMETHODIMP CAudioRenderer::OnEndofPackets(void)
  731. {
  732.     HX_RESULT pnr = HXR_OK;
  733.     /* we should release any remaining sub-superblocks to audio services here*/
  734.     m_bEndOfPackets = TRUE;
  735.     if (IsRebuffering())
  736.     {
  737.         EndRebuffer();
  738.     }
  739.     m_pMutex->Lock();
  740. #ifdef _MACINTOSH
  741.     // since we don't get as many time sync calls on the mac
  742.     // and we want to make sure to write all of the packets
  743.     // to audio services, make sure we have 2 seconds of
  744.     // data buffered in audio services now.
  745.     AttemptToSatisfyDryRequest(m_ulLastWriteTime + 2000);
  746. #endif
  747.     m_pMutex->Unlock();
  748.     return HXR_OK;
  749. }
  750. /*
  751.  *  IHXDryNotification methods
  752.  */
  753. /************************************************************************
  754.  *  Method:
  755.  *      OnDryNotification
  756.  *  Purpose:
  757.  *     This function is called when it is time to write to audio device
  758.  *     and there is not enough data in the audio stream. The renderer can
  759.  *     then decide to add more data to the audio stream. This should be
  760.  *     done synchronously within the call to this function.
  761.  *     It is OK to not write any data. Silence will be played instead.
  762.  */
  763. STDMETHODIMP CAudioRenderer::OnDryNotification(UINT32 /*IN*/ ulCurrentStreamTime,
  764.    UINT32 /*IN*/ ulMinimumDurationRequired)
  765. {
  766.     MLOG_MISC(m_pErrorMessages, "ODN (%lu,%lu)n",
  767.               ulCurrentStreamTime, ulMinimumDurationRequired);
  768.     /* If the renderer is delayed, do not report rebuffer status until the
  769.      * packets are really due i.e. until Current time + Preroll is greater
  770.      * than the Delay time.
  771.      */
  772.     m_pMutex->Lock();
  773.     if (m_bDoneWritingPackets)
  774.     {
  775. goto exit;
  776.     }
  777.     if (NO_TIME_SET != m_ulLastWriteTime &&
  778. IsTimeGreater(ulCurrentStreamTime, m_ulLastWriteTime + TIME_FUDGE))
  779.     {
  780. // if the stream time reported by audio services is ahead of the
  781. // current writing time of the renderer, update the writing time
  782. // of the renderer so it catches up with the audio services stream
  783. m_ulLastWriteTime = ulCurrentStreamTime;
  784.     }
  785.     if (!m_bFirstPacket &&
  786. IsTimeGreater(ulCurrentStreamTime + m_ulPreroll, m_ulDelay) &&
  787. (NO_TIME_SET == m_ulLastWriteTime ||
  788. IsTimeGreater(ulCurrentStreamTime + TIME_FUDGE, m_ulLastWriteTime)))
  789.     {
  790. // Try to write some audio to satisfy the audio stream
  791. HX_RESULT pnr = HXR_OK;
  792. UINT32 ulAudioWantedTime =
  793.     (ulCurrentStreamTime + ulMinimumDurationRequired);
  794. pnr = AttemptToSatisfyDryRequest(ulAudioWantedTime);
  795. // if we couldn't satisfy the request and we have not
  796. // recieved all of our packets, and we have started playing,
  797. // tell the core to rebuffer
  798.         if ((FAILED(pnr) || HXR_NO_DATA == pnr) && !m_bEndOfPackets &&
  799.             IsTimeGreaterOrEqual(ulCurrentStreamTime, m_ulDelay) &&
  800.             IsTimeLess(m_ulLastWriteTime, ulAudioWantedTime))
  801.         {
  802.             StartRebuffer(ulAudioWantedTime);
  803.         }
  804.     }
  805. exit:
  806.     m_pMutex->Unlock();
  807.     return HXR_OK;
  808. }
  809. /************************************************************************
  810.  *  IHXStatistics Methods
  811.  */
  812. /************************************************************************
  813.  *  InitializeStatistics
  814.  */
  815. STDMETHODIMP CAudioRenderer::InitializeStatistics(UINT32 ulRegistryID)
  816. {
  817.     BOOL bCodecNameKnown = FALSE;
  818.     char* pValue = NULL;
  819.     HX_RESULT retVal = HXR_UNEXPECTED;
  820.     m_ulRegistryID = ulRegistryID;
  821. #if defined(HELIX_FEATURE_STATS)
  822.     if (m_pAudioStats)
  823.     {
  824. retVal = HXR_OK;
  825.     }
  826.     if (SUCCEEDED(retVal))
  827.     {
  828. pValue = (char*) GetCodecName();
  829. if (pValue != NULL)
  830. {
  831.     ReportStat(AS_CODEC_NAME, pValue);
  832.     bCodecNameKnown = TRUE;
  833. }
  834.     }
  835.     if (SUCCEEDED(retVal))
  836.     {
  837. pValue = (char*) GetRendererName();
  838. if (pValue != NULL)
  839. {
  840.     ReportStat(AS_REND_NAME, pValue);
  841.     // If Codec name is unknown, use a more generic renderer name
  842.     if (!bCodecNameKnown)
  843.     {
  844. ReportStat(AS_CODEC_NAME, pValue);
  845.     }
  846. }
  847.     }
  848.     if (SUCCEEDED(retVal))
  849.     {
  850. pValue = (char*) GetCodecFourCC();
  851. if (pValue != NULL)
  852. {
  853.     ReportStat(AS_CODEC_4CC, pValue);
  854. }
  855.     }
  856.     if (SUCCEEDED(retVal))
  857.     {
  858. HXAudioFormat audioFmt;
  859. audioFmt.uChannels = 0;
  860. audioFmt.ulSamplesPerSec = 0;
  861. audioFmt.uBitsPerSample = 0;
  862. if (m_pAudioFormat)
  863. {
  864.     m_pAudioFormat->GetAudioFormat(audioFmt);
  865. }
  866. ReportStat(AS_CHANNELS, (INT32) audioFmt.uChannels);
  867. ReportStat(AS_SAMPLING_RATE, (INT32) audioFmt.ulSamplesPerSec);
  868. ReportStat(AS_SAMPLE_SIZE, (INT32) audioFmt.uBitsPerSample);
  869.     }
  870.     if (SUCCEEDED(retVal))
  871.     {
  872. retVal = m_pAudioStats->DisplayStats(m_ulRegistryID);
  873.     }
  874.     return retVal;
  875. #else
  876.     return HXR_NOTIMPL;
  877. #endif /* HELIX_FEATURE_STATS */
  878. }
  879. /************************************************************************
  880.  *  UpdateStatistics
  881.  */
  882. STDMETHODIMP CAudioRenderer::UpdateStatistics()
  883. {
  884. #if defined(HELIX_FEATURE_STATS)
  885.     HX_RESULT retVal = HXR_UNEXPECTED;
  886.     if (m_pAudioStats)
  887.     {
  888. retVal = HXR_OK;
  889.     }
  890.     if (SUCCEEDED(retVal))
  891.     {
  892. retVal = m_pAudioStats->DisplayStats(m_ulRegistryID);
  893.     }
  894.     return retVal;
  895. #else
  896.     return HXR_NOTIMPL;
  897. #endif /* HELIX_FEATURE_STATS */
  898. }
  899. /****************************************************************************
  900.  *  Renderer's customizable fuctions - can be called any time
  901.  */
  902. /****************************************************************************
  903.  *  GetStreamVersion
  904.  */
  905. void CAudioRenderer::GetStreamVersion(ULONG32 &ulThisMajorVersion,
  906.       ULONG32 &ulThisMinorVersion)
  907. {
  908.     ulThisMajorVersion = STREAM_MAJOR_VERSION;
  909.     ulThisMinorVersion = STREAM_MINOR_VERSION;
  910. }
  911. /****************************************************************************
  912.  *  GetContentVersion
  913.  */
  914. void CAudioRenderer::GetContentVersion(ULONG32 &ulThisMajorVersion,
  915.        ULONG32 &ulThisMinorVersion)
  916. {
  917.     ulThisMajorVersion = CONTENT_MAJOR_VERSION;
  918.     ulThisMinorVersion = CONTENT_MINOR_VERSION;
  919. }
  920. /****************************************************************************
  921.  *  GetUpgradeMimeType
  922.  */
  923. const char* CAudioRenderer::GetUpgradeMimeType(void)
  924. {
  925.     const char** pStreamMimeTypes = NULL;
  926.     UINT32 ulInitialGranularity;
  927.     GetRendererInfo(pStreamMimeTypes, ulInitialGranularity);
  928.     if (pStreamMimeTypes)
  929.     {
  930. return pStreamMimeTypes[0];
  931.     }
  932.     return NULL;
  933. }
  934. /****************************************************************************
  935.  *  GetRendererName
  936.  */
  937. const char* CAudioRenderer::GetRendererName(void)
  938. {
  939.     return BASE_AUDIO_RENDERER_NAME;
  940. }
  941. /****************************************************************************
  942.  *  GetCodecName
  943.  */
  944. const char* CAudioRenderer::GetCodecName(void)
  945. {
  946.     return NULL;
  947. }
  948. /****************************************************************************
  949.  *  GetCoGetCodecFourCCdec4CC
  950.  */
  951. const char* CAudioRenderer::GetCodecFourCC(void)
  952. {
  953.     return NULL;
  954. }
  955. /****************************************************************************
  956.  *  CreateFormatObject
  957.  */
  958. CAudioFormat* CAudioRenderer::CreateFormatObject(IHXValues* pHeader)
  959. {
  960.     return new CAudioFormat(m_pCommonClassFactory,
  961.     this);
  962. }
  963. /////////////////////////////////////////////////////////////////////////////
  964. //  Method:
  965. // CAudioRenderer::InitAudioStream
  966. HX_RESULT CAudioRenderer::InitAudioStream(IHXValues* pHeader,
  967.   IHXAudioStream** ppAudioStream)
  968. {
  969.     HX_RESULT retVal = HXR_OK;
  970.     // init so we can HX_RELEASE on error.
  971.     *ppAudioStream = NULL;
  972.     retVal = m_pAudioPlayer->CreateAudioStream(ppAudioStream);
  973.     if (SUCCEEDED(retVal))
  974.     {
  975. IHXCommonClassFactory* pCommonClassFactory;
  976. if (HXR_OK == (*ppAudioStream)->QueryInterface(IID_IHXCommonClassFactory,
  977.     (void**)&pCommonClassFactory))
  978. {
  979.     m_pAudioFormat->OverrideFactory(pCommonClassFactory);
  980.     pCommonClassFactory->Release();
  981. }
  982. HXAudioFormat audioFmt;
  983. m_pAudioFormat->GetAudioFormat(audioFmt);
  984. #if defined(HELIX_FEATURE_STATS)
  985. ReportStat(AS_CHANNELS, (INT32) audioFmt.uChannels);
  986. ReportStat(AS_SAMPLING_RATE, (INT32) audioFmt.ulSamplesPerSec);
  987. ReportStat(AS_SAMPLE_SIZE, (INT32) audioFmt.uBitsPerSample);
  988. #endif /* #if defined(HELIX_FEATURE_STATS) */
  989. /* Add default dry notification BEFORE initializing the audio
  990.  * stream. This is so that if we are started mid presentation
  991.  * and there was no audio present earlier, the timeline will
  992.  * change from being a fake timeline to audio timeline and
  993.  * the audio services will write audio for initial pushdown
  994.  * time. We need to get dry notifications so that we can halt
  995.  * the timeline, if the renderer does not have enough data.
  996.  */
  997. IHXDryNotification* pDryNot = NULL;
  998. // Get my own DryNotification interface with an add
  999. QueryInterface(IID_IHXDryNotification, (void**)&pDryNot);
  1000. retVal = (*ppAudioStream)->AddDryNotification(pDryNot);
  1001. HX_ASSERT(SUCCEEDED(retVal));
  1002.         MLOG_MISC(m_pErrorMessages, "AS Init (%u,%u,%lu,%u)n",
  1003.                   audioFmt.uChannels, audioFmt.uBitsPerSample,
  1004.                   audioFmt.ulSamplesPerSec, audioFmt.uMaxBlockSize);
  1005. retVal = (*ppAudioStream)->Init(&audioFmt, pHeader);
  1006. HX_RELEASE(pDryNot);
  1007.     }
  1008.     if (HXR_OK != retVal)
  1009.     {
  1010. HX_RELEASE((*ppAudioStream));
  1011.     }
  1012.     return retVal;
  1013. }
  1014. /////////////////////////////////////////////////////////////////////////////
  1015. //  Method:
  1016. // CAudioRenderer::WriteToAudioServices
  1017. HX_RESULT CAudioRenderer::WriteToAudioServices(HXAudioData* pAudioData)
  1018. {
  1019.     HX_RESULT pnr = HXR_OK;
  1020.     BOOL bTryWrite = TRUE;
  1021.     // Can the audio stream change on the fly?
  1022.     // If so, then check for any change. If not,
  1023.     // then skip the check.
  1024.     if (m_bCanChangeAudioStream)
  1025.     {
  1026.         BOOL bAudioStreamChanged = FALSE;
  1027.         pnr = CheckForAudioStreamChange(bAudioStreamChanged);
  1028.         if (FAILED(pnr))
  1029.         {
  1030.             return pnr;
  1031.         }
  1032.         if (bAudioStreamChanged)
  1033.         {
  1034.             pAudioData->uAudioStreamType = TIMED_AUDIO;
  1035.         }
  1036.     }
  1037.     while (bTryWrite)
  1038.     {
  1039. pnr = CheckAudioServices();
  1040.         if (FAILED(pnr))
  1041.         {
  1042.             return pnr;
  1043.         }
  1044.         MLOG_MISC(m_pErrorMessages, "AS Write (%lu,%lu,%lu) ms=%lu tick=%lun",
  1045.                   (pAudioData->pData ? pAudioData->pData->GetSize() : 0),
  1046.                   pAudioData->ulAudioTime,
  1047.                   pAudioData->uAudioStreamType,
  1048.                   m_pAudioFormat->ConvertBytesToMs((pAudioData->pData ? pAudioData->pData->GetSize() : 0)),
  1049.                   HX_GET_BETTERTICKCOUNT());
  1050. DEBUG_OUTF_IDX(m_ulCurAudioStream, AUDREND_FLOW_FILE, 
  1051.        (s, "Audio Write: Time=%u, Bytes=%u, Duration=%u, %sn",
  1052.     pAudioData->ulAudioTime,
  1053.     (pAudioData->pData ? pAudioData->pData->GetSize() : 0),
  1054.     m_pAudioFormat->ConvertBytesToMs((pAudioData->pData ? pAudioData->pData->GetSize() : 0)),
  1055.     ((pAudioData->uAudioStreamType == STREAMING_AUDIO) ? "STREAMING" : "TIMED")
  1056.     ));
  1057.         // Write to AS
  1058.         if (m_ppAudioStream[m_ulCurAudioStream])
  1059.             pnr = m_ppAudioStream[m_ulCurAudioStream]->Write( pAudioData );
  1060. if (SUCCEEDED(pnr))
  1061. {
  1062.     CalculateMaxTimeStamp(pAudioData);
  1063.     bTryWrite = FALSE;
  1064. }
  1065. else
  1066. {
  1067.     // we got an error on write, check what time the audio stream
  1068.     // expects data for
  1069.     HXAudioData audioData;
  1070.     audioData.pData = NULL;
  1071.             if (m_ppAudioStream[m_ulCurAudioStream])
  1072.                 m_ppAudioStream[m_ulCurAudioStream]->Write( &audioData );
  1073.     if (IsTimeLess(audioData.ulAudioTime, pAudioData->ulAudioTime))
  1074.     {
  1075. // we are skipping ahead and should just mark this packet
  1076. // as timed and write it again
  1077. pAudioData->uAudioStreamType = TIMED_AUDIO;
  1078.     }
  1079.     else if (IsTimeGreater(audioData.ulAudioTime, pAudioData->ulAudioTime) &&
  1080. IsTimeLessOrEqual(audioData.ulAudioTime, pAudioData->ulAudioTime +
  1081. m_pAudioFormat->ConvertBytesToMs(pAudioData->pData->GetSize())))
  1082.     {
  1083. // we are a little behind but at least part of this stream
  1084. // is on time, we should clip off this buffer to the time
  1085. // the audio stream wants and try again.
  1086. bTryWrite = m_pAudioFormat->ClipAudioBuffer(pAudioData,
  1087.     audioData.ulAudioTime, TRUE);
  1088.     }
  1089.     else
  1090.     {
  1091. // we are a lot behind and should tell this format to discard
  1092. // data until the audio stream time.
  1093. m_pAudioFormat->
  1094.     DiscardAudioUntil(audioData.ulAudioTime);
  1095. // we don't want to try again with this data
  1096. bTryWrite = FALSE;
  1097.     }
  1098. }
  1099.     }
  1100.     // Handle exiting rebuffer started by OnDryNotification from
  1101.     // Audio Services
  1102.     // if we just wrote audio to audio services that is greater than
  1103.     // or equal to the audio wanted time from the dry notification
  1104.     // call then we can leave buffering
  1105.     
  1106.     if (IsRebuffering() &&
  1107.         IsTimeGreaterOrEqual(m_ulLastWriteTime, m_ulAudioWantedTime))
  1108.     {
  1109.         EndRebuffer();
  1110.     }
  1111.     return pnr;
  1112. }
  1113. /////////////////////////////////////////////////////////////////////////////
  1114. //  Method:
  1115. // CAudioRenderer::DoAudio
  1116. //
  1117. //  Note:  See Switchsod.txt for how this is supposed to work, please keep
  1118. // the sod up to date with changes here too.
  1119. //
  1120. HX_RESULT CAudioRenderer::DoAudio(UINT32& ulAudioTime,
  1121.   AUDIO_STATE audioState)
  1122. {
  1123.     HX_RESULT retVal;
  1124.     HXAudioData audioData;
  1125.     ULONG32 ulPreviousLastWriteTime;
  1126.     LONG32 lTimeDelta;
  1127.     audioData.pData = NULL;
  1128.     audioData.ulAudioTime = ulAudioTime = 0;
  1129.     // write the lowest stream to audio services
  1130.     ulPreviousLastWriteTime = m_ulLastWriteTime;
  1131.     do
  1132.     {
  1133. retVal = m_pAudioFormat->CreateAudioFrame(
  1134.     audioData,
  1135.     (m_bEndOfPackets) ? AUDIO_END_OF_PACKETS : audioState);
  1136. if (retVal == HXR_OK)
  1137. {
  1138.     audioData.uAudioStreamType = TIMED_AUDIO;
  1139.         // Update the timestamp of the audio services write
  1140.         audioData.ulAudioTime = AdjustTimestamp(audioData.ulAudioTime, m_lTimeOffset);
  1141.     if (m_ulLastWriteTime != NO_TIME_SET)
  1142.     {
  1143. lTimeDelta = audioData.ulAudioTime -
  1144.      m_ulLastWriteTime;
  1145. HX_ASSERT(lTimeDelta >= (-TIME_FUDGE));
  1146. if (lTimeDelta <= TIME_FUDGE)
  1147. {
  1148.     audioData.uAudioStreamType = STREAMING_AUDIO;
  1149. }
  1150. #ifdef _AUDREND_FLOW_LOG
  1151. else if (lTimeDelta < (-TIME_FUDGE))
  1152. {
  1153.     DEBUG_OUTF_IDX(m_ulCurAudioStream, AUDREND_FLOW_FILE, 
  1154.        (s, "Overlapping Audio: Time=%u, LastWriteTime=%u, Overlap=%dn",
  1155.     audioData.ulAudioTime,
  1156.     m_ulLastWriteTime,
  1157.     -lTimeDelta
  1158.     ));
  1159. }
  1160. #endif // _AUDREND_FLOW_LOG
  1161.     }
  1162.     retVal = WriteToAudioServices(&audioData);
  1163. }
  1164. else
  1165. {
  1166.     break;
  1167. }
  1168.                                // do not loop here if writing to
  1169.                                // satisfy dry notification
  1170.      } while (audioState != AUDIO_DRYNOTIFICATION &&
  1171.             ((m_ulLastWriteTime - ulPreviousLastWriteTime) <
  1172.      MAX_AUDIO_WRITE_TIME));
  1173.     // release the data buffer if we got one
  1174.     HX_RELEASE(audioData.pData);
  1175.     // update the out param
  1176.     ulAudioTime = audioData.ulAudioTime;
  1177.     return retVal;
  1178. }
  1179. HX_RESULT CAudioRenderer::AttemptToSatisfyDryRequest(UINT32 ulAudioWantedTime)
  1180. {
  1181.     HX_RESULT pnr = HXR_OK;
  1182.     UINT32 ulAudioTime = 0;
  1183.     while (HXR_OK == pnr &&
  1184. IsTimeGreaterOrEqual(ulAudioWantedTime, m_ulLastWriteTime))
  1185.     {
  1186. pnr = DoAudio(ulAudioTime, AUDIO_DRYNOTIFICATION);
  1187.     }
  1188.     return pnr;
  1189. }
  1190. void
  1191. CAudioRenderer::CalculateMaxTimeStamp(HXAudioData* pAudioData)
  1192. {
  1193.     UINT32 ulTimestamp = pAudioData->ulAudioTime +
  1194. m_pAudioFormat->ConvertBytesToMs(pAudioData->pData->GetSize());
  1195.     if (m_ulLastWriteTime == NO_TIME_SET ||
  1196. IsTimeLess(m_ulLastWriteTime, ulTimestamp))
  1197.     {
  1198. m_ulLastWriteTime = ulTimestamp;
  1199.     }
  1200. }
  1201. HX_RESULT CAudioRenderer::CheckForAudioStreamChange(REF(BOOL) rbAudioStreamChanged)
  1202. {
  1203.     HX_RESULT retVal = HXR_FAIL;
  1204.     if (m_pAudioFormat)
  1205.     {
  1206. retVal = HXR_OK;
  1207. // Check to see if the audio format has changed
  1208. if (HasAudioFormatChanged())
  1209. {
  1210.     // Transfer the current audio stream to
  1211.     // a newly created audio stream
  1212.     retVal = IncrementAudioStream();
  1213.     rbAudioStreamChanged = SUCCEEDED(retVal);
  1214. }
  1215.     }
  1216.     return retVal;
  1217. }
  1218. BOOL CAudioRenderer::HasAudioFormatChanged()
  1219. {
  1220.     BOOL bRet = FALSE;
  1221.     if (m_pAudioFormat)
  1222.     {
  1223.         // Get the audio format from the CAudioFormat object
  1224.         HXAudioFormat cAudioFormat1;
  1225.         HX_RESULT retVal = m_pAudioFormat->GetAudioFormat(cAudioFormat1);
  1226.         if (SUCCEEDED(retVal))
  1227.         {
  1228.             // Get the audio format from the current IHXAudioStream object
  1229.             if (m_ppAudioStream &&
  1230.                 m_ulCurAudioStream < m_ulNumAudioStreams &&
  1231.                 m_ppAudioStream[m_ulCurAudioStream])
  1232.             {
  1233.                 IHXAudioStream2* pStream2 = NULL;
  1234.                 retVal = m_ppAudioStream[m_ulCurAudioStream]->QueryInterface(IID_IHXAudioStream2,
  1235.                                                                              (void**) &pStream2);
  1236.                 if (SUCCEEDED(retVal))
  1237.                 {
  1238.                     HXAudioFormat cAudioFormat2;
  1239.                     retVal = pStream2->GetAudioFormat(&cAudioFormat2);
  1240.                     if (SUCCEEDED(retVal))
  1241.                     {
  1242.                         // Check if the formats are different
  1243.                         if (cAudioFormat1.uChannels       != cAudioFormat2.uChannels       ||
  1244.                             cAudioFormat1.uBitsPerSample  != cAudioFormat2.uBitsPerSample  ||
  1245.                             cAudioFormat1.ulSamplesPerSec != cAudioFormat2.ulSamplesPerSec ||
  1246.                             cAudioFormat1.uMaxBlockSize    > cAudioFormat2.uMaxBlockSize)
  1247.                         {
  1248.                             bRet = TRUE;
  1249.                         }
  1250.                     }
  1251.                 }
  1252.                 HX_RELEASE(pStream2);
  1253.             }
  1254.         }
  1255.     }
  1256.     return bRet;
  1257. }
  1258. HX_RESULT CAudioRenderer::IncrementAudioStream()
  1259. {
  1260.     HX_RESULT retVal = HXR_FAIL;
  1261.     if (m_ulCurAudioStream + 1 >= m_ulNumAudioStreams)
  1262.     {
  1263.         // We need to create a larger buffer to hold the
  1264.         // audio stream pointers
  1265.         UINT32 ulNewSize = m_ulNumAudioStreams * 2;
  1266.         IHXAudioStream** ppAudioStream = new IHXAudioStream* [ulNewSize];
  1267.         if (ppAudioStream)
  1268.         {
  1269.             // NULL out the buffer
  1270.             memset((void*) ppAudioStream, 0, ulNewSize * sizeof(IHXAudioStream*));
  1271.             // Copy the current pointers
  1272.             memcpy((void*) ppAudioStream, /* Flawfinder: ignore */
  1273.                    (const void*) m_ppAudioStream,
  1274.                    m_ulNumAudioStreams * sizeof(IHXAudioStream*));
  1275.             // Delete the old array
  1276.             HX_VECTOR_DELETE(m_ppAudioStream);
  1277.             // Assign the new one
  1278.             m_ppAudioStream = ppAudioStream;
  1279.             // Assign the new size
  1280.             m_ulNumAudioStreams = ulNewSize;
  1281.         }
  1282.     }
  1283.     if (m_ulCurAudioStream + 1 < m_ulNumAudioStreams)
  1284.     {
  1285.         // Remove the dry notification from the old stream
  1286.         if (m_ppAudioStream[m_ulCurAudioStream])
  1287.         {
  1288.             IHXAudioStream2* pStream2 = NULL;
  1289.             m_ppAudioStream[m_ulCurAudioStream]->QueryInterface(IID_IHXAudioStream2,
  1290.                                                                 (void**) &pStream2);
  1291.             if (pStream2)
  1292.             {
  1293.                 // Get our own IHXDryNotification interface
  1294.                 IHXDryNotification* pDryNot = NULL;
  1295.                 QueryInterface(IID_IHXDryNotification, (void**) &pDryNot);
  1296.                 if (pDryNot)
  1297.                 {
  1298.                     pStream2->RemoveDryNotification(pDryNot);
  1299.                 }
  1300.                 HX_RELEASE(pDryNot);
  1301.             }
  1302.             HX_RELEASE(pStream2);
  1303.         }
  1304.         // Init the new stream
  1305.         retVal = InitAudioStream(m_pHeader, &m_ppAudioStream[m_ulCurAudioStream + 1]);
  1306.         if (SUCCEEDED(retVal))
  1307.         {
  1308.             // Increment the current audio stream index
  1309.             m_ulCurAudioStream += 1;
  1310.         }
  1311.     }
  1312.     return retVal;
  1313. }
  1314. BOOL CAudioRenderer::IsRebuffering() const
  1315. {
  1316.     return (NO_TIME_SET != m_ulAudioWantedTime) ? TRUE : FALSE;
  1317. }
  1318. void CAudioRenderer::StartRebuffer(UINT32 ulAudioWantedTime)
  1319. {
  1320.     if (m_pStream)
  1321.     {
  1322.         m_ulAudioWantedTime = ulAudioWantedTime;
  1323.         m_pStream->ReportRebufferStatus(1,0);
  1324.     }
  1325. }
  1326. void CAudioRenderer::EndRebuffer()
  1327. {
  1328.     m_ulAudioWantedTime = NO_TIME_SET;
  1329.     if (m_pStream)
  1330.     {
  1331.         m_pStream->ReportRebufferStatus(1,1);
  1332.     }
  1333. }