rarender.cpp
上传用户:zhongxx05
上传日期:2007-06-06
资源大小:33641k
文件大小:106k
- /* ***** BEGIN LICENSE BLOCK *****
- * Version: RCSL 1.0/RPSL 1.0
- *
- * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved.
- *
- * The contents of this file, and the files included with this file, are
- * subject to the current version of the RealNetworks Public Source License
- * Version 1.0 (the "RPSL") available at
- * http://www.helixcommunity.org/content/rpsl unless you have licensed
- * the file under the RealNetworks Community Source License Version 1.0
- * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl,
- * in which case the RCSL will apply. You may also obtain the license terms
- * directly from RealNetworks. You may not use this file except in
- * compliance with the RPSL or, if you have a valid RCSL with RealNetworks
- * applicable to this file, the RCSL. Please see the applicable RPSL or
- * RCSL for the rights, obligations and limitations governing use of the
- * contents of the file.
- *
- * This file is part of the Helix DNA Technology. RealNetworks is the
- * developer of the Original Code and owns the copyrights in the portions
- * it created.
- *
- * This file, and the files included with this file, is distributed and made
- * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- *
- * Technology Compatibility Kit Test Suite(s) Location:
- * http://www.helixcommunity.org/content/tck
- *
- * Contributor(s):
- *
- * ***** END LICENSE BLOCK ***** */
- /****************************************************************************
- * Includes
- */
- #include "hlxclib/stdio.h"
- #include "hlxclib/string.h" // needed for memcpy, needed by hxmarsh.h
- #include "rarender.ver"
- #include "rarender.h"
- #if defined(HELIX_FEATURE_PREFERENCES)
- #include "hxprefs.h"
- #include "hxprefutil.h"
- #endif /* HELIX_FEATURE_PREFERENCES */
- #ifdef _WINCE
- #include <winbase.h>
- #endif
- #include "hxtypes.h"
- #include "hxver.h"
- /****************************************************************************
- * Defines
- */
- #ifdef _DEBUG
- #undef HX_THIS_FILE
- static const char HX_THIS_FILE[] = __FILE__;
- #endif
- #define MAXIMUM_GRANULARITY 100
- #define MINIMUM_GRANULARITY 20
- #define DEFAULT_DRY_NOTIFICATION 0
- #define MAX_TRANSPORT_BUFFER_DURATION 20000
- //#define RA_TEST_LOSS
- #if !defined(HELIX_FEATURE_DLLACCESS_CLIENT)
- ENABLE_DLLACCESS_PATHS(RACodec);
- #endif // HELIX_FEATURE_DLLACCESS_CLIENT
- //#define RARENDER_LOGING_ON
- #ifdef RARENDER_LOGING_ON
- #define LOG_PATH "C:\Log\rarender\"
- #define RASYNC_FILE LOG_PATH##"sync.txt"
- #define ONPACKET_FILE LOG_PATH##"packet.txt"
- #define AUDIOSERVICES_FILE LOG_PATH##"write.txt"
- #define SWITCH_FILE LOG_PATH##"switch.txt"
- #define DOAUDIO_FILE LOG_PATH##"doaudio.txt"
- #define PREREDSTONE_FILE LOG_PATH##"hack.txt"
- #define LATESTPACKET_FILE LOG_PATH##"latest.txt"
- #define LOSS_FILE LOG_PATH##"loss.txt"
- #else
- #define RASYNC_FILE 0
- #define ONPACKET_FILE 0
- #define AUDIOSERVICES_FILE 0
- #define SWITCH_FILE 0
- #define DOAUDIO_FILE 0
- #define PREREDSTONE_FILE 0
- #define LATESTPACKET_FILE 0
- #define LOSS_FILE 0
- #endif
- #ifdef LOG_BUFFERING_ENABLED
- #define BUF_LOG_FILE "C:\buffer.txt"
- #define LOG_BUFFERING(x, y) {
- char* s = NULL;
- FILE* f1;
- s = new char[2048];
- if(s){
- sprintf y; /* Flawfinder: ignore */
- f1 = (x)?(::fopen(x, "a+")):(NULL);
- (f1)?(::fprintf(f1, s), ::fclose(f1)):(0);
- delete [] s;
- }
- }
- #else // LOG_BUFFERING_ENABLED
- #define LOG_BUFFERING(x, y)
- #endif // LOG_BUFFERING_ENABLED
- // The value of 120 for audio pushdown presumes an AUDIO_GRANULARITY of 40:
- // 120 = 3 blocks. Note that this value is too small for general use and
- // may need to be tweaked depending on the cpu and hardware being used. A
- // slower system than the one tested on may not be able to keep pnaudio from
- // starving with buffers this small.
- #define OPTIMAL_HEAP_MIN_AUDIO_PUSHDOWN 480 // ms
- const char* const CRealAudioRenderer::zm_pName = "RealAudio";
- const char* const CRealAudioRenderer::zm_pDescription = "RealNetworks RealAudio Renderer Plugin";
- const char* const CRealAudioRenderer::zm_pCopyright = "(c) 1995-2002 RealNetworks, Inc. All rights reserved.rnrn"
- "RealNetworks RealAudio 8 Audio Codec:rn"
- "Copyright (c) 1995-2002 RealNetworks, Inc. All rights reserved.rnrn"
- "ATRAC3rn"
- "Copyright (c) 2000 Sony Corporation. All rights reserved.rnrn"
- "aacPlusrn"
- "aacPlus developed by Coding Technologies. All rights reserved.rnrn"
- "DolbyNet(tm) audio system manufactured under license from Dolby Laboratories Licensing Corporation.rn"
- "Copyright (c) 1996-1997, Dolby Laboratories Licensing Corporation. All rights reserved.rnrn"
- "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"
- "The ACELP(r).net codec in this product is used under license from VoiceAge Corporationrn"
- "Copyright (c) 1998,1999, 2000 VoiceAge Corporation. All rights reserved.rn";
- const char* const CRealAudioRenderer::zm_pMoreInfoURL = HXVER_MOREINFO;
- const char* const CRealAudioRenderer::zm_pStreamMimeTypes[] =
- {REALAUDIO_MIME_TYPE, REALAUDIO_MULTIRATE_MIME_TYPE, REALAUDIO_MULTIRATE_LIVE_MIME_TYPE, NULL};
- const char* const CRealAudioRenderer::zm_pAdditionalAutoUpgradeInfo[] =
- {"", "#unk_c"};
- /// These two constants are consistent with those defined in
- /// HXWatermarkBufferControl
- #define REBUFFERING_SKIP
- #define MAX_TRANSPORT_BUFFER_DURATION 20000
- #define MAX_TRASPORT_BUFFER_BYTES 3000000
- /************************************************************************
- * Method:
- * IHXPlugin::InitPlugin
- * Purpose:
- * Initializes the plugin for use. This interface must always be
- * called before any other method is called. This is primarily needed
- * so that the plugin can have access to the context for creation of
- * IHXBuffers and IMalloc.
- */
- STDMETHODIMP CRealAudioRenderer::InitPlugin(IUnknown* /*IN*/ pContext)
- {
- m_pContext = pContext;
- m_pContext->AddRef();
- if (HXR_OK != m_pContext->QueryInterface(IID_IHXCommonClassFactory, (void **)&m_pCommonClassFactory))
- {
- return HXR_FAILED;
- }
- #if defined(HELIX_FEATURE_STATS)
- m_pContext->QueryInterface(IID_IHXRegistry, (void**)&m_pRegistry);
- #endif // HELIX_FEATURE_STATS
- return HXR_OK;
- }
- /************************************************************************
- * Method:
- * IHXPlugin::GetPluginInfo
- * Purpose:
- * Returns the basic information about this plugin. Including:
- *
- * bLoadMultiple whether or not this plugin DLL can be loaded
- * multiple times. All File Formats must set
- * this value to TRUE.
- * pDescription which is used in about UIs (can be NULL)
- * pCopyright which is used in about UIs (can be NULL)
- * pMoreInfoURL which is used in about UIs (can be NULL)
- */
- STDMETHODIMP CRealAudioRenderer::GetPluginInfo
- (
- REF(BOOL) /*OUT*/ bLoadMultiple,
- REF(const char*) /*OUT*/ pDescription,
- REF(const char*) /*OUT*/ pCopyright,
- REF(const char*) /*OUT*/ pMoreInfoURL,
- REF(ULONG32) /*OUT*/ ulVersionNumber
- )
- {
- bLoadMultiple = TRUE; // Must be true for file formats.
- pDescription = zm_pDescription;
- pCopyright = zm_pCopyright;
- pMoreInfoURL = zm_pMoreInfoURL;
- ulVersionNumber = TARVER_ULONG32_VERSION;
- return HXR_OK;
- }
- /************************************************************************
- * Method:
- * IHXPlugin::GetRendererInfo
- * Purpose:
- * If this object is a file format object this method returns
- * information vital to the instantiation of file format plugins.
- * If this object is not a file format object, it should return
- * HXR_UNEXPECTED.
- */
- STDMETHODIMP CRealAudioRenderer::GetRendererInfo
- (
- REF(const char**) /*OUT*/ pStreamMimeTypes,
- REF(UINT32) /*OUT*/ unInitialGranularity
- )
- {
- pStreamMimeTypes = (const char**)zm_pStreamMimeTypes;
- unInitialGranularity = m_ulCurrentGranularity; // OnTimeSync() every 100ms
- return HXR_OK;
- }
- // *** IUnknown methods ***
- /////////////////////////////////////////////////////////////////////////
- // Method:
- // IUnknown::QueryInterface
- // Purpose:
- // Implement this to export the interfaces supported by your
- // object.
- //
- STDMETHODIMP CRealAudioRenderer::QueryInterface(REFIID riid, void** ppvObj)
- {
- QInterfaceList qiList[] =
- {
- { GET_IIDHANDLE(IID_IUnknown), (IUnknown*) (IHXPlugin*) this},
- { GET_IIDHANDLE(IID_IHXPlugin), (IHXPlugin*) this},
- { GET_IIDHANDLE(IID_IHXRenderer), (IHXRenderer*) this},
- { GET_IIDHANDLE(IID_IHXInterruptSafe), (IHXInterruptSafe*) this},
- { GET_IIDHANDLE(IID_IHXASMStreamSink), (IHXASMStreamSink*) this},
- { GET_IIDHANDLE(IID_IHXDryNotification), (IHXDryNotification*) this},
- #if defined(HELIX_FEATURE_RAREND_BANDWIDTH_LISTER)
- { GET_IIDHANDLE(IID_IHXBandwidthLister), (IHXBandwidthLister*) this},
- #endif // HELIX_FEATURE_RAREND_BANDWIDTH_LISTER
- #if defined(HELIX_FEATURE_STATS)
- { GET_IIDHANDLE(IID_IHXStatistics), (IHXStatistics*) this},
- #endif // HELIX_FEATURE_STATS
- #if defined(HELIX_FEATURE_SETSRCPROPS)
- { GET_IIDHANDLE(IID_IHXValues), (IHXValues*) this},
- #endif /* #if defined(HELIX_FEATURE_SETSRCPROPS) */
- { GET_IIDHANDLE(IID_IHXUpdateProperties), (IHXUpdateProperties*) this}
- };
- return QIFind(qiList, QILISTSIZE(qiList), riid, ppvObj);
- }
- /////////////////////////////////////////////////////////////////////////
- // Method:
- // IUnknown::AddRef
- // Purpose:
- // Everyone usually implements this the same... feel free to use
- // this implementation.
- //
- STDMETHODIMP_(ULONG32) CRealAudioRenderer::AddRef()
- {
- return _AddRef();
- }
- /////////////////////////////////////////////////////////////////////////
- // Method:
- // IUnknown::Release
- // Purpose:
- // Everyone usually implements this the same... feel free to use
- // this implementation.
- //
- STDMETHODIMP_(ULONG32) CRealAudioRenderer::Release()
- {
- return _Release();
- }
- CRealAudioRenderer::CRealAudioRenderer()
- : m_lRefCount(0)
- , m_pContext(NULL)
- , m_pStream(NULL)
- , m_pBufferingStats(NULL)
- , m_ulPreroll(0)
- , m_bReportOKStatus(FALSE)
- , m_ulCurrentTimelineTime(0)
- , m_pAudioPlayer(NULL)
- , m_pAudioPushdown2(NULL)
- , m_pCommonClassFactory(NULL)
- , m_ulRegistryID(0)
- , m_pRegistry(NULL)
- , m_ulSmartStreamRegID(0)
- , m_ulNameRegID(0)
- , m_ulCodecRegID(0)
- , m_ulRateRegID(0)
- , m_ulChannelsRegID(0)
- , m_ulSurroundRegID(0)
- , m_bEndOfPackets(FALSE)
- , m_bDoneWritingPackets(FALSE)
- , m_bInSeekMode(FALSE)
- , m_ulCurrentGranularity(MAXIMUM_GRANULARITY)
- , m_bStreamSwitchable(FALSE)
- , m_uNumOfSubStreams(0)
- , m_uNumOfRules(0)
- , m_ulDuration(0)
- , m_bFirstPacket(TRUE)
- , m_bDelayOffsetSet(FALSE)
- , m_bAllStreamsToBeUnregistered(FALSE)
- , m_ulLatestStreamTime(NO_TIME_SET)
- , m_fLatestStreamTime(0.0)
- , m_ulLatestActualTime(NO_TIME_SET)
- , m_ulDelay(0)
- , m_lTimeLineOffset(0)
- , m_usCurrentDryNotificationStream(NO_STREAM_SET)
- , m_usPreviousDryNotificationStream(NO_STREAM_SET)
- , m_usThisSourceStream(NO_STREAM_SET)
- , m_pErrorMessages(0)
- , m_pRuleToFlagMap(NULL)
- , m_pMutex(NULL)
- #ifdef _MACINTOSH
- , m_bProcessingPacket(FALSE)
- , m_pDryCallback(NULL)
- #endif
- , m_pRuleMap(NULL)
- , m_pRaFormats(NULL)
- , m_pAudioStreams(NULL)
- , m_PlayState(stopped)
- , m_bPreRedstonePlayer(TRUE)
- , m_uSyncUnregisterStream(NO_STREAM_SET)
- , m_ulSyncUnregisterTime(NO_TIME_SET)
- #if defined(HELIX_CONFIG_SLUGGISHAUTOUPGRADE)
- , m_pASMStream(NULL)
- #endif
- , m_pValues(NULL)
- , m_ulSrcPropertySubStream(NO_STREAM_SET)
- , m_ppVBRDepack(NULL)
- {
- }
- CRealAudioRenderer::~CRealAudioRenderer()
- {
- EndStream();
- HX_DELETE(m_pMutex);
- }
- // *** IHXRenderer methods ***
- /////////////////////////////////////////////////////////////////////////
- // Method:
- // IHXRenderer::StartStream
- // Purpose:
- // Called by client engine to inform the renderer of the stream it
- // will be rendering. The stream interface can provide access to
- // its source or player. This method also provides access to the
- // primary client controller interface.
- //
- STDMETHODIMP
- CRealAudioRenderer::StartStream
- (
- IHXStream* pStream,
- IHXPlayer* pPlayer
- )
- {
- HX_RESULT hr = HXR_OK;
- // Save for later use!
- m_pStream = pStream;
- if (m_pStream)
- {
- m_pStream->AddRef();
- }
- // get interface to report errors
- if (HXR_OK != pPlayer->QueryInterface(IID_IHXErrorMessages, (void **)&m_pErrorMessages))
- {
- hr = HXR_FAILED;
- goto cleanup;
- }
- // get interface to audio player
- if (HXR_OK != pPlayer->QueryInterface(IID_IHXAudioPlayer, (void**) &m_pAudioPlayer))
- {
- hr = HXR_FAILED;
- goto cleanup;
- }
- #ifdef REBUFFERING__SKIP
- if (m_pStream)
- {
- IHXStreamSource* pSource = 0;
- if (m_pStream->GetSource(pSource) == HXR_OK)
- {
- if (pSource)
- {
- pSource->QueryInterface(IID_IHXSourceBufferingStats,
- (void**) &m_pBufferingStats);
- HX_RELEASE(pSource);
- }
- }
- }
- #endif // #ifdef REBUFFERING__SKIP
- pPlayer->QueryInterface(IID_IHXAudioPushdown2, (void**) &m_pAudioPushdown2);
- #ifdef HELIX_CONFIG_MIN_PCM_PUSHDOWN_BYTES
- m_pAudioPushdown2->SetAudioPushdown( OPTIMAL_HEAP_MIN_AUDIO_PUSHDOWN );
- #endif // HELIX_CONFIG_MIN_PCM_PUSHDOWN_BYTES
- cleanup:
- if (HXR_OK != hr)
- {
- HX_RELEASE(m_pErrorMessages);
- HX_RELEASE(m_pAudioPlayer);
- HX_RELEASE(m_pAudioPushdown2);
- }
- return hr;
- }
- /////////////////////////////////////////////////////////////////////////
- // Method:
- // IHXRenderer::EndStream
- // Purpose:
- // Called by client engine to inform the renderer that the stream
- // is was rendering is closed.
- //
- STDMETHODIMP CRealAudioRenderer::EndStream()
- {
- #ifdef _MACINTOSH
- if (m_pDryCallback != NULL)
- {
- m_pDryCallback->Cancel();
- HX_RELEASE(m_pDryCallback);
- }
- #endif
- if ((m_usCurrentDryNotificationStream != NO_STREAM_SET) &&
- m_pAudioStreams != NULL &&
- m_pAudioStreams[m_usCurrentDryNotificationStream] != NULL)
- {
- RemoveCurrentDryNotification();
- m_usCurrentDryNotificationStream = NO_STREAM_SET;
- }
- m_PlayState = stopped;
- FlushUnregisterQueue(TRUE);
- // We're done with these...
- HX_RELEASE(m_pContext);
- HX_RELEASE(m_pCommonClassFactory);
- #if defined(HELIX_FEATURE_STATS)
- HX_RELEASE(m_pRegistry);
- #endif // HELIX_FEATURE_STATS
- HX_RELEASE(m_pBufferingStats);
- HX_RELEASE(m_pStream);
- #if defined(HELIX_CONFIG_SLUGGISHAUTOUPGRADE)
- HX_RELEASE(m_pASMStream);
- #endif
- HX_RELEASE(m_pAudioPlayer);
- HX_RELEASE(m_pAudioPushdown2);
- HX_RELEASE(m_pErrorMessages);
- #if defined(HELIX_FEATURE_SETSRCPROPS)
- HX_RELEASE(m_pValues);
- #endif /* #if defined(HELIX_FEATURE_SETSRCPROPS) */
- UINT16 i = 0;
- for (i = 0; i < m_uNumOfSubStreams; i++)
- {
- if (m_pRaFormats[i])
- {
- if (m_pRaFormats[i]->m_pAudioSync && m_pRaFormats[i]->m_bRegistered)
- {
- m_pRaFormats[i]->m_bRegistered = FALSE;
- m_pRaFormats[i]->m_pAudioSync->UnRegister();
- DEBUG_OUTF_IDX(i, RA_FLOW_FILE,
- (s, "Sync Stopn"));
- }
- HX_RELEASE(m_pRaFormats[i]->m_pAudioSync);
- HX_RELEASE(m_pAudioStreams[i]);
- HX_DELETE(m_pRaFormats[i]);
- #if defined(HELIX_FEATURE_AUDIO_CODEC_RAAC)
- HX_DELETE(m_ppVBRDepack[i]);
- #endif
- }
- }
- // we might get called twice and don't want to go through
- // the above loop again.
- m_uNumOfSubStreams = 0;
- HX_VECTOR_DELETE(m_pRuleMap);
- HX_VECTOR_DELETE(m_pAudioStreams);
- HX_VECTOR_DELETE(m_pRaFormats);
- #if defined(HELIX_FEATURE_AUDIO_CODEC_RAAC)
- HX_VECTOR_DELETE(m_ppVBRDepack);
- #endif
- FlushUnregisterQueue(TRUE);
- if (m_pRuleToFlagMap != NULL)
- {
- HX_VECTOR_DELETE(m_pRuleToFlagMap->rule_to_flag_map);
- HX_DELETE(m_pRuleToFlagMap);
- }
- return HXR_OK;
- }
- /////////////////////////////////////////////////////////////////////////
- // Method:
- // IHXRenderer::OnHeader
- // Purpose:
- // Called by client engine when a header for this renderer is
- // available. The header will arrive before any packets.
- //
- STDMETHODIMP CRealAudioRenderer::OnHeader(IHXValues* pHeader)
- {
- IHXBuffer* pOpaqueData = NULL;
- IHXBuffer* pRuleToFlagMapValue = NULL;
- IHXUpgradeCollection* pUpgradeCollection = NULL;
- BOOL bForceStartTrackTime = FALSE;
- BOOL bForceEndTrackTime = FALSE;
- UINT32 ulPreroll = 0;
- UINT32 ulIsInterleaved = 0;
- UINT32 ulBytesRead = 0;
- UINT32 ulTrackStartTime = 0;
- UINT32 ulTrackEndTime = 0;
- UINT32 ulStreamNumber = 0;
- HX_RESULT retVal = HXR_OK;
- UINT32 ulBufferSize = 0;
- UINT32 ulID = 0;
- UINT16 i = 0;
- BYTE* pCursor = NULL;
- BYTE* pData = NULL;
- BOOL bDecoderNotFound = FALSE;
- char* pAllCodecs = NULL;
- UINT32 ulSubStream = 0; // highest bitrate substream
- UINT32 ulAllCodecBufLen = 0;
- UINT16 usQuality = 4; // highest quality is my default.
- #if defined(HELIX_FEATURE_PREFERENCES)
- GetQualityPreference(usQuality);
- #endif /* #if defined(HELIX_FEATURE_PREFERENCES) */
- BOOL bMaxSampleRate = (usQuality >= 2); // most of the code uses this as the turn off point
- UINT16 nFirstStreamToInit = 0; // init first first
- UINT32 ulCurrentSampleRate = bMaxSampleRate ? 8000 : 44000; // lowest sample rate we ever want to have
- UINT16 uCurrentNumChannels = 1;
- INT32 lProtocolVersion = 0;
- BOOL bIsPNM = FALSE;
- IHXStreamSource* pSource = NULL;
- ULONG32 numRulesToBlock = 0;
- #if defined(HELIX_FEATURE_AUTOUPGRADE)
- // check the stream versions
- pHeader->AddRef();
- retVal = CheckStreamVersions(pHeader);
- pHeader->Release();
- // if the stream versions didn't checkout, bail
- if (retVal != HXR_OK)
- {
- goto cleanup;
- }
- #endif
- if (SUCCEEDED(pHeader->GetPropertyULONG32("StreamNumber", ulStreamNumber)))
- {
- m_usThisSourceStream = (UINT16) ulStreamNumber;
- }
- pHeader->GetPropertyBuffer ("OpaqueData", pOpaqueData);
- pHeader->GetPropertyULONG32("Preroll", ulPreroll);
- // XXXgfw to fix a problem with the core not handling very small
- // preroll values. This should be removed as the client audio
- // services gets reworked to properly handle small preroll values.
- if( ulPreroll < 500 )
- {
- ulPreroll = 500; //a typical value for 193kbps RA content.
- pHeader->SetPropertyULONG32("Preroll", ulPreroll);
- }
-
- pHeader->GetPropertyULONG32("IsInterleaved", ulIsInterleaved);
- pHeader->GetPropertyULONG32("Duration", m_ulDuration);
- if (HXR_OK == pHeader->GetPropertyULONG32("TrackStartTime", ulTrackStartTime))
- {
- bForceStartTrackTime = TRUE;
- }
- pHeader->GetPropertyULONG32("Delay", m_ulDelay);
- if (HXR_OK == pHeader->GetPropertyULONG32("TrackEndTime", ulTrackEndTime))
- {
- bForceEndTrackTime = TRUE;
- }
- if (HXR_OK ==
- pHeader->GetPropertyBuffer(RULE_TO_FLAG_MAP_PROPERTY,
- pRuleToFlagMapValue))
- {
- m_pRuleToFlagMap = new RuleToFlagMap;
- if(!m_pRuleToFlagMap)
- {
- retVal = HXR_OUTOFMEMORY;
- goto cleanup;
- }
- m_pRuleToFlagMap->unpack(pRuleToFlagMapValue->GetBuffer(),
- pRuleToFlagMapValue->GetSize());
- }
- HX_RELEASE(pRuleToFlagMapValue);
- m_ulPreroll = ulPreroll;
- pData = pOpaqueData->GetBuffer();
- pCursor = pData;
- ulBufferSize = pOpaqueData->GetSize();
- // format ID
- memcpy((UCHAR*)&ulID, pCursor, sizeof(UINT32)); /* Flawfinder: ignore */
- ulID = DwToHost(ulID);
- if (RM_MULTIHEADER_OBJECT == ulID)
- {
- MultiStreamHeader multiStreamHeader;
- pCursor = multiStreamHeader.unpack(pData, ulBufferSize);
- ulBufferSize -= (pCursor - pData);
- m_bStreamSwitchable = TRUE;
- m_uNumOfSubStreams = multiStreamHeader.num_headers;
- // # of rules
- m_uNumOfRules = multiStreamHeader.num_rules;
- m_pRuleMap = new UINT16[m_uNumOfRules];
- if(!m_pRuleMap)
- {
- retVal = HXR_OUTOFMEMORY;
- goto cleanup;
- }
- // retrieve the rule map
- for (i = 0; i < m_uNumOfRules; i++)
- {
- m_pRuleMap[i] = multiStreamHeader.rule_to_header_map[i];
- }
- // must delete the rule map since PMC doesn't generate distructors
- HX_VECTOR_DELETE(multiStreamHeader.rule_to_header_map);
- }
- else if (RA_FORMAT_ID == ulID)
- {
- m_uNumOfSubStreams = 1;
- }
- else
- {
- retVal = HXR_FAILED;
- goto cleanup;
- }
- // allocate all of our per stream structures and initialize them
- m_pRaFormats = new CRaFormat*[m_uNumOfSubStreams];
- if(!m_pRaFormats)
- {
- retVal = HXR_OUTOFMEMORY;
- goto cleanup;
- }
- ::memset(m_pRaFormats, 0, sizeof(CRaFormat*) * m_uNumOfSubStreams);
- m_pAudioStreams = new IHXAudioStream*[m_uNumOfSubStreams];
- if(!m_pAudioStreams)
- {
- retVal = HXR_OUTOFMEMORY;
- goto cleanup;
- }
- ::memset(m_pAudioStreams, 0, sizeof(IHXAudioStream*) * m_uNumOfSubStreams);
- #if defined(HELIX_FEATURE_AUDIO_CODEC_RAAC)
- m_ppVBRDepack = new CVBRSimpleDepacketizer* [m_uNumOfSubStreams];
- if(!m_ppVBRDepack)
- {
- retVal = HXR_OUTOFMEMORY;
- goto cleanup;
- }
- ::memset(m_ppVBRDepack, 0, sizeof(CVBRSimpleDepacketizer*) * m_uNumOfSubStreams);
- #endif /* #if defined(HELIX_FEATURE_AUDIO_CODEC_RAAC) */
- #if defined(HELIX_FEATURE_STATS)
- if (m_pRegistry)
- {
- // Check the stats to get the protocol and protocol version
- // so we can special case 3.0 and earlier servers that send
- // timestamps in tenths of a second
- if (HXR_OK == m_pStream->GetSource(pSource))
- {
- IHXRegistryID* pSourceIRegID = NULL;
- if (HXR_OK == pSource->QueryInterface(IID_IHXRegistryID,
- (void**)&pSourceIRegID))
- {
- UINT32 ulRegistryID;
- if (HXR_OK == pSourceIRegID->GetID(ulRegistryID))
- {
- char szRegistryEntry[MAX_DISPLAY_NAME] = {0}; /* Flawfinder: ignore */
- IHXBuffer* pszRegistryName = NULL;
- // Get the current registry key name
- if (HXR_OK == m_pRegistry->GetPropName(ulRegistryID,
- pszRegistryName))
- {
- SafeSprintf(szRegistryEntry, MAX_DISPLAY_NAME, "%s.ProtocolVersion",
- pszRegistryName->GetBuffer());
- m_pRegistry->GetIntByName(szRegistryEntry,
- lProtocolVersion);
- IHXBuffer* pProtocolString = NULL;
- SafeSprintf(szRegistryEntry, MAX_DISPLAY_NAME, "%s.Protocol",
- pszRegistryName->GetBuffer());
- if (HXR_OK ==
- m_pRegistry->GetStrByName(szRegistryEntry,
- pProtocolString) && pProtocolString != NULL)
- {
- bIsPNM = ( 0 == strcasecmp("PNM",
- (const char*)pProtocolString->GetBuffer()));
- }
- HX_RELEASE(pProtocolString);
- }
- HX_RELEASE(pszRegistryName);
- }
- HX_RELEASE(pSourceIRegID);
- }
- HX_RELEASE(pSource);
- }
- }
- #endif // HELIX_FEATURE_STATS
- // create codecs buffer
- #if defined(HELIX_FEATURE_STATS)
- ulAllCodecBufLen = (m_uNumOfSubStreams * 6) + 1;
- pAllCodecs = new char[ulAllCodecBufLen];
- if(!pAllCodecs)
- {
- retVal = HXR_OUTOFMEMORY;
- goto cleanup;
- }
- *pAllCodecs = ' ';
- #endif /* #if defined(HELIX_FEATURE_STATS) */
- // instantiate the RA format/audio stream objects for
- // each sub-stream
- for (i = 0;
- (retVal == HXR_OK) && (i < m_uNumOfSubStreams);
- i++)
- {
- m_pRaFormats[i] = CreateRaFormat(i);
- // initialize the Format for this header
- m_pRaFormats[i]->ForceInterleaved(ulIsInterleaved);
- m_pRaFormats[i]->SetProtocolInfo(bIsPNM, lProtocolVersion);
- #if defined(HELIX_FEATURE_AUDIO_CODEC_RAAC)
- // Determine which ASM rule specifies a keyframe for this substream
- UINT16 usKeyFrameRuleNum = 0;
- for (UINT16 q = 0; q < m_pRuleToFlagMap->num_rules; q++)
- {
- BOOL bRuleForThisSubStream = TRUE;
- if (m_bStreamSwitchable && m_pRuleMap && m_pRuleMap[q] != i)
- {
- bRuleForThisSubStream = FALSE;
- }
- if (bRuleForThisSubStream &&
- m_pRuleToFlagMap->rule_to_flag_map[q] & HX_KEYFRAME_FLAG)
- {
- // This is the keyframe rule for this substream
- usKeyFrameRuleNum = q;
- break;
- }
- }
- #endif /* #if defined(HELIX_FEATURE_AUDIO_CODEC_RAAC) */
- UINT32 ulReadRAHeaderSize = ulBufferSize;
- if (m_bStreamSwitchable)
- {
- // adjust the header size so we only read this header
- ulReadRAHeaderSize = getlong(pCursor);
- pCursor += sizeof(UINT32);
- ulBufferSize -= sizeof(UINT32);
- }
- retVal = m_pRaFormats[i]->NewReadRAHeader(pCursor, ulReadRAHeaderSize,
- bForceStartTrackTime, bForceEndTrackTime, ulTrackStartTime,
- ulTrackEndTime, &ulBytesRead, pAllCodecs, ulAllCodecBufLen);
- if (HXR_OK == retVal)
- {
- #if defined(HELIX_FEATURE_AUDIO_CODEC_RAAC)
- // Check if this substream is RAAC and VBRS
- char* pInterID = m_pRaFormats[i]->GetInterleaverName();
- if (pInterID &&
- (!strcmp((const char*) pInterID, RA_INTERLEAVER_VBRS_ID) ||
- !strcmp((const char*) pInterID, RA_INTERLEAVER_VBRF_ID)))
- {
- // Create a VBR depacketizer for this sub-stream
- HX_DELETE(m_ppVBRDepack[i]);
- m_ppVBRDepack[i] = new CVBRSimpleDepacketizer();
- if (m_ppVBRDepack[i])
- {
- // Init the depacketizer
- retVal = m_ppVBRDepack[i]->Init(m_pContext,
- m_pRaFormats[i]->GetMSPerBlock(),
- m_usThisSourceStream,
- usKeyFrameRuleNum,
- FALSE);
- }
- }
- #endif /* #if defined(HELIX_FEATURE_AUDIO_CODEC_RAAC) */
- HXAudioFormat audioFmt;
- m_pRaFormats[i]->GetAudioFormat(audioFmt);
- if ((bMaxSampleRate && audioFmt.ulSamplesPerSec > ulCurrentSampleRate) ||
- (!bMaxSampleRate && audioFmt.ulSamplesPerSec < ulCurrentSampleRate))
- {
- ulCurrentSampleRate = audioFmt.ulSamplesPerSec;
- uCurrentNumChannels = audioFmt.uChannels;
- nFirstStreamToInit = i;
- }
- else if (audioFmt.ulSamplesPerSec == ulCurrentSampleRate &&
- audioFmt.uChannels > uCurrentNumChannels)
- {
- uCurrentNumChannels = audioFmt.uChannels;
- nFirstStreamToInit = i;
- }
- }
- // mask out DECODER_NOT_FOUND so we can try all of the streams and find
- // all of the decoders that aren't installed and upgrade them all at once
- if (retVal == HXR_DEC_NOT_FOUND)
- {
- #if defined(HELIX_CONFIG_SLUGGISHAUTOUPGRADE)
- if( m_pRuleMap )
- {
- if( m_pStream && !m_pASMStream )
- {
- if( m_pStream->QueryInterface(IID_IHXASMStream2,
- (void**)&m_pASMStream) == HXR_OK )
- {
- m_pASMStream->AddRef();
- }
- }
- if( m_pASMStream )
- {
- // Find all rules for this stream
- for( int ii=0; ii<m_uNumOfRules; ii++ )
- {
- if( m_pRuleMap[ii] == i )
- {
- m_pASMStream->Disable( ii );
- numRulesToBlock++;
- }
- }
- }
- } // if m_pRuleMap
- if( ( numRulesToBlock == m_uNumOfRules ) || ( numRulesToBlock == 1 && m_uNumOfRules == 0 ) )
- {
- bDecoderNotFound = TRUE;
- }
- retVal = HXR_OK;
- #else
- retVal = HXR_OK;
- bDecoderNotFound = TRUE;
- #endif
- }
- pCursor += ulBytesRead;
- ulBufferSize -= ulBytesRead;
- }
- #if defined(HELIX_CONFIG_SLUGGISHAUTOUPGRADE)
- if( m_pASMStream && bDecoderNotFound == FALSE )
- {
- HX_RESULT retVal = m_pASMStream->ReCompute();
- if( retVal == HXR_FAIL )
- {
- bDecoderNotFound = TRUE;
- }
- }
- #endif // (HELIX_CONFIG_SLUGGISHAUTOUPGRADE)
- // write all codecs list to registry
- #if defined(HELIX_FEATURE_STATS)
- WriteCodecsToRegistry(pAllCodecs);
- // clean up char array
- HX_VECTOR_DELETE(pAllCodecs);
- #endif // HELIX_FEATURE_STATS
- // if we don't have any other errors but we are missing one or more
- // decoders, reset the result code to decoder not found so upgrade
- // gets kicked off.
- if (HXR_OK == retVal && bDecoderNotFound)
- {
- retVal = HXR_DEC_NOT_FOUND;
- }
- // This helps insure we get the audio device opened at the
- // sampling rate and # channels we want.
- if (HXR_OK == retVal)
- {
- retVal = InitAudioStream(m_pRaFormats[nFirstStreamToInit], pHeader,
- &m_pAudioStreams[nFirstStreamToInit]);
- for (i = 0; retVal == HXR_OK &&
- i < m_uNumOfSubStreams ; i++)
- {
- if (i != nFirstStreamToInit)
- {
- retVal = InitAudioStream(m_pRaFormats[i], pHeader,
- &m_pAudioStreams[i]);
- }
- }
- }
- // add the default dry notification when we are all done
- if (HXR_OK == retVal)
- {
- AddDryNotification(DEFAULT_DRY_NOTIFICATION);
- }
- #if defined(HELIX_FEATURE_SETSRCPROPS)
- // Do we have more than one substream?
- if (m_uNumOfSubStreams > 1)
- {
- // Here we need to find the highest bitrate stream
- UINT32 ulMaxBps = 0;
- for (UINT32 i = 0; i < m_uNumOfSubStreams; i++)
- {
- UINT32 ulBps = m_pRaFormats[i]->GetBitRate();
- if (ulBps > ulMaxBps)
- {
- ulMaxBps = ulBps;
- ulSubStream = i;
- }
- }
- }
- // Save the highest bitrate substream index
- m_ulSrcPropertySubStream = ulSubStream;
- #endif /* #if defined(HELIX_FEATURE_SETSRCPROPS) */
- cleanup:
- if (retVal == HXR_OK && !m_pMutex)
- {
- #ifdef THREADS_SUPPORTED
- HXMutex::MakeMutex(m_pMutex);
- #else
- HXMutex::MakeStubMutex(m_pMutex);
- #endif
- }
- HX_RELEASE(pUpgradeCollection);
- HX_RELEASE(pOpaqueData);
- return retVal;
- }
- CRaFormat* CRealAudioRenderer::CreateRaFormat(UINT16 uStreamNum)
- {
- return new CRaFormat(m_pContext,
- m_pCommonClassFactory,
- m_pErrorMessages,
- m_pRuleToFlagMap ?
- m_pRuleToFlagMap->rule_to_flag_map : NULL,
- uStreamNum);
- }
- /////////////////////////////////////////////////////////////////////////////
- // Method:
- // CRealAudioRenderer::CheckStreamVersions
- HX_RESULT
- CRealAudioRenderer::CheckStreamVersions(IHXValues* pHeader)
- {
- // check stream and content versions so an upgrade can
- // be called if necessary...
- HX_RESULT pnr = HXR_OK;
- #if defined(HELIX_FEATURE_AUTOUPGRADE)
- BOOL bVersionOK = TRUE;
- UINT32 ulStreamVersion = 0;
- UINT32 ulContentVersion = 0;
- if(HXR_OK == pHeader->GetPropertyULONG32("StreamVersion",
- ulStreamVersion))
- {
- UINT32 ulMajorVersion = HX_GET_MAJOR_VERSION(ulStreamVersion);
- UINT32 ulMinorVersion = HX_GET_MINOR_VERSION(ulStreamVersion);
- if((ulMajorVersion > STREAM_MAJOR_VERSION) ||
- (ulMinorVersion > STREAM_MINOR_VERSION &&
- ulMajorVersion == STREAM_MAJOR_VERSION))
- {
- bVersionOK = FALSE;
- }
- }
- if(bVersionOK &&
- HXR_OK == pHeader->GetPropertyULONG32("ContentVersion",
- ulContentVersion))
- {
- UINT32 ulMajorVersion = HX_GET_MAJOR_VERSION(ulContentVersion);
- UINT32 ulMinorVersion = HX_GET_MINOR_VERSION(ulContentVersion);
- if((ulMajorVersion > CONTENT_MAJOR_VERSION) ||
- (ulMinorVersion > CONTENT_MINOR_VERSION &&
- ulMajorVersion == CONTENT_MAJOR_VERSION))
- {
- bVersionOK = FALSE;
- }
- }
- if(!bVersionOK)
- {
- IHXUpgradeCollection* pUpColl = NULL;
- if(m_pContext &&
- (HXR_OK == m_pContext->QueryInterface(IID_IHXUpgradeCollection,
- (void**)&pUpColl)))
- {
- CHXBuffer* pBuffer = NULL;
- m_pCommonClassFactory->CreateInstance(IID_IHXBuffer, (void**) &pBuffer);
- if (pBuffer)
- {
- //XXXEH- in future, we may want to distinguish between
- // "unknown content version" & "unknown stream version".
- // For now, just treat both as "unknown content version":
- LONG32 bufsize = strlen(zm_pStreamMimeTypes[0]) +
- strlen(zm_pAdditionalAutoUpgradeInfo[
- unknownRAContentVersion]) + 1;
- pBuffer->Set((BYTE*)zm_pStreamMimeTypes[0], bufsize);
- unsigned char* pBuf = pBuffer->GetBuffer();
- pBuf[strlen(zm_pStreamMimeTypes[0])] = ' ';
- SafeStrCat((char *)pBuf, zm_pAdditionalAutoUpgradeInfo[ /* Flawfinder: ignore */
- unknownRAContentVersion], pBuffer->GetSize());
- pUpColl->Add(eUT_Required, pBuffer, 0, 0);
- HX_RELEASE(pBuffer);
- HX_RELEASE(pUpColl);
- }
- }
- pnr = HXR_FAIL;
- }
- #endif /* #if defined(HELIX_FEATURE_AUTOUPGRADE) */
- return pnr;
- }
- /////////////////////////////////////////////////////////////////////////////
- // Method:
- // CRealAudioRenderer::InitAudioStream
- HX_RESULT
- CRealAudioRenderer::InitAudioStream(CRaFormat* pRaFormat, IHXValues* pHeader,
- IHXAudioStream** ppAudioStream)
- {
- HX_RESULT retVal;
- // init so we can HX_RELEASE on error.
- *ppAudioStream = NULL;
- pRaFormat->m_pAudioSync = NULL;
- retVal = m_pAudioPlayer->CreateAudioStream(ppAudioStream);
- if (HXR_OK == retVal)
- {
- retVal = (*ppAudioStream)->QueryInterface(IID_IHXRealAudioSync,
- (void**)&(pRaFormat->m_pAudioSync));
- if (HXR_OK == retVal)
- {
- IHXCommonClassFactory* pCommonClassFactory;
- if (HXR_OK == (*ppAudioStream)->QueryInterface(IID_IHXCommonClassFactory,
- (void**)&pCommonClassFactory))
- {
- // if we can get a class factory from the ccf, it's
- // a redstone or later core
- m_bPreRedstonePlayer = FALSE;
- pRaFormat->OverrideFactory(pCommonClassFactory);
- pCommonClassFactory->Release();
- }
- HXAudioFormat audioFmt;
- pRaFormat->GetAudioFormat(audioFmt);
- /* Add default dry notification BEFORE initializing the audio
- * stream. This is so that if we are started mid presentation
- * and there was no audio present earlier, the timeline will
- * change from being a fake timeline to audio timeline and
- * the audio services will write audio for initial pushdown
- * time. We need to get dry notifications so that we can halt
- * the timeline, if the renderer does not have enough data.
- */
- retVal = (*ppAudioStream)->Init(&audioFmt, pHeader);
- }
- }
- if (HXR_OK != retVal)
- {
- HX_RELEASE((*ppAudioStream));
- HX_RELEASE(pRaFormat->m_pAudioSync);
- }
- return retVal;
- }
- /////////////////////////////////////////////////////////////////////////////
- // Method:
- // CRealAudioRenderer::AddDryNotification
- HX_RESULT
- CRealAudioRenderer::AddDryNotification(UINT16 usStreamNumber)
- {
- HX_RESULT pnr = HXR_OK;
- if (m_pAudioStreams == NULL)
- {
- pnr = HXR_FAILED;
- }
- if ((HXR_OK == pnr) &&
- (usStreamNumber != m_usCurrentDryNotificationStream))
- {
- if (m_usCurrentDryNotificationStream != NO_STREAM_SET)
- {
- HX_ASSERT(m_pAudioStreams[m_usCurrentDryNotificationStream] != NULL);
- QueueUnregisterSync(m_usCurrentDryNotificationStream,
- m_ulLatestActualTime);
- RemoveCurrentDryNotification();
- DEBUG_OUT(m_pErrorMessages, DOL_REALAUDIO,
- (s, "Switching FROM: %u - Removing DryNotification",
- m_usCurrentDryNotificationStream));
- }
- IHXDryNotification* pDryNot = NULL;
- QueryInterface(IID_IHXDryNotification, (void**)&pDryNot);
- HX_ASSERT(m_pAudioStreams[usStreamNumber] != NULL);
- if (pDryNot)
- {
- pnr = m_pAudioStreams[usStreamNumber]->AddDryNotification(pDryNot);
- }
- DEBUG_OUTF_IDX(usStreamNumber, RA_FLOW_FILE,
- (s, "Dry-Notif. Start: %sn", (pnr == HXR_OK) ? "OK" : "FAIL"));
- HX_ASSERT(SUCCEEDED(pnr));
- m_usCurrentDryNotificationStream = usStreamNumber;
- DEBUG_OUT(m_pErrorMessages, DOL_REALAUDIO,
- (s, "Switching TO: %u - Adding DryNotification",
- m_usCurrentDryNotificationStream));
- // fix up the granularity for this stream
- // we want to be called twice as frequently as our block size. That
- // way we will "over write" to audio services if we have extra data.
- // This will allow build up of an audio pushdown.
- ULONG32 ulNewGranularity =
- (UINT32) (m_pRaFormats[usStreamNumber]->GetMSPerBlock() / 2);
- if (ulNewGranularity != m_ulCurrentGranularity)
- {
- m_ulCurrentGranularity = ulNewGranularity;
- m_pStream->SetGranularity(m_ulCurrentGranularity);
- DEBUG_OUTF_IDX(usStreamNumber, RA_FLOW_FILE,
- (s, "Granularity Set: %un",
- m_ulCurrentGranularity));
- }
- HX_RELEASE(pDryNot);
- }
- if (pnr == HXR_OK)
- {
- DoSyncRegister(m_usCurrentDryNotificationStream);
- }
- return pnr;
- }
- /////////////////////////////////////////////////////////////////////////////
- // Method:
- // CRealAudioRenderer::DoSyncRegister
- void CRealAudioRenderer::DoSyncRegister(UINT16 uStreamNumber)
- {
- if (m_pRaFormats &&
- m_pRaFormats[uStreamNumber]->m_pAudioSync &&
- (!m_pRaFormats[uStreamNumber]->m_bRegistered))
- {
- DEBUG_OUTF_IDX(uStreamNumber, RA_FLOW_FILE,
- (s, "Sync Startn"));
- m_pRaFormats[uStreamNumber]->m_bRegistered = TRUE;
- m_pRaFormats[uStreamNumber]->m_pAudioSync->Register();
- }
- }
- void CRealAudioRenderer::UnregisterTimeSyncs(UINT32 ulCurrentTime)
- {
- UINT16 uCurrentStream = m_uSyncUnregisterStream;
- if (uCurrentStream != NO_STREAM_SET)
- {
- BOOL bStreamDone = m_pRaFormats[uCurrentStream]->IsStreamDone();
- if ((m_bAllStreamsToBeUnregistered &&
- (IsTimeGreaterOrEqual(ulCurrentTime, m_ulDuration) ||
- bStreamDone)) ||
- ((m_ulSyncUnregisterTime == NO_TIME_SET) &&
- IsTimeGreaterOrEqual(ulCurrentTime,
- m_ulSyncUnregisterTime)))
- {
- CRealAudioRenderer::QueueUnregisterSync(uCurrentStream,
- NO_TIME_SET);
- }
- }
- }
- /////////////////////////////////////////////////////////////////////////////
- // Method:
- // CRealAudioRenderer::QueueUnregisterSync
- void CRealAudioRenderer::QueueUnregisterSync(UINT16 uStream, UINT32 ulTime)
- {
- if ((m_uSyncUnregisterStream != NO_STREAM_SET) &&
- (uStream != m_uSyncUnregisterStream))
- {
- CRealAudioRenderer::QueueUnregisterSync(m_uSyncUnregisterStream,
- NO_TIME_SET);
- }
- m_ulSyncUnregisterTime = ulTime;
- if (ulTime == NO_TIME_SET)
- {
- if (m_pRaFormats &&
- m_pRaFormats[uStream]->m_pAudioSync &&
- m_pRaFormats[uStream]->m_bRegistered)
- {
- m_pRaFormats[uStream]->m_bRegistered = FALSE;
- m_pRaFormats[uStream]->m_pAudioSync->UnRegister();
- m_uSyncUnregisterStream = NO_STREAM_SET;
- DEBUG_OUTF_IDX(uStream, RA_FLOW_FILE,
- (s, "Sync Stopn"));
- }
- }
- else
- {
- m_ulSyncUnregisterTime = uStream;
- }
- }
- void CRealAudioRenderer::FlushUnregisterQueue(BOOL bDestroy)
- {
- if (m_uSyncUnregisterStream != NO_STREAM_SET)
- {
- QueueUnregisterSync(m_uSyncUnregisterStream, NO_TIME_SET);
- }
- }
- /////////////////////////////////////////////////////////////////////////////
- // Method:
- // CRealAudioRenderer::WriteToAudioServices
- HX_RESULT
- CRealAudioRenderer::WriteToAudioServices(UINT16 uStreamNumber,
- HXAudioData* pAudioData,
- UINT32 ulActualTimestamp)
- {
- HX_RESULT pnr = HXR_OK;
- BOOL bTryWrite = TRUE;
- ULONG32 ulAttemptCount = 0;
- while (bTryWrite && (ulAttemptCount < 3))
- {
- // Write to AS
- pnr = m_pAudioStreams[uStreamNumber]->Write(pAudioData);
- LogAudioWrite(uStreamNumber, pAudioData, ulActualTimestamp, pnr);
- ulAttemptCount++;
- if (SUCCEEDED(pnr))
- {
- if (m_pRaFormats[uStreamNumber]->m_bRegistered)
- {
- // FudgeTimeStamp doesn't need first parameter anymore
- m_pRaFormats[uStreamNumber]->m_pAudioSync->FudgeTimestamp(0,
- ulActualTimestamp);
- }
- CalculateMaxTimeStamp(uStreamNumber,
- pAudioData,
- ulActualTimestamp);
- bTryWrite = FALSE;
- }
- #ifdef HELIX_FEATURE_RAREND_PREREDSTONE_SUPPORT
- else if (m_bPreRedstonePlayer)
- {
- if (HXR_NONCONTIGUOUS_PACKET == pnr)
- {
- // we are skipping ahead and should just mark this packet
- // as timed and write it again
- pAudioData->uAudioStreamType = TIMED_AUDIO;
- DEBUG_OUT(m_pErrorMessages, DOL_REALAUDIO_EXTENDED,
- (s, "skipping AS stream %u's time ahead to %lut0x%X", uStreamNumber,
- pAudioData->ulAudioTime, pnr));
- DEBUG_OUTF(PREREDSTONE_FILE,
- (s, "skipping AS stream %u's time ahead to %lut0x%Xn", uStreamNumber,
- pAudioData->ulAudioTime, pnr));
- }
- else
- {
- HX_ASSERT(m_bPreRedstonePlayer);
- // we've likely written a late packet but it's not safe to
- // ask all rmacore's what time the stream has so we wait for
- // a dry notification, where we are told what the time is
- m_usPreviousDryNotificationStream = m_usCurrentDryNotificationStream;
- if (FAILED(AddDryNotification(uStreamNumber)))
- {
- // I guess we just jump ahead a second?? and try again
- DEBUG_OUT(m_pErrorMessages, DOL_REALAUDIO_EXTENDED,
- (s, "Behind Unknown ms on %u's jumping ahead to %lut0x%X", uStreamNumber,
- pAudioData->ulAudioTime + 1000, pnr));
- DEBUG_OUTF(PREREDSTONE_FILE,
- (s, "Behind Unknown ms on %u's jumping ahead to %lut0x%Xn", uStreamNumber,
- pAudioData->ulAudioTime + 1000, pnr));
- m_pRaFormats[uStreamNumber]->
- DiscardTillEndOfCrossFade(pAudioData->ulAudioTime + 1000);
- // reset dry notification
- AddDryNotification(m_usPreviousDryNotificationStream);
- m_usPreviousDryNotificationStream = NO_STREAM_SET;
- }
- // get out of the loop...
- bTryWrite = FALSE;
- }
- }
- #endif // HELIX_FEATURE_RAREND_PREREDSTONE_SUPPORT
- else
- {
- // we got an error on write, check what time the audio stream
- // expects data for
- HXAudioData audioData;
- INT32 lTimeDiff;
- audioData.pData = NULL;
- m_pAudioStreams[uStreamNumber]->Write(&audioData);
- if (m_ulLatestStreamTime != NO_TIME_SET)
- {
- lTimeDiff = (LONG32) (audioData.ulAudioTime - m_ulLatestStreamTime);
- OffsetLatestTime(uStreamNumber, lTimeDiff);
- }
- DEBUG_OUTF_IDX(uStreamNumber, RA_FLOW_FILE,
- (s, "Audio Stream Report: Time=%un",
- audioData.ulAudioTime));
- DEBUG_OUT(m_pErrorMessages, DOL_REALAUDIO_EXTENDED,
- (s, "Failed AS->Writet%ut%lut%lut%dt0x%X", uStreamNumber,
- pAudioData->ulAudioTime, audioData.ulAudioTime,
- pAudioData->uAudioStreamType, pnr));
- DEBUG_OUTF(AUDIOSERVICES_FILE,
- (s, "Failed AS->Writet%ut%lut%lut%dt0x%Xn", uStreamNumber,
- pAudioData->ulAudioTime, audioData.ulAudioTime,
- pAudioData->uAudioStreamType, pnr));
- if (IsTimeLess(audioData.ulAudioTime, pAudioData->ulAudioTime))
- {
- // we are skipping ahead and should just mark this packet
- // as timed and write it again
- pAudioData->uAudioStreamType = TIMED_AUDIO;
- DEBUG_OUT(m_pErrorMessages, DOL_REALAUDIO_EXTENDED,
- (s, "skipping AS stream %u's time ahead to %lut0x%X", uStreamNumber,
- pAudioData->ulAudioTime, pnr));
- DEBUG_OUTF(AUDIOSERVICES_FILE,
- (s, "skipping AS stream %u's time ahead to %lut0x%Xn", uStreamNumber,
- pAudioData->ulAudioTime, pnr));
- }
- else if (IsTimeGreater(audioData.ulAudioTime, pAudioData->ulAudioTime) &&
- IsTimeLessOrEqual(audioData.ulAudioTime, pAudioData->ulAudioTime +
- ((UINT32) (m_pRaFormats[uStreamNumber]->ConvertBytesToMs(pAudioData->pData->GetSize())))))
- {
- // we are a little behind but at least part of this stream
- // is on time, we should clip off this buffer to the time
- // the audio stream wants and try again.
- bTryWrite = m_pRaFormats[uStreamNumber]->ClipAudioBuffer(pAudioData,
- ulActualTimestamp, audioData.ulAudioTime, TRUE);
- DEBUG_OUT(m_pErrorMessages, DOL_REALAUDIO_EXTENDED,
- (s, "A little bit behind on stream %u's clip buffer to %lut0x%X", uStreamNumber,
- audioData.ulAudioTime, pnr));
- DEBUG_OUTF(AUDIOSERVICES_FILE,
- (s, "A little bit behind on stream %u's clip buffer to %lut0x%Xn", uStreamNumber,
- audioData.ulAudioTime, pnr));
- }
- else
- {
- DEBUG_OUT(m_pErrorMessages, DOL_REALAUDIO_EXTENDED,
- (s, "A lot behind on stream %u's skipping ahead to %lut0x%X", uStreamNumber,
- audioData.ulAudioTime, pnr));
- DEBUG_OUTF(AUDIOSERVICES_FILE,
- (s, "A lot behind on stream %u's skipping ahead to %lut0x%Xn", uStreamNumber,
- audioData.ulAudioTime, pnr));
- UINT32 ulLatestActualTime = NO_TIME_SET;
- UINT32 ulLatestStreamTime = NO_TIME_SET;
- // we are a lot behind and should tell this format to discard
- // data until the audio stream time.
- GetLatestTimesForStream(uStreamNumber,
- ulLatestActualTime,
- ulLatestStreamTime);
- if (ulLatestActualTime == NO_TIME_SET)
- {
- ulLatestActualTime = m_ulLatestActualTime;
- }
- if (ulLatestActualTime != NO_TIME_SET)
- {
- m_pRaFormats[uStreamNumber]->
- DiscardTillEndOfCrossFade(ulLatestActualTime);
- }
- // we don't want to try again with this data
- bTryWrite = FALSE;
- }
- }
- }
- if (SUCCEEDED(pnr))
- {
- DEBUG_OUT(m_pErrorMessages, DOL_REALAUDIO_EXTENDED,
- (s, "wt%ut%lut%lut%lut0x%Xt%d", uStreamNumber,
- pAudioData->ulAudioTime, m_ulCurrentTimelineTime, ulActualTimestamp,
- pnr, pAudioData->uAudioStreamType));
- DEBUG_OUTF(AUDIOSERVICES_FILE,
- (s, "wt%ut%lut%lut%lut0x%lXt%dn", uStreamNumber,
- pAudioData->ulAudioTime, m_ulCurrentTimelineTime, ulActualTimestamp,
- pnr, pAudioData->uAudioStreamType));
- }
- return pnr;
- }
- void
- CRealAudioRenderer::GetLatestTimesForStream(UINT16 uStream,
- UINT32& ulLatestActualTime,
- UINT32& ulLatestStreamTime)
- {
- ulLatestActualTime = m_ulLatestActualTime;
- ulLatestStreamTime = m_ulLatestStreamTime;
- }
- BOOL CRealAudioRenderer::IsCrossfadeInProgress(void)
- {
- return FALSE;
- }
- /////////////////////////////////////////////////////////////////////////////
- // Method:
- // CRealAudioRenderer::DoAudio
- //
- // Note: See Switchsod.txt for how this is supposed to work, please keep
- // the sod up to date with changes here too.
- //
- HX_RESULT
- CRealAudioRenderer::DoAudio(UINT32& ulAudioTime, AUDIO_STATE audioState = AUDIO_NORMAL)
- {
- #ifdef HELIX_CONFIG_ONLY_DECODE_IF_DRY
- // Only decode if our audio buffers are 'dry' -- unless we're not
- // playing yet, because in that case we're not going to go dry.
- // The second condition totally screws up seeking.
- //if( audioState != AUDIO_DRYNOTIFICATION && m_PlayState != buffering )
- if( audioState != AUDIO_DRYNOTIFICATION )
- {
- return HXR_OK;
- }
- // if we could ask the audio stream how many PCM buffers are curently
- // in its write list, we could make sure we don't write any more if the
- // numbers is greater than n.
- #endif // HELIX_CONFIG_ONLY_DECODE_IF_DRY
- HX_RESULT pnr = HXR_NO_DATA;
- UINT32 ulActualTimestamp = 0;
- UINT16 nActive= 0;
- UINT16 uLowest = NO_STREAM_SET;
- UINT16 uLongestOverlap = NO_STREAM_SET;
- UINT32 ulLowestStartTime = NO_TIME_SET;
- UINT32 ulLowestEndTime = NO_TIME_SET;
- UINT32 ulLatestActualTime;
- UINT32 ulLatestStreamTime;
- HXAudioData audioData;
- audioData.pData = NULL;
- audioData.ulAudioTime = ulAudioTime = 0;
- // if we are waiting for dry notification, return imediately.
- if (m_usPreviousDryNotificationStream != NO_STREAM_SET)
- {
- HX_ASSERT(m_bPreRedstonePlayer);
- return HXR_OK;
- }
- // if we are cross fading, set the audio state right.
- if (IsCrossfadeInProgress() && (audioState == AUDIO_NORMAL))
- {
- audioState = AUDIO_CROSSFADE;
- }
- FindLowestStartTime(uLowest, ulLowestStartTime, ulLowestEndTime, nActive);
- DEBUG_OUTF(DOAUDIO_FILE, (s, "Lowest: Stream=%u Start=%lu End=%lu Active=%un",
- uLowest, ulLowestStartTime, ulLowestEndTime, nActive));
- // Identify latest packet time for purposes of gap filling
- GetLatestTimesForStream(uLowest, ulLatestActualTime, ulLatestStreamTime);
- // if the ulLowestStartTime is > m_ulLatestStreamTime or NO_TIME_SET
- // then we need to fill with loss generated from the last known stream?
- if ((ulLatestActualTime != NO_TIME_SET) &&
- ((ulLowestStartTime != NO_TIME_SET) &&
- IsTimeGreater(ulLowestStartTime, ulLatestActualTime + RA_TIME_FUDGE)) &&
- ((uLowest == m_usCurrentDryNotificationStream) ||
- IsCrossfadeInProgress()))
- {
- DEBUG_OUT(m_pErrorMessages, DOL_REALAUDIO,
- (s, "Gap from %lu on %d(%d) to %lu on %d -- write loss",
- ulLowestStartTime, uLowest, audioState,
- ulLatestActualTime, m_usCurrentDryNotificationStream));
- pnr = m_pRaFormats[uLowest]->
- GenerateLostAudioData(ulLowestStartTime,
- audioData,
- ulActualTimestamp,
- ulLatestActualTime,
- ulLatestStreamTime);
- DEBUG_OUTF(LOSS_FILE,
- (s, "Gap from %lu on %d(%d) to %lu on %d -- write losst%lut%lun",
- ulLowestStartTime, uLowest, audioState,
- ulLatestActualTime, uLowest,
- audioData.ulAudioTime, ulLatestActualTime));
- if (SUCCEEDED(pnr) && (pnr != HXR_NO_DATA))
- {
- pnr = WriteToAudioServices(uLowest, &audioData, ulActualTimestamp);
- DEBUG_OUTF(DOAUDIO_FILE, (s, "Write Loss:t%ut%lut%lut%ct%dt0x%Xn",
- uLowest, audioData.ulAudioTime, ulActualTimestamp,
- (!IsCrossfadeInProgress())?('F'):('T'), audioState, pnr));
- // Set uLowest to NO_STREAM_SET and nActive to 0 to prevent
- // further processing.
- uLowest = NO_STREAM_SET;
- nActive = 0;
- }
- HX_RELEASE(audioData.pData);
- }
- else if (ulLowestStartTime == NO_TIME_SET)
- {
- m_bDoneWritingPackets = m_bEndOfPackets;
- }
- // if more than one active format and we're not currently cross
- // fading, loop through the formats looking for overlap,
- // if I find it, remember that stream and it's current time
- // range end time. If I find another stream that overlaps, with a
- // greater current time range end time, flush the current time range
- // on the first and make the longer time range one the overlap candidate.
- if ((nActive > 1) &&
- (uLowest != NO_STREAM_SET) &&
- (!IsCrossfadeInProgress()))
- {
- FindLongestOverlap(uLowest, ulLowestEndTime,
- nActive, uLongestOverlap,
- audioState);
- }
- if (ulLatestActualTime == NO_TIME_SET)
- {
- ulLatestActualTime = m_ulLatestActualTime;
- ulLatestStreamTime = m_ulLatestStreamTime;
- }
- // if there's an overlap candidate, setup crossfade on the two streams
- if (uLongestOverlap != NO_STREAM_SET)
- {
- pnr = AttemptCrossfade(uLowest, // From stream
- uLongestOverlap, // To stream
- ulLatestActualTime,
- ulLatestStreamTime,
- audioData.ulAudioTime, // Out from stream start time
- ulActualTimestamp,
- audioState);
- }
- else if (uLowest != NO_STREAM_SET)
- {
- // write the lowest stream to audio services
- pnr = m_pRaFormats[uLowest]->GetAudioData(
- audioData,
- ulActualTimestamp,
- (m_bEndOfPackets) ? (AUDIO_END_OF_PACKETS) : (audioState),
- ulLatestActualTime,
- ulLatestStreamTime);
- if (HXR_OK == pnr)
- {
- pnr = WriteToAudioServices(uLowest,
- &audioData,
- ulActualTimestamp);
- }
- else if (HXR_OUTOFMEMORY == pnr)
- {
- return pnr;
- }
- DEBUG_OUTF(DOAUDIO_FILE, (s, "Write Lowest:t%ut%lut%lut%ct%dt0x%Xn",
- uLowest, audioData.ulAudioTime, ulActualTimestamp,
- (!IsCrossfadeInProgress())?('T'):('F'), audioState, pnr));
- }
- // release the data buffer if we got one
- HX_RELEASE(audioData.pData);
- // if we are cross fading, check to see if the cross fade is over
- if ((uLowest != NO_STREAM_SET) &&
- SUCCEEDED(pnr) &&
- (HXR_NO_DATA != pnr))
- {
- if (IsCrossfadeInProgress())
- {
- pnr = AttemptCrossfadeTermination(uLowest,
- ulActualTimestamp,
- (pnr == HXR_STREAM_DONE));
- }
- }
- // if I didn't write audio on the current dry notification stream but I
- // did on another stream, make that stream the current dry notification
- // stream
- if ((pnr == HXR_OK) &&
- (uLowest != NO_STREAM_SET) &&
- (!IsCrossfadeInProgress()) &&
- (uLowest != m_usCurrentDryNotificationStream))
- {
- DEBUG_OUTF(DOAUDIO_FILE, (s, "New DN stream: %ut%lun", uLowest, pnr));
- AddDryNotification(uLowest);
- }
- // update the out param
- ulAudioTime = audioData.ulAudioTime;
- return pnr;
- }
- BOOL CRealAudioRenderer::HaveDataToWrite()
- {
- BOOL bRet = FALSE;
- for (UINT16 i = 0; !bRet && (i < m_uNumOfSubStreams); i++)
- {
- // we delt with the current dry notification stream above
- if (m_pRaFormats[i]->IsActive())
- {
- UINT32 ulCurrentStartTime = 0;
- UINT32 ulCurrentEndTime = 0;
- HX_RESULT pnr = m_pRaFormats[i]->
- GetNextAudioDataTime(ulCurrentStartTime, ulCurrentEndTime);
- if ((pnr == HXR_OK) && (ulCurrentStartTime != NO_TIME_SET))
- {
- bRet = TRUE;
- }
- }
- }
- return bRet;
- }
- /////////////////////////////////////////////////////////////////////////////
- // Method:
- // CRealAudioRenderer::FindLowestStartTime
- HX_RESULT
- CRealAudioRenderer::FindLowestStartTime(UINT16& uLowest, UINT32& ulLowestStartTime,
- UINT32& ulLowestEndTime, UINT16& nActive)
- {
- UINT16 i;
- UINT32 ulCurrentStartTime = 0;
- UINT32 ulCurrentEndTime = 0;
- HX_RESULT pnr = HXR_OK;
- uLowest = NO_STREAM_SET;
- ulLowestStartTime = NO_TIME_SET;
- nActive = 0;
- for (i = 0; i < m_uNumOfSubStreams; i++)
- {
- // we delt with the current dry notification stream above
- if (m_pRaFormats[i]->IsActive())
- {
- nActive++;
- pnr = m_pRaFormats[i]->
- GetNextAudioDataTime(ulCurrentStartTime, ulCurrentEndTime);
- if ((pnr == HXR_OK) &&
- (ulCurrentStartTime != NO_TIME_SET) &&
- ((ulLowestStartTime == NO_TIME_SET) ||
- IsTimeLess(ulCurrentStartTime, ulLowestStartTime)))
- {
- uLowest = i;
- ulLowestStartTime = ulCurrentStartTime;
- ulLowestEndTime = ulCurrentEndTime;
- }
- }
- }
- return HXR_OK;
- }
- /////////////////////////////////////////////////////////////////////////////
- // Method:
- // CRealAudioRenderer::FindLongestOverlap
- HX_RESULT
- CRealAudioRenderer::FindLongestOverlap(UINT16 uLowest, UINT32 ulLowestEndTime,
- UINT16 nActive, UINT16& uLongestOverlap,
- AUDIO_STATE& audioState)
- {
- uLongestOverlap = NO_STREAM_SET;
- return HXR_OK;
- }
- HX_RESULT CRealAudioRenderer::AttemptCrossfade(UINT16 uLowest,
- UINT16 uLongetOverlap,
- UINT32 ulLatestActualTime,
- UINT32 ulLatestStreamTime,
- UINT32& ulFromStreamTimeStart,
- UINT32& ulFromActualTimeStart,
- AUDIO_STATE audioState)
- {
- return HXR_FAIL;
- }
- HX_RESULT
- CRealAudioRenderer::AttemptCrossfadeTermination(UINT16& uStream,
- UINT32 ulActualTimestamp,
- BOOL bStreamDone)
- {
- uStream = NO_STREAM_SET;
- return (bStreamDone ? HXR_STREAM_DONE : HXR_OK);
- }
- /////////////////////////////////////////////////////////////////////////
- // Method:
- // IHXRenderer::OnPacket
- // Purpose:
- // Called by client engine when a packet for this renderer is
- // due.
- // lTimeOffset is the amount of time that we lag behind the main player time line
- // so if the start time of the track is 10 seconds, lTimeOffset will be 10000 (msec)
- // (the first packet's time stamp will be 0 but the player will be at time=10sec)
- //
- STDMETHODIMP
- CRealAudioRenderer::OnPacket(IHXPacket* pPacket, LONG32 lTimeOffset)
- {
- #if defined(RA_TEST_LOSS)
- static INT32 lNum = 0;
- if (lNum >= 100 && lNum < 106)
- {
- IHXPacket* pLostPacket = NULL;
- m_pCommonClassFactory->CreateInstance(CLSID_IHXPacket, (void**) &pLostPacket);
- if (pLostPacket)
- {
- pLostPacket->Set(0, 0, pPacket->GetStreamNumber(), 0, 0);
- pLostPacket->SetAsLost();
- pPacket = pLostPacket;
- }
- }
- lNum++;
- #endif
- #if defined(HELIX_FEATURE_AUDIO_CODEC_RAAC)
- HX_RESULT retVal = HXR_FAIL;
- if (pPacket)
- {
- if (!pPacket->IsLost())
- {
- // Get the substream of this packet
- UINT16 usSubStream = 0;
- UINT16 usASMRuleNum = pPacket->GetASMRuleNumber();
- if (m_bStreamSwitchable && m_pRuleMap && usASMRuleNum < m_uNumOfRules)
- {
- usSubStream = m_pRuleMap[usASMRuleNum];
- }
- if (usSubStream < m_uNumOfSubStreams)
- {
- // If we have a VBR depacketizer for this substream,
- // then run this packet through it. Otherwise, send
- // the packet on to _OnPacket() as normal.
- if (m_ppVBRDepack[usSubStream])
- {
- m_ppVBRDepack[usSubStream]->PutPacket(pPacket);
- retVal = HXR_OK;
- HX_RESULT rv = HXR_OK;
- while (SUCCEEDED(rv) && SUCCEEDED(retVal))
- {
- IHXPacket* pOutPacket = NULL;
- rv = m_ppVBRDepack[usSubStream]->GetPacket(pOutPacket);
- if (SUCCEEDED(rv))
- {
- retVal = _OnPacket(pOutPacket, lTimeOffset);
- }
- HX_RELEASE(pOutPacket);
- }
- }
- else
- {
- retVal = _OnPacket(pPacket, lTimeOffset);
- }
- }
- }
- else
- {
- retVal = _OnPacket(pPacket, lTimeOffset);
- }
- }
- return retVal;
- #else
- return _OnPacket(pPacket, lTimeOffset);
- #endif
- }
- /////////////////////////////////////////////////////////////////////////
- // Method:
- // IHXRenderer::OnTimeSync
- // Purpose:
- // Called by client engine to inform the renderer of the current
- // time relative to the streams synchronized time-line. The
- // renderer should use this time value to update its display or
- // render it's stream data accordingly.
- //
- STDMETHODIMP CRealAudioRenderer::OnTimeSync(ULONG32 ulTime)
- {
- HX_RESULT retVal = HXR_OK;
- m_pMutex->Lock();
- // if we get a timesync we must be playing
- m_PlayState = playing;
- // Here's a good time to actually render the data!
- m_ulCurrentTimelineTime = ulTime;
- /***
- if (m_usCurrentDryNotificationStream != NO_TIME_SET)
- {
- DEBUG_OUTF_IDX(m_usCurrentDryNotificationStream, RA_FLOW_FILE,
- (s, "Time Sync: %un", m_ulCurrentTimelineTime));
- }
- ***/
- DEBUG_OUTF(RASYNC_FILE, (s, "RAtOnTimeSync:t%lun", ulTime));
- // unregister any time syncs.
- UnregisterTimeSyncs(ulTime);
- #ifdef _MACINTOSH
- /* On Mac, since we do not have Mutex, we do not want to process
- * data if we are within OnPacket call
- */
- if (m_bProcessingPacket)
- {
- goto exit;
- }
- m_bProcessingPacket = TRUE;
- #endif /*_MACINTOSH*/
- // Write to AS
- UINT32 ulAudioTime;
- retVal = DoAudio(ulAudioTime);
- if (m_ulCurrentGranularity < MINIMUM_GRANULARITY)
- {
- // if our granularity is less than the minimum granularity of the system.
- // then call do audio again. We should always decode at least twice the
- // amount of data as our granularity.
- retVal = DoAudio(ulAudioTime);
- }
- if( retVal == HXR_OUTOFMEMORY )
- {
- if( m_pErrorMessages )
- {
- m_pErrorMessages->Report( HXLOG_ERR, retVal, 0, NULL, NULL );
- }
- }
- else
- {
- retVal = HXR_OK;
- }
- #ifdef _MACINTOSH
- m_bProcessingPacket = FALSE;
- exit:
- #endif /*_MACINTOSH*/
- m_pMutex->Unlock();
- return retVal;
- }
- /////////////////////////////////////////////////////////////////////////
- // Method:
- // IHXRenderer::OnPreSeek
- // Purpose:
- // Called by client engine to inform the renderer that a seek is
- // about to occur. The render is informed the last time for the
- // stream's time line before the seek, as well as the first new
- // time for the stream's time line after the seek will be completed.
- //
- STDMETHODIMP CRealAudioRenderer::OnPreSeek(ULONG32 ulOldTime,
- ULONG32 ulNewTime)
- {
- m_PlayState = seeking;
- m_ulCurrentTimelineTime = ulNewTime;
- m_bEndOfPackets = FALSE;
- m_bDoneWritingPackets = FALSE;
- m_bInSeekMode = TRUE;
- m_bFirstPacket = TRUE;
- DEBUG_OUTF(RASYNC_FILE, (s, "RAtPreSeekt%lut%lun", ulOldTime, ulNewTime));
- UINT16 i = 0;
- for (i = 0; i < m_uNumOfSubStreams; i++)
- {
- m_pRaFormats[i]->OnSeek(ulOldTime,ulNewTime);
- m_pRaFormats[i]->m_ulLastPacketTime = NO_TIME_SET;
- m_pRaFormats[i]->m_ulBytesWrite = 0;
- if (m_pRaFormats[i]->m_pAudioSync && m_pRaFormats[i]->m_bRegistered)
- {
- m_pRaFormats[i]->m_bRegistered = FALSE;
- m_pRaFormats[i]->m_pAudioSync->UnRegister();
- DEBUG_OUTF_IDX(i, RA_FLOW_FILE,
- (s, "Sync Stopn"));
- }
- }
- // flush the unregister queue since we just unregistered every stream
- FlushUnregisterQueue();
- m_ulLatestStreamTime = NO_TIME_SET;
- m_ulLatestActualTime = NO_TIME_SET;
- m_fLatestStreamTime = 0.0;
- m_bAllStreamsToBeUnregistered = FALSE;
- if (m_usCurrentDryNotificationStream == NO_TIME_SET)
- {
- AddDryNotification(DEFAULT_DRY_NOTIFICATION);
- }
- return HXR_OK;
- }
- /////////////////////////////////////////////////////////////////////////
- // Method:
- // IHXRenderer::OnPostSeek
- // Purpose:
- // Called by client engine to inform the renderer that a seek has
- // just occured. The render is informed the last time for the
- // stream's time line before the seek, as well as the first new
- // time for the stream's time line after the seek.
- //
- STDMETHODIMP CRealAudioRenderer::OnPostSeek(ULONG32 ulOldTime, ULONG32 ulNewTime)
- {
- DEBUG_OUTF(RASYNC_FILE, (s, "RAtPostSeekt%lut%lun", ulOldTime, ulNewTime));
- #if defined(HELIX_FEATURE_AUDIO_CODEC_RAAC)
- for (UINT16 i = 0; i < m_uNumOfSubStreams; i++)
- {
- if (m_ppVBRDepack[i])
- {
- m_ppVBRDepack[i]->OnSeek(ulOldTime, ulNewTime);
- }
- }
- #endif /* #if defined(HELIX_FEATURE_AUDIO_CODEC_RAAC) */
- m_bInSeekMode = FALSE;
- return HXR_OK;
- }
- /////////////////////////////////////////////////////////////////////////
- // Method:
- // IHXRenderer::OnPause
- // Purpose:
- // Called by client engine to inform the renderer that a pause has
- // just occured. The render is informed the last time for the
- // stream's time line before the pause.
- //
- STDMETHODIMP CRealAudioRenderer::OnPause(ULONG32 ulTime)
- {
- m_PlayState = paused;
- return HXR_OK;
- }
- /////////////////////////////////////////////////////////////////////////
- // Method:
- // IHXRenderer::OnBegin
- // Purpose:
- // Called by client engine to inform the renderer that a begin or
- // resume has just occured. The render is informed the first time
- // for the stream's time line after the resume.
- //
- STDMETHODIMP CRealAudioRenderer::OnBegin(ULONG32 ulTime)
- {
- return HXR_OK;
- }
- /////////////////////////////////////////////////////////////////////////
- // Method:
- // IHXRenderer::OnBuffering
- // Purpose:
- // Called by client engine to inform the renderer that buffering
- // of data is occuring. The render is informed of the reason for
- // the buffering (start-up of stream, seek has occured, network
- // congestion, etc.), as well as percentage complete of the
- // buffering process.
- //
- STDMETHODIMP CRealAudioRenderer::OnBuffering(ULONG32 ulFlags, UINT16 unPercentComplete)
- {
- m_PlayState = buffering;
- return HXR_OK;
- }
- /////////////////////////////////////////////////////////////////////////
- // Method:
- // IHXRenderer::GetDisplayType
- // Purpose:
- // Called by client engine to ask the renderer for it's preferred
- // display type. When layout information is not present, the
- // renderer will be asked for it's prefered display type. Depending
- // on the display type a buffer of additional information may be
- // needed. This buffer could contain information about preferred
- // window size.
- //
- STDMETHODIMP CRealAudioRenderer::GetDisplayType
- (
- REF(HX_DISPLAY_TYPE) ulFlags,
- REF(IHXBuffer*) pBuffer
- )
- {
- ulFlags = HX_DISPLAY_NONE;
- return HXR_OK;
- }
- /************************************************************************
- * Method:
- * IHXRenderer::OnEndofPackets
- * Purpose:
- * Called by client engine to inform the renderer that all the
- * packets have been delivered. However, if the user seeks before
- * EndStream() is called, renderer may start getting packets again
- * and the client engine will eventually call this function again.
- */
- STDMETHODIMP CRealAudioRenderer::OnEndofPackets(void)
- {
- /* we should release any remaining sub-superblocks to audio services here*/
- m_bEndOfPackets = TRUE;
- if (m_bReportOKStatus && m_pStream)
- {
- m_bReportOKStatus = FALSE;
- m_pStream->ReportRebufferStatus(1,1);
- }
- m_pMutex->Lock();
- UINT16 i = 0;
- for (i = 0; i < m_uNumOfSubStreams; i++)
- {
- m_pRaFormats[i]->OnEndofPackets();
- #ifdef _MACINTOSH
- UINT32 ulActualTimestamp = 0;
- HXAudioData audioData;
- audioData.pData = NULL;
- audioData.ulAudioTime = 0;
- // XXXJEFFA Get rid of this while loop. There shouldn't be
- // any while loops in the renderer.
- while (m_pRaFormats[i]->GetAudioData(audioData,
- ulActualTimestamp,
- AUDIO_END_OF_PACKETS,
- m_ulLatestActualTime,
- m_ulLatestStreamTime) == HXR_OK)
- {
- HX_RESULT pnr = m_pAudioStreams[i]->Write(&audioData );
- LogAudioWrite(i, &audioData, ulActualTimestamp, pnr);
- HX_ASSERT(SUCCEEDED(pnr));
- m_pRaFormats[i]->m_pAudioSync->FudgeTimestamp(m_pRaFormats[i]->m_ulBytesWrite,
- ulActualTimestamp);
- m_pRaFormats[i]->m_ulBytesWrite += (audioData.pData)->GetSize();
- CalculateMaxTimeStamp(i, &audioData, ulActualTimestamp);
- HX_RELEASE(audioData.pData);
- m_pRaFormats[i]->m_ulLastPacketTime = audioData.ulAudioTime;
- }
- #endif
- }
- m_bAllStreamsToBeUnregistered = TRUE;
- m_pMutex->Unlock();
- return HXR_OK;
- }
- /*
- * IHXDryNotification methods
- */
- /************************************************************************
- * Method:
- * OnDryNotification
- * Purpose:
- * This function is called when it is time to write to audio device
- * and there is not enough data in the audio stream. The renderer can
- * then decide to add more data to the audio stream. This should be
- * done synchronously within the call to this function.
- * It is OK to not write any data. Silence will be played instead.
- */
- STDMETHODIMP CRealAudioRenderer::OnDryNotification(UINT32 /*IN*/ ulCurrentStreamTime,
- UINT32 /*IN*/ ulMinimumDurationRequired)
- {
- /* If the renderer is delayed, do not report rebuffer status until the
- * packets are really due i.e. until Current time + Preroll is greater
- * than the Delay time.
- */
- m_pMutex->Lock();
- if (m_bDoneWritingPackets)
- {
- goto exit;
- }
- #ifdef HELIX_FEATURE_RAREND_PREREDSTONE_SUPPORT
- if (m_usPreviousDryNotificationStream != NO_STREAM_SET)
- {
- HX_ASSERT(m_bPreRedstonePlayer);
- UINT32 ulCurrentStartTime, ulCurrentEndTime;
- // get the next audio time for this format
- m_pRaFormats[m_usCurrentDryNotificationStream]->GetNextAudioDataTime(ulCurrentStartTime, ulCurrentEndTime);
- DEBUG_OUT(m_pErrorMessages, DOL_REALAUDIO_EXTENDED,
- (s, "PreviousDryNot(%u): Behind on stream %u's skipping ahead to %lu",
- m_usPreviousDryNotificationStream, m_usCurrentDryNotificationStream, ulCurrentStreamTime));
- DEBUG_OUTF(AUDIOSERVICES_FILE,
- (s, "PreviousDryNot(%u): Behind on stream %u's skipping ahead to %lun",
- m_usPreviousDryNotificationStream, m_usCurrentDryNotificationStream, ulCurrentStreamTime));
- // if it is < ulCurrentStreamTime we discard until ulCurrentStreamTime
- if (IsTimeLess(ulCurrentStartTime, ulCurrentStreamTime))
- {
- m_pRaFormats[m_usCurrentDryNotificationStream]->
- DiscardTillEndOfCrossFade(ulCurrentStreamTime);
- }
- // reset dry notification
- AddDryNotification(m_usPreviousDryNotificationStream);
- m_usPreviousDryNotificationStream = NO_STREAM_SET;
- }
- else
- #endif // HELIX_FEATURE_RAREND_PREREDSTONE_SUPPORT
- if (NO_TIME_SET != m_ulLatestStreamTime &&
- IsTimeGreater(ulCurrentStreamTime, m_ulLatestStreamTime + RA_TIME_FUDGE))
- {
- // if the stream time reported by audio services is ahead of the
- // current writing time of the renderer, update the writing time
- // of the renderer so it catches up with the audio services stream
- DEBUG_OUTF(LATESTPACKET_FILE,
- (s, "DryNotificationt%ut%lut%lun",
- m_usCurrentDryNotificationStream, m_ulLatestStreamTime, ulCurrentStreamTime));
- ULONG32 ulTimeDiff = ulCurrentStreamTime - m_ulLatestStreamTime;
- m_ulLatestStreamTime += ulTimeDiff;
- m_fLatestStreamTime = UINT32_TO_DOUBLE(m_ulLatestStreamTime);
- m_ulLatestActualTime += ulTimeDiff;
- DEBUG_OUT(m_pErrorMessages, DOL_REALAUDIO_EXTENDED,
- (s, "Behind on stream %u's skipping ahead to %lu",
- m_usCurrentDryNotificationStream, ulCurrentStreamTime));
- DEBUG_OUTF(AUDIOSERVICES_FILE,
- (s, "Behind on stream %u's skipping ahead to %lun",
- m_usCurrentDryNotificationStream, ulCurrentStreamTime));
- }
- DEBUG_OUTF(SWITCH_FILE,
- (s, "OnDryNotification(%p)t%ct%lu > %lut%lu > %lun", this, (!m_bFirstPacket)?('T'):('F'),
- ulCurrentStreamTime + m_ulPreroll, m_ulDelay,
- ulCurrentStreamTime + RA_TIME_FUDGE, m_ulLatestStreamTime));
- if (!m_bFirstPacket &&
- IsTimeGreater(ulCurrentStreamTime + m_ulPreroll, m_ulDelay) &&
- (NO_TIME_SET == m_ulLatestStreamTime ||
- IsTimeGreater(ulCurrentStreamTime + RA_TIME_FUDGE, m_ulLatestStreamTime)))
- {
- // Try to write some audio to satisfy the audio stream
- HX_RESULT pnr = HXR_OK;
- UINT32 ulAudioWantedTime =
- (ulCurrentStreamTime + ulMinimumDurationRequired);
- DEBUG_OUT(m_pErrorMessages, DOL_REALAUDIO_EXTENDED,
- (s, "OnDryNotificationt%lut%lut%lu", ulCurrentStreamTime,
- ulMinimumDurationRequired,
- m_ulLatestStreamTime));
- DEBUG_OUTF(SWITCH_FILE,
- (s, "OnDryNotificationt%lut%lut%lun", ulCurrentStreamTime,
- ulMinimumDurationRequired,
- m_ulLatestStreamTime));
- #ifdef _MACINTOSH
- if (!m_bProcessingPacket)
- {
- m_bProcessingPacket = TRUE;
- pnr = AttemptToSatisfyDryRequest(ulAudioWantedTime);
- m_bProcessingPacket = FALSE;
- LOG_BUFFERING(BUF_LOG_FILE,
- (s, "Dry Notif: StreamTime=%u Duration=%u %sn",
- ulAudioWantedTime, ulMinimumDurationRequired,
- (pnr == HXR_OK) ? "Satisfied" : "Dry"));
- }
- else
- {
- ScheduleDryCallback(ulAudioWantedTime);
- pnr = HXR_NO_DATA;
- }
- #else
- pnr = AttemptToSatisfyDryRequest(ulAudioWantedTime);
- LOG_BUFFERING(BUF_LOG_FILE,
- (s, "Dry Notif: StreamTime=%u Duration=%u %sn",
- ulAudioWantedTime, ulMinimumDurationRequired,
- (pnr == HXR_OK) ? "Satisfied" : "Dry"));
- #endif
- // if we couldn't satisfy the request and we have not
- // recieved all of our packets, and we have started playing,
- // tell the core to rebuffer
- if ((FAILED(pnr) || HXR_NO_DATA == pnr) && !m_bEndOfPackets &&
- IsTimeGreaterOrEqual(ulCurrentStreamTime, m_ulDelay))
- {
- BOOL bSkipRebuffer = FALSE;
- #ifdef REBUFFERING_SKIP
- /// We only do this for live now
- IHXStreamSource* pSource = NULL;
- m_pStream->GetSource(pSource);
- if (pSource != NULL && pSource->IsLive())
- {
-
- if (m_pBufferingStats && (m_usThisSourceStream != NO_STREAM_SET))
- {
- INT64 llLowestTimestamp = 0;
- INT64 llHighestTimestamp = 0;
- UINT32 ulNumBytes = 0;
- BOOL bDone = FALSE;
- if (SUCCEEDED(m_pBufferingStats->GetCurrentBuffering(
- m_usThisSourceStream,
- llLowestTimestamp,
- llHighestTimestamp,
- ulNumBytes,
- bDone)))
- {
- if (ulNumBytes != 0)
- {
- if ((llHighestTimestamp - llLowestTimestamp) > MAX_TRANSPORT_BUFFER_DURATION
- || ulNumBytes >= MAX_TRASPORT_BUFFER_BYTES)
- {
- bSkipRebuffer = TRUE;
- DEBUG_OUT(m_pErrorMessages, DOL_REALAUDIO,
- (s, "Skipping Buffering on stream %u", m_usCurrentDryNotificationStream));
- }
- }
- #ifdef LOG_BUFFERING_ENABLED
- ULONG32 ulTransportDuration = (ULONG32) (llHighestTimestamp - llLowestTimestamp);
- LOG_BUFFERING(BUF_LOG_FILE,
- (s, "Buffering: DurationAtTransport=%u BytesAtTransport=%u %sn",
- ulTransportDuration, ulNumBytes,
- bSkipRebuffer ? "Skipped" : "Engaged"));
- #endif // LOG_BUFFERING_ENABLED
- }
- }
- }
- HX_RELEASE(pSource);
- #endif // REBUFFERING_SKIP
- // If we have no data to give due to loss, do not rebuffer
- if (!bSkipRebuffer)
- {
- m_bReportOKStatus = TRUE;
- m_pStream->ReportRebufferStatus(1,0);
- DEBUG_OUTF(SWITCH_FILE,
- (s, "Entering Bufferingt%un", m_usCurrentDryNotificationStream));
- DEBUG_OUT(m_pErrorMessages, DOL_REALAUDIO,
- (s, "Entering Buffering on stream %u", m_usCurrentDryNotificationStream));
- }
- }
- // If we are not rebuffering even though have no data to feed,
- // advance the audio time
- if (FAILED(pnr))
- {
- if (!m_bReportOKStatus)
- {
- m_ulLatestStreamTime = ulCurrentStreamTime + ulMinimumDurationRequired;
- m_fLatestStreamTime = UINT32_TO_DOUBLE(m_ulLatestStreamTime);
- m_ulLatestActualTime += ulMinimumDurationRequired;
- }
- }
- }
- exit:
- m_pMutex->Unlock();
- return HXR_OK;
- }
- #ifdef _MACINTOSH
- void
- CRealAudioRenderer::ScheduleDryCallback(UINT32 ulAudioWantedTime)
- {
- if (m_pDryCallback == NULL)
- {
- CDryNotificationCallback* pCallback =
- CDryNotificationCallback::CreateInstance(ulAudioWantedTime, this,
- m_pContext);
- if (pCallback != NULL)
- {
- m_pDryCallback = pCallback;
- m_pDryCallback->ScheduleCallback();
- }
- }
- else
- {
- m_pDryCallback->UpdateAudioTimeWanted(ulAudioWantedTime);
- }
- }
- #endif /*_MACINTOSH */
- STDMETHODIMP
- CRealAudioRenderer::AttemptToSatisfyDryRequest(UINT32 ulAudioWantedTime)
- {
- HX_RESULT pnr = HXR_OK;
- UINT32 ulAudioTime = 0;
- while (m_usPreviousDryNotificationStream == NO_STREAM_SET &&
- HXR_OK == pnr &&
- ((NO_TIME_SET == m_ulLatestStreamTime) ||
- IsTimeGreaterOrEqual(ulAudioWantedTime, m_ulLatestStreamTime)))
- {
- pnr = DoAudio(ulAudioTime, AUDIO_DRYNOTIFICATION);
- DEBUG_OUTF(SWITCH_FILE,
- (s, "AttemptToSatisfyDryRequestt%lut%lut%ut0x%Xn", m_ulLatestStreamTime,
- ulAudioWantedTime, m_usCurrentDryNotificationStream, pnr));
- DEBUG_OUT(m_pErrorMessages, DOL_REALAUDIO_EXTENDED,
- (s, "AttemptToSatisfyDryRequestt%lut%lut%ut0x%X", m_ulLatestStreamTime,
- ulAudioWantedTime, m_usCurrentDryNotificationStream, pnr));
- if (HXR_LATE_PACKET == pnr)
- {
- /* Reset the return value to HXR_OK because
- * we want to keep writing if we wrote late
- * data
- */
- pnr = HXR_OK;
- }
- }
- #ifdef _MACINTOSH
- HX_RELEASE(m_pDryCallback);
- // if we get here by the callback, we want to turn off
- // bufferning if we can
- if (m_bReportOKStatus && IsTimeGreaterOrEqual(m_ulLatestStreamTime, ulAudioWantedTime))
- {
- m_bReportOKStatus = FALSE;
- m_pStream->ReportRebufferStatus(1,1);
- }
- #endif
- return pnr;
- }
- void
- CRealAudioRenderer::CalculateMaxTimeStamp(UINT16 uStreamNumber,
- HXAudioData* pAudioData,
- UINT32 ulActualTimestamp,
- UINT32* pulDataDuration,
- double* pfDataDuration)
- {
- double fDataDuration =
- m_pRaFormats[uStreamNumber]->ConvertBytesToMs(pAudioData->pData->GetSize());
- UINT32 ulDataDuration = (UINT32) (fDataDuration + 0.5);
- AdvanceLatestTime(pAudioData->ulAudioTime,
- ulActualTimestamp,
- ulDataDuration,
- fDataDuration,
- m_ulLatestStreamTime,
- m_fLatestStreamTime,
- m_ulLatestActualTime);
- if (pulDataDuration)
- {
- *pulDataDuration = ulDataDuration;
- }
- if (pfDataDuration)
- {
- *pfDataDuration = fDataDuration;
- }
- }
- void
- CRealAudioRenderer::AdvanceLatestTime(UINT32 ulBaseStreamTime,
- UINT32 ulBaseActualTime,
- UINT32 ulDurationAdvance,
- double fDurationAdvance,
- UINT32 &ulLatestStreamTime,
- double &fLatestStreamTime,
- UINT32 &ulLatestActualTime)
- {
- UINT32 ulStreamEndTimestamp = ulBaseStreamTime + ulDurationAdvance;
- if ((ulLatestStreamTime == NO_TIME_SET) ||
- IsTimeLess(ulLatestStreamTime, ulStreamEndTimestamp))
- {
- if ((ulLatestStreamTime == NO_TIME_SET) ||
- ((ulBaseStreamTime - ulLatestStreamTime) > RA_TIME_FUDGE))
- {
- fLatestStreamTime = UINT32_TO_DOUBLE(ulBaseStreamTime);
- }
- INCREMENT_FLOAT_TS(fLatestStreamTime, fDurationAdvance);
- ulLatestStreamTime = (ULONG32) (fLatestStreamTime);
- ulLatestActualTime = ulBaseActualTime + ulDurationAdvance;
- if (ulLatestStreamTime == NO_TIME_SET)
- {
- ulLatestStreamTime++;
- }
- if (ulLatestActualTime == NO_TIME_SET)
- {
- ulLatestActualTime++;
- }
- }
- }
- void
- CRealAudioRenderer::OffsetLatestTime(UINT16 uStreamNumber,
- INT32 lTimeOffset)
- {
- m_ulLatestStreamTime += lTimeOffset;
- m_ulLatestActualTime += lTimeOffset;
- m_fLatestStreamTime += ((double) lTimeOffset);
- }
- void CRealAudioRenderer::WriteCodecsToRegistry(const char* pAllCodecs)
- {
- #if defined(HELIX_FEATURE_STATS)
- if (m_pRegistry)
- {
- char szRegistryEntry[MAX_DISPLAY_NAME] = {0}; /* Flawfinder: ignore */
- IHXBuffer* pszRegistryName = NULL;
- // Get the current registry key name
- if (HXR_OK == m_pRegistry->GetPropName(m_ulRegistryID, pszRegistryName))
- {
- SafeSprintf (szRegistryEntry, MAX_DISPLAY_NAME, "%s.AllCodecs", pszRegistryName->GetBuffer());
- IHXBuffer* pValue = NULL;
- m_pCommonClassFactory->CreateInstance(IID_IHXBuffer, (void**) &pValue);
- if (pValue)
- {
- pValue->Set((UCHAR*) pAllCodecs, strlen(pAllCodecs)+1);
- m_pRegistry->AddStr(szRegistryEntry, pValue);
- pValue->Release();
- }
- pszRegistryName->Release();
- pszRegistryName = NULL;
- }
- }
- #endif // HELIX_FEATURE_STATS
- }
- STDMETHODIMP
- CRealAudioRenderer::InitializeStatistics
- (
- UINT32 /*IN*/ ulRegistryID
- )
- {
- #if defined(HELIX_FEATURE_STATS)
- m_ulRegistryID = ulRegistryID;
- m_ulSmartStreamRegID = 0;
- m_ulNameRegID = 0;
- m_ulCodecRegID = 0;
- m_ulCodecTextRegID = 0;
- m_ulCodec4CCRegID = 0;
- m_ulRateRegID = 0;
- m_ulChannelsRegID = 0;
- #endif // HELIX_FEATURE_STATS
- return HXR_OK;
- }
- STDMETHODIMP
- CRealAudioRenderer::UpdateStatistics()
- {
- #if defined(HELIX_FEATURE_STATS)
- if (m_pRegistry)
- {
- char szRegistryEntry[MAX_DISPLAY_NAME] = {0}; /* Flawfinder: ignore */
- IHXBuffer* pszRegistryName = NULL;
- if (m_usCurrentDryNotificationStream != NO_STREAM_SET &&
- m_pRaFormats[m_usCurrentDryNotificationStream])
- {
- m_pRaFormats[m_usCurrentDryNotificationStream]->UpdateStatistics(
- m_pRegistry, m_ulRegistryID, m_ulCodecRegID, m_ulCodecTextRegID,
- m_ulCodec4CCRegID, m_ulRateRegID, m_ulChannelsRegID,
- m_ulSurroundRegID);
- }
- if (!m_ulSmartStreamRegID || !m_ulNameRegID)
- {
- // Get the current registry key name
- if (HXR_OK == m_pRegistry->GetPropName(m_ulRegistryID, pszRegistryName))
- {
- SafeSprintf (szRegistryEntry, MAX_DISPLAY_NAME, "%s.SureStream", pszRegistryName->GetBuffer());
- IHXBuffer* pValue = NULL;
- m_pCommonClassFactory->CreateInstance(IID_IHXBuffer, (void**) &pValue);
- if (pValue)
- {
- if (m_bStreamSwitchable && m_uNumOfSubStreams > 1)
- {
- pValue->Set((const UCHAR*)"TRUE ", 5);
- }
- else
- {
- pValue->Set((const UCHAR*)"FALSE ", 6);
- }
- m_ulSmartStreamRegID = m_pRegistry->AddStr(szRegistryEntry, pValue);
- HX_RELEASE(pValue);
- }
- SafeSprintf (szRegistryEntry, MAX_DISPLAY_NAME, "%s.Name", pszRegistryName->GetBuffer());
- pValue = NULL;
- m_pCommonClassFactory->CreateInstance(IID_IHXBuffer, (void**) &pValue);
- if (pValue)
- {
- pValue->Set((const UCHAR*)zm_pName, strlen(zm_pName) + 1);
- m_ulNameRegID = m_pRegistry->AddStr(szRegistryEntry, pValue);
- HX_RELEASE(pValue);
- }
- HX_RELEASE(pszRegistryName);
- }
- }
- else
- {
- IHXBuffer* pValue = NULL;
- m_pCommonClassFactory->CreateInstance(IID_IHXBuffer, (void**) &pValue);
- if (pValue)
- {
- if (m_bStreamSwitchable && m_uNumOfSubStreams > 1)
- {
- pValue->Set((const UCHAR*)"TRUE ", 5);
- }
- else
- {
- pValue->Set((const UCHAR*)"FALSE ", 6);
- }
- m_pRegistry->SetStrById(m_ulSmartStreamRegID, pValue);
- HX_RELEASE(pValue);
- }
- pValue = NULL;
- m_pCommonClassFactory->CreateInstance(IID_IHXBuffer, (void**) &pValue);
- if (pValue)
- {
- pValue->Set((const UCHAR*)zm_pName, strlen(zm_pName) + 1);
- m_pRegistry->SetStrById(m_ulNameRegID, pValue);
- HX_RELEASE(pValue);
- }
- }
- }
- #endif // HELIX_FEATURE_STATS
- return HXR_OK;
- }
- void
- CRealAudioRenderer::AddCodec(IHXValues* pValues,
- char* codec,
- UINT32 real_bandwidth,
- UINT32 sort_bandwidth,
- int whichcodec)
- {
- #if defined(HELIX_FEATURE_RAREND_BANDWIDTH_LISTER)
- IHXBuffer* pBuffer;
- char namebuf[20]; /* Flawfinder: ignore */
- IHXCommonClassFactory* pCommonClassFactory;
- if(HXR_OK != m_pContext->QueryInterface(IID_IHXCommonClassFactory,
- (void**)&pCommonClassFactory))
- return;
- if(HXR_OK != pCommonClassFactory->CreateInstance(CLSID_IHXBuffer,
- (void**)&pBuffer))
- {
- pCommonClassFactory->Release();
- return;
- }
- pBuffer->Set((UINT8*)codec, 5);
- sprintf(namebuf, "Codec.%03d", whichcodec); /* Flawfinder: ignore */
- pValues->SetPropertyBuffer(namebuf, pBuffer);
- pBuffer->Release();
- sprintf(namebuf, "Bandwidth.%03d", whichcodec); /* Flawfinder: ignore */
- pValues->SetPropertyULONG32(namebuf, real_bandwidth);
- sprintf(namebuf, "Priority.%03d", whichcodec); /* Flawfinder: ignore */
- pValues->SetPropertyULONG32(namebuf, sort_bandwidth);
- pCommonClassFactory->Release();
- #endif // HELIX_FEATURE_RAREND_BANDWIDTH_LISTER
- }
- STDMETHODIMP
- CRealAudioRenderer::GetBandwidthInfo(IHXValues* pValues)
- {
- #if defined(HELIX_FEATURE_RAREND_BANDWIDTH_LISTER)
- int whichcodec = 0;
- AddCodec(pValues, "dnet", 100, 100, whichcodec++);
- AddCodec(pValues, "dnet", 50, 50, whichcodec++);
- AddCodec(pValues, "dnet", 40, 40, whichcodec++);
- AddCodec(pValues, "dnet", 25, 25, whichcodec++);
- AddCodec(pValues, "sipr", 20, 21, whichcodec++);
- AddCodec(pValues, "dnet", 20, 20, whichcodec++);
- AddCodec(pValues, "28_8", 36, 19, whichcodec++);
- AddCodec(pValues, "dnet", 15, 15, whichcodec++);
- AddCodec(pValues, "sipr", 10, 11, whichcodec++);
- AddCodec(pValues, "dnet", 10, 10, whichcodec++);
- AddCodec(pValues, "sipr", 8, 9, whichcodec++);
- AddCodec(pValues, "sipr", 6, 8, whichcodec++);
- AddCodec(pValues, "lpcJ", 18, 7, whichcodec++);
- AddCodec(pValues, "05_6", 7, 6, whichcodec++);
- pValues->SetPropertyULONG32("CodecCount", whichcodec);
- #endif // HELIX_FEATURE_RAREND_BANDWIDTH_LISTER
- return HXR_OK;
- }
- void CRealAudioRenderer::RemoveCurrentDryNotification()
- {
- IHXAudioStream2* pAudioStream2 = NULL;
- m_pAudioStreams[m_usCurrentDryNotificationStream]->QueryInterface(IID_IHXAudioStream2,
- (void**) &pAudioStream2);
- if (pAudioStream2)
- {
- pAudioStream2->RemoveDryNotification((IHXDryNotification*) this);
- DEBUG_OUTF_IDX(m_usCurrentDryNotificationStream, RA_FLOW_FILE, (s, "Dry-Notif. Stopn"));
- }
- HX_RELEASE(pAudioStream2);
- }
- /************************************************************************
- * Method:
- * IHXASMStreamSink::GetQualityPreference
- * Purpose:
- * Gets the quality slider preference. Used to determine how
- * we add streams to audio services for stream switching content
- */
- HX_RESULT
- CRealAudioRenderer::GetQualityPreference(UINT16& usQuality)
- {
- HX_RESULT pnr = HXR_OK;
- #if defined(HELIX_FEATURE_PREFERENCES)
- IHXBuffer* pBuffer = NULL;
- IHXPreferences* pPreferences = 0;
- if (!m_pContext ||
- m_pContext->QueryInterface(IID_IHXPreferences, (void**) &pPreferences) !=
- HXR_OK)
- {
- pnr = HXR_INVALID_PARAMETER;
- }
- else
- {
- ReadPrefINT16(pPreferences, "Quality", usQuality);
- }
- HX_RELEASE(pPreferences);
- #endif /* #if defined(HELIX_FEATURE_PREFERENCES) */
- return pnr;
- }
- /************************************************************************
- * Method:
- * IHXUpdateProperties::UpdatePacketTimeOffset
- * Purpose:
- * Call this method to update the timestamp offset of cached packets
- */
- STDMETHODIMP
- CRealAudioRenderer::UpdatePacketTimeOffset(INT32 lTimeOffset)
- {
- m_pMutex->Lock();
- m_ulCurrentTimelineTime += lTimeOffset;
- m_ulLatestStreamTime += lTimeOffset;
- m_fLatestStreamTime += (double) lTimeOffset;
- m_ulLatestActualTime += lTimeOffset;
- m_lTimeLineOffset -= lTimeOffset;
- HX_RESULT rc = HXR_OK;
- for (int i = 0; i < m_uNumOfSubStreams; i++)
- {
- HX_ASSERT(m_pRaFormats[i] && m_pAudioStreams[i]);
- if (m_pRaFormats[i])
- {
- // No interfaces in CRaFormat, so this is hard bound
- m_pRaFormats[i]->UpdatePacketTimeOffset(lTimeOffset);
- }
- if (m_pAudioStreams[i])
- {
- IHXUpdateProperties* pUpdateProperties = NULL;
- if (SUCCEEDED(rc = m_pAudioStreams[i]->QueryInterface(IID_IHXUpdateProperties,
- (void**) &pUpdateProperties)))
- {
- pUpdateProperties->UpdatePacketTimeOffset(lTimeOffset);
- HX_RELEASE(pUpdateProperties);
- }
- else
- {
- HX_ASSERT(FALSE);
- m_pMutex->Unlock();
- return rc;
- }
- }
- }
- m_pMutex->Unlock();
- return rc;
- }
- /************************************************************************
- * Method:
- * IHXUpdateProperties::UpdatePlayTimes
- * Purpose:
- * Call this method to update the playtime attributes
- */
- STDMETHODIMP
- CRealAudioRenderer::UpdatePlayTimes(IHXValues* pProps)
- {
- int i = 0;
- UINT32 ulDelay = 0;
- UINT32 ulDuration = 0;
- m_pMutex->Lock();
- if (HXR_OK == pProps->GetPropertyULONG32("Delay", ulDelay))
- {
- m_ulDelay = ulDelay;
- }
- if (HXR_OK == pProps->GetPropertyULONG32("Duration", ulDuration))
- {
- m_ulDuration = ulDuration;
- }
- for (i = 0; i < m_uNumOfSubStreams; i++)
- {
- m_pRaFormats[i]->UpdatePlayTimes(pProps);
- }
- m_pMutex->Unlock();
- return HXR_OK;
- }
- STDMETHODIMP CRealAudioRenderer::SetPropertyULONG32(const char* pName, ULONG32 ulVal)
- {
- HX_RESULT retVal = HXR_FAIL;
- #if defined(HELIX_FEATURE_SETSRCPROPS)
- // Check if we need to create m_pValues
- // and set the source properties
- CheckForSetSourceProperties();
- if (m_pValues)
- {
- retVal = m_pValues->SetPropertyULONG32(pName, ulVal);
- }
- #endif // HELIX_FEATURE_SETSRCPROPS
- return retVal;
- }
- STDMETHODIMP CRealAudioRenderer::GetPropertyULONG32(const char* pName, REF(ULONG32) rulVal)
- {
- HX_RESULT retVal = HXR_FAIL;
- #if defined(HELIX_FEATURE_SETSRCPROPS)
- // Try to dynamically get the property first
- retVal = GetSourcePropertyULONG32(pName, rulVal);
- if (FAILED(retVal) && m_pValues)
- {
- // We failed dynamically try m_pValues
- retVal = m_pValues->GetPropertyULONG32(pName, rulVal);
- }
- #endif // HELIX_FEATURE_SETSRCPROPS
- return retVal;
- }
- STDMETHODIMP CRealAudioRenderer::GetFirstPropertyULONG32(REF(const char*) rpName, REF(ULONG32) rulVal)
- {
- HX_RESULT retVal = HXR_FAIL;
- #if defined(HELIX_FEATURE_SETSRCPROPS)
- // Check if we need to create m_pValues
- // and set the source properties
- CheckForSetSourceProperties(TRUE);
- if (m_pValues)
- {
- retVal = m_pValues->GetFirstPropertyULONG32(rpName, rulVal);
- }
- #endif // HELIX_FEATURE_SETSRCPROPS
- return retVal;
- }
- STDMETHODIMP CRealAudioRenderer::GetNextPropertyULONG32(REF(const char*) rpName, REF(ULONG32) rulVal)
- {
- HX_RESULT retVal = HXR_FAIL;
- #if defined(HELIX_FEATURE_SETSRCPROPS)
- // Check if we need to create m_pValues
- // and set the source properties
- CheckForSetSourceProperties();
- if (m_pValues)
- {
- retVal = m_pValues->GetNextPropertyULONG32(rpName, rulVal);
- }
- #endif // HELIX_FEATURE_SETSRCPROPS
- return retVal;
- }
- STDMETHODIMP CRealAudioRenderer::SetPropertyBuffer(const char* pName, IHXBuffer* pVal)
- {
- HX_RESULT retVal = HXR_FAIL;
- #if defined(HELIX_FEATURE_SETSRCPROPS)
- // Check if we need to create m_pValues
- // and set the source properties
- CheckForSetSourceProperties();
- if (m_pValues)
- {
- retVal = m_pValues->SetPropertyBuffer(pName, pVal);
- }
- #endif // HELIX_FEATURE_SETSRCPROPS
- return retVal;
- }
- STDMETHODIMP CRealAudioRenderer::GetPropertyBuffer(const char* pName, REF(IHXBuffer*) rpVal)
- {
- HX_RESULT retVal = HXR_FAIL;
- #if defined(HELIX_FEATURE_SETSRCPROPS)
- if (m_pValues)
- {
- retVal = m_pValues->GetPropertyBuffer(pName, rpVal);
- }
- #endif // HELIX_FEATURE_SETSRCPROPS
- return retVal;
- }
- STDMETHODIMP CRealAudioRenderer::GetFirstPropertyBuffer(REF(const char*) rpName, REF(IHXBuffer*) rpVal)
- {
- HX_RESULT retVal = HXR_FAIL;
- #if defined(HELIX_FEATURE_SETSRCPROPS)
- // Check if we need to create m_pValues
- // and set the source properties
- CheckForSetSourceProperties(TRUE);
- if (m_pValues)
- {
- retVal = m_pValues->GetFirstPropertyBuffer(rpName, rpVal);
- }
- #endif // HELIX_FEATURE_SETSRCPROPS
- return retVal;
- }
- STDMETHODIMP CRealAudioRenderer::GetNextPropertyBuffer(REF(const char*) rpName, REF(IHXBuffer*) rpVal)
- {
- HX_RESULT retVal = HXR_FAIL;
- #if defined(HELIX_FEATURE_SETSRCPROPS)
- // Check if we need to create m_pValues
- // and set the source properties
- CheckForSetSourceProperties();
- if (m_pValues)
- {
- retVal = m_pValues->GetNextPropertyBuffer(rpName, rpVal);
- }
- #endif // HELIX_FEATURE_SETSRCPROPS
- return retVal;
- }
- STDMETHODIMP CRealAudioRenderer::SetPropertyCString(const char* pName, IHXBuffer* pVal)
- {
- HX_RESULT retVal = HXR_FAIL;
- #if defined(HELIX_FEATURE_SETSRCPROPS)
- // Check if we need to create m_pValues
- // and set the source properties
- CheckForSetSourceProperties();
- if (m_pValues)
- {
- retVal = m_pValues->SetPropertyCString(pName, pVal);
- }
- #endif // HELIX_FEATURE_SETSRCPROPS
- return retVal;
- }
- STDMETHODIMP CRealAudioRenderer::GetPropertyCString(const char* pName, REF(IHXBuffer*) rpVal)
- {
- HX_RESULT retVal = HXR_FAIL;
- #if defined(HELIX_FEATURE_SETSRCPROPS)
- // Try to dynamically get the property first
- retVal = GetSourcePropertyCString(pName, rpVal);
- if (FAILED(retVal) && m_pValues)
- {
- // We failed dynamically try m_pValues
- retVal = m_pValues->GetPropertyCString(pName, rpVal);
- }
- #endif // HELIX_FEATURE_SETSRCPROPS
- return retVal;
- }
- STDMETHODIMP CRealAudioRenderer::GetFirstPropertyCString(REF(const char*) rpName, REF(IHXBuffer*) rpVal)
- {
- HX_RESULT retVal = HXR_FAIL;
- #if defined(HELIX_FEATURE_SETSRCPROPS)
- // Check if we need to create m_pValues
- // and set the source properties
- CheckForSetSourceProperties(TRUE);
- if (m_pValues)
- {
- retVal = m_pValues->GetFirstPropertyCString(rpName, rpVal);
- }
- #endif // HELIX_FEATURE_SETSRCPROPS
- return retVal;
- }
- STDMETHODIMP CRealAudioRenderer::GetNextPropertyCString(REF(const char*) rpName, REF(IHXBuffer*) rpVal)
- {
- HX_RESULT retVal = HXR_FAIL;
- #if defined(HELIX_FEATURE_SETSRCPROPS)
- // Check if we need to create m_pValues
- // and set the source properties
- CheckForSetSourceProperties();
- if (m_pValues)
- {
- retVal = m_pValues->GetNextPropertyCString(rpName, rpVal);
- }
- #endif // HELIX_FEATURE_SETSRCPROPS
- return retVal;
- }
- void CRealAudioRenderer::CheckForSetSourceProperties(BOOL bForceRefresh)
- {
- #if defined(HELIX_FEATURE_SETSRCPROPS)
- // Do we already have m_pValues?
- if (!m_pValues && m_pCommonClassFactory)
- {
- // Create m_pValues
- m_pCommonClassFactory->CreateInstance(CLSID_IHXValues, (void**) &m_pValues);
- // Force a refresh if we just created m_pValues
- bForceRefresh = TRUE;
- }
- if (m_pValues && bForceRefresh)
- {
- // Refresh the source prroperties
- UINT32 ulValue = 0;
- IHXBuffer* pBuffer = NULL;
- if (SUCCEEDED(GetSourcePropertyCString("SrcCodec", pBuffer)))
- {
- m_pValues->SetPropertyCString("SrcCodec", pBuffer);
- }
- if (SUCCEEDED(GetSourcePropertyULONG32("SrcBitRate", ulValue)))
- {
- m_pValues->SetPropertyULONG32("SrcBitRate", ulValue);
- }
- if (SUCCEEDED(GetSourcePropertyULONG32("SrcVBREnabled", ulValue)))
- {
- m_pValues->SetPropertyULONG32("SrcVBREnabled", ulValue);
- }
- if (SUCCEEDED(GetSourcePropertyULONG32("SrcSamplesPerSecond", ulValue)))
- {
- m_pValues->SetPropertyULONG32("SrcSamplesPerSecond", ulValue);
- }
- if (SUCCEEDED(GetSourcePropertyULONG32("SrcBitsPerSample", ulValue)))
- {
- m_pValues->SetPropertyULONG32("SrcBitsPerSample", ulValue);
- }
- if (SUCCEEDED(GetSourcePropertyULONG32("SrcNumChannels", ulValue)))
- {
- m_pValues->SetPropertyULONG32("SrcNumChannels", ulValue);
- }
- if (SUCCEEDED(GetSourcePropertyULONG32("SrcInterleaved", ulValue)))
- {
- m_pValues->SetPropertyULONG32("SrcInterleaved", ulValue);
- }
- HX_RELEASE(pBuffer);
- }
- #endif // HELIX_FEATURE_SETSRCPROPS
- }
- HX_RESULT CRealAudioRenderer::GetSourcePropertyULONG32(const char* pszProp, REF(ULONG32) rulVal)
- {
- HX_RESULT retVal = HXR_FAIL;
- #if defined(HELIX_FEATURE_SETSRCPROPS)
- // First we must decide which substream to use. If we
- // have received a packet, then we use
- // m_usCurrentDryNotificationStream (checking that it
- // is not NO_STREAM_SET, of course). If we have not received
- // a packet, then we use m_ulSrcPropertySubStream (checking
- // that it is not NO_STREAM_SET, of course). If we can't
- // use either of these, then we fail.
- UINT32 ulSubStream = NO_STREAM_SET;
- // Have we received a packet yet?
- if (!m_bFirstPacket)
- {
- // Try to use m_usCurrentDryNotificationStream
- if (m_usCurrentDryNotificationStream != NO_STREAM_SET)
- {
- ulSubStream = m_usCurrentDryNotificationStream;
- }
- }
- if (ulSubStream == NO_STREAM_SET)
- {
- // Try to use m_ulSrcPropertySubStream
- if (m_ulSrcPropertySubStream != NO_STREAM_SET)
- {
- ulSubStream = m_ulSrcPropertySubStream;
- }
- }
- if (ulSubStream != NO_STREAM_SET &&
- ulSubStream < m_uNumOfSubStreams &&
- m_pRaFormats[ulSubStream])
- {
- if (!strcmp(pszProp, "SrcBitRate"))
- {
- rulVal = m_pRaFormats[ulSubStream]->GetBitRate();
- retVal = HXR_OK;
- }
- else if (!strcmp(pszProp, "SrcVBREnabled"))
- {
- rulVal = 0;
- retVal = HXR_OK;
- }
- else if (!strcmp(pszProp, "SrcSamplesPerSecond"))
- {
- rulVal = m_pRaFormats[ulSubStream]->GetSamplesPerSecond();
- retVal = HXR_OK;
- }
- else if (!strcmp(pszProp, "SrcBitsPerSample"))
- {
- rulVal = m_pRaFormats[ulSubStream]->GetBitsPerSample();
- retVal = HXR_OK;
- }
- else if (!strcmp(pszProp, "SrcNumChannels"))
- {
- rulVal = m_pRaFormats[ulSubStream]->GetNumChannels();
- retVal = HXR_OK;
- }
- else if (!strcmp(pszProp, "SrcInterleaved"))
- {
- rulVal = m_pRaFormats[ulSubStream]->IsInterleaved();
- retVal = HXR_OK;
- }
- }
- #endif // HELIX_FEATURE_SETSRCPROPS
- return retVal;
- }
- HX_RESULT CRealAudioRenderer::GetSourcePropertyCString(const char* pszProp, REF(IHXBuffer*) rpBuffer)
- {
- HX_RESULT retVal = HXR_FAIL;
- #if defined(HELIX_FEATURE_SETSRCPROPS)
- // First we must decide which substream to use. If we
- // have received a packet, then we use
- // m_usCurrentDryNotificationStream (checking that it
- // is not NO_STREAM_SET, of course). If we have not received
- // a packet, then we use m_ulSrcPropertySubStream (checking
- // that it is not NO_STREAM_SET, of course). If we can't
- // use either of these, then we fail.
- UINT32 ulSubStream = NO_STREAM_SET;
- // Have we received a packet yet?
- if (!m_bFirstPacket)
- {
- // Try to use m_usCurrentDryNotificationStream
- if (m_usCurrentDryNotificationStream != NO_STREAM_SET)
- {
- ulSubStream = m_usCurrentDryNotificationStream;
- }
- }
- if (ulSubStream == NO_STREAM_SET)
- {
- // Try to use m_ulSrcPropertySubStream
- if (m_ulSrcPropertySubStream != NO_STREAM_SET)
- {
- ulSubStream = m_ulSrcPropertySubStream;
- }
- }
- if (ulSubStream != NO_STREAM_SET &&
- ulSubStream < m_uNumOfSubStreams &&
- m_pRaFormats[ulSubStream])
- {
- if (!strcmp(pszProp, "SrcCodec"))
- {
- retVal = CreateStringBuffer(rpBuffer,
- m_pRaFormats[ulSubStream]->GetCodecName(),
- m_pContext);
- }
- }
- #endif // HELIX_FEATURE_SETSRCPROPS
- return retVal;
- }
- void CRealAudioRenderer::LogAudioWrite(UINT16 uStreamNumber,
- HXAudioData* pAudioData,
- UINT32 ulActualTimestamp,
- HX_RESULT retVal)
- {
- DEBUG_OUTF_IDX(uStreamNumber, RA_FLOW_FILE,
- (s, "AWrite: %u[%u%]<-->%u[%u%] %s %sn",
- pAudioData->ulAudioTime,
- ulActualTimestamp,
- pAudioData->ulAudioTime +
- ((UINT32) (m_pRaFormats[uStreamNumber]->ConvertBytesToMs(pAudioData->pData->GetSize()))),
- ulActualTimestamp +
- ((UINT32) (m_pRaFormats[uStreamNumber]->ConvertBytesToMs(pAudioData->pData->GetSize()))),
- (pAudioData->uAudioStreamType == STREAMING_AUDIO) ? "STREAMING" : "TIMED",
- (retVal == HXR_OK) ? "OK" : "FAIL"));
- }
- HX_RESULT CRealAudioRenderer::_OnPacket(IHXPacket* pPacket, INT32 lTimeOffset)
- {
- HX_RESULT retVal = HXR_OK;
- UINT16 uStreamForThisPacket = 0;
- m_lTimeLineOffset = lTimeOffset;
- #ifdef _MACINTOSH
- if (m_pDryCallback != NULL)
- {
- HX_ASSERT(m_bReportOKStatus);
- m_pDryCallback->Cancel();
- m_pDryCallback->Func();
- HX_RELEASE(m_pDryCallback);
- }
- #endif
- DEBUG_OUTF(RASYNC_FILE, (s, "RAtOnPacket:t%lun", pPacket->GetTime()));
- /* Ignore any pre-seek packets or NULL packets */
- if (m_bInSeekMode || pPacket == NULL)
- {
- return HXR_OK;
- }
- #ifdef _MACINTOSH
- m_bProcessingPacket = TRUE;
- #endif // _MACINTOSH
- m_pMutex->Lock();
- if(pPacket->IsLost())
- {
- if (m_bStreamSwitchable)
- {
- for (int i = 0; i < m_uNumOfSubStreams; i++)
- {
- m_pRaFormats[i]->LossOccured();
- }
- }
- else
- {
- m_pRaFormats[uStreamForThisPacket]->OnPacket(pPacket, lTimeOffset,
- m_pRuleToFlagMap->rule_to_flag_map);
- }
- DEBUG_OUT(m_pErrorMessages, DOL_REALAUDIO_EXTENDED, (s, "ptLostt?t?"));
- DEBUG_OUTF(ONPACKET_FILE, (s, "ptLostt?t?n"));
- }
- else
- {
- DEBUG_OUT(m_pErrorMessages, DOL_REALAUDIO_EXTENDED, (s, "pt%ut%lut%u",
- (m_bStreamSwitchable)?(m_pRuleMap[pPacket->GetASMRuleNumber()]):(0), pPacket->GetTime(),
- pPacket->GetASMRuleNumber()));
- DEBUG_OUTF(ONPACKET_FILE, (s, "pt%ut%lut%ut%un",
- (m_bStreamSwitchable)?(m_pRuleMap[pPacket->GetASMRuleNumber()]):(0), pPacket->GetTime(),
- pPacket->GetASMRuleNumber(), pPacket->GetASMFlags()));
- UINT32 ulCurrentPacketTime = pPacket->GetTime();
- if (m_bStreamSwitchable)
- {
- uStreamForThisPacket = m_pRuleMap[pPacket->GetASMRuleNumber()];
- }
- /*
- * if this packet is late, we don't want to add it to the format so we don't
- * think we are switching to a stream with packets that are late.
- * late packets could happen if the "time out" for the last packets
- * of the from stream happened and we considered the rest of them
- * lost. If that is why this packet is late, nothing we can do but
- * throw it away. If a packet is late for some other reason
- * it's either bad content or something else messed up with the
- * stream and we could be harsh and stop the stream but I'd rather
- * think we should drop the packet and continue.
- */
- if (NO_TIME_SET == m_pRaFormats[uStreamForThisPacket]->m_ulLastPacketTime ||
- IsTimeGreaterOrEqual(ulCurrentPacketTime, m_pRaFormats[uStreamForThisPacket]->m_ulLastPacketTime))
- {
- if (!m_bDelayOffsetSet)
- {
- IHXStreamSource* pSource = NULL;
- m_pStream->GetSource(pSource);
- // the delay is always 0 based and we might not start from 0 in live
- // since we compare packet times with delay, we want to make delay
- // relative to my packet stream times instead of 0. We just update
- // delay here because the time of the first packet adjusted for the
- // the time offset is the time we want to be writing to audio services
- // and it will be the delay.
- if (pSource != NULL && pSource->IsLive())
- {
- m_ulDelay = AdjustTimestamp(pPacket->GetTime(), lTimeOffset);
- // since the core will not call OnTimeSync() till it fulfils the preroll,
- // for live streams, m_ulCurrentTimelineTime will be set to 0 during initial
- // buffering. If we happen to call reportrebufferstatus for a delayed
- // live stream running for long duration -- more than MAX_TIMESTAMP_GAP),
- // we will never come out of buffering since
- // IsTimeGreaterOrEqual will fail and we will never call
- // reportrebufferstatus(1,1).
- m_ulCurrentTimelineTime = m_ulDelay;
- }
- HX_RELEASE(pSource);
- m_bDelayOffsetSet = TRUE;
- #ifdef HELIX_FEATURE_RAREND_PREREDSTONE_SUPPORT
- if (m_bPreRedstonePlayer)
- {
- // XXXJEFFA hack here for Live SureStream content with U3 players
- // and earlier. There is a bug in AudioServices, fixed in
- // pnaudiohxaudstr.cpp rev 1.11 where the audio streams that don't
- // get written to from the start of the stream (the ones we switch to
- // after initial subscription) will reset their lastWriteTime to the
- // base time the first time we write to them instead of having
- // accumulated time from the start of the stream along with the
- // stream we have been writing. Writing a 0 size instantainious audio
- // buffer here gets the lastWriteTime of the stream set to the live
- // base time from the beginning and works around the bug.
- //
- HXAudioData audioData;
- audioData.ulAudioTime = 0;
- audioData.uAudioStreamType = INSTANTANEOUS_AUDIO;
- m_pCommonClassFactory->CreateInstance(CLSID_IHXBuffer, (void**)&(audioData.pData));
- if (audioData.pData != NULL)
- {
- audioData.pData->SetSize(0);
- for (int k = 0; k < m_uNumOfSubStreams; k++)
- {
- m_pAudioStreams[k]->Write( &audioData );
- LogAudioWrite((UINT16) k,
- &audioData,
- audioData.ulAudioTime,
- HXR_OK);
- }
- HX_RELEASE(audioData.pData);
- }
- }
- #endif // HELIX_FEATURE_RAREND_PREREDSTONE_SUPPORT
- }
- if (m_bFirstPacket)
- {
- AddDryNotification(uStreamForThisPacket);
- m_bFirstPacket = FALSE;
- }
- // pass the packet to the RaFormat
- m_pRaFormats[uStreamForThisPacket]->OnPacket(pPacket, lTimeOffset,
- m_pRuleToFlagMap->rule_to_flag_map);
- // record this is the last packet time we've seen on this
- // stream
- m_pRaFormats[uStreamForThisPacket]->m_ulLastPacketTime =
- ulCurrentPacketTime;
- }
- }
- if (m_PlayState != playing)
- {
- // Take this chance to write audio to audio services
- UINT32 ulAudioTime;
- DoAudio(ulAudioTime);
- }
- // Handle exiting rebuffer started by OnDryNotification from
- // Audio Services
- if(!pPacket->IsLost() && m_bReportOKStatus)
- {
- // if we've recieved a packet that fills our preroll
- // and we have data to write, then we report we've recieved
- // all the packets we need
- if (HaveDataToWrite() &&
- IsTimeGreaterOrEqual(AdjustTimestamp(pPacket->GetTime(),
- lTimeOffset),
- (m_ulCurrentTimelineTime + max(m_ulPreroll, 1000))))
- {
- m_bReportOKStatus = FALSE;
- m_pStream->ReportRebufferStatus(1,1);
- DEBUG_OUT(m_pErrorMessages, DOL_REALAUDIO,
- (s, "Leaving Bufferingt%ut%ut%lu", m_usCurrentDryNotificationStream, uStreamForThisPacket, pPacket->GetTime()));
- DEBUG_OUTF(SWITCH_FILE,
- (s, "Leaving Bufferingt%ut%un", m_usCurrentDryNotificationStream, uStreamForThisPacket));
- }
- }
- #ifdef _MACINTOSH
- m_bProcessingPacket = FALSE;
- #endif // _MACINTOSH
- m_pMutex->Unlock();
- return retVal;
- }
- HX_RESULT STDAPICALLTYPE CRealAudioRenderer::HXCreateInstance(IUnknown** ppUnk)
- {
- HX_RESULT retVal = HXR_FAIL;
- if (ppUnk)
- {
- CRealAudioRenderer* pObj = new CRealAudioRenderer();
- if (pObj)
- {
- retVal = pObj->QueryInterface(IID_IUnknown, (void**) ppUnk);
- if (FAILED(retVal))
- {
- HX_DELETE(pObj);
- }
- }
- }
- return retVal;
- }