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

Symbian

开发平台:

C/C++

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