rarender.cpp
Upload User: dangjiwu
Upload Date: 2013-07-19
Package Size: 42019k
Code Size: 106k
Category:

Symbian

Development Platform:

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. /****************************************************************************
  36.  *  Includes
  37.  */
  38. #include "hlxclib/stdio.h"
  39. #include "hlxclib/string.h" // needed for memcpy, needed by hxmarsh.h
  40. #include "rarender.ver"
  41. #include "rarender.h"
  42. #if defined(HELIX_FEATURE_PREFERENCES)
  43. #include "hxprefs.h"
  44. #include "hxprefutil.h"
  45. #endif /* HELIX_FEATURE_PREFERENCES */
  46. #ifdef _WINCE
  47. #include <winbase.h>
  48. #endif
  49. #include "hxtypes.h"
  50. #include "hxver.h"
  51. /****************************************************************************
  52.  *  Defines
  53.  */
  54. #ifdef _DEBUG
  55. #undef HX_THIS_FILE
  56. static const char HX_THIS_FILE[] = __FILE__;
  57. #endif
  58. #define MAXIMUM_GRANULARITY 100
  59. #define MINIMUM_GRANULARITY 20
  60. #define DEFAULT_DRY_NOTIFICATION    0
  61. #define MAX_TRANSPORT_BUFFER_DURATION 20000
  62. //#define RA_TEST_LOSS
  63. #if !defined(HELIX_FEATURE_DLLACCESS_CLIENT)
  64. ENABLE_DLLACCESS_PATHS(RACodec);
  65. #endif // HELIX_FEATURE_DLLACCESS_CLIENT
  66. //#define RARENDER_LOGING_ON
  67. #ifdef RARENDER_LOGING_ON
  68. #define LOG_PATH     "C:\Log\rarender\"
  69. #define RASYNC_FILE     LOG_PATH##"sync.txt"
  70. #define ONPACKET_FILE     LOG_PATH##"packet.txt"
  71. #define AUDIOSERVICES_FILE  LOG_PATH##"write.txt"
  72. #define SWITCH_FILE     LOG_PATH##"switch.txt"
  73. #define DOAUDIO_FILE     LOG_PATH##"doaudio.txt"
  74. #define PREREDSTONE_FILE    LOG_PATH##"hack.txt"
  75. #define LATESTPACKET_FILE   LOG_PATH##"latest.txt"
  76. #define LOSS_FILE     LOG_PATH##"loss.txt"
  77. #else
  78. #define RASYNC_FILE     0
  79. #define ONPACKET_FILE     0
  80. #define AUDIOSERVICES_FILE  0
  81. #define SWITCH_FILE     0
  82. #define DOAUDIO_FILE     0
  83. #define PREREDSTONE_FILE    0
  84. #define LATESTPACKET_FILE   0
  85. #define LOSS_FILE     0
  86. #endif
  87. #ifdef LOG_BUFFERING_ENABLED
  88. #define BUF_LOG_FILE "C:\buffer.txt"
  89. #define LOG_BUFFERING(x, y) {
  90.     char* s = NULL;
  91.     FILE* f1;
  92.     s = new char[2048];
  93.                             if(s){                                      
  94.     sprintf y; /* Flawfinder: ignore */
  95.     f1 = (x)?(::fopen(x, "a+")):(NULL);
  96.     (f1)?(::fprintf(f1, s), ::fclose(f1)):(0);
  97.     delete [] s;
  98.             }                                           
  99.        }
  100. #else // LOG_BUFFERING_ENABLED
  101. #define LOG_BUFFERING(x, y)
  102. #endif // LOG_BUFFERING_ENABLED
  103. // The value of 120 for audio pushdown presumes an AUDIO_GRANULARITY of 40:
  104. // 120 = 3 blocks. Note that this value is too small for general use and
  105. // may need to be tweaked depending on the cpu and hardware being used. A
  106. // slower system than the one tested on may not be able to keep pnaudio from
  107. // starving with buffers this small.
  108. #define OPTIMAL_HEAP_MIN_AUDIO_PUSHDOWN 480 // ms
  109. const char* const CRealAudioRenderer::zm_pName    = "RealAudio";
  110. const char* const CRealAudioRenderer::zm_pDescription    = "RealNetworks RealAudio Renderer Plugin";
  111. const char* const CRealAudioRenderer::zm_pCopyright      = "(c) 1995-2002 RealNetworks, Inc. All rights reserved.rnrn"
  112.     "RealNetworks RealAudio 8 Audio Codec:rn"
  113.     "Copyright (c) 1995-2002 RealNetworks, Inc. All rights reserved.rnrn"
  114.     "ATRAC3rn"
  115.     "Copyright (c) 2000 Sony Corporation. All rights reserved.rnrn"
  116.     "aacPlusrn" 
  117.     "aacPlus developed by Coding Technologies. All rights reserved.rnrn"
  118.     "DolbyNet(tm) audio system manufactured under license from Dolby Laboratories Licensing Corporation.rn"
  119.     "Copyright (c) 1996-1997, Dolby Laboratories Licensing Corporation. All rights reserved.rnrn"
  120.     "ACELP(r) is either registered trademark or trademark of VoiceAge Corporation in the United States and/or other countries and used under license from VoiceAge Corporationrn"
  121.     "The ACELP(r).net codec in this product is used under license from VoiceAge Corporationrn"
  122.     "Copyright (c) 1998,1999, 2000 VoiceAge Corporation.  All rights reserved.rn";
  123. const char* const CRealAudioRenderer::zm_pMoreInfoURL    = HXVER_MOREINFO;
  124. const char* const CRealAudioRenderer::zm_pStreamMimeTypes[] =
  125. {REALAUDIO_MIME_TYPE, REALAUDIO_MULTIRATE_MIME_TYPE, REALAUDIO_MULTIRATE_LIVE_MIME_TYPE, NULL};
  126. const char* const CRealAudioRenderer::zm_pAdditionalAutoUpgradeInfo[] =
  127. {"", "#unk_c"};
  128. /// These two constants are consistent with those defined in 
  129. /// HXWatermarkBufferControl
  130. #define REBUFFERING_SKIP
  131. #define MAX_TRANSPORT_BUFFER_DURATION 20000
  132. #define MAX_TRASPORT_BUFFER_BYTES 3000000
  133. /************************************************************************
  134.  *  Method:
  135.  *    IHXPlugin::InitPlugin
  136.  *  Purpose:
  137.  *    Initializes the plugin for use. This interface must always be
  138.  *    called before any other method is called. This is primarily needed
  139.  *    so that the plugin can have access to the context for creation of
  140.  *    IHXBuffers and IMalloc.
  141.  */
  142. STDMETHODIMP CRealAudioRenderer::InitPlugin(IUnknown* /*IN*/ pContext)
  143. {
  144.     m_pContext = pContext;
  145.     m_pContext->AddRef();
  146.     if (HXR_OK != m_pContext->QueryInterface(IID_IHXCommonClassFactory, (void **)&m_pCommonClassFactory))
  147.     {
  148. return HXR_FAILED;
  149.     }
  150. #if defined(HELIX_FEATURE_STATS)
  151.     m_pContext->QueryInterface(IID_IHXRegistry, (void**)&m_pRegistry);
  152. #endif // HELIX_FEATURE_STATS
  153.     return HXR_OK;
  154. }
  155. /************************************************************************
  156.  *  Method:
  157.  *    IHXPlugin::GetPluginInfo
  158.  *  Purpose:
  159.  *    Returns the basic information about this plugin. Including:
  160.  *
  161.  *    bLoadMultiple whether or not this plugin DLL can be loaded
  162.  * multiple times. All File Formats must set
  163.  * this value to TRUE.
  164.  *    pDescription which is used in about UIs (can be NULL)
  165.  *    pCopyright which is used in about UIs (can be NULL)
  166.  *    pMoreInfoURL which is used in about UIs (can be NULL)
  167.  */
  168. STDMETHODIMP CRealAudioRenderer::GetPluginInfo
  169. (
  170.     REF(BOOL)        /*OUT*/ bLoadMultiple,
  171.     REF(const char*) /*OUT*/ pDescription,
  172.     REF(const char*) /*OUT*/ pCopyright,
  173.     REF(const char*) /*OUT*/ pMoreInfoURL,
  174.     REF(ULONG32)     /*OUT*/ ulVersionNumber
  175. )
  176. {
  177.     bLoadMultiple = TRUE;   // Must be true for file formats.
  178.     pDescription    = zm_pDescription;
  179.     pCopyright     = zm_pCopyright;
  180.     pMoreInfoURL    = zm_pMoreInfoURL;
  181.     ulVersionNumber = TARVER_ULONG32_VERSION;
  182.     return HXR_OK;
  183. }
  184. /************************************************************************
  185.  *  Method:
  186.  *    IHXPlugin::GetRendererInfo
  187.  *  Purpose:
  188.  *    If this object is a file format object this method returns
  189.  *    information vital to the instantiation of file format plugins.
  190.  *    If this object is not a file format object, it should return
  191.  *    HXR_UNEXPECTED.
  192.  */
  193. STDMETHODIMP CRealAudioRenderer::GetRendererInfo
  194. (
  195.     REF(const char**) /*OUT*/ pStreamMimeTypes,
  196.     REF(UINT32)      /*OUT*/ unInitialGranularity
  197. )
  198. {
  199.     pStreamMimeTypes = (const char**)zm_pStreamMimeTypes;
  200.     unInitialGranularity = m_ulCurrentGranularity; // OnTimeSync() every 100ms
  201.     return HXR_OK;
  202. }
  203. // *** IUnknown methods ***
  204. /////////////////////////////////////////////////////////////////////////
  205. //  Method:
  206. // IUnknown::QueryInterface
  207. //  Purpose:
  208. // Implement this to export the interfaces supported by your
  209. // object.
  210. //
  211. STDMETHODIMP CRealAudioRenderer::QueryInterface(REFIID riid, void** ppvObj)
  212. {
  213.     QInterfaceList qiList[] =
  214.     {
  215. { GET_IIDHANDLE(IID_IUnknown),            (IUnknown*) (IHXPlugin*) this},
  216. { GET_IIDHANDLE(IID_IHXPlugin),           (IHXPlugin*) this},
  217. { GET_IIDHANDLE(IID_IHXRenderer),         (IHXRenderer*) this},
  218. { GET_IIDHANDLE(IID_IHXInterruptSafe),    (IHXInterruptSafe*) this},
  219. { GET_IIDHANDLE(IID_IHXASMStreamSink),    (IHXASMStreamSink*) this},
  220. { GET_IIDHANDLE(IID_IHXDryNotification),  (IHXDryNotification*) this},
  221. #if defined(HELIX_FEATURE_RAREND_BANDWIDTH_LISTER)
  222. { GET_IIDHANDLE(IID_IHXBandwidthLister),  (IHXBandwidthLister*) this},
  223. #endif // HELIX_FEATURE_RAREND_BANDWIDTH_LISTER
  224. #if defined(HELIX_FEATURE_STATS)
  225. { GET_IIDHANDLE(IID_IHXStatistics),       (IHXStatistics*) this},
  226. #endif // HELIX_FEATURE_STATS
  227. #if defined(HELIX_FEATURE_SETSRCPROPS)
  228. { GET_IIDHANDLE(IID_IHXValues),           (IHXValues*) this},
  229. #endif /* #if defined(HELIX_FEATURE_SETSRCPROPS) */
  230. { GET_IIDHANDLE(IID_IHXUpdateProperties), (IHXUpdateProperties*) this}
  231.     };
  232.     return QIFind(qiList, QILISTSIZE(qiList), riid, ppvObj);
  233. }
  234. /////////////////////////////////////////////////////////////////////////
  235. //  Method:
  236. // IUnknown::AddRef
  237. //  Purpose:
  238. // Everyone usually implements this the same... feel free to use
  239. // this implementation.
  240. //
  241. STDMETHODIMP_(ULONG32) CRealAudioRenderer::AddRef()
  242. {
  243.     return _AddRef();
  244. }
  245. /////////////////////////////////////////////////////////////////////////
  246. //  Method:
  247. // IUnknown::Release
  248. //  Purpose:
  249. // Everyone usually implements this the same... feel free to use
  250. // this implementation.
  251. //
  252. STDMETHODIMP_(ULONG32) CRealAudioRenderer::Release()
  253. {
  254.     return _Release();
  255. }
  256. CRealAudioRenderer::CRealAudioRenderer()
  257. : m_lRefCount(0)
  258. , m_pContext(NULL)
  259. , m_pStream(NULL)
  260. , m_pBufferingStats(NULL)
  261. , m_ulPreroll(0)
  262. , m_bReportOKStatus(FALSE)
  263. , m_ulCurrentTimelineTime(0)
  264. , m_pAudioPlayer(NULL)
  265. , m_pAudioPushdown2(NULL)
  266. , m_pCommonClassFactory(NULL)
  267. , m_ulRegistryID(0)
  268. , m_pRegistry(NULL)
  269. , m_ulSmartStreamRegID(0)
  270. , m_ulNameRegID(0)
  271. , m_ulCodecRegID(0)
  272. , m_ulRateRegID(0)
  273. , m_ulChannelsRegID(0)
  274. , m_ulSurroundRegID(0)
  275. , m_bEndOfPackets(FALSE)
  276. , m_bDoneWritingPackets(FALSE)
  277. , m_bInSeekMode(FALSE)
  278. , m_ulCurrentGranularity(MAXIMUM_GRANULARITY)
  279. , m_bStreamSwitchable(FALSE)
  280. , m_uNumOfSubStreams(0)
  281. , m_uNumOfRules(0)
  282. , m_ulDuration(0)
  283. , m_bFirstPacket(TRUE)
  284. , m_bDelayOffsetSet(FALSE)
  285. , m_bAllStreamsToBeUnregistered(FALSE)
  286. , m_ulLatestStreamTime(NO_TIME_SET)
  287. , m_fLatestStreamTime(0.0)
  288. , m_ulLatestActualTime(NO_TIME_SET)
  289. , m_ulDelay(0)
  290. , m_lTimeLineOffset(0)
  291. , m_usCurrentDryNotificationStream(NO_STREAM_SET)
  292. , m_usPreviousDryNotificationStream(NO_STREAM_SET)
  293. , m_usThisSourceStream(NO_STREAM_SET)
  294. , m_pErrorMessages(0)
  295.         , m_pRuleToFlagMap(NULL)
  296. , m_pMutex(NULL)
  297. #ifdef _MACINTOSH
  298. , m_bProcessingPacket(FALSE)
  299. , m_pDryCallback(NULL)
  300. #endif
  301. , m_pRuleMap(NULL)
  302. , m_pRaFormats(NULL)
  303. , m_pAudioStreams(NULL)
  304. , m_PlayState(stopped)
  305. , m_bPreRedstonePlayer(TRUE)
  306. , m_uSyncUnregisterStream(NO_STREAM_SET)
  307. , m_ulSyncUnregisterTime(NO_TIME_SET)
  308. , m_pASMStream(NULL)
  309.         , m_pValues(NULL)
  310.         , m_ulSrcPropertySubStream(NO_STREAM_SET)
  311.         , m_ppVBRDepack(NULL)
  312. {
  313. }
  314. CRealAudioRenderer::~CRealAudioRenderer()
  315. {
  316.     EndStream();
  317.     HX_DELETE(m_pMutex);
  318. }
  319. // *** IHXRenderer methods ***
  320. /////////////////////////////////////////////////////////////////////////
  321. //  Method:
  322. // IHXRenderer::StartStream
  323. //  Purpose:
  324. // Called by client engine to inform the renderer of the stream it
  325. // will be rendering. The stream interface can provide access to
  326. // its source or player. This method also provides access to the
  327. // primary client controller interface.
  328. //
  329. STDMETHODIMP
  330. CRealAudioRenderer::StartStream
  331. (
  332.     IHXStream*     pStream,
  333.     IHXPlayer*     pPlayer
  334. )
  335. {
  336.     HX_RESULT hr = HXR_OK;
  337.     // Save for later use!
  338.     m_pStream  = pStream;
  339.     if (m_pStream)
  340.     {
  341. m_pStream->AddRef();
  342.     }
  343.     // get interface to report errors
  344.     if (HXR_OK != pPlayer->QueryInterface(IID_IHXErrorMessages, (void **)&m_pErrorMessages))
  345.     {
  346. hr = HXR_FAILED;
  347. goto cleanup;
  348.     }
  349.     // get interface to audio player
  350.     if (HXR_OK != pPlayer->QueryInterface(IID_IHXAudioPlayer, (void**) &m_pAudioPlayer))
  351.     {
  352.         hr = HXR_FAILED;
  353. goto cleanup;
  354.     }
  355. #ifdef REBUFFERING__SKIP
  356.     if (m_pStream)
  357.     {
  358. IHXStreamSource* pSource = 0;
  359. if (m_pStream->GetSource(pSource) == HXR_OK)
  360. {
  361.     if (pSource)
  362.     {
  363. pSource->QueryInterface(IID_IHXSourceBufferingStats,
  364. (void**) &m_pBufferingStats);
  365. HX_RELEASE(pSource);
  366.     }
  367. }
  368.     }
  369. #endif // #ifdef REBUFFERING__SKIP
  370.     pPlayer->QueryInterface(IID_IHXAudioPushdown2, (void**) &m_pAudioPushdown2);
  371. #ifdef HELIX_CONFIG_MIN_PCM_PUSHDOWN_BYTES
  372.     m_pAudioPushdown2->SetAudioPushdown( OPTIMAL_HEAP_MIN_AUDIO_PUSHDOWN );
  373. #endif // HELIX_CONFIG_MIN_PCM_PUSHDOWN_BYTES
  374. cleanup:
  375.     if (HXR_OK != hr)
  376.     {
  377. HX_RELEASE(m_pErrorMessages);
  378. HX_RELEASE(m_pAudioPlayer);
  379. HX_RELEASE(m_pAudioPushdown2);
  380.     }
  381.     return hr;
  382. }
  383. /////////////////////////////////////////////////////////////////////////
  384. //  Method:
  385. // IHXRenderer::EndStream
  386. //  Purpose:
  387. // Called by client engine to inform the renderer that the stream
  388. // is was rendering is closed.
  389. //
  390. STDMETHODIMP CRealAudioRenderer::EndStream()
  391. {
  392. #ifdef _MACINTOSH
  393.     if (m_pDryCallback != NULL)
  394.     {
  395. m_pDryCallback->Cancel();
  396. HX_RELEASE(m_pDryCallback);
  397.     }
  398. #endif
  399.     if ((m_usCurrentDryNotificationStream != NO_STREAM_SET) &&
  400. m_pAudioStreams != NULL &&
  401. m_pAudioStreams[m_usCurrentDryNotificationStream] != NULL)
  402.     {
  403.         RemoveCurrentDryNotification();
  404.         m_usCurrentDryNotificationStream = NO_STREAM_SET;
  405.     }
  406.     m_PlayState = stopped;
  407.     FlushUnregisterQueue(TRUE);
  408.     // We're done with these...
  409.     HX_RELEASE(m_pContext);
  410.     HX_RELEASE(m_pCommonClassFactory);
  411. #if defined(HELIX_FEATURE_STATS)
  412.     HX_RELEASE(m_pRegistry);
  413. #endif // HELIX_FEATURE_STATS
  414.     HX_RELEASE(m_pBufferingStats);
  415.     HX_RELEASE(m_pStream);
  416.     HX_RELEASE(m_pASMStream);
  417.     HX_RELEASE(m_pAudioPlayer);
  418.     HX_RELEASE(m_pAudioPushdown2);
  419.     HX_RELEASE(m_pErrorMessages);
  420. #if defined(HELIX_FEATURE_SETSRCPROPS)
  421.     HX_RELEASE(m_pValues);
  422. #endif /* #if defined(HELIX_FEATURE_SETSRCPROPS) */
  423.     UINT16 i = 0;
  424.     for (i = 0; i < m_uNumOfSubStreams; i++)
  425.     {
  426. if (m_pRaFormats[i])
  427. {
  428.     if (m_pRaFormats[i]->m_pAudioSync && m_pRaFormats[i]->m_bRegistered)
  429.     {
  430. m_pRaFormats[i]->m_bRegistered  = FALSE;
  431. m_pRaFormats[i]->m_pAudioSync->UnRegister();
  432. DEBUG_OUTF_IDX(i, RA_FLOW_FILE,
  433.        (s, "Sync Stopn"));
  434.     }
  435.     HX_RELEASE(m_pRaFormats[i]->m_pAudioSync);
  436.     HX_RELEASE(m_pAudioStreams[i]);
  437.     HX_DELETE(m_pRaFormats[i]);
  438. #if defined(HELIX_FEATURE_AUDIO_CODEC_RAAC)
  439.             HX_DELETE(m_ppVBRDepack[i]);
  440. #endif
  441. }
  442.     }
  443.     // we might get called twice and don't want to go through
  444.     // the above loop again.
  445.     m_uNumOfSubStreams = 0;
  446.     HX_VECTOR_DELETE(m_pRuleMap);
  447.     HX_VECTOR_DELETE(m_pAudioStreams);
  448.     HX_VECTOR_DELETE(m_pRaFormats);
  449. #if defined(HELIX_FEATURE_AUDIO_CODEC_RAAC)
  450.     HX_VECTOR_DELETE(m_ppVBRDepack);
  451. #endif
  452.     FlushUnregisterQueue(TRUE);
  453.     if (m_pRuleToFlagMap != NULL)
  454.     {
  455. HX_VECTOR_DELETE(m_pRuleToFlagMap->rule_to_flag_map);
  456. HX_DELETE(m_pRuleToFlagMap);
  457.     }
  458.     return HXR_OK;
  459. }
  460. /////////////////////////////////////////////////////////////////////////
  461. //  Method:
  462. // IHXRenderer::OnHeader
  463. //  Purpose:
  464. // Called by client engine when a header for this renderer is
  465. // available. The header will arrive before any packets.
  466. //
  467. STDMETHODIMP CRealAudioRenderer::OnHeader(IHXValues* pHeader)
  468. {
  469.     IHXBuffer* pOpaqueData = NULL;
  470.     IHXBuffer* pRuleToFlagMapValue = NULL;
  471.     IHXUpgradeCollection* pUpgradeCollection = NULL;
  472.     BOOL    bForceStartTrackTime = FALSE;
  473.     BOOL    bForceEndTrackTime = FALSE;
  474.     UINT32  ulPreroll = 0;
  475.     UINT32  ulIsInterleaved = 0;
  476.     UINT32  ulBytesRead = 0;
  477.     UINT32  ulTrackStartTime = 0;
  478.     UINT32  ulTrackEndTime = 0;
  479.     UINT32  ulStreamNumber = 0;
  480.     HX_RESULT retVal = HXR_OK;
  481.     UINT32 ulBufferSize = 0;
  482.     UINT32 ulID = 0;
  483.     UINT16 i = 0;
  484.     BYTE* pCursor = NULL;
  485.     BYTE* pData = NULL;
  486.     BOOL bDecoderNotFound = FALSE;
  487.     char* pAllCodecs = NULL;
  488.     UINT32 ulSubStream = 0; // highest bitrate substream
  489.     UINT32 ulAllCodecBufLen = 0;
  490.     UINT16 usQuality = 4;   // highest quality is my default.
  491. #if defined(HELIX_FEATURE_PREFERENCES)
  492.     GetQualityPreference(usQuality);
  493. #endif /* #if defined(HELIX_FEATURE_PREFERENCES) */
  494.     BOOL bMaxSampleRate = (usQuality >= 2); // most of the code uses this as the turn off point
  495.     UINT16 nFirstStreamToInit = 0;  // init first first
  496.     UINT32 ulCurrentSampleRate = bMaxSampleRate ? 8000 : 44000; // lowest sample rate we ever want to have
  497.     UINT16 uCurrentNumChannels = 1;
  498.     INT32 lProtocolVersion = 0;
  499.     BOOL bIsPNM = FALSE;
  500.     IHXStreamSource* pSource = NULL;
  501.     ULONG32 numRulesToBlock = 0;
  502. #if defined(HELIX_FEATURE_AUTOUPGRADE)
  503.     // check the stream versions
  504.     pHeader->AddRef();
  505.     retVal = CheckStreamVersions(pHeader);
  506.     pHeader->Release();
  507.     // if the stream versions didn't checkout, bail
  508.     if (retVal != HXR_OK)
  509.     {
  510. goto cleanup;
  511.     }
  512. #endif
  513.     if (SUCCEEDED(pHeader->GetPropertyULONG32("StreamNumber", ulStreamNumber)))
  514.     {
  515. m_usThisSourceStream = (UINT16) ulStreamNumber;
  516.     }
  517.     pHeader->GetPropertyBuffer ("OpaqueData",       pOpaqueData);
  518.     pHeader->GetPropertyULONG32("Preroll",          ulPreroll);
  519.     // XXXgfw to fix a problem with the core not handling very small
  520.     // preroll values. This should be removed as the client audio
  521.     // services gets reworked to properly handle small preroll values.
  522.     if( ulPreroll < 500 )
  523.     {
  524.         ulPreroll = 500; //a typical value for 193kbps RA content.
  525.         pHeader->SetPropertyULONG32("Preroll", ulPreroll);
  526.     }
  527.     
  528.     pHeader->GetPropertyULONG32("IsInterleaved",    ulIsInterleaved);
  529.     pHeader->GetPropertyULONG32("Duration",     m_ulDuration);
  530.     if (HXR_OK == pHeader->GetPropertyULONG32("TrackStartTime", ulTrackStartTime))
  531.     {
  532. bForceStartTrackTime = TRUE;
  533.     }
  534.     pHeader->GetPropertyULONG32("Delay", m_ulDelay);
  535.     if (HXR_OK == pHeader->GetPropertyULONG32("TrackEndTime", ulTrackEndTime))
  536.     {
  537. bForceEndTrackTime = TRUE;
  538.     }
  539.     if (HXR_OK ==
  540. pHeader->GetPropertyBuffer(RULE_TO_FLAG_MAP_PROPERTY,
  541. pRuleToFlagMapValue))
  542.     {
  543. m_pRuleToFlagMap = new RuleToFlagMap;
  544.         if(!m_pRuleToFlagMap)
  545.         {
  546.             retVal = HXR_OUTOFMEMORY;
  547.             goto cleanup;
  548.         }
  549. m_pRuleToFlagMap->unpack(pRuleToFlagMapValue->GetBuffer(),
  550. pRuleToFlagMapValue->GetSize());
  551.     }
  552.     HX_RELEASE(pRuleToFlagMapValue);
  553.     m_ulPreroll = ulPreroll;
  554.     pData = pOpaqueData->GetBuffer();
  555.     pCursor = pData;
  556.     ulBufferSize = pOpaqueData->GetSize();
  557.     // format ID
  558.     memcpy((UCHAR*)&ulID, pCursor, sizeof(UINT32)); /* Flawfinder: ignore */
  559.     ulID = DwToHost(ulID);
  560.     if (RM_MULTIHEADER_OBJECT == ulID)
  561.     {
  562. MultiStreamHeader multiStreamHeader;
  563. pCursor = multiStreamHeader.unpack(pData, ulBufferSize);
  564. ulBufferSize -= (pCursor - pData);
  565. m_bStreamSwitchable = TRUE;
  566. m_uNumOfSubStreams = multiStreamHeader.num_headers;
  567. // # of rules
  568. m_uNumOfRules = multiStreamHeader.num_rules;
  569. m_pRuleMap = new UINT16[m_uNumOfRules];
  570.         if(!m_pRuleMap)
  571.         {
  572.             retVal = HXR_OUTOFMEMORY;
  573.             goto cleanup;
  574.         }
  575. // retrieve the rule map
  576. for (i = 0; i < m_uNumOfRules; i++)
  577. {
  578.     m_pRuleMap[i] = multiStreamHeader.rule_to_header_map[i];
  579. }
  580. // must delete the rule map since PMC doesn't generate distructors
  581. HX_VECTOR_DELETE(multiStreamHeader.rule_to_header_map);
  582.     }
  583.     else if (RA_FORMAT_ID == ulID)
  584.     {
  585. m_uNumOfSubStreams = 1;
  586.     }
  587.     else
  588.     {
  589. retVal = HXR_FAILED;
  590. goto cleanup;
  591.     }
  592.     // allocate all of our per stream structures and initialize them
  593.     m_pRaFormats = new CRaFormat*[m_uNumOfSubStreams];
  594.     if(!m_pRaFormats)
  595.     {
  596. retVal = HXR_OUTOFMEMORY;
  597. goto cleanup;
  598.     }
  599.     ::memset(m_pRaFormats, 0, sizeof(CRaFormat*) * m_uNumOfSubStreams);
  600.     m_pAudioStreams = new IHXAudioStream*[m_uNumOfSubStreams];
  601.     if(!m_pAudioStreams)
  602.     {
  603. retVal = HXR_OUTOFMEMORY;
  604. goto cleanup;
  605.     }
  606.     ::memset(m_pAudioStreams, 0, sizeof(IHXAudioStream*) * m_uNumOfSubStreams);
  607. #if defined(HELIX_FEATURE_AUDIO_CODEC_RAAC)
  608.     m_ppVBRDepack = new CVBRSimpleDepacketizer* [m_uNumOfSubStreams];
  609.     if(!m_ppVBRDepack)
  610.     {
  611. retVal = HXR_OUTOFMEMORY;
  612. goto cleanup;
  613.     }
  614.     ::memset(m_ppVBRDepack, 0, sizeof(CVBRSimpleDepacketizer*) * m_uNumOfSubStreams);
  615. #endif /* #if defined(HELIX_FEATURE_AUDIO_CODEC_RAAC) */
  616. #if defined(HELIX_FEATURE_STATS)
  617.     if (m_pRegistry)
  618.     {
  619.         // Check the stats to get the protocol and protocol version
  620.         // so we can special case 3.0 and earlier servers that send
  621.         // timestamps in tenths of a second
  622.         if (HXR_OK == m_pStream->GetSource(pSource))
  623.         {
  624.     IHXRegistryID* pSourceIRegID = NULL;
  625.     if (HXR_OK == pSource->QueryInterface(IID_IHXRegistryID,
  626.         (void**)&pSourceIRegID))
  627.     {
  628.         UINT32 ulRegistryID;
  629.         if (HXR_OK == pSourceIRegID->GetID(ulRegistryID))
  630.         {
  631.     char     szRegistryEntry[MAX_DISPLAY_NAME] = {0}; /* Flawfinder: ignore */
  632.     IHXBuffer* pszRegistryName = NULL;
  633.     // Get the current registry key name
  634.     if (HXR_OK == m_pRegistry->GetPropName(ulRegistryID,
  635.         pszRegistryName))
  636.     {
  637.         SafeSprintf(szRegistryEntry, MAX_DISPLAY_NAME, "%s.ProtocolVersion",
  638.     pszRegistryName->GetBuffer());
  639.         m_pRegistry->GetIntByName(szRegistryEntry,
  640.     lProtocolVersion);
  641.         IHXBuffer* pProtocolString = NULL;
  642.         SafeSprintf(szRegistryEntry, MAX_DISPLAY_NAME, "%s.Protocol",
  643.     pszRegistryName->GetBuffer());
  644.         if (HXR_OK ==
  645.     m_pRegistry->GetStrByName(szRegistryEntry,
  646.     pProtocolString) && pProtocolString != NULL)
  647.         {
  648.     bIsPNM = ( 0 == strcasecmp("PNM",
  649.         (const char*)pProtocolString->GetBuffer()));
  650.         }
  651.         HX_RELEASE(pProtocolString);
  652.     }
  653.     HX_RELEASE(pszRegistryName);
  654.         }
  655.         HX_RELEASE(pSourceIRegID);
  656.     }
  657.     HX_RELEASE(pSource);
  658.         }
  659.     }
  660. #endif // HELIX_FEATURE_STATS
  661.     // create codecs buffer
  662. #if defined(HELIX_FEATURE_STATS)
  663.     ulAllCodecBufLen = (m_uNumOfSubStreams * 6) + 1;
  664.     pAllCodecs = new char[ulAllCodecBufLen];
  665.     if(!pAllCodecs)
  666.     {
  667.         retVal = HXR_OUTOFMEMORY;
  668.         goto cleanup;
  669.     }
  670.     *pAllCodecs = '';
  671. #endif /* #if defined(HELIX_FEATURE_STATS) */
  672.     // instantiate the RA format/audio stream objects for
  673.     // each sub-stream
  674.     for (i = 0;
  675.  (retVal == HXR_OK) && (i < m_uNumOfSubStreams);
  676.  i++)
  677.     {
  678. m_pRaFormats[i] = CreateRaFormat(i);
  679. // initialize the Format for this header
  680. m_pRaFormats[i]->ForceInterleaved(ulIsInterleaved);
  681. m_pRaFormats[i]->SetProtocolInfo(bIsPNM, lProtocolVersion);
  682. #if defined(HELIX_FEATURE_AUDIO_CODEC_RAAC)
  683.         // Determine which ASM rule specifies a keyframe for this substream
  684.         UINT16 usKeyFrameRuleNum = 0;
  685.         for (UINT16 q = 0; q < m_pRuleToFlagMap->num_rules; q++)
  686.         {
  687.             BOOL bRuleForThisSubStream = TRUE;
  688.             if (m_bStreamSwitchable && m_pRuleMap && m_pRuleMap[q] != i)
  689.             {
  690.                 bRuleForThisSubStream = FALSE;
  691.             }
  692.             if (bRuleForThisSubStream &&
  693.                 m_pRuleToFlagMap->rule_to_flag_map[q] & HX_KEYFRAME_FLAG)
  694.             {
  695.                 // This is the keyframe rule for this substream
  696.                 usKeyFrameRuleNum = q;
  697.                 break;
  698.             }
  699.         }
  700. #endif /* #if defined(HELIX_FEATURE_AUDIO_CODEC_RAAC) */
  701. UINT32 ulReadRAHeaderSize = ulBufferSize;
  702. if (m_bStreamSwitchable)
  703. {
  704.     // adjust the header size so we only read this header
  705.     ulReadRAHeaderSize = getlong(pCursor);
  706.     pCursor += sizeof(UINT32);
  707.     ulBufferSize -= sizeof(UINT32);
  708. }
  709. retVal = m_pRaFormats[i]->NewReadRAHeader(pCursor, ulReadRAHeaderSize,
  710.     bForceStartTrackTime, bForceEndTrackTime, ulTrackStartTime,
  711.     ulTrackEndTime, &ulBytesRead,  pAllCodecs, ulAllCodecBufLen);
  712. if (HXR_OK == retVal)
  713. {
  714. #if defined(HELIX_FEATURE_AUDIO_CODEC_RAAC)
  715.             // Check if this substream is RAAC and VBRS
  716.             char* pInterID = m_pRaFormats[i]->GetInterleaverName();
  717.             if (pInterID &&
  718.                 (!strcmp((const char*) pInterID, RA_INTERLEAVER_VBRS_ID) ||
  719.                  !strcmp((const char*) pInterID, RA_INTERLEAVER_VBRF_ID)))
  720.             {
  721.                 // Create a VBR depacketizer for this sub-stream
  722.                 HX_DELETE(m_ppVBRDepack[i]);
  723.                 m_ppVBRDepack[i] = new CVBRSimpleDepacketizer();
  724.                 if (m_ppVBRDepack[i])
  725.                 {
  726.                     // Init the depacketizer
  727.                     retVal = m_ppVBRDepack[i]->Init(m_pContext,
  728.                                                     m_pRaFormats[i]->GetMSPerBlock(),
  729.                                                     m_usThisSourceStream,
  730.                                                     usKeyFrameRuleNum,
  731.                                                     FALSE);
  732.                 }
  733.             }
  734. #endif /* #if defined(HELIX_FEATURE_AUDIO_CODEC_RAAC) */
  735.     HXAudioFormat audioFmt;
  736.     m_pRaFormats[i]->GetAudioFormat(audioFmt);
  737.     if ((bMaxSampleRate  && audioFmt.ulSamplesPerSec > ulCurrentSampleRate) ||
  738.                 (!bMaxSampleRate && audioFmt.ulSamplesPerSec < ulCurrentSampleRate))
  739.     {
  740. ulCurrentSampleRate = audioFmt.ulSamplesPerSec;
  741. uCurrentNumChannels = audioFmt.uChannels;
  742. nFirstStreamToInit = i;
  743.     }
  744.     else if (audioFmt.ulSamplesPerSec == ulCurrentSampleRate &&
  745.      audioFmt.uChannels > uCurrentNumChannels)
  746.     {
  747. uCurrentNumChannels = audioFmt.uChannels;
  748. nFirstStreamToInit = i;
  749.     }
  750. }
  751. // mask out DECODER_NOT_FOUND so we can try all of the streams and find
  752. // all of the decoders that aren't installed and upgrade them all at once
  753. if (retVal == HXR_DEC_NOT_FOUND)
  754. {
  755. #if defined(HELIX_CONFIG_SLUGGISHAUTOUPGRADE)
  756.     if( m_pRuleMap )
  757.             {
  758.                 if( m_pStream && !m_pASMStream )
  759.         {
  760.             if( m_pStream->QueryInterface(IID_IHXASMStream2,
  761.         (void**)&m_pASMStream) == HXR_OK )
  762.                     {
  763.                         m_pASMStream->AddRef();
  764.                     }
  765.         }
  766.         if( m_pASMStream )
  767.                 {
  768.             // Find all rules for this stream
  769.             for( int ii=0; ii<m_uNumOfRules; ii++ )
  770.     {
  771.         if( m_pRuleMap[ii] == i )
  772. {
  773.                     m_pASMStream->Disable( ii );
  774.                     numRulesToBlock++;
  775. }
  776.     }
  777.                 }
  778.     } // if m_pRuleMap
  779.     if( ( numRulesToBlock == m_uNumOfRules ) || ( numRulesToBlock == 1 && m_uNumOfRules == 0 ) )
  780.     {
  781.        bDecoderNotFound = TRUE;
  782.     }
  783.     retVal = HXR_OK;
  784. #else
  785.     retVal = HXR_OK;
  786.     bDecoderNotFound = TRUE;
  787. #endif
  788. }
  789. pCursor += ulBytesRead;
  790. ulBufferSize -= ulBytesRead;
  791.     }
  792. #if defined(HELIX_CONFIG_SLUGGISHAUTOUPGRADE)
  793.     if( m_pASMStream && bDecoderNotFound == FALSE )
  794.     {
  795.        HX_RESULT retVal = m_pASMStream->ReCompute();
  796.        if( retVal == HXR_FAIL )
  797.        {
  798.            bDecoderNotFound = TRUE;
  799.        }
  800.     }
  801. #endif // (HELIX_CONFIG_SLUGGISHAUTOUPGRADE)
  802.     // write all codecs list to registry
  803. #if defined(HELIX_FEATURE_STATS)
  804.     WriteCodecsToRegistry(pAllCodecs);
  805.     // clean up char array
  806.     HX_VECTOR_DELETE(pAllCodecs);
  807. #endif // HELIX_FEATURE_STATS
  808.     // if we don't have any other errors but we are missing one or more
  809.     // decoders, reset the result code to decoder not found so upgrade
  810.     // gets kicked off.
  811.     if (HXR_OK == retVal && bDecoderNotFound)
  812.     {
  813. retVal = HXR_DEC_NOT_FOUND;
  814.     }
  815.     // This helps insure we get the audio device opened at the
  816.     // sampling rate and # channels we want.
  817.     if (HXR_OK == retVal)
  818.     {
  819. retVal = InitAudioStream(m_pRaFormats[nFirstStreamToInit], pHeader,
  820.     &m_pAudioStreams[nFirstStreamToInit]);
  821. for (i = 0; retVal == HXR_OK &&
  822. i < m_uNumOfSubStreams ; i++)
  823. {
  824.     if (i != nFirstStreamToInit)
  825.     {
  826. retVal = InitAudioStream(m_pRaFormats[i], pHeader,
  827.      &m_pAudioStreams[i]);
  828.     }
  829. }
  830.     }
  831.     // add the default dry notification when we are all done
  832.     if (HXR_OK == retVal)
  833.     {
  834. AddDryNotification(DEFAULT_DRY_NOTIFICATION);
  835.     }
  836. #if defined(HELIX_FEATURE_SETSRCPROPS)
  837.     // Do we have more than one substream?
  838.     if (m_uNumOfSubStreams > 1)
  839.     {
  840.         // Here we need to find the highest bitrate stream
  841.         UINT32 ulMaxBps = 0;
  842.         for (UINT32 i = 0; i < m_uNumOfSubStreams; i++)
  843.         {
  844.             UINT32 ulBps = m_pRaFormats[i]->GetBitRate();
  845.             if (ulBps > ulMaxBps)
  846.             {
  847.                 ulMaxBps    = ulBps;
  848.                 ulSubStream = i;
  849.             }
  850.         }
  851.     }
  852.     // Save the highest bitrate substream index
  853.     m_ulSrcPropertySubStream = ulSubStream;
  854. #endif /* #if defined(HELIX_FEATURE_SETSRCPROPS) */
  855. cleanup:
  856.     if (retVal == HXR_OK && !m_pMutex)
  857.     {
  858. #ifdef THREADS_SUPPORTED
  859. HXMutex::MakeMutex(m_pMutex);
  860. #else
  861. HXMutex::MakeStubMutex(m_pMutex);
  862. #endif
  863.     }
  864.     HX_RELEASE(pUpgradeCollection);
  865.     HX_RELEASE(pOpaqueData);
  866.     return retVal;
  867. }
  868. CRaFormat* CRealAudioRenderer::CreateRaFormat(UINT16 uStreamNum)
  869. {
  870.     return new CRaFormat(m_pContext,
  871.  m_pCommonClassFactory,
  872.  m_pErrorMessages,
  873.  m_pRuleToFlagMap ?
  874.     m_pRuleToFlagMap->rule_to_flag_map : NULL,
  875.  uStreamNum);
  876. }
  877. /////////////////////////////////////////////////////////////////////////////
  878. //  Method:
  879. // CRealAudioRenderer::CheckStreamVersions
  880. HX_RESULT
  881. CRealAudioRenderer::CheckStreamVersions(IHXValues* pHeader)
  882. {
  883.     // check stream and content versions so an upgrade can
  884.     // be called if necessary...
  885.     HX_RESULT pnr = HXR_OK;
  886. #if defined(HELIX_FEATURE_AUTOUPGRADE)
  887.     BOOL bVersionOK = TRUE;
  888.     UINT32 ulStreamVersion = 0;
  889.     UINT32 ulContentVersion = 0;
  890.     if(HXR_OK == pHeader->GetPropertyULONG32("StreamVersion",
  891. ulStreamVersion))
  892.     {
  893. UINT32 ulMajorVersion = HX_GET_MAJOR_VERSION(ulStreamVersion);
  894. UINT32 ulMinorVersion = HX_GET_MINOR_VERSION(ulStreamVersion);
  895. if((ulMajorVersion > STREAM_MAJOR_VERSION) ||
  896.    (ulMinorVersion > STREAM_MINOR_VERSION &&
  897. ulMajorVersion == STREAM_MAJOR_VERSION))
  898. {
  899. bVersionOK = FALSE;
  900. }
  901.     }
  902.     if(bVersionOK &&
  903.        HXR_OK == pHeader->GetPropertyULONG32("ContentVersion",
  904.            ulContentVersion))
  905.     {
  906. UINT32 ulMajorVersion = HX_GET_MAJOR_VERSION(ulContentVersion);
  907. UINT32 ulMinorVersion = HX_GET_MINOR_VERSION(ulContentVersion);
  908. if((ulMajorVersion > CONTENT_MAJOR_VERSION) ||
  909.    (ulMinorVersion > CONTENT_MINOR_VERSION &&
  910. ulMajorVersion == CONTENT_MAJOR_VERSION))
  911. {
  912. bVersionOK = FALSE;
  913. }
  914.     }
  915.     if(!bVersionOK)
  916.     {
  917. IHXUpgradeCollection* pUpColl = NULL;
  918. if(m_pContext &&
  919.    (HXR_OK == m_pContext->QueryInterface(IID_IHXUpgradeCollection,
  920. (void**)&pUpColl)))
  921. {
  922. CHXBuffer* pBuffer = NULL;
  923.                 m_pCommonClassFactory->CreateInstance(IID_IHXBuffer, (void**) &pBuffer);
  924. if (pBuffer)
  925. {
  926.     //XXXEH- in future, we may want to distinguish between
  927.     // "unknown content version" & "unknown stream version".
  928.     // For now, just treat both as "unknown content version":
  929.     LONG32 bufsize = strlen(zm_pStreamMimeTypes[0]) +
  930.     strlen(zm_pAdditionalAutoUpgradeInfo[
  931.     unknownRAContentVersion]) + 1;
  932.     pBuffer->Set((BYTE*)zm_pStreamMimeTypes[0], bufsize);
  933.     unsigned char* pBuf = pBuffer->GetBuffer();
  934.     pBuf[strlen(zm_pStreamMimeTypes[0])] = '';
  935.     SafeStrCat((char *)pBuf, zm_pAdditionalAutoUpgradeInfo[ /* Flawfinder: ignore */
  936.     unknownRAContentVersion], pBuffer->GetSize());
  937.     pUpColl->Add(eUT_Required, pBuffer, 0, 0);
  938.     HX_RELEASE(pBuffer);
  939.     HX_RELEASE(pUpColl);
  940. }
  941. }
  942. pnr = HXR_FAIL;
  943.     }
  944. #endif /* #if defined(HELIX_FEATURE_AUTOUPGRADE) */
  945.     return pnr;
  946. }
  947. /////////////////////////////////////////////////////////////////////////////
  948. //  Method:
  949. // CRealAudioRenderer::InitAudioStream
  950. HX_RESULT
  951. CRealAudioRenderer::InitAudioStream(CRaFormat* pRaFormat, IHXValues* pHeader,
  952.     IHXAudioStream** ppAudioStream)
  953. {
  954.     HX_RESULT retVal;
  955.     // init so we can HX_RELEASE on error.
  956.     *ppAudioStream = NULL;
  957.     pRaFormat->m_pAudioSync = NULL;
  958.     retVal = m_pAudioPlayer->CreateAudioStream(ppAudioStream);
  959.     if (HXR_OK == retVal)
  960.     {
  961. retVal = (*ppAudioStream)->QueryInterface(IID_IHXRealAudioSync,
  962. (void**)&(pRaFormat->m_pAudioSync));
  963. if (HXR_OK == retVal)
  964. {
  965.     IHXCommonClassFactory* pCommonClassFactory;
  966.     if (HXR_OK == (*ppAudioStream)->QueryInterface(IID_IHXCommonClassFactory,
  967. (void**)&pCommonClassFactory))
  968.     {
  969. // if we can get a class factory from the ccf, it's
  970. // a redstone or later core
  971. m_bPreRedstonePlayer = FALSE;
  972. pRaFormat->OverrideFactory(pCommonClassFactory);
  973. pCommonClassFactory->Release();
  974.     }
  975.     HXAudioFormat audioFmt;
  976.     pRaFormat->GetAudioFormat(audioFmt);
  977.     /* Add default dry notification BEFORE initializing the audio
  978.      * stream. This is so that if we are started mid presentation
  979.      * and there was no audio present earlier, the timeline will
  980.      * change from being a fake timeline to audio timeline and
  981.      * the audio services will write audio for initial pushdown
  982.      * time. We need to get dry notifications so that we can halt
  983.      * the timeline, if the renderer does not have enough data.
  984.      */
  985.     retVal = (*ppAudioStream)->Init(&audioFmt, pHeader);
  986. }
  987.     }
  988.     if (HXR_OK != retVal)
  989.     {
  990. HX_RELEASE((*ppAudioStream));
  991. HX_RELEASE(pRaFormat->m_pAudioSync);
  992.     }
  993.     return retVal;
  994. }
  995. /////////////////////////////////////////////////////////////////////////////
  996. //  Method:
  997. // CRealAudioRenderer::AddDryNotification
  998. HX_RESULT
  999. CRealAudioRenderer::AddDryNotification(UINT16 usStreamNumber)
  1000. {
  1001.     HX_RESULT pnr = HXR_OK;
  1002.     if (m_pAudioStreams == NULL)
  1003.     {
  1004. pnr = HXR_FAILED;
  1005.     }
  1006.     if ((HXR_OK == pnr) &&
  1007. (usStreamNumber != m_usCurrentDryNotificationStream))
  1008.     {
  1009. if (m_usCurrentDryNotificationStream != NO_STREAM_SET)
  1010. {
  1011.     HX_ASSERT(m_pAudioStreams[m_usCurrentDryNotificationStream] != NULL);
  1012.     QueueUnregisterSync(m_usCurrentDryNotificationStream,
  1013. m_ulLatestActualTime);
  1014.             RemoveCurrentDryNotification();
  1015.     DEBUG_OUT(m_pErrorMessages, DOL_REALAUDIO,
  1016. (s, "Switching FROM: %u - Removing DryNotification",
  1017. m_usCurrentDryNotificationStream));
  1018. }
  1019. IHXDryNotification* pDryNot = NULL;
  1020. QueryInterface(IID_IHXDryNotification, (void**)&pDryNot);
  1021. HX_ASSERT(m_pAudioStreams[usStreamNumber] != NULL);
  1022. if (pDryNot)
  1023. {
  1024.     pnr = m_pAudioStreams[usStreamNumber]->AddDryNotification(pDryNot);
  1025. }
  1026. DEBUG_OUTF_IDX(usStreamNumber, RA_FLOW_FILE,
  1027.     (s, "Dry-Notif. Start: %sn", (pnr == HXR_OK) ? "OK" : "FAIL"));
  1028. HX_ASSERT(SUCCEEDED(pnr));
  1029.         m_usCurrentDryNotificationStream = usStreamNumber;
  1030. DEBUG_OUT(m_pErrorMessages, DOL_REALAUDIO,
  1031. (s, "Switching TO: %u - Adding DryNotification",
  1032. m_usCurrentDryNotificationStream));
  1033. // fix up the granularity for this stream
  1034. // we want to be called twice as frequently as our block size.  That
  1035. // way we will "over write" to audio services if we have extra data.
  1036. // This will allow build up of an audio pushdown.
  1037. ULONG32 ulNewGranularity =
  1038.     (UINT32) (m_pRaFormats[usStreamNumber]->GetMSPerBlock() / 2);
  1039. if (ulNewGranularity != m_ulCurrentGranularity)
  1040. {
  1041.     m_ulCurrentGranularity = ulNewGranularity;
  1042.     m_pStream->SetGranularity(m_ulCurrentGranularity);
  1043.     DEBUG_OUTF_IDX(usStreamNumber, RA_FLOW_FILE,
  1044.    (s, "Granularity Set: %un",
  1045.     m_ulCurrentGranularity));
  1046. }
  1047. HX_RELEASE(pDryNot);
  1048.     }
  1049.     if (pnr == HXR_OK)
  1050.     {
  1051. DoSyncRegister(m_usCurrentDryNotificationStream);
  1052.     }
  1053.     return pnr;
  1054. }
  1055. /////////////////////////////////////////////////////////////////////////////
  1056. //  Method:
  1057. // CRealAudioRenderer::DoSyncRegister
  1058. void CRealAudioRenderer::DoSyncRegister(UINT16 uStreamNumber)
  1059. {
  1060.     if (m_pRaFormats &&
  1061. m_pRaFormats[uStreamNumber]->m_pAudioSync &&
  1062. (!m_pRaFormats[uStreamNumber]->m_bRegistered))
  1063.     {
  1064. DEBUG_OUTF_IDX(uStreamNumber, RA_FLOW_FILE,
  1065.        (s, "Sync Startn"));
  1066. m_pRaFormats[uStreamNumber]->m_bRegistered = TRUE;
  1067. m_pRaFormats[uStreamNumber]->m_pAudioSync->Register();
  1068.     }
  1069. }
  1070. void CRealAudioRenderer::UnregisterTimeSyncs(UINT32 ulCurrentTime)
  1071. {
  1072.     UINT16 uCurrentStream = m_uSyncUnregisterStream;
  1073.     if (uCurrentStream != NO_STREAM_SET)
  1074.     {
  1075. BOOL bStreamDone = m_pRaFormats[uCurrentStream]->IsStreamDone();
  1076. if ((m_bAllStreamsToBeUnregistered &&
  1077.      (IsTimeGreaterOrEqual(ulCurrentTime, m_ulDuration) ||
  1078.       bStreamDone)) ||
  1079.     ((m_ulSyncUnregisterTime == NO_TIME_SET) &&
  1080.      IsTimeGreaterOrEqual(ulCurrentTime,
  1081.   m_ulSyncUnregisterTime)))
  1082. {
  1083.     CRealAudioRenderer::QueueUnregisterSync(uCurrentStream,
  1084.     NO_TIME_SET);
  1085. }
  1086.     }
  1087. }
  1088. /////////////////////////////////////////////////////////////////////////////
  1089. //  Method:
  1090. // CRealAudioRenderer::QueueUnregisterSync
  1091. void CRealAudioRenderer::QueueUnregisterSync(UINT16 uStream, UINT32 ulTime)
  1092. {
  1093.     if ((m_uSyncUnregisterStream != NO_STREAM_SET) &&
  1094. (uStream != m_uSyncUnregisterStream))
  1095.     {
  1096. CRealAudioRenderer::QueueUnregisterSync(m_uSyncUnregisterStream,
  1097. NO_TIME_SET);
  1098.     }
  1099.     m_ulSyncUnregisterTime = ulTime;
  1100.     if (ulTime == NO_TIME_SET)
  1101.     {
  1102. if (m_pRaFormats &&
  1103.     m_pRaFormats[uStream]->m_pAudioSync &&
  1104.     m_pRaFormats[uStream]->m_bRegistered)
  1105. {
  1106.     m_pRaFormats[uStream]->m_bRegistered = FALSE;
  1107.     m_pRaFormats[uStream]->m_pAudioSync->UnRegister();
  1108.     m_uSyncUnregisterStream = NO_STREAM_SET;
  1109.     DEBUG_OUTF_IDX(uStream, RA_FLOW_FILE,
  1110.    (s, "Sync Stopn"));
  1111. }
  1112.     }
  1113.     else
  1114.     {
  1115. m_ulSyncUnregisterTime = uStream;
  1116.     }
  1117. }
  1118. void CRealAudioRenderer::FlushUnregisterQueue(BOOL bDestroy)
  1119. {
  1120.     if (m_uSyncUnregisterStream != NO_STREAM_SET)
  1121.     {
  1122. QueueUnregisterSync(m_uSyncUnregisterStream, NO_TIME_SET);
  1123.     }
  1124. }
  1125. /////////////////////////////////////////////////////////////////////////////
  1126. //  Method:
  1127. // CRealAudioRenderer::WriteToAudioServices
  1128. HX_RESULT
  1129. CRealAudioRenderer::WriteToAudioServices(UINT16 uStreamNumber,
  1130.  HXAudioData* pAudioData,
  1131.  UINT32 ulActualTimestamp)
  1132. {
  1133.     HX_RESULT pnr = HXR_OK;
  1134.     BOOL bTryWrite = TRUE;
  1135.     ULONG32 ulAttemptCount = 0;
  1136.     while (bTryWrite && (ulAttemptCount < 3))
  1137.     {
  1138. // Write to AS
  1139. pnr = m_pAudioStreams[uStreamNumber]->Write(pAudioData);
  1140. LogAudioWrite(uStreamNumber, pAudioData, ulActualTimestamp, pnr);
  1141. ulAttemptCount++;
  1142. if (SUCCEEDED(pnr))
  1143. {
  1144.     if (m_pRaFormats[uStreamNumber]->m_bRegistered)
  1145.     {
  1146. // FudgeTimeStamp doesn't need first parameter anymore
  1147. m_pRaFormats[uStreamNumber]->m_pAudioSync->FudgeTimestamp(0,
  1148.     ulActualTimestamp);
  1149.     }
  1150.     CalculateMaxTimeStamp(uStreamNumber,
  1151.   pAudioData,
  1152.   ulActualTimestamp);
  1153.     bTryWrite = FALSE;
  1154. }
  1155. #ifdef HELIX_FEATURE_RAREND_PREREDSTONE_SUPPORT
  1156. else if (m_bPreRedstonePlayer)
  1157. {
  1158.     if (HXR_NONCONTIGUOUS_PACKET == pnr)
  1159.     {
  1160. // we are skipping ahead and should just mark this packet
  1161. // as timed and write it again
  1162. pAudioData->uAudioStreamType = TIMED_AUDIO;
  1163. DEBUG_OUT(m_pErrorMessages, DOL_REALAUDIO_EXTENDED,
  1164.     (s, "skipping AS stream %u's time ahead to %lut0x%X", uStreamNumber,
  1165.     pAudioData->ulAudioTime, pnr));
  1166. DEBUG_OUTF(PREREDSTONE_FILE,
  1167.     (s, "skipping AS stream %u's time ahead to %lut0x%Xn", uStreamNumber,
  1168.     pAudioData->ulAudioTime, pnr));
  1169.     }
  1170.     else
  1171.     {
  1172. HX_ASSERT(m_bPreRedstonePlayer);
  1173. // we've likely written a late packet but it's not safe to
  1174. // ask all rmacore's what time the stream has so we wait for
  1175. // a dry notification, where we are told what the time is
  1176. m_usPreviousDryNotificationStream = m_usCurrentDryNotificationStream;
  1177. if (FAILED(AddDryNotification(uStreamNumber)))
  1178. {
  1179.     // I guess we just jump ahead a second?? and try again
  1180.     DEBUG_OUT(m_pErrorMessages, DOL_REALAUDIO_EXTENDED,
  1181. (s, "Behind Unknown ms on %u's jumping ahead to %lut0x%X", uStreamNumber,
  1182. pAudioData->ulAudioTime + 1000, pnr));
  1183.     DEBUG_OUTF(PREREDSTONE_FILE,
  1184. (s, "Behind Unknown ms on %u's jumping ahead to %lut0x%Xn", uStreamNumber,
  1185. pAudioData->ulAudioTime + 1000, pnr));
  1186.     m_pRaFormats[uStreamNumber]->
  1187. DiscardTillEndOfCrossFade(pAudioData->ulAudioTime + 1000);
  1188.     // reset dry notification
  1189.     AddDryNotification(m_usPreviousDryNotificationStream);
  1190.     m_usPreviousDryNotificationStream = NO_STREAM_SET;
  1191. }
  1192. // get out of the loop...
  1193. bTryWrite = FALSE;
  1194.     }
  1195. }
  1196. #endif // HELIX_FEATURE_RAREND_PREREDSTONE_SUPPORT
  1197. else
  1198. {
  1199.     // we got an error on write, check what time the audio stream
  1200.     // expects data for
  1201.     HXAudioData audioData;
  1202.     INT32 lTimeDiff;
  1203.     audioData.pData = NULL;
  1204.     m_pAudioStreams[uStreamNumber]->Write(&audioData);
  1205.     if (m_ulLatestStreamTime != NO_TIME_SET)
  1206.     {
  1207. lTimeDiff = (LONG32) (audioData.ulAudioTime - m_ulLatestStreamTime);
  1208. OffsetLatestTime(uStreamNumber, lTimeDiff);
  1209.     }
  1210.     DEBUG_OUTF_IDX(uStreamNumber, RA_FLOW_FILE,
  1211.    (s, "Audio Stream Report: Time=%un",
  1212.     audioData.ulAudioTime));
  1213.     DEBUG_OUT(m_pErrorMessages, DOL_REALAUDIO_EXTENDED,
  1214. (s, "Failed AS->Writet%ut%lut%lut%dt0x%X", uStreamNumber,
  1215. pAudioData->ulAudioTime, audioData.ulAudioTime,
  1216. pAudioData->uAudioStreamType, pnr));
  1217.     DEBUG_OUTF(AUDIOSERVICES_FILE,
  1218. (s, "Failed AS->Writet%ut%lut%lut%dt0x%Xn", uStreamNumber,
  1219. pAudioData->ulAudioTime, audioData.ulAudioTime,
  1220. pAudioData->uAudioStreamType, pnr));
  1221.     if (IsTimeLess(audioData.ulAudioTime, pAudioData->ulAudioTime))
  1222.     {
  1223. // we are skipping ahead and should just mark this packet
  1224. // as timed and write it again
  1225. pAudioData->uAudioStreamType = TIMED_AUDIO;
  1226. DEBUG_OUT(m_pErrorMessages, DOL_REALAUDIO_EXTENDED,
  1227.     (s, "skipping AS stream %u's time ahead to %lut0x%X", uStreamNumber,
  1228.     pAudioData->ulAudioTime, pnr));
  1229. DEBUG_OUTF(AUDIOSERVICES_FILE,
  1230.     (s, "skipping AS stream %u's time ahead to %lut0x%Xn", uStreamNumber,
  1231.     pAudioData->ulAudioTime, pnr));
  1232.     }
  1233.     else if (IsTimeGreater(audioData.ulAudioTime, pAudioData->ulAudioTime) &&
  1234.      IsTimeLessOrEqual(audioData.ulAudioTime, pAudioData->ulAudioTime +
  1235.       ((UINT32) (m_pRaFormats[uStreamNumber]->ConvertBytesToMs(pAudioData->pData->GetSize())))))
  1236.     {
  1237. // we are a little behind but at least part of this stream
  1238. // is on time, we should clip off this buffer to the time
  1239. // the audio stream wants and try again.
  1240. bTryWrite = m_pRaFormats[uStreamNumber]->ClipAudioBuffer(pAudioData,
  1241.     ulActualTimestamp, audioData.ulAudioTime, TRUE);
  1242. DEBUG_OUT(m_pErrorMessages, DOL_REALAUDIO_EXTENDED,
  1243.     (s, "A little bit behind on stream %u's clip buffer to %lut0x%X", uStreamNumber,
  1244.     audioData.ulAudioTime, pnr));
  1245. DEBUG_OUTF(AUDIOSERVICES_FILE,
  1246.     (s, "A little bit behind on stream %u's clip buffer to %lut0x%Xn", uStreamNumber,
  1247.     audioData.ulAudioTime, pnr));
  1248.     }
  1249.     else
  1250.     {
  1251. DEBUG_OUT(m_pErrorMessages, DOL_REALAUDIO_EXTENDED,
  1252.     (s, "A lot behind on stream %u's skipping ahead to %lut0x%X", uStreamNumber,
  1253.     audioData.ulAudioTime, pnr));
  1254. DEBUG_OUTF(AUDIOSERVICES_FILE,
  1255.     (s, "A lot behind on stream %u's skipping ahead to %lut0x%Xn", uStreamNumber,
  1256.     audioData.ulAudioTime, pnr));
  1257. UINT32 ulLatestActualTime = NO_TIME_SET;
  1258. UINT32 ulLatestStreamTime = NO_TIME_SET;
  1259. // we are a lot behind and should tell this format to discard
  1260. // data until the audio stream time.
  1261. GetLatestTimesForStream(uStreamNumber,
  1262. ulLatestActualTime,
  1263. ulLatestStreamTime);
  1264. if (ulLatestActualTime == NO_TIME_SET)
  1265. {
  1266.     ulLatestActualTime = m_ulLatestActualTime;
  1267. }
  1268. if (ulLatestActualTime != NO_TIME_SET)
  1269. {
  1270.     m_pRaFormats[uStreamNumber]->
  1271. DiscardTillEndOfCrossFade(ulLatestActualTime);
  1272. }
  1273. // we don't want to try again with this data
  1274. bTryWrite = FALSE;
  1275.     }
  1276. }
  1277.     }
  1278.     if (SUCCEEDED(pnr))
  1279.     {
  1280. DEBUG_OUT(m_pErrorMessages, DOL_REALAUDIO_EXTENDED,
  1281.          (s, "wt%ut%lut%lut%lut0x%Xt%d", uStreamNumber,
  1282.     pAudioData->ulAudioTime, m_ulCurrentTimelineTime, ulActualTimestamp,
  1283.     pnr, pAudioData->uAudioStreamType));
  1284. DEBUG_OUTF(AUDIOSERVICES_FILE,
  1285.     (s, "wt%ut%lut%lut%lut0x%lXt%dn", uStreamNumber,
  1286.     pAudioData->ulAudioTime, m_ulCurrentTimelineTime, ulActualTimestamp,
  1287.     pnr, pAudioData->uAudioStreamType));
  1288.     }
  1289.     return pnr;
  1290. }
  1291. void
  1292. CRealAudioRenderer::GetLatestTimesForStream(UINT16 uStream,
  1293.     UINT32& ulLatestActualTime,
  1294.     UINT32& ulLatestStreamTime)
  1295. {
  1296.     ulLatestActualTime = m_ulLatestActualTime;
  1297.     ulLatestStreamTime = m_ulLatestStreamTime;
  1298. }
  1299. BOOL CRealAudioRenderer::IsCrossfadeInProgress(void)
  1300. {
  1301.     return FALSE;
  1302. }
  1303. /////////////////////////////////////////////////////////////////////////////
  1304. //  Method:
  1305. // CRealAudioRenderer::DoAudio
  1306. //
  1307. //  Note:  See Switchsod.txt for how this is supposed to work, please keep
  1308. // the sod up to date with changes here too.
  1309. //
  1310. HX_RESULT
  1311. CRealAudioRenderer::DoAudio(UINT32& ulAudioTime, AUDIO_STATE audioState = AUDIO_NORMAL)
  1312. {
  1313. #ifdef HELIX_CONFIG_ONLY_DECODE_IF_DRY
  1314.     // Only decode if our audio buffers are 'dry' -- unless we're not
  1315.     // playing yet, because in that case we're not going to go dry.
  1316.     // The second condition totally screws up seeking.
  1317.     //if( audioState != AUDIO_DRYNOTIFICATION && m_PlayState != buffering )
  1318.     if( audioState != AUDIO_DRYNOTIFICATION )
  1319.     {
  1320.        return HXR_OK;
  1321.     }
  1322.     // if we could ask the audio stream how many PCM buffers are curently
  1323.     // in its write list, we could make sure we don't write any more if the
  1324.     // numbers is greater than n.
  1325. #endif // HELIX_CONFIG_ONLY_DECODE_IF_DRY
  1326.     HX_RESULT pnr = HXR_NO_DATA;
  1327.     UINT32 ulActualTimestamp = 0;
  1328.     UINT16 nActive= 0;
  1329.     UINT16 uLowest = NO_STREAM_SET;
  1330.     UINT16 uLongestOverlap = NO_STREAM_SET;
  1331.     UINT32 ulLowestStartTime = NO_TIME_SET;
  1332.     UINT32 ulLowestEndTime = NO_TIME_SET;
  1333.     UINT32 ulLatestActualTime;
  1334.     UINT32 ulLatestStreamTime;
  1335.     HXAudioData    audioData;
  1336.     audioData.pData = NULL;
  1337.     audioData.ulAudioTime = ulAudioTime = 0;
  1338.     // if we are waiting for dry notification, return imediately.
  1339.     if (m_usPreviousDryNotificationStream != NO_STREAM_SET)
  1340.     {
  1341. HX_ASSERT(m_bPreRedstonePlayer);
  1342. return HXR_OK;
  1343.     }
  1344.     // if we are cross fading, set the audio state right.
  1345.     if (IsCrossfadeInProgress() && (audioState == AUDIO_NORMAL))
  1346.     {
  1347. audioState = AUDIO_CROSSFADE;
  1348.     }
  1349.     FindLowestStartTime(uLowest, ulLowestStartTime, ulLowestEndTime, nActive);
  1350.     DEBUG_OUTF(DOAUDIO_FILE, (s, "Lowest: Stream=%u Start=%lu End=%lu Active=%un",
  1351.        uLowest, ulLowestStartTime, ulLowestEndTime, nActive));
  1352.     // Identify latest packet time for purposes of gap filling
  1353.     GetLatestTimesForStream(uLowest, ulLatestActualTime, ulLatestStreamTime);
  1354.     // if the ulLowestStartTime is > m_ulLatestStreamTime or NO_TIME_SET
  1355.     // then we need to fill with loss generated from the last known stream?
  1356.     if ((ulLatestActualTime != NO_TIME_SET) &&
  1357. ((ulLowestStartTime != NO_TIME_SET) &&
  1358.  IsTimeGreater(ulLowestStartTime, ulLatestActualTime + RA_TIME_FUDGE)) &&
  1359. ((uLowest == m_usCurrentDryNotificationStream) ||
  1360.  IsCrossfadeInProgress()))
  1361.     {
  1362.         DEBUG_OUT(m_pErrorMessages, DOL_REALAUDIO,
  1363.     (s, "Gap from %lu on %d(%d) to %lu on %d -- write loss",
  1364. ulLowestStartTime, uLowest, audioState,
  1365. ulLatestActualTime, m_usCurrentDryNotificationStream));
  1366. pnr = m_pRaFormats[uLowest]->
  1367.     GenerateLostAudioData(ulLowestStartTime,
  1368.   audioData,
  1369.   ulActualTimestamp,
  1370.   ulLatestActualTime,
  1371.   ulLatestStreamTime);
  1372.         DEBUG_OUTF(LOSS_FILE,
  1373.     (s, "Gap from %lu on %d(%d) to %lu on %d -- write losst%lut%lun",
  1374. ulLowestStartTime, uLowest, audioState,
  1375. ulLatestActualTime, uLowest,
  1376. audioData.ulAudioTime, ulLatestActualTime));
  1377. if (SUCCEEDED(pnr) && (pnr != HXR_NO_DATA))
  1378. {
  1379.     pnr = WriteToAudioServices(uLowest, &audioData, ulActualTimestamp);
  1380.     DEBUG_OUTF(DOAUDIO_FILE, (s, "Write Loss:t%ut%lut%lut%ct%dt0x%Xn",
  1381. uLowest, audioData.ulAudioTime, ulActualTimestamp,
  1382. (!IsCrossfadeInProgress())?('F'):('T'), audioState, pnr));
  1383.     // Set uLowest to NO_STREAM_SET and nActive to 0 to prevent
  1384.     // further processing.
  1385.     uLowest = NO_STREAM_SET;
  1386.     nActive = 0;
  1387. }
  1388. HX_RELEASE(audioData.pData);
  1389.     }
  1390.     else if (ulLowestStartTime == NO_TIME_SET)
  1391.     {
  1392. m_bDoneWritingPackets = m_bEndOfPackets;
  1393.     }
  1394.     // if more than one active format and we're not currently cross
  1395.     // fading, loop through the formats looking for overlap,
  1396.     // if I find it, remember that stream and it's current time
  1397.     // range end time.  If I find another stream that overlaps, with a
  1398.     // greater current time range end time, flush the current time range
  1399.     // on the first and make the longer time range one the overlap candidate.
  1400.     if ((nActive > 1) &&
  1401. (uLowest != NO_STREAM_SET) &&
  1402. (!IsCrossfadeInProgress()))
  1403.     {
  1404. FindLongestOverlap(uLowest, ulLowestEndTime,
  1405.    nActive, uLongestOverlap,
  1406.    audioState);
  1407.     }
  1408.     if (ulLatestActualTime == NO_TIME_SET)
  1409.     {
  1410. ulLatestActualTime = m_ulLatestActualTime;
  1411. ulLatestStreamTime = m_ulLatestStreamTime;
  1412.     }
  1413.     // if there's an overlap candidate, setup crossfade on the two streams
  1414.     if (uLongestOverlap != NO_STREAM_SET)
  1415.     {
  1416. pnr = AttemptCrossfade(uLowest, // From stream
  1417.        uLongestOverlap, // To stream
  1418.        ulLatestActualTime,
  1419.        ulLatestStreamTime,
  1420.        audioData.ulAudioTime, // Out from stream start time
  1421.        ulActualTimestamp,
  1422.        audioState);
  1423.     }
  1424.     else if (uLowest != NO_STREAM_SET)
  1425.     {
  1426. // write the lowest stream to audio services
  1427. pnr = m_pRaFormats[uLowest]->GetAudioData(
  1428. audioData,
  1429. ulActualTimestamp,
  1430. (m_bEndOfPackets) ? (AUDIO_END_OF_PACKETS) : (audioState),
  1431. ulLatestActualTime,
  1432. ulLatestStreamTime);
  1433. if (HXR_OK == pnr)
  1434. {
  1435.     pnr = WriteToAudioServices(uLowest,
  1436.        &audioData,
  1437.        ulActualTimestamp);
  1438. }
  1439. else if (HXR_OUTOFMEMORY == pnr)
  1440. {
  1441.             return pnr;
  1442. }
  1443. DEBUG_OUTF(DOAUDIO_FILE, (s, "Write Lowest:t%ut%lut%lut%ct%dt0x%Xn",
  1444.     uLowest, audioData.ulAudioTime, ulActualTimestamp,
  1445.     (!IsCrossfadeInProgress())?('T'):('F'), audioState, pnr));
  1446.     }
  1447.     // release the data buffer if we got one
  1448.     HX_RELEASE(audioData.pData);
  1449.     // if we are cross fading, check to see if the cross fade is over
  1450.     if ((uLowest != NO_STREAM_SET) &&
  1451. SUCCEEDED(pnr) &&
  1452. (HXR_NO_DATA != pnr))
  1453.     {
  1454. if (IsCrossfadeInProgress())
  1455. {
  1456.     pnr = AttemptCrossfadeTermination(uLowest,
  1457.       ulActualTimestamp,
  1458.       (pnr == HXR_STREAM_DONE));
  1459. }
  1460.     }
  1461.     // if I didn't write audio on the current dry notification stream but I
  1462.     // did on another stream, make that stream the current dry notification
  1463.     // stream
  1464.     if ((pnr == HXR_OK) &&
  1465. (uLowest != NO_STREAM_SET) &&
  1466. (!IsCrossfadeInProgress()) &&
  1467. (uLowest != m_usCurrentDryNotificationStream))
  1468.     {
  1469. DEBUG_OUTF(DOAUDIO_FILE, (s, "New DN stream: %ut%lun", uLowest, pnr));
  1470. AddDryNotification(uLowest);
  1471.     }
  1472.     // update the out param
  1473.     ulAudioTime = audioData.ulAudioTime;
  1474.     return pnr;
  1475. }
  1476. BOOL CRealAudioRenderer::HaveDataToWrite()
  1477. {
  1478.     BOOL bRet = FALSE;
  1479.     for (UINT16 i = 0; !bRet && (i < m_uNumOfSubStreams); i++)
  1480.     {
  1481. // we delt with the current dry notification stream above
  1482. if (m_pRaFormats[i]->IsActive())
  1483. {
  1484.     UINT32 ulCurrentStartTime = 0;
  1485.     UINT32 ulCurrentEndTime = 0;
  1486.     HX_RESULT pnr = m_pRaFormats[i]->
  1487. GetNextAudioDataTime(ulCurrentStartTime, ulCurrentEndTime);
  1488.     if ((pnr == HXR_OK) && (ulCurrentStartTime != NO_TIME_SET))
  1489.     {
  1490. bRet = TRUE;
  1491.     }
  1492. }
  1493.     }
  1494.     return bRet;
  1495. }
  1496. /////////////////////////////////////////////////////////////////////////////
  1497. //  Method:
  1498. // CRealAudioRenderer::FindLowestStartTime
  1499. HX_RESULT
  1500. CRealAudioRenderer::FindLowestStartTime(UINT16& uLowest, UINT32& ulLowestStartTime,
  1501. UINT32& ulLowestEndTime, UINT16& nActive)
  1502. {
  1503.     UINT16 i;
  1504.     UINT32 ulCurrentStartTime = 0;
  1505.     UINT32 ulCurrentEndTime = 0;
  1506.     HX_RESULT pnr = HXR_OK;
  1507.     uLowest = NO_STREAM_SET;
  1508.     ulLowestStartTime = NO_TIME_SET;
  1509.     nActive = 0;
  1510.     for (i = 0; i < m_uNumOfSubStreams; i++)
  1511.     {
  1512. // we delt with the current dry notification stream above
  1513. if (m_pRaFormats[i]->IsActive())
  1514. {
  1515.     nActive++;
  1516.     pnr = m_pRaFormats[i]->
  1517. GetNextAudioDataTime(ulCurrentStartTime, ulCurrentEndTime);
  1518.     if ((pnr == HXR_OK) &&
  1519. (ulCurrentStartTime != NO_TIME_SET) &&
  1520. ((ulLowestStartTime == NO_TIME_SET) ||
  1521.  IsTimeLess(ulCurrentStartTime, ulLowestStartTime)))
  1522.     {
  1523. uLowest = i;
  1524. ulLowestStartTime = ulCurrentStartTime;
  1525. ulLowestEndTime = ulCurrentEndTime;
  1526.     }
  1527. }
  1528.     }
  1529.     return HXR_OK;
  1530. }
  1531. /////////////////////////////////////////////////////////////////////////////
  1532. //  Method:
  1533. // CRealAudioRenderer::FindLongestOverlap
  1534. HX_RESULT
  1535. CRealAudioRenderer::FindLongestOverlap(UINT16 uLowest, UINT32 ulLowestEndTime,
  1536.        UINT16 nActive, UINT16& uLongestOverlap,
  1537.        AUDIO_STATE& audioState)
  1538. {
  1539.     uLongestOverlap = NO_STREAM_SET;
  1540.     return HXR_OK;
  1541. }
  1542. HX_RESULT CRealAudioRenderer::AttemptCrossfade(UINT16 uLowest,
  1543.        UINT16 uLongetOverlap,
  1544.        UINT32 ulLatestActualTime,
  1545.        UINT32 ulLatestStreamTime,
  1546.        UINT32& ulFromStreamTimeStart,
  1547.        UINT32& ulFromActualTimeStart,
  1548.        AUDIO_STATE audioState)
  1549. {
  1550.     return HXR_FAIL;
  1551. }
  1552. HX_RESULT
  1553. CRealAudioRenderer::AttemptCrossfadeTermination(UINT16& uStream,
  1554. UINT32 ulActualTimestamp,
  1555. BOOL bStreamDone)
  1556. {
  1557.     uStream = NO_STREAM_SET;
  1558.     return (bStreamDone ? HXR_STREAM_DONE : HXR_OK);
  1559. }
  1560. /////////////////////////////////////////////////////////////////////////
  1561. //  Method:
  1562. // IHXRenderer::OnPacket
  1563. //  Purpose:
  1564. // Called by client engine when a packet for this renderer is
  1565. // due.
  1566. // lTimeOffset is the amount of time that we lag behind the main player time line
  1567. // so if the start time of the track is 10 seconds, lTimeOffset will be 10000 (msec)
  1568. // (the first packet's time stamp will be 0 but the player will be at time=10sec)
  1569. //
  1570. STDMETHODIMP
  1571. CRealAudioRenderer::OnPacket(IHXPacket* pPacket, LONG32 lTimeOffset)
  1572. {
  1573. #if defined(RA_TEST_LOSS)
  1574.     static INT32 lNum = 0;
  1575.     if (lNum >= 100 && lNum < 106)
  1576.     {
  1577.         IHXPacket* pLostPacket = NULL;
  1578.         m_pCommonClassFactory->CreateInstance(CLSID_IHXPacket, (void**) &pLostPacket);
  1579.         if (pLostPacket)
  1580.         {
  1581.             pLostPacket->Set(0, 0, pPacket->GetStreamNumber(), 0, 0);
  1582.             pLostPacket->SetAsLost();
  1583.             pPacket = pLostPacket;
  1584.         }
  1585.     }
  1586.     lNum++;
  1587. #endif
  1588. #if defined(HELIX_FEATURE_AUDIO_CODEC_RAAC)
  1589.     HX_RESULT retVal = HXR_FAIL;
  1590.     if (pPacket)
  1591.     {
  1592.         if (!pPacket->IsLost())
  1593.         {
  1594.             // Get the substream of this packet
  1595.             UINT16 usSubStream  = 0;
  1596.             UINT16 usASMRuleNum = pPacket->GetASMRuleNumber();
  1597.             if (m_bStreamSwitchable && m_pRuleMap && usASMRuleNum < m_uNumOfRules)
  1598.             {
  1599.                 usSubStream = m_pRuleMap[usASMRuleNum];
  1600.             }
  1601.             if (usSubStream < m_uNumOfSubStreams)
  1602.             {
  1603.                 // If we have a VBR depacketizer for this substream,
  1604.                 // then run this packet through it. Otherwise, send
  1605.                 // the packet on to _OnPacket() as normal.
  1606.                 if (m_ppVBRDepack[usSubStream])
  1607.                 {
  1608.                     m_ppVBRDepack[usSubStream]->PutPacket(pPacket);
  1609.                     retVal = HXR_OK;
  1610.                     HX_RESULT rv = HXR_OK;
  1611.                     while (SUCCEEDED(rv) && SUCCEEDED(retVal))
  1612.                     {
  1613.                         IHXPacket* pOutPacket = NULL;
  1614.                         rv = m_ppVBRDepack[usSubStream]->GetPacket(pOutPacket);
  1615.                         if (SUCCEEDED(rv))
  1616.                         {
  1617.                             retVal = _OnPacket(pOutPacket, lTimeOffset);
  1618.                         }
  1619.                         HX_RELEASE(pOutPacket);
  1620.                     }
  1621.                 }
  1622.                 else
  1623.                 {
  1624.                     retVal = _OnPacket(pPacket, lTimeOffset);
  1625.                 }
  1626.             }
  1627.         }
  1628.         else
  1629.         {
  1630.             retVal = _OnPacket(pPacket, lTimeOffset);
  1631.         }
  1632.     }
  1633.     return retVal;
  1634. #else
  1635.     return _OnPacket(pPacket, lTimeOffset);
  1636. #endif
  1637. }
  1638. /////////////////////////////////////////////////////////////////////////
  1639. //  Method:
  1640. // IHXRenderer::OnTimeSync
  1641. //  Purpose:
  1642. // Called by client engine to inform the renderer of the current
  1643. // time relative to the streams synchronized time-line. The
  1644. // renderer should use this time value to update its display or
  1645. // render it's stream data accordingly.
  1646. //
  1647. STDMETHODIMP CRealAudioRenderer::OnTimeSync(ULONG32 ulTime)
  1648. {
  1649.     HX_RESULT retVal = HXR_OK;
  1650.     m_pMutex->Lock();
  1651.     // if we get a timesync we must be playing
  1652.     m_PlayState = playing;
  1653.     // Here's a good time to actually render the data!
  1654.     m_ulCurrentTimelineTime = ulTime;
  1655.     /***
  1656.     if (m_usCurrentDryNotificationStream != NO_TIME_SET)
  1657.     {
  1658. DEBUG_OUTF_IDX(m_usCurrentDryNotificationStream, RA_FLOW_FILE,
  1659.        (s, "Time Sync: %un", m_ulCurrentTimelineTime));
  1660.     }
  1661.     ***/
  1662.     DEBUG_OUTF(RASYNC_FILE, (s, "RAtOnTimeSync:t%lun", ulTime));
  1663.     // unregister any time syncs.
  1664.     UnregisterTimeSyncs(ulTime);
  1665. #ifdef _MACINTOSH
  1666.     /* On Mac, since we do not have Mutex, we do not want to process
  1667.      * data if we are within OnPacket call
  1668.      */
  1669.     if (m_bProcessingPacket)
  1670.     {
  1671. goto exit;
  1672.     }
  1673.     m_bProcessingPacket = TRUE;
  1674. #endif /*_MACINTOSH*/
  1675.     // Write to AS
  1676.     UINT32 ulAudioTime;
  1677.     retVal = DoAudio(ulAudioTime);
  1678.     if (m_ulCurrentGranularity < MINIMUM_GRANULARITY)
  1679.     {
  1680. // if our granularity is less than the minimum granularity of the system.
  1681. // then call do audio again.  We should always decode at least twice the
  1682. // amount of data as our granularity.
  1683. retVal = DoAudio(ulAudioTime);
  1684.     }
  1685.     if( retVal == HXR_OUTOFMEMORY )
  1686.     {
  1687.         if( m_pErrorMessages )
  1688.         {
  1689.             m_pErrorMessages->Report( HXLOG_ERR, retVal, 0, NULL, NULL );
  1690.         }
  1691.     }
  1692.     else
  1693.     {
  1694.         retVal = HXR_OK;
  1695.     }
  1696. #ifdef _MACINTOSH
  1697.     m_bProcessingPacket = FALSE;
  1698. exit:
  1699. #endif /*_MACINTOSH*/
  1700.     m_pMutex->Unlock();
  1701.     return retVal;
  1702. }
  1703. /////////////////////////////////////////////////////////////////////////
  1704. //  Method:
  1705. // IHXRenderer::OnPreSeek
  1706. //  Purpose:
  1707. // Called by client engine to inform the renderer that a seek is
  1708. // about to occur. The render is informed the last time for the
  1709. // stream's time line before the seek, as well as the first new
  1710. // time for the stream's time line after the seek will be completed.
  1711. //
  1712. STDMETHODIMP CRealAudioRenderer::OnPreSeek(ULONG32 ulOldTime,
  1713.    ULONG32 ulNewTime)
  1714. {
  1715.     m_PlayState = seeking;
  1716.     m_ulCurrentTimelineTime = ulNewTime;
  1717.     m_bEndOfPackets = FALSE;
  1718.     m_bDoneWritingPackets = FALSE;
  1719.     m_bInSeekMode   = TRUE;
  1720.     m_bFirstPacket = TRUE;
  1721.     DEBUG_OUTF(RASYNC_FILE, (s, "RAtPreSeekt%lut%lun", ulOldTime, ulNewTime));
  1722.     UINT16 i = 0;
  1723.     for (i = 0; i < m_uNumOfSubStreams; i++)
  1724.     {
  1725. m_pRaFormats[i]->OnSeek(ulOldTime,ulNewTime);
  1726. m_pRaFormats[i]->m_ulLastPacketTime = NO_TIME_SET;
  1727. m_pRaFormats[i]->m_ulBytesWrite = 0;
  1728. if (m_pRaFormats[i]->m_pAudioSync && m_pRaFormats[i]->m_bRegistered)
  1729. {
  1730.     m_pRaFormats[i]->m_bRegistered  = FALSE;
  1731.     m_pRaFormats[i]->m_pAudioSync->UnRegister();
  1732.     DEBUG_OUTF_IDX(i, RA_FLOW_FILE,
  1733.    (s, "Sync Stopn"));
  1734. }
  1735.     }
  1736.     // flush the unregister queue since we just unregistered every stream
  1737.     FlushUnregisterQueue();
  1738.     m_ulLatestStreamTime     = NO_TIME_SET;
  1739.     m_ulLatestActualTime     = NO_TIME_SET;
  1740.     m_fLatestStreamTime     = 0.0;
  1741.     m_bAllStreamsToBeUnregistered   = FALSE;
  1742.     if (m_usCurrentDryNotificationStream == NO_TIME_SET)
  1743.     {
  1744. AddDryNotification(DEFAULT_DRY_NOTIFICATION);
  1745.     }
  1746.     return HXR_OK;
  1747. }
  1748. /////////////////////////////////////////////////////////////////////////
  1749. //  Method:
  1750. // IHXRenderer::OnPostSeek
  1751. //  Purpose:
  1752. // Called by client engine to inform the renderer that a seek has
  1753. // just occured. The render is informed the last time for the
  1754. // stream's time line before the seek, as well as the first new
  1755. // time for the stream's time line after the seek.
  1756. //
  1757. STDMETHODIMP CRealAudioRenderer::OnPostSeek(ULONG32 ulOldTime, ULONG32 ulNewTime)
  1758. {
  1759.     DEBUG_OUTF(RASYNC_FILE, (s, "RAtPostSeekt%lut%lun", ulOldTime, ulNewTime));
  1760. #if defined(HELIX_FEATURE_AUDIO_CODEC_RAAC)
  1761.     for (UINT16 i = 0; i < m_uNumOfSubStreams; i++)
  1762.     {
  1763.         if (m_ppVBRDepack[i])
  1764.         {
  1765.             m_ppVBRDepack[i]->OnSeek(ulOldTime, ulNewTime);
  1766.         }
  1767.     }
  1768. #endif /* #if defined(HELIX_FEATURE_AUDIO_CODEC_RAAC) */
  1769.     m_bInSeekMode   = FALSE;
  1770.     return HXR_OK;
  1771. }
  1772. /////////////////////////////////////////////////////////////////////////
  1773. //  Method:
  1774. // IHXRenderer::OnPause
  1775. //  Purpose:
  1776. // Called by client engine to inform the renderer that a pause has
  1777. // just occured. The render is informed the last time for the
  1778. // stream's time line before the pause.
  1779. //
  1780. STDMETHODIMP CRealAudioRenderer::OnPause(ULONG32 ulTime)
  1781. {
  1782.     m_PlayState = paused;
  1783.     return HXR_OK;
  1784. }
  1785. /////////////////////////////////////////////////////////////////////////
  1786. //  Method:
  1787. // IHXRenderer::OnBegin
  1788. //  Purpose:
  1789. // Called by client engine to inform the renderer that a begin or
  1790. // resume has just occured. The render is informed the first time
  1791. // for the stream's time line after the resume.
  1792. //
  1793. STDMETHODIMP CRealAudioRenderer::OnBegin(ULONG32 ulTime)
  1794. {
  1795.     return HXR_OK;
  1796. }
  1797. /////////////////////////////////////////////////////////////////////////
  1798. //  Method:
  1799. // IHXRenderer::OnBuffering
  1800. //  Purpose:
  1801. // Called by client engine to inform the renderer that buffering
  1802. // of data is occuring. The render is informed of the reason for
  1803. // the buffering (start-up of stream, seek has occured, network
  1804. // congestion, etc.), as well as percentage complete of the
  1805. // buffering process.
  1806. //
  1807. STDMETHODIMP CRealAudioRenderer::OnBuffering(ULONG32 ulFlags, UINT16 unPercentComplete)
  1808. {
  1809.     m_PlayState = buffering;
  1810.     return HXR_OK;
  1811. }
  1812. /////////////////////////////////////////////////////////////////////////
  1813. //  Method:
  1814. // IHXRenderer::GetDisplayType
  1815. //  Purpose:
  1816. // Called by client engine to ask the renderer for it's preferred
  1817. // display type. When layout information is not present, the
  1818. // renderer will be asked for it's prefered display type. Depending
  1819. // on the display type a buffer of additional information may be
  1820. // needed. This buffer could contain information about preferred
  1821. // window size.
  1822. //
  1823. STDMETHODIMP CRealAudioRenderer::GetDisplayType
  1824. (
  1825.     REF(HX_DISPLAY_TYPE)   ulFlags,
  1826.     REF(IHXBuffer*)     pBuffer
  1827. )
  1828. {
  1829.     ulFlags = HX_DISPLAY_NONE;
  1830.     return HXR_OK;
  1831. }
  1832. /************************************************************************
  1833.  * Method:
  1834.  *     IHXRenderer::OnEndofPackets
  1835.  * Purpose:
  1836.  *     Called by client engine to inform the renderer that all the
  1837.  *     packets have been delivered. However, if the user seeks before
  1838.  *     EndStream() is called, renderer may start getting packets again
  1839.  *     and the client engine will eventually call this function again.
  1840.  */
  1841. STDMETHODIMP CRealAudioRenderer::OnEndofPackets(void)
  1842. {
  1843.     /* we should release any remaining sub-superblocks to audio services here*/
  1844.     m_bEndOfPackets = TRUE;
  1845.     if (m_bReportOKStatus && m_pStream)
  1846.     {
  1847. m_bReportOKStatus = FALSE;
  1848. m_pStream->ReportRebufferStatus(1,1);
  1849.     }
  1850.     m_pMutex->Lock();
  1851.     UINT16  i = 0;
  1852.     for (i = 0; i < m_uNumOfSubStreams; i++)
  1853.     {
  1854. m_pRaFormats[i]->OnEndofPackets();
  1855. #ifdef _MACINTOSH
  1856.         UINT32 ulActualTimestamp = 0;
  1857. HXAudioData audioData;
  1858. audioData.pData = NULL;
  1859. audioData.ulAudioTime = 0;
  1860. // XXXJEFFA Get rid of this while loop.  There shouldn't be
  1861. // any while loops in the renderer.
  1862. while (m_pRaFormats[i]->GetAudioData(audioData,
  1863.      ulActualTimestamp,
  1864.      AUDIO_END_OF_PACKETS,
  1865.      m_ulLatestActualTime,
  1866.      m_ulLatestStreamTime) == HXR_OK)
  1867. {
  1868.     HX_RESULT pnr = m_pAudioStreams[i]->Write(&audioData );
  1869.     LogAudioWrite(i, &audioData, ulActualTimestamp, pnr);
  1870.     HX_ASSERT(SUCCEEDED(pnr));
  1871.          m_pRaFormats[i]->m_pAudioSync->FudgeTimestamp(m_pRaFormats[i]->m_ulBytesWrite,
  1872.          ulActualTimestamp);
  1873.          m_pRaFormats[i]->m_ulBytesWrite += (audioData.pData)->GetSize();
  1874.     CalculateMaxTimeStamp(i, &audioData, ulActualTimestamp);
  1875.     HX_RELEASE(audioData.pData);
  1876.     m_pRaFormats[i]->m_ulLastPacketTime = audioData.ulAudioTime;
  1877. }
  1878. #endif
  1879.     }
  1880.     m_bAllStreamsToBeUnregistered   = TRUE;
  1881.     m_pMutex->Unlock();
  1882.     return HXR_OK;
  1883. }
  1884. /*
  1885.  *  IHXDryNotification methods
  1886.  */
  1887. /************************************************************************
  1888.  *  Method:
  1889.  *      OnDryNotification
  1890.  *  Purpose:
  1891.  *     This function is called when it is time to write to audio device
  1892.  *     and there is not enough data in the audio stream. The renderer can
  1893.  *     then decide to add more data to the audio stream. This should be
  1894.  *     done synchronously within the call to this function.
  1895.  *     It is OK to not write any data. Silence will be played instead.
  1896.  */
  1897. STDMETHODIMP CRealAudioRenderer::OnDryNotification(UINT32 /*IN*/ ulCurrentStreamTime,
  1898.    UINT32 /*IN*/ ulMinimumDurationRequired)
  1899. {
  1900.     /* If the renderer is delayed, do not report rebuffer status until the
  1901.      * packets are really due i.e. until Current time + Preroll is greater
  1902.      * than the Delay time.
  1903.      */
  1904.     m_pMutex->Lock();
  1905.     if (m_bDoneWritingPackets)
  1906.     {
  1907. goto exit;
  1908.     }
  1909. #ifdef HELIX_FEATURE_RAREND_PREREDSTONE_SUPPORT
  1910.     if (m_usPreviousDryNotificationStream != NO_STREAM_SET)
  1911.     {
  1912. HX_ASSERT(m_bPreRedstonePlayer);
  1913. UINT32 ulCurrentStartTime, ulCurrentEndTime;
  1914. // get the next audio time for this format
  1915. m_pRaFormats[m_usCurrentDryNotificationStream]->GetNextAudioDataTime(ulCurrentStartTime, ulCurrentEndTime);
  1916. DEBUG_OUT(m_pErrorMessages, DOL_REALAUDIO_EXTENDED,
  1917. (s, "PreviousDryNot(%u):  Behind on stream %u's skipping ahead to %lu",
  1918. m_usPreviousDryNotificationStream, m_usCurrentDryNotificationStream, ulCurrentStreamTime));
  1919. DEBUG_OUTF(AUDIOSERVICES_FILE,
  1920. (s, "PreviousDryNot(%u):  Behind on stream %u's skipping ahead to %lun",
  1921. m_usPreviousDryNotificationStream, m_usCurrentDryNotificationStream, ulCurrentStreamTime));
  1922. // if it is < ulCurrentStreamTime we discard until ulCurrentStreamTime
  1923. if (IsTimeLess(ulCurrentStartTime, ulCurrentStreamTime))
  1924. {
  1925.     m_pRaFormats[m_usCurrentDryNotificationStream]->
  1926. DiscardTillEndOfCrossFade(ulCurrentStreamTime);
  1927. }
  1928. // reset dry notification
  1929. AddDryNotification(m_usPreviousDryNotificationStream);
  1930. m_usPreviousDryNotificationStream = NO_STREAM_SET;
  1931.     }
  1932.     else
  1933. #endif // HELIX_FEATURE_RAREND_PREREDSTONE_SUPPORT
  1934.     if (NO_TIME_SET != m_ulLatestStreamTime &&
  1935. IsTimeGreater(ulCurrentStreamTime, m_ulLatestStreamTime + RA_TIME_FUDGE))
  1936.     {
  1937. // if the stream time reported by audio services is ahead of the
  1938. // current writing time of the renderer, update the writing time
  1939. // of the renderer so it catches up with the audio services stream
  1940. DEBUG_OUTF(LATESTPACKET_FILE,
  1941. (s, "DryNotificationt%ut%lut%lun",
  1942. m_usCurrentDryNotificationStream, m_ulLatestStreamTime, ulCurrentStreamTime));
  1943. ULONG32 ulTimeDiff = ulCurrentStreamTime - m_ulLatestStreamTime;
  1944. m_ulLatestStreamTime += ulTimeDiff;
  1945. m_fLatestStreamTime = UINT32_TO_DOUBLE(m_ulLatestStreamTime);
  1946. m_ulLatestActualTime += ulTimeDiff;
  1947. DEBUG_OUT(m_pErrorMessages, DOL_REALAUDIO_EXTENDED,
  1948. (s, "Behind on stream %u's skipping ahead to %lu",
  1949. m_usCurrentDryNotificationStream, ulCurrentStreamTime));
  1950. DEBUG_OUTF(AUDIOSERVICES_FILE,
  1951. (s, "Behind on stream %u's skipping ahead to %lun",
  1952. m_usCurrentDryNotificationStream, ulCurrentStreamTime));
  1953.     }
  1954.     DEBUG_OUTF(SWITCH_FILE,
  1955. (s, "OnDryNotification(%p)t%ct%lu > %lut%lu > %lun", this, (!m_bFirstPacket)?('T'):('F'),
  1956.        ulCurrentStreamTime + m_ulPreroll, m_ulDelay,
  1957.        ulCurrentStreamTime + RA_TIME_FUDGE, m_ulLatestStreamTime));
  1958.     if (!m_bFirstPacket &&
  1959. IsTimeGreater(ulCurrentStreamTime + m_ulPreroll, m_ulDelay) &&
  1960. (NO_TIME_SET == m_ulLatestStreamTime ||
  1961. IsTimeGreater(ulCurrentStreamTime + RA_TIME_FUDGE, m_ulLatestStreamTime)))
  1962.     {
  1963. // Try to write some audio to satisfy the audio stream
  1964. HX_RESULT pnr = HXR_OK;
  1965. UINT32 ulAudioWantedTime =
  1966.     (ulCurrentStreamTime + ulMinimumDurationRequired);
  1967. DEBUG_OUT(m_pErrorMessages, DOL_REALAUDIO_EXTENDED,
  1968.    (s, "OnDryNotificationt%lut%lut%lu", ulCurrentStreamTime,
  1969.    ulMinimumDurationRequired,
  1970.    m_ulLatestStreamTime));
  1971. DEBUG_OUTF(SWITCH_FILE,
  1972.    (s, "OnDryNotificationt%lut%lut%lun", ulCurrentStreamTime,
  1973.    ulMinimumDurationRequired,
  1974.    m_ulLatestStreamTime));
  1975. #ifdef _MACINTOSH
  1976. if (!m_bProcessingPacket)
  1977. {
  1978.     m_bProcessingPacket = TRUE;
  1979.     pnr = AttemptToSatisfyDryRequest(ulAudioWantedTime);
  1980.     m_bProcessingPacket = FALSE;
  1981.     LOG_BUFFERING(BUF_LOG_FILE,
  1982.       (s, "Dry Notif: StreamTime=%u Duration=%u %sn",
  1983.        ulAudioWantedTime, ulMinimumDurationRequired,
  1984.        (pnr == HXR_OK) ? "Satisfied" : "Dry"));
  1985. }
  1986. else
  1987. {
  1988.     ScheduleDryCallback(ulAudioWantedTime);
  1989.     pnr = HXR_NO_DATA;
  1990. }
  1991. #else
  1992. pnr = AttemptToSatisfyDryRequest(ulAudioWantedTime);
  1993. LOG_BUFFERING(BUF_LOG_FILE,
  1994.       (s, "Dry Notif: StreamTime=%u Duration=%u %sn",
  1995.        ulAudioWantedTime, ulMinimumDurationRequired,
  1996.        (pnr == HXR_OK) ? "Satisfied" : "Dry"));
  1997. #endif
  1998. // if we couldn't satisfy the request and we have not
  1999. // recieved all of our packets, and we have started playing,
  2000. // tell the core to rebuffer
  2001. if ((FAILED(pnr) || HXR_NO_DATA == pnr) && !m_bEndOfPackets &&
  2002.     IsTimeGreaterOrEqual(ulCurrentStreamTime, m_ulDelay))
  2003. {
  2004.     BOOL bSkipRebuffer = FALSE;
  2005. #ifdef REBUFFERING_SKIP
  2006.            /// We only do this for live now
  2007.             IHXStreamSource* pSource = NULL;
  2008.     m_pStream->GetSource(pSource);
  2009.     if (pSource != NULL && pSource->IsLive())
  2010.             {
  2011.     
  2012.         if (m_pBufferingStats && (m_usThisSourceStream != NO_STREAM_SET))
  2013.         {
  2014.     INT64 llLowestTimestamp = 0;
  2015.     INT64 llHighestTimestamp = 0;
  2016.     UINT32 ulNumBytes = 0;
  2017.     BOOL bDone = FALSE;
  2018.     if (SUCCEEDED(m_pBufferingStats->GetCurrentBuffering(
  2019.         m_usThisSourceStream,
  2020.                                         llLowestTimestamp, 
  2021.                                         llHighestTimestamp,
  2022.                                         ulNumBytes,
  2023.                                         bDone)))
  2024.     {
  2025.         if (ulNumBytes != 0)
  2026.         {
  2027.      if ((llHighestTimestamp - llLowestTimestamp) > MAX_TRANSPORT_BUFFER_DURATION
  2028.                                      || ulNumBytes >= MAX_TRASPORT_BUFFER_BYTES)
  2029.         {
  2030.             bSkipRebuffer = TRUE;
  2031.                          DEBUG_OUT(m_pErrorMessages, DOL_REALAUDIO,
  2032.                (s, "Skipping Buffering on stream %u", m_usCurrentDryNotificationStream));
  2033.                  }
  2034.         }    
  2035. #ifdef LOG_BUFFERING_ENABLED
  2036.         ULONG32 ulTransportDuration = (ULONG32) (llHighestTimestamp - llLowestTimestamp);
  2037.         LOG_BUFFERING(BUF_LOG_FILE, 
  2038.       (s, "Buffering: DurationAtTransport=%u BytesAtTransport=%u %sn", 
  2039.        ulTransportDuration, ulNumBytes,
  2040.        bSkipRebuffer ? "Skipped" : "Engaged"));
  2041. #endif // LOG_BUFFERING_ENABLED
  2042.     }
  2043.         }
  2044.             }
  2045.             HX_RELEASE(pSource);
  2046. #endif // REBUFFERING_SKIP
  2047.     // If we have no data to give due to loss, do not rebuffer
  2048.     if (!bSkipRebuffer)
  2049.     {
  2050. m_bReportOKStatus = TRUE;
  2051. m_pStream->ReportRebufferStatus(1,0);
  2052. DEBUG_OUTF(SWITCH_FILE,
  2053.     (s, "Entering Bufferingt%un", m_usCurrentDryNotificationStream));
  2054. DEBUG_OUT(m_pErrorMessages, DOL_REALAUDIO,
  2055.     (s, "Entering Buffering on stream %u", m_usCurrentDryNotificationStream));
  2056.     }
  2057. }
  2058. // If we are not rebuffering even though have no data to feed,
  2059. // advance the audio time
  2060. if (FAILED(pnr))
  2061. {
  2062.     if (!m_bReportOKStatus)
  2063.     {
  2064. m_ulLatestStreamTime = ulCurrentStreamTime + ulMinimumDurationRequired;
  2065. m_fLatestStreamTime = UINT32_TO_DOUBLE(m_ulLatestStreamTime);
  2066. m_ulLatestActualTime += ulMinimumDurationRequired;
  2067.     }
  2068. }
  2069.     }
  2070. exit:
  2071.     m_pMutex->Unlock();
  2072.     return HXR_OK;
  2073. }
  2074. #ifdef _MACINTOSH
  2075. void
  2076. CRealAudioRenderer::ScheduleDryCallback(UINT32 ulAudioWantedTime)
  2077. {
  2078.     if (m_pDryCallback == NULL)
  2079.     {
  2080. CDryNotificationCallback* pCallback =
  2081.     CDryNotificationCallback::CreateInstance(ulAudioWantedTime, this,
  2082.     m_pContext);
  2083. if (pCallback != NULL)
  2084. {
  2085.     m_pDryCallback = pCallback;
  2086.     m_pDryCallback->ScheduleCallback();
  2087. }
  2088.     }
  2089.     else
  2090.     {
  2091. m_pDryCallback->UpdateAudioTimeWanted(ulAudioWantedTime);
  2092.     }
  2093. }
  2094. #endif /*_MACINTOSH */
  2095. STDMETHODIMP
  2096. CRealAudioRenderer::AttemptToSatisfyDryRequest(UINT32 ulAudioWantedTime)
  2097. {
  2098.     HX_RESULT pnr = HXR_OK;
  2099.     UINT32 ulAudioTime = 0;
  2100.     while (m_usPreviousDryNotificationStream == NO_STREAM_SET &&
  2101.            HXR_OK == pnr &&
  2102.            ((NO_TIME_SET == m_ulLatestStreamTime) ||
  2103.             IsTimeGreaterOrEqual(ulAudioWantedTime, m_ulLatestStreamTime)))
  2104.     {
  2105. pnr = DoAudio(ulAudioTime, AUDIO_DRYNOTIFICATION);
  2106. DEBUG_OUTF(SWITCH_FILE,
  2107.     (s, "AttemptToSatisfyDryRequestt%lut%lut%ut0x%Xn", m_ulLatestStreamTime,
  2108.     ulAudioWantedTime, m_usCurrentDryNotificationStream, pnr));
  2109. DEBUG_OUT(m_pErrorMessages, DOL_REALAUDIO_EXTENDED,
  2110.     (s, "AttemptToSatisfyDryRequestt%lut%lut%ut0x%X", m_ulLatestStreamTime,
  2111.     ulAudioWantedTime, m_usCurrentDryNotificationStream, pnr));
  2112. if (HXR_LATE_PACKET == pnr)
  2113. {
  2114.     /* Reset the return value to HXR_OK because
  2115.      * we want to keep writing if we wrote late
  2116.      * data
  2117.      */
  2118.     pnr = HXR_OK;
  2119. }
  2120.     }
  2121. #ifdef _MACINTOSH
  2122.     HX_RELEASE(m_pDryCallback);
  2123.     // if we get here by the callback, we want to turn off
  2124.     // bufferning if we can
  2125.     if (m_bReportOKStatus && IsTimeGreaterOrEqual(m_ulLatestStreamTime, ulAudioWantedTime))
  2126.     {
  2127. m_bReportOKStatus = FALSE;
  2128. m_pStream->ReportRebufferStatus(1,1);
  2129.     }
  2130. #endif
  2131.     return pnr;
  2132. }
  2133. void
  2134. CRealAudioRenderer::CalculateMaxTimeStamp(UINT16 uStreamNumber,
  2135.   HXAudioData* pAudioData,
  2136.   UINT32 ulActualTimestamp,
  2137.   UINT32* pulDataDuration,
  2138.   double* pfDataDuration)
  2139. {
  2140.     double fDataDuration =
  2141. m_pRaFormats[uStreamNumber]->ConvertBytesToMs(pAudioData->pData->GetSize());
  2142.     UINT32 ulDataDuration = (UINT32) (fDataDuration + 0.5);
  2143.     AdvanceLatestTime(pAudioData->ulAudioTime,
  2144.       ulActualTimestamp,
  2145.       ulDataDuration,
  2146.       fDataDuration,
  2147.       m_ulLatestStreamTime,
  2148.       m_fLatestStreamTime,
  2149.       m_ulLatestActualTime);
  2150.     if (pulDataDuration)
  2151.     {
  2152. *pulDataDuration = ulDataDuration;
  2153.     }
  2154.     if (pfDataDuration)
  2155.     {
  2156. *pfDataDuration = fDataDuration;
  2157.     }
  2158. }
  2159. void
  2160. CRealAudioRenderer::AdvanceLatestTime(UINT32 ulBaseStreamTime,
  2161.       UINT32 ulBaseActualTime,
  2162.       UINT32 ulDurationAdvance,
  2163.       double fDurationAdvance,
  2164.       UINT32 &ulLatestStreamTime,
  2165.       double &fLatestStreamTime,
  2166.       UINT32 &ulLatestActualTime)
  2167. {
  2168.     UINT32 ulStreamEndTimestamp = ulBaseStreamTime + ulDurationAdvance;
  2169.     if ((ulLatestStreamTime == NO_TIME_SET) ||
  2170. IsTimeLess(ulLatestStreamTime, ulStreamEndTimestamp))
  2171.     {
  2172. if ((ulLatestStreamTime == NO_TIME_SET) ||
  2173.     ((ulBaseStreamTime - ulLatestStreamTime) > RA_TIME_FUDGE))
  2174. {
  2175.     fLatestStreamTime = UINT32_TO_DOUBLE(ulBaseStreamTime);
  2176. }
  2177. INCREMENT_FLOAT_TS(fLatestStreamTime, fDurationAdvance);
  2178. ulLatestStreamTime = (ULONG32) (fLatestStreamTime);
  2179. ulLatestActualTime = ulBaseActualTime + ulDurationAdvance;
  2180. if (ulLatestStreamTime == NO_TIME_SET)
  2181. {
  2182.     ulLatestStreamTime++;
  2183. }
  2184. if (ulLatestActualTime == NO_TIME_SET)
  2185. {
  2186.     ulLatestActualTime++;
  2187. }
  2188.     }
  2189. }
  2190. void
  2191. CRealAudioRenderer::OffsetLatestTime(UINT16 uStreamNumber,
  2192.      INT32 lTimeOffset)
  2193. {
  2194.     m_ulLatestStreamTime += lTimeOffset;
  2195.     m_ulLatestActualTime += lTimeOffset;
  2196.     m_fLatestStreamTime += ((double) lTimeOffset);
  2197. }
  2198. void CRealAudioRenderer::WriteCodecsToRegistry(const char* pAllCodecs)
  2199. {
  2200. #if defined(HELIX_FEATURE_STATS)
  2201.     if (m_pRegistry)
  2202.     {
  2203.         char     szRegistryEntry[MAX_DISPLAY_NAME] = {0}; /* Flawfinder: ignore */
  2204.         IHXBuffer*     pszRegistryName = NULL;
  2205.         // Get the current registry key name
  2206.         if (HXR_OK == m_pRegistry->GetPropName(m_ulRegistryID, pszRegistryName))
  2207.         {
  2208.     SafeSprintf (szRegistryEntry, MAX_DISPLAY_NAME, "%s.AllCodecs", pszRegistryName->GetBuffer());
  2209.             IHXBuffer* pValue = NULL;
  2210.             m_pCommonClassFactory->CreateInstance(IID_IHXBuffer, (void**) &pValue);
  2211.             if (pValue)
  2212.             {
  2213.                 pValue->Set((UCHAR*) pAllCodecs, strlen(pAllCodecs)+1);
  2214.                 m_pRegistry->AddStr(szRegistryEntry, pValue);
  2215.                 pValue->Release();
  2216.             }
  2217.     pszRegistryName->Release();
  2218.     pszRegistryName = NULL;
  2219.         }
  2220.     }
  2221. #endif // HELIX_FEATURE_STATS
  2222. }
  2223. STDMETHODIMP
  2224. CRealAudioRenderer::InitializeStatistics
  2225. (
  2226.     UINT32 /*IN*/ ulRegistryID
  2227. )
  2228. {
  2229. #if defined(HELIX_FEATURE_STATS)
  2230.    m_ulRegistryID = ulRegistryID;
  2231.    m_ulSmartStreamRegID = 0;
  2232.    m_ulNameRegID = 0;
  2233.    m_ulCodecRegID = 0;
  2234.    m_ulCodecTextRegID = 0;
  2235.    m_ulCodec4CCRegID = 0;
  2236.    m_ulRateRegID = 0;
  2237.    m_ulChannelsRegID = 0;
  2238. #endif // HELIX_FEATURE_STATS
  2239.    return HXR_OK;
  2240. }
  2241. STDMETHODIMP
  2242. CRealAudioRenderer::UpdateStatistics()
  2243. {
  2244. #if defined(HELIX_FEATURE_STATS)
  2245.     if (m_pRegistry)
  2246.     {
  2247.         char     szRegistryEntry[MAX_DISPLAY_NAME] = {0}; /* Flawfinder: ignore */
  2248.         IHXBuffer*     pszRegistryName = NULL;
  2249.         if (m_usCurrentDryNotificationStream != NO_STREAM_SET &&
  2250.            m_pRaFormats[m_usCurrentDryNotificationStream])
  2251.         {
  2252.            m_pRaFormats[m_usCurrentDryNotificationStream]->UpdateStatistics(
  2253.                m_pRegistry, m_ulRegistryID, m_ulCodecRegID, m_ulCodecTextRegID,
  2254.                m_ulCodec4CCRegID, m_ulRateRegID, m_ulChannelsRegID,
  2255.        m_ulSurroundRegID);
  2256.         }
  2257.         if (!m_ulSmartStreamRegID || !m_ulNameRegID)
  2258.         {
  2259.     // Get the current registry key name
  2260.     if (HXR_OK == m_pRegistry->GetPropName(m_ulRegistryID, pszRegistryName))
  2261.     {
  2262.         SafeSprintf (szRegistryEntry, MAX_DISPLAY_NAME, "%s.SureStream", pszRegistryName->GetBuffer());
  2263.         IHXBuffer* pValue = NULL;
  2264.                 m_pCommonClassFactory->CreateInstance(IID_IHXBuffer, (void**) &pValue);
  2265.         if (pValue)
  2266.                 {
  2267.                     if (m_bStreamSwitchable && m_uNumOfSubStreams > 1)
  2268.                     {
  2269.                         pValue->Set((const UCHAR*)"TRUE", 5);
  2270.                     }
  2271.                     else
  2272.                     {
  2273.                         pValue->Set((const UCHAR*)"FALSE", 6);
  2274.                     }
  2275.                     m_ulSmartStreamRegID = m_pRegistry->AddStr(szRegistryEntry, pValue);
  2276.                     HX_RELEASE(pValue);
  2277.                 }
  2278.         SafeSprintf (szRegistryEntry, MAX_DISPLAY_NAME, "%s.Name", pszRegistryName->GetBuffer());
  2279.         pValue = NULL;
  2280.                 m_pCommonClassFactory->CreateInstance(IID_IHXBuffer, (void**) &pValue);
  2281.                 if (pValue)
  2282.                 {
  2283.                     pValue->Set((const UCHAR*)zm_pName, strlen(zm_pName) + 1);
  2284.                     m_ulNameRegID = m_pRegistry->AddStr(szRegistryEntry, pValue);
  2285.                     HX_RELEASE(pValue);
  2286.                 }
  2287.         HX_RELEASE(pszRegistryName);
  2288.     }
  2289.         }
  2290.         else
  2291.         {
  2292.     IHXBuffer* pValue = NULL;
  2293.             m_pCommonClassFactory->CreateInstance(IID_IHXBuffer, (void**) &pValue);
  2294.             if (pValue)
  2295.             {
  2296.                 if (m_bStreamSwitchable && m_uNumOfSubStreams > 1)
  2297.                 {
  2298.                     pValue->Set((const UCHAR*)"TRUE", 5);
  2299.                 }
  2300.                 else
  2301.                 {
  2302.                     pValue->Set((const UCHAR*)"FALSE", 6);
  2303.                 }
  2304.                 m_pRegistry->SetStrById(m_ulSmartStreamRegID, pValue);
  2305.                 HX_RELEASE(pValue);
  2306.             }
  2307.     pValue = NULL;
  2308.             m_pCommonClassFactory->CreateInstance(IID_IHXBuffer, (void**) &pValue);
  2309.             if (pValue)
  2310.             {
  2311.                 pValue->Set((const UCHAR*)zm_pName, strlen(zm_pName) + 1);
  2312.                 m_pRegistry->SetStrById(m_ulNameRegID, pValue);
  2313.                 HX_RELEASE(pValue);
  2314.             }
  2315.         }
  2316.     }
  2317. #endif // HELIX_FEATURE_STATS
  2318.     return HXR_OK;
  2319. }
  2320. void
  2321. CRealAudioRenderer::AddCodec(IHXValues* pValues,
  2322.  char* codec,
  2323.  UINT32 real_bandwidth,
  2324.  UINT32 sort_bandwidth,
  2325.  int whichcodec)
  2326. {
  2327. #if defined(HELIX_FEATURE_RAREND_BANDWIDTH_LISTER)
  2328.     IHXBuffer* pBuffer;
  2329.     char namebuf[20]; /* Flawfinder: ignore */
  2330.     IHXCommonClassFactory* pCommonClassFactory;
  2331.     if(HXR_OK != m_pContext->QueryInterface(IID_IHXCommonClassFactory,
  2332.   (void**)&pCommonClassFactory))
  2333. return;
  2334.     if(HXR_OK != pCommonClassFactory->CreateInstance(CLSID_IHXBuffer,
  2335.    (void**)&pBuffer))
  2336.     {
  2337. pCommonClassFactory->Release();
  2338. return;
  2339.     }
  2340.     pBuffer->Set((UINT8*)codec, 5);
  2341.     sprintf(namebuf, "Codec.%03d", whichcodec); /* Flawfinder: ignore */
  2342.     pValues->SetPropertyBuffer(namebuf, pBuffer);
  2343.     pBuffer->Release();
  2344.     sprintf(namebuf, "Bandwidth.%03d", whichcodec); /* Flawfinder: ignore */
  2345.     pValues->SetPropertyULONG32(namebuf, real_bandwidth);
  2346.     sprintf(namebuf, "Priority.%03d", whichcodec); /* Flawfinder: ignore */
  2347.     pValues->SetPropertyULONG32(namebuf, sort_bandwidth);
  2348.     pCommonClassFactory->Release();
  2349. #endif // HELIX_FEATURE_RAREND_BANDWIDTH_LISTER
  2350. }
  2351. STDMETHODIMP
  2352. CRealAudioRenderer::GetBandwidthInfo(IHXValues* pValues)
  2353. {
  2354. #if defined(HELIX_FEATURE_RAREND_BANDWIDTH_LISTER)
  2355.     int whichcodec = 0;
  2356.     AddCodec(pValues, "dnet", 100, 100, whichcodec++);
  2357.     AddCodec(pValues, "dnet", 50, 50, whichcodec++);
  2358.     AddCodec(pValues, "dnet", 40, 40, whichcodec++);
  2359.     AddCodec(pValues, "dnet", 25, 25, whichcodec++);
  2360.     AddCodec(pValues, "sipr", 20, 21, whichcodec++);
  2361.     AddCodec(pValues, "dnet", 20, 20, whichcodec++);
  2362.     AddCodec(pValues, "28_8", 36, 19, whichcodec++);
  2363.     AddCodec(pValues, "dnet", 15, 15, whichcodec++);
  2364.     AddCodec(pValues, "sipr", 10, 11, whichcodec++);
  2365.     AddCodec(pValues, "dnet", 10, 10, whichcodec++);
  2366.     AddCodec(pValues, "sipr", 8,  9, whichcodec++);
  2367.     AddCodec(pValues, "sipr", 6,  8, whichcodec++);
  2368.     AddCodec(pValues, "lpcJ", 18, 7, whichcodec++);
  2369.     AddCodec(pValues, "05_6", 7, 6, whichcodec++);
  2370.     pValues->SetPropertyULONG32("CodecCount", whichcodec);
  2371. #endif // HELIX_FEATURE_RAREND_BANDWIDTH_LISTER
  2372.     return HXR_OK;
  2373. }
  2374. void CRealAudioRenderer::RemoveCurrentDryNotification()
  2375. {
  2376.     IHXAudioStream2* pAudioStream2 = NULL;
  2377.     m_pAudioStreams[m_usCurrentDryNotificationStream]->QueryInterface(IID_IHXAudioStream2,
  2378.                                                                       (void**) &pAudioStream2);
  2379.     if (pAudioStream2)
  2380.     {
  2381.         pAudioStream2->RemoveDryNotification((IHXDryNotification*) this);
  2382.         DEBUG_OUTF_IDX(m_usCurrentDryNotificationStream, RA_FLOW_FILE, (s, "Dry-Notif. Stopn"));
  2383.     }
  2384.     HX_RELEASE(pAudioStream2);
  2385. }
  2386. /************************************************************************
  2387.  * Method:
  2388.  *     IHXASMStreamSink::GetQualityPreference
  2389.  * Purpose:
  2390.  *     Gets the quality slider preference.  Used to determine how
  2391.  *     we add streams to audio services for stream switching content
  2392.  */
  2393. HX_RESULT
  2394. CRealAudioRenderer::GetQualityPreference(UINT16& usQuality)
  2395. {
  2396.     HX_RESULT pnr = HXR_OK;
  2397. #if defined(HELIX_FEATURE_PREFERENCES)
  2398.     IHXBuffer* pBuffer = NULL;
  2399.     IHXPreferences* pPreferences = 0;
  2400.     if (!m_pContext ||
  2401. m_pContext->QueryInterface(IID_IHXPreferences, (void**) &pPreferences) !=
  2402.     HXR_OK)
  2403.     {
  2404. pnr = HXR_INVALID_PARAMETER;
  2405.     }
  2406.     else
  2407.     {
  2408. ReadPrefINT16(pPreferences, "Quality", usQuality);
  2409.     }
  2410.     HX_RELEASE(pPreferences);
  2411. #endif /* #if defined(HELIX_FEATURE_PREFERENCES) */
  2412.     return pnr;
  2413. }
  2414. /************************************************************************
  2415.  * Method:
  2416.  *     IHXUpdateProperties::UpdatePacketTimeOffset
  2417.  * Purpose:
  2418.  *     Call this method to update the timestamp offset of cached packets
  2419.  */
  2420. STDMETHODIMP
  2421. CRealAudioRenderer::UpdatePacketTimeOffset(INT32 lTimeOffset)
  2422. {
  2423.     m_pMutex->Lock();
  2424.     m_ulCurrentTimelineTime += lTimeOffset;
  2425.     m_ulLatestStreamTime += lTimeOffset;
  2426.     m_fLatestStreamTime += (double) lTimeOffset;
  2427.     m_ulLatestActualTime += lTimeOffset;
  2428.     m_lTimeLineOffset -= lTimeOffset;
  2429.     HX_RESULT rc = HXR_OK;
  2430.     for (int i = 0; i < m_uNumOfSubStreams; i++)
  2431.     {
  2432.         HX_ASSERT(m_pRaFormats[i] && m_pAudioStreams[i]);
  2433. if (m_pRaFormats[i])
  2434. {
  2435.             // No interfaces in CRaFormat, so this is hard bound
  2436.             m_pRaFormats[i]->UpdatePacketTimeOffset(lTimeOffset);
  2437.         }
  2438.         if (m_pAudioStreams[i])
  2439.         {
  2440.             IHXUpdateProperties* pUpdateProperties = NULL;
  2441.             if (SUCCEEDED(rc = m_pAudioStreams[i]->QueryInterface(IID_IHXUpdateProperties,
  2442.                                                (void**) &pUpdateProperties)))
  2443.             {
  2444.                 pUpdateProperties->UpdatePacketTimeOffset(lTimeOffset);
  2445.                 HX_RELEASE(pUpdateProperties);
  2446.             }
  2447.             else
  2448.             {
  2449.                HX_ASSERT(FALSE);
  2450.                m_pMutex->Unlock();
  2451.        return rc;
  2452.             }
  2453. }
  2454.     }
  2455.     m_pMutex->Unlock();
  2456.     return rc;
  2457. }
  2458. /************************************************************************
  2459.  * Method:
  2460.  *     IHXUpdateProperties::UpdatePlayTimes
  2461.  * Purpose:
  2462.  *     Call this method to update the playtime attributes
  2463.  */
  2464. STDMETHODIMP
  2465. CRealAudioRenderer::UpdatePlayTimes(IHXValues* pProps)
  2466. {
  2467.     int     i = 0;
  2468.     UINT32  ulDelay = 0;
  2469.     UINT32  ulDuration = 0;
  2470.     m_pMutex->Lock();
  2471.     if (HXR_OK == pProps->GetPropertyULONG32("Delay", ulDelay))
  2472.     {
  2473. m_ulDelay = ulDelay;
  2474.     }
  2475.     if (HXR_OK == pProps->GetPropertyULONG32("Duration", ulDuration))
  2476.     {
  2477. m_ulDuration = ulDuration;
  2478.     }
  2479.     for (i = 0; i < m_uNumOfSubStreams; i++)
  2480.     {
  2481. m_pRaFormats[i]->UpdatePlayTimes(pProps);
  2482.     }
  2483.     m_pMutex->Unlock();
  2484.     return HXR_OK;
  2485. }
  2486. STDMETHODIMP CRealAudioRenderer::SetPropertyULONG32(const char* pName, ULONG32 ulVal)
  2487. {
  2488.     HX_RESULT retVal = HXR_FAIL;
  2489. #if defined(HELIX_FEATURE_SETSRCPROPS)
  2490.     // Check if we need to create m_pValues
  2491.     // and set the source properties
  2492.     CheckForSetSourceProperties();
  2493.     if (m_pValues)
  2494.     {
  2495.         retVal = m_pValues->SetPropertyULONG32(pName, ulVal);
  2496.     }
  2497. #endif // HELIX_FEATURE_SETSRCPROPS
  2498.     return retVal;
  2499. }
  2500. STDMETHODIMP CRealAudioRenderer::GetPropertyULONG32(const char* pName, REF(ULONG32) rulVal)
  2501. {
  2502.     HX_RESULT retVal = HXR_FAIL;
  2503. #if defined(HELIX_FEATURE_SETSRCPROPS)
  2504.     // Try to dynamically get the property first
  2505.     retVal = GetSourcePropertyULONG32(pName, rulVal);
  2506.     if (FAILED(retVal) && m_pValues)
  2507.     {
  2508.         // We failed dynamically try m_pValues
  2509.         retVal = m_pValues->GetPropertyULONG32(pName, rulVal);
  2510.     }
  2511. #endif // HELIX_FEATURE_SETSRCPROPS
  2512.     return retVal;
  2513. }
  2514. STDMETHODIMP CRealAudioRenderer::GetFirstPropertyULONG32(REF(const char*) rpName, REF(ULONG32) rulVal)
  2515. {
  2516.     HX_RESULT retVal = HXR_FAIL;
  2517. #if defined(HELIX_FEATURE_SETSRCPROPS)
  2518.     // Check if we need to create m_pValues
  2519.     // and set the source properties
  2520.     CheckForSetSourceProperties(TRUE);
  2521.     if (m_pValues)
  2522.     {
  2523.         retVal = m_pValues->GetFirstPropertyULONG32(rpName, rulVal);
  2524.     }
  2525. #endif // HELIX_FEATURE_SETSRCPROPS
  2526.     return retVal;
  2527. }
  2528. STDMETHODIMP CRealAudioRenderer::GetNextPropertyULONG32(REF(const char*) rpName, REF(ULONG32) rulVal)
  2529. {
  2530.     HX_RESULT retVal = HXR_FAIL;
  2531. #if defined(HELIX_FEATURE_SETSRCPROPS)
  2532.     // Check if we need to create m_pValues
  2533.     // and set the source properties
  2534.     CheckForSetSourceProperties();
  2535.     if (m_pValues)
  2536.     {
  2537.         retVal = m_pValues->GetNextPropertyULONG32(rpName, rulVal);
  2538.     }
  2539. #endif // HELIX_FEATURE_SETSRCPROPS
  2540.     return retVal;
  2541. }
  2542. STDMETHODIMP CRealAudioRenderer::SetPropertyBuffer(const char* pName, IHXBuffer* pVal)
  2543. {
  2544.     HX_RESULT retVal = HXR_FAIL;
  2545. #if defined(HELIX_FEATURE_SETSRCPROPS)
  2546.     // Check if we need to create m_pValues
  2547.     // and set the source properties
  2548.     CheckForSetSourceProperties();
  2549.     if (m_pValues)
  2550.     {
  2551.         retVal = m_pValues->SetPropertyBuffer(pName, pVal);
  2552.     }
  2553. #endif // HELIX_FEATURE_SETSRCPROPS
  2554.     return retVal;
  2555. }
  2556. STDMETHODIMP CRealAudioRenderer::GetPropertyBuffer(const char* pName, REF(IHXBuffer*) rpVal)
  2557. {
  2558.     HX_RESULT retVal = HXR_FAIL;
  2559. #if defined(HELIX_FEATURE_SETSRCPROPS)
  2560.     if (m_pValues)
  2561.     {
  2562.         retVal = m_pValues->GetPropertyBuffer(pName, rpVal);
  2563.     }
  2564. #endif // HELIX_FEATURE_SETSRCPROPS
  2565.     return retVal;
  2566. }
  2567. STDMETHODIMP CRealAudioRenderer::GetFirstPropertyBuffer(REF(const char*) rpName, REF(IHXBuffer*) rpVal)
  2568. {
  2569.     HX_RESULT retVal = HXR_FAIL;
  2570. #if defined(HELIX_FEATURE_SETSRCPROPS)
  2571.     // Check if we need to create m_pValues
  2572.     // and set the source properties
  2573.     CheckForSetSourceProperties(TRUE);
  2574.     if (m_pValues)
  2575.     {
  2576.         retVal = m_pValues->GetFirstPropertyBuffer(rpName, rpVal);
  2577.     }
  2578. #endif // HELIX_FEATURE_SETSRCPROPS
  2579.     return retVal;
  2580. }
  2581. STDMETHODIMP CRealAudioRenderer::GetNextPropertyBuffer(REF(const char*) rpName, REF(IHXBuffer*) rpVal)
  2582. {
  2583.     HX_RESULT retVal = HXR_FAIL;
  2584. #if defined(HELIX_FEATURE_SETSRCPROPS)
  2585.     // Check if we need to create m_pValues
  2586.     // and set the source properties
  2587.     CheckForSetSourceProperties();
  2588.     if (m_pValues)
  2589.     {
  2590.         retVal = m_pValues->GetNextPropertyBuffer(rpName, rpVal);
  2591.     }
  2592. #endif // HELIX_FEATURE_SETSRCPROPS
  2593.     return retVal;
  2594. }
  2595. STDMETHODIMP CRealAudioRenderer::SetPropertyCString(const char* pName, IHXBuffer* pVal)
  2596. {
  2597.     HX_RESULT retVal = HXR_FAIL;
  2598. #if defined(HELIX_FEATURE_SETSRCPROPS)
  2599.     // Check if we need to create m_pValues
  2600.     // and set the source properties
  2601.     CheckForSetSourceProperties();
  2602.     if (m_pValues)
  2603.     {
  2604.         retVal = m_pValues->SetPropertyCString(pName, pVal);
  2605.     }
  2606. #endif // HELIX_FEATURE_SETSRCPROPS
  2607.     return retVal;
  2608. }
  2609. STDMETHODIMP CRealAudioRenderer::GetPropertyCString(const char* pName, REF(IHXBuffer*) rpVal)
  2610. {
  2611.     HX_RESULT retVal = HXR_FAIL;
  2612. #if defined(HELIX_FEATURE_SETSRCPROPS)
  2613.     // Try to dynamically get the property first
  2614.     retVal = GetSourcePropertyCString(pName, rpVal);
  2615.     if (FAILED(retVal) && m_pValues)
  2616.     {
  2617.         // We failed dynamically try m_pValues
  2618.         retVal = m_pValues->GetPropertyCString(pName, rpVal);
  2619.     }
  2620. #endif // HELIX_FEATURE_SETSRCPROPS
  2621.     return retVal;
  2622. }
  2623. STDMETHODIMP CRealAudioRenderer::GetFirstPropertyCString(REF(const char*) rpName, REF(IHXBuffer*) rpVal)
  2624. {
  2625.     HX_RESULT retVal = HXR_FAIL;
  2626. #if defined(HELIX_FEATURE_SETSRCPROPS)
  2627.     // Check if we need to create m_pValues
  2628.     // and set the source properties
  2629.     CheckForSetSourceProperties(TRUE);
  2630.     if (m_pValues)
  2631.     {
  2632.         retVal = m_pValues->GetFirstPropertyCString(rpName, rpVal);
  2633.     }
  2634. #endif // HELIX_FEATURE_SETSRCPROPS
  2635.     return retVal;
  2636. }
  2637. STDMETHODIMP CRealAudioRenderer::GetNextPropertyCString(REF(const char*) rpName, REF(IHXBuffer*) rpVal)
  2638. {
  2639.     HX_RESULT retVal = HXR_FAIL;
  2640. #if defined(HELIX_FEATURE_SETSRCPROPS)
  2641.     // Check if we need to create m_pValues
  2642.     // and set the source properties
  2643.     CheckForSetSourceProperties();
  2644.     if (m_pValues)
  2645.     {
  2646.         retVal = m_pValues->GetNextPropertyCString(rpName, rpVal);
  2647.     }
  2648. #endif // HELIX_FEATURE_SETSRCPROPS
  2649.     return retVal;
  2650. }
  2651. void CRealAudioRenderer::CheckForSetSourceProperties(BOOL bForceRefresh)
  2652. {
  2653. #if defined(HELIX_FEATURE_SETSRCPROPS)
  2654.     // Do we already have m_pValues?
  2655.     if (!m_pValues && m_pCommonClassFactory)
  2656.     {
  2657.         // Create m_pValues
  2658.         m_pCommonClassFactory->CreateInstance(CLSID_IHXValues, (void**) &m_pValues);
  2659.         // Force a refresh if we just created m_pValues
  2660.         bForceRefresh = TRUE;
  2661.     }
  2662.     if (m_pValues && bForceRefresh)
  2663.     {
  2664.         // Refresh the source prroperties
  2665.         UINT32     ulValue = 0;
  2666.         IHXBuffer* pBuffer = NULL;
  2667.         if (SUCCEEDED(GetSourcePropertyCString("SrcCodec", pBuffer)))
  2668.         {
  2669.             m_pValues->SetPropertyCString("SrcCodec", pBuffer);
  2670.         }
  2671.         if (SUCCEEDED(GetSourcePropertyULONG32("SrcBitRate", ulValue)))
  2672.         {
  2673.             m_pValues->SetPropertyULONG32("SrcBitRate", ulValue);
  2674.         }
  2675.         if (SUCCEEDED(GetSourcePropertyULONG32("SrcVBREnabled", ulValue)))
  2676.         {
  2677.             m_pValues->SetPropertyULONG32("SrcVBREnabled", ulValue);
  2678.         }
  2679.         if (SUCCEEDED(GetSourcePropertyULONG32("SrcSamplesPerSecond", ulValue)))
  2680.         {
  2681.             m_pValues->SetPropertyULONG32("SrcSamplesPerSecond", ulValue);
  2682.         }
  2683.         if (SUCCEEDED(GetSourcePropertyULONG32("SrcBitsPerSample", ulValue)))
  2684.         {
  2685.             m_pValues->SetPropertyULONG32("SrcBitsPerSample", ulValue);
  2686.         }
  2687.         if (SUCCEEDED(GetSourcePropertyULONG32("SrcNumChannels", ulValue)))
  2688.         {
  2689.             m_pValues->SetPropertyULONG32("SrcNumChannels", ulValue);
  2690.         }
  2691.         if (SUCCEEDED(GetSourcePropertyULONG32("SrcInterleaved", ulValue)))
  2692.         {
  2693.             m_pValues->SetPropertyULONG32("SrcInterleaved", ulValue);
  2694.         }
  2695.         HX_RELEASE(pBuffer);
  2696.     }
  2697. #endif // HELIX_FEATURE_SETSRCPROPS
  2698. }
  2699. HX_RESULT CRealAudioRenderer::GetSourcePropertyULONG32(const char* pszProp, REF(ULONG32) rulVal)
  2700. {
  2701.     HX_RESULT retVal = HXR_FAIL;
  2702. #if defined(HELIX_FEATURE_SETSRCPROPS)
  2703.     // First we must decide which substream to use. If we
  2704.     // have received a packet, then we use
  2705.     // m_usCurrentDryNotificationStream (checking that it
  2706.     // is not NO_STREAM_SET, of course). If we have not received
  2707.     // a packet, then we use m_ulSrcPropertySubStream (checking
  2708.     // that it is not NO_STREAM_SET, of course). If we can't
  2709.     // use either of these, then we fail.
  2710.     UINT32 ulSubStream = NO_STREAM_SET;
  2711.     // Have we received a packet yet?
  2712.     if (!m_bFirstPacket)
  2713.     {
  2714.         // Try to use m_usCurrentDryNotificationStream
  2715.         if (m_usCurrentDryNotificationStream != NO_STREAM_SET)
  2716.         {
  2717.             ulSubStream = m_usCurrentDryNotificationStream;
  2718.         }
  2719.     }
  2720.     if (ulSubStream == NO_STREAM_SET)
  2721.     {
  2722.         // Try to use m_ulSrcPropertySubStream
  2723.         if (m_ulSrcPropertySubStream != NO_STREAM_SET)
  2724.         {
  2725.             ulSubStream = m_ulSrcPropertySubStream;
  2726.         }
  2727.     }
  2728.     if (ulSubStream != NO_STREAM_SET &&
  2729.         ulSubStream < m_uNumOfSubStreams &&
  2730.         m_pRaFormats[ulSubStream])
  2731.     {
  2732.         if (!strcmp(pszProp, "SrcBitRate"))
  2733.         {
  2734.             rulVal = m_pRaFormats[ulSubStream]->GetBitRate();
  2735.             retVal = HXR_OK;
  2736.         }
  2737.         else if (!strcmp(pszProp, "SrcVBREnabled"))
  2738.         {
  2739.             rulVal = 0;
  2740.             retVal = HXR_OK;
  2741.         }
  2742.         else if (!strcmp(pszProp, "SrcSamplesPerSecond"))
  2743.         {
  2744.             rulVal = m_pRaFormats[ulSubStream]->GetSamplesPerSecond();
  2745.             retVal = HXR_OK;
  2746.         }
  2747.         else if (!strcmp(pszProp, "SrcBitsPerSample"))
  2748.         {
  2749.             rulVal = m_pRaFormats[ulSubStream]->GetBitsPerSample();
  2750.             retVal = HXR_OK;
  2751.         }
  2752.         else if (!strcmp(pszProp, "SrcNumChannels"))
  2753.         {
  2754.             rulVal = m_pRaFormats[ulSubStream]->GetNumChannels();
  2755.             retVal = HXR_OK;
  2756.         }
  2757.         else if (!strcmp(pszProp, "SrcInterleaved"))
  2758.         {
  2759.             rulVal = m_pRaFormats[ulSubStream]->IsInterleaved();
  2760.             retVal = HXR_OK;
  2761.         }
  2762.     }
  2763. #endif // HELIX_FEATURE_SETSRCPROPS
  2764.     return retVal;
  2765. }
  2766. HX_RESULT CRealAudioRenderer::GetSourcePropertyCString(const char* pszProp, REF(IHXBuffer*) rpBuffer)
  2767. {
  2768.     HX_RESULT retVal = HXR_FAIL;
  2769. #if defined(HELIX_FEATURE_SETSRCPROPS)
  2770.     // First we must decide which substream to use. If we
  2771.     // have received a packet, then we use
  2772.     // m_usCurrentDryNotificationStream (checking that it
  2773.     // is not NO_STREAM_SET, of course). If we have not received
  2774.     // a packet, then we use m_ulSrcPropertySubStream (checking
  2775.     // that it is not NO_STREAM_SET, of course). If we can't
  2776.     // use either of these, then we fail.
  2777.     UINT32 ulSubStream = NO_STREAM_SET;
  2778.     // Have we received a packet yet?
  2779.     if (!m_bFirstPacket)
  2780.     {
  2781.         // Try to use m_usCurrentDryNotificationStream
  2782.         if (m_usCurrentDryNotificationStream != NO_STREAM_SET)
  2783.         {
  2784.             ulSubStream = m_usCurrentDryNotificationStream;
  2785.         }
  2786.     }
  2787.     if (ulSubStream == NO_STREAM_SET)
  2788.     {
  2789.         // Try to use m_ulSrcPropertySubStream
  2790.         if (m_ulSrcPropertySubStream != NO_STREAM_SET)
  2791.         {
  2792.             ulSubStream = m_ulSrcPropertySubStream;
  2793.         }
  2794.     }
  2795.     if (ulSubStream != NO_STREAM_SET &&
  2796.         ulSubStream < m_uNumOfSubStreams &&
  2797.         m_pRaFormats[ulSubStream])
  2798.     {
  2799.         if (!strcmp(pszProp, "SrcCodec"))
  2800.         {
  2801.             retVal = CreateStringBuffer(rpBuffer,
  2802.                                         m_pRaFormats[ulSubStream]->GetCodecName(),
  2803.                                         m_pContext);
  2804.         }
  2805.     }
  2806. #endif // HELIX_FEATURE_SETSRCPROPS
  2807.     return retVal;
  2808. }
  2809. void CRealAudioRenderer::LogAudioWrite(UINT16 uStreamNumber,
  2810.        HXAudioData* pAudioData,
  2811.        UINT32 ulActualTimestamp,
  2812.        HX_RESULT retVal)
  2813. {
  2814.     DEBUG_OUTF_IDX(uStreamNumber, RA_FLOW_FILE,
  2815. (s, "AWrite: %u[%u%]<-->%u[%u%] %s %sn",
  2816.  pAudioData->ulAudioTime,
  2817.  ulActualTimestamp,
  2818.  pAudioData->ulAudioTime +
  2819.     ((UINT32) (m_pRaFormats[uStreamNumber]->ConvertBytesToMs(pAudioData->pData->GetSize()))),
  2820.  ulActualTimestamp +
  2821.     ((UINT32) (m_pRaFormats[uStreamNumber]->ConvertBytesToMs(pAudioData->pData->GetSize()))),
  2822.  (pAudioData->uAudioStreamType == STREAMING_AUDIO) ? "STREAMING" : "TIMED",
  2823.  (retVal == HXR_OK) ? "OK" : "FAIL"));
  2824. }
  2825. HX_RESULT CRealAudioRenderer::_OnPacket(IHXPacket* pPacket, INT32 lTimeOffset)
  2826. {
  2827.     HX_RESULT     retVal = HXR_OK;
  2828.     UINT16     uStreamForThisPacket = 0;
  2829.     m_lTimeLineOffset = lTimeOffset;
  2830. #ifdef _MACINTOSH
  2831.     if (m_pDryCallback != NULL)
  2832.     {
  2833. HX_ASSERT(m_bReportOKStatus);
  2834. m_pDryCallback->Cancel();
  2835. m_pDryCallback->Func();
  2836. HX_RELEASE(m_pDryCallback);
  2837.     }
  2838. #endif
  2839.     DEBUG_OUTF(RASYNC_FILE, (s, "RAtOnPacket:t%lun",  pPacket->GetTime()));
  2840.     /* Ignore any pre-seek packets or NULL packets */
  2841.     if (m_bInSeekMode || pPacket == NULL)
  2842.     {
  2843. return HXR_OK;
  2844.     }
  2845. #ifdef _MACINTOSH
  2846.     m_bProcessingPacket = TRUE;
  2847. #endif // _MACINTOSH
  2848.     m_pMutex->Lock();
  2849.     if(pPacket->IsLost())
  2850.     {
  2851. if (m_bStreamSwitchable)
  2852. {
  2853.     for (int i = 0; i < m_uNumOfSubStreams; i++)
  2854.     {
  2855. m_pRaFormats[i]->LossOccured();
  2856.     }
  2857. }
  2858. else
  2859. {
  2860.     m_pRaFormats[uStreamForThisPacket]->OnPacket(pPacket, lTimeOffset,
  2861. m_pRuleToFlagMap->rule_to_flag_map);
  2862. }
  2863. DEBUG_OUT(m_pErrorMessages, DOL_REALAUDIO_EXTENDED, (s, "ptLostt?t?"));
  2864. DEBUG_OUTF(ONPACKET_FILE, (s, "ptLostt?t?n"));
  2865.     }
  2866.     else
  2867.     {
  2868. DEBUG_OUT(m_pErrorMessages, DOL_REALAUDIO_EXTENDED, (s, "pt%ut%lut%u",
  2869.     (m_bStreamSwitchable)?(m_pRuleMap[pPacket->GetASMRuleNumber()]):(0), pPacket->GetTime(),
  2870.     pPacket->GetASMRuleNumber()));
  2871. DEBUG_OUTF(ONPACKET_FILE, (s, "pt%ut%lut%ut%un",
  2872.     (m_bStreamSwitchable)?(m_pRuleMap[pPacket->GetASMRuleNumber()]):(0), pPacket->GetTime(),
  2873.     pPacket->GetASMRuleNumber(), pPacket->GetASMFlags()));
  2874. UINT32 ulCurrentPacketTime = pPacket->GetTime();
  2875. if (m_bStreamSwitchable)
  2876. {
  2877.     uStreamForThisPacket = m_pRuleMap[pPacket->GetASMRuleNumber()];
  2878. }
  2879. /*
  2880.  * if this packet is late, we don't want to add it to the format so we don't
  2881.  * think we are switching to a stream with packets that are late.
  2882.  * late packets could happen if the "time out" for the last packets
  2883.  * of the from stream happened and we considered the rest of them
  2884.  * lost.  If that is why this packet is late, nothing we can do but
  2885.  * throw it away.  If a packet is late for some other reason
  2886.  * it's either bad content or something else messed up with the
  2887.  * stream and we could be harsh and stop the stream but I'd rather
  2888.  * think we should drop the packet and continue.
  2889.  */
  2890. if (NO_TIME_SET == m_pRaFormats[uStreamForThisPacket]->m_ulLastPacketTime ||
  2891.     IsTimeGreaterOrEqual(ulCurrentPacketTime, m_pRaFormats[uStreamForThisPacket]->m_ulLastPacketTime))
  2892. {
  2893.     if (!m_bDelayOffsetSet)
  2894.     {
  2895. IHXStreamSource* pSource = NULL;
  2896. m_pStream->GetSource(pSource);
  2897. // the delay is always 0 based and we might not start from 0 in live
  2898. // since we compare packet times with delay, we want to make delay
  2899. // relative to my packet stream times instead of 0.  We just update
  2900. // delay here because the time of the first packet adjusted for the
  2901. // the time offset is the time we want to be writing to audio services
  2902. // and it will be the delay.
  2903. if (pSource != NULL && pSource->IsLive())
  2904. {
  2905.     m_ulDelay = AdjustTimestamp(pPacket->GetTime(), lTimeOffset);
  2906.     // since the core will not call OnTimeSync() till it fulfils the preroll,
  2907.     // for live streams, m_ulCurrentTimelineTime will be set to 0 during initial
  2908.     // buffering. If we happen to call reportrebufferstatus for a delayed
  2909.     // live stream running for long duration -- more than MAX_TIMESTAMP_GAP),
  2910.     // we will never come out of buffering since
  2911.     // IsTimeGreaterOrEqual will fail and we will never call
  2912.     // reportrebufferstatus(1,1).
  2913.     m_ulCurrentTimelineTime = m_ulDelay;
  2914. }
  2915. HX_RELEASE(pSource);
  2916. m_bDelayOffsetSet = TRUE;
  2917. #ifdef HELIX_FEATURE_RAREND_PREREDSTONE_SUPPORT
  2918. if (m_bPreRedstonePlayer)
  2919. {
  2920.     // XXXJEFFA hack here for Live SureStream content with U3 players
  2921.     // and earlier.  There is a bug in AudioServices, fixed in
  2922.     // pnaudiohxaudstr.cpp rev 1.11 where the audio streams that don't
  2923.     // get written to from the start of the stream (the ones we switch to
  2924.     // after initial subscription) will reset their lastWriteTime to the
  2925.     // base time the first time we write to them instead of having
  2926.     // accumulated time from the start of the stream along with the
  2927.     // stream we have been writing.  Writing a 0 size instantainious audio
  2928.     // buffer here gets the lastWriteTime of the stream set to the live
  2929.     // base time from the beginning and works around the bug.
  2930.     //
  2931.     HXAudioData audioData;
  2932.     audioData.ulAudioTime = 0;
  2933.     audioData.uAudioStreamType = INSTANTANEOUS_AUDIO;
  2934.     m_pCommonClassFactory->CreateInstance(CLSID_IHXBuffer, (void**)&(audioData.pData));
  2935.     if (audioData.pData != NULL)
  2936.     {
  2937. audioData.pData->SetSize(0);
  2938. for (int k = 0; k < m_uNumOfSubStreams; k++)
  2939. {
  2940.     m_pAudioStreams[k]->Write( &audioData );
  2941.     LogAudioWrite((UINT16) k,
  2942.   &audioData,
  2943.   audioData.ulAudioTime,
  2944.   HXR_OK);
  2945. }
  2946. HX_RELEASE(audioData.pData);
  2947.     }
  2948. }
  2949. #endif // HELIX_FEATURE_RAREND_PREREDSTONE_SUPPORT
  2950.     }
  2951.     if (m_bFirstPacket)
  2952.     {
  2953. AddDryNotification(uStreamForThisPacket);
  2954. m_bFirstPacket = FALSE;
  2955.     }
  2956.     // pass the packet to the RaFormat
  2957.     m_pRaFormats[uStreamForThisPacket]->OnPacket(pPacket, lTimeOffset,
  2958. m_pRuleToFlagMap->rule_to_flag_map);
  2959.     // record this is the last packet time we've seen on this
  2960.     // stream
  2961.     m_pRaFormats[uStreamForThisPacket]->m_ulLastPacketTime =
  2962. ulCurrentPacketTime;
  2963. }
  2964.     }
  2965.     if (m_PlayState != playing)
  2966.     {
  2967. // Take this chance to write audio to audio services
  2968. UINT32 ulAudioTime;
  2969. DoAudio(ulAudioTime);
  2970.     }
  2971.     // Handle exiting rebuffer started by OnDryNotification from
  2972.     // Audio Services
  2973.     if(!pPacket->IsLost() && m_bReportOKStatus)
  2974.     {
  2975.         // if we've recieved a packet that fills our preroll
  2976. // and we have data to write, then we report we've recieved 
  2977. // all the packets we need
  2978. if (HaveDataToWrite() &&
  2979.     IsTimeGreaterOrEqual(AdjustTimestamp(pPacket->GetTime(), 
  2980.  lTimeOffset),
  2981.     (m_ulCurrentTimelineTime + max(m_ulPreroll, 1000))))
  2982.         {
  2983.     m_bReportOKStatus = FALSE;
  2984.     m_pStream->ReportRebufferStatus(1,1);
  2985.     DEBUG_OUT(m_pErrorMessages, DOL_REALAUDIO,
  2986. (s, "Leaving Bufferingt%ut%ut%lu", m_usCurrentDryNotificationStream, uStreamForThisPacket, pPacket->GetTime()));
  2987.     DEBUG_OUTF(SWITCH_FILE,
  2988. (s, "Leaving Bufferingt%ut%un", m_usCurrentDryNotificationStream, uStreamForThisPacket));
  2989. }
  2990.     }
  2991. #ifdef _MACINTOSH
  2992.     m_bProcessingPacket = FALSE;
  2993. #endif // _MACINTOSH
  2994.     m_pMutex->Unlock();
  2995.     return retVal;
  2996. }
  2997. HX_RESULT STDAPICALLTYPE CRealAudioRenderer::HXCreateInstance(IUnknown** ppUnk)
  2998. {
  2999.     HX_RESULT retVal = HXR_FAIL;
  3000.     if (ppUnk)
  3001.     {
  3002.         CRealAudioRenderer* pObj = new CRealAudioRenderer();
  3003.         if (pObj)
  3004.         {
  3005.             retVal = pObj->QueryInterface(IID_IUnknown, (void**) ppUnk);
  3006.             if (FAILED(retVal))
  3007.             {
  3008.                 HX_DELETE(pObj);
  3009.             }
  3010.         }
  3011.     }
  3012.     return retVal;
  3013. }