audrend.cpp
上传用户:dangjiwu
上传日期:2013-07-19
资源大小:42019k
文件大小:45k
- /* ***** 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 ***** */
- // #define _AUDREND_FLOW_LOG
- #define TIME_SYNC_GRANULARITY 100 // in milliseconds
- #define MAX_AUDIO_WRITE_TIME 200 // in milliseconds
- #define STREAM_MAJOR_VERSION 0
- #define STREAM_MINOR_VERSION 0
- #define CONTENT_MAJOR_VERSION 0
- #define CONTENT_MINOR_VERSION 0
- #define TIME_FUDGE 5
- #define BASE_AUDIO_RENDERER_NAME "Basic Audio"
- #define MINIMAL_AUDIO_PUSHDOWN 120
- #ifdef _AUDREND_FLOW_LOG
- #define AUDREND_FLOW_FILE "C:\audrend.txt"
- #else // _AUDREND_FLOW_LOG
- #define AUDREND_FLOW_FILE NULL
- #endif // _AUDREND_FLOW_LOG
- /****************************************************************************
- * Includes
- */
- #include "hlxclib/stdio.h"
- #include "hlxclib/string.h"
- #include "audrend.ver"
- #include "hxtypes.h"
- #include "hxcom.h"
- #include "hxcomm.h"
- #include "ihxpckts.h"
- #include "hxcore.h"
- #include "hxrendr.h"
- #include "hxplugn.h"
- #include "hxasm.h"
- #include "hxver.h"
- #include "hxupgrd.h"
- #include "hxengin.h"
- #include "hxprefs.h"
- #include "hxerror.h"
- #include "hxausvc.h"
- #include "hxthread.h"
- #include "hxstrutl.h"
- #include "hxtick.h"
- #include "hxassert.h"
- #include "hxbuffer.h"
- #include "addupcol.h"
- #include "errdbg.h"
- #include "adjtime.h"
- #include "hxver.h"
- #include "audrmlog.h"
- #include "audrend.h"
- #include "hxheap.h"
- #ifdef _DEBUG
- #undef HX_THIS_FILE
- static const char HX_THIS_FILE[] = __FILE__;
- #endif // HX_THIS_FILE
- /****************************************************************************
- * Constants
- */
- const char* const CAudioRenderer::zm_pDescription = "RealNetworks Audio Renderer Plugin";
- const char* const CAudioRenderer::zm_pCopyright = HXVER_COPYRIGHT;
- const char* const CAudioRenderer::zm_pMoreInfoURL = HXVER_MOREINFO;
- const char* const CAudioRenderer::zm_pStreamMimeTypes[] =
- {
- "audio/NULL",
- NULL
- };
- /************************************************************************
- * CAudioRenderer
- */
- /************************************************************************
- * Constructor/Destructor
- */
- CAudioRenderer::CAudioRenderer()
- : m_pContext(NULL)
- , m_pStream(NULL)
- , m_pBackChannel(NULL)
- , m_pHeader(NULL)
- , m_pErrorMessages(NULL)
- , m_pCommonClassFactory(NULL)
- , m_pPreferences(NULL)
- , m_pRegistry(NULL)
- , m_ulRegistryID(0)
- , m_ulPreroll(0)
- , m_ulAudioWantedTime(NO_TIME_SET)
- , m_ulLastWriteTime(NO_TIME_SET)
- , m_pAudioPlayer(NULL)
- , m_bEndOfPackets(FALSE)
- , m_bDoneWritingPackets(FALSE)
- , m_bInSeekMode(FALSE)
- , m_ulDuration(0)
- , m_bFirstPacket(TRUE)
- , m_bDelayOffsetSet(FALSE)
- , m_ulDelay(0)
- , m_pMutex(NULL)
- , m_bProcessingPacket(FALSE)
- , m_pAudioFormat(NULL)
- , m_PlayState(stopped)
- , m_lRefCount(0)
- , m_ppAudioStream(NULL)
- , m_pAudioStats(NULL)
- , m_ulNumAudioStreams(0)
- , m_ulCurAudioStream(0)
- , m_bCanChangeAudioStream(FALSE)
- , m_lTimeOffset(0)
- {
- // Allocate space for an initial number of pointers
- m_ppAudioStream = new IHXAudioStream* [AUDREND_INITIAL_NUMSTREAMPTRS];
- if (m_ppAudioStream)
- {
- memset((void*) m_ppAudioStream, 0, AUDREND_INITIAL_NUMSTREAMPTRS * sizeof(IHXAudioStream*));
- m_ulNumAudioStreams = AUDREND_INITIAL_NUMSTREAMPTRS;
- }
- }
- CAudioRenderer::~CAudioRenderer()
- {
- EndStream();
- #if defined(HELIX_FEATURE_STATS)
- HX_DELETE(m_pAudioStats);
- #endif /* HELIX_FEATURE_STATS */
- HX_DELETE(m_pMutex);
- HX_RELEASE(m_pContext);
- HX_RELEASE(m_pHeader);
- HX_RELEASE(m_pErrorMessages);
- HX_RELEASE(m_pCommonClassFactory);
- HX_RELEASE(m_pPreferences);
- HX_RELEASE(m_pRegistry);
- }
- /************************************************************************
- * IHXPlugin Methods
- */
- /************************************************************************
- * 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 CAudioRenderer::InitPlugin(IUnknown* /*IN*/ pContext)
- {
- HX_RESULT retVal = HXR_OK;
- HX_ASSERT(pContext);
- m_pContext = pContext;
- m_pContext->AddRef();
- retVal = m_pContext->QueryInterface(IID_IHXCommonClassFactory,
- (void**) &m_pCommonClassFactory);
- m_pContext->QueryInterface(IID_IHXPreferences,
- (void**) &m_pPreferences);
- m_pContext->QueryInterface(IID_IHXRegistry, (void**) &m_pRegistry);
- if (SUCCEEDED(retVal) && !m_pMutex)
- {
- #ifdef THREADS_SUPPORTED
- retVal = HXMutex::MakeMutex(m_pMutex);
- #else // THREADS_SUPPORTED
- retVal = HXMutex::MakeStubMutex(m_pMutex);
- #endif // THREADS_SUPPORTED
- }
- #if defined(HELIX_FEATURE_STATS)
- if (SUCCEEDED(retVal))
- {
- m_pAudioStats = new CAudioStatistics(m_pContext);
- retVal = HXR_OUTOFMEMORY;
- if (m_pAudioStats)
- {
- retVal = HXR_OK;
- }
- }
- #endif /* HELIX_FEATURE_STATS */
- // Get the IHXErrorMessages interface. Not an error
- // if it's not supported
- HX_RELEASE(m_pErrorMessages);
- m_pContext->QueryInterface(IID_IHXErrorMessages,
- (void**) &m_pErrorMessages);
- if (FAILED(retVal))
- {
- HX_RELEASE(m_pCommonClassFactory);
- HX_RELEASE(m_pPreferences);
- HX_RELEASE(m_pRegistry);
- }
- return retVal;
- }
- /************************************************************************
- * 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 CAudioRenderer::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 CAudioRenderer::GetRendererInfo
- (
- REF(const char**) /*OUT*/ pStreamMimeTypes,
- REF(UINT32) /*OUT*/ unInitialGranularity
- )
- {
- pStreamMimeTypes = (const char**)zm_pStreamMimeTypes;
- unInitialGranularity = TIME_SYNC_GRANULARITY;
- return HXR_OK;
- }
- // *** IUnknown methods ***
- /****************************************************************************
- * IUnknown::QueryInterface ref: hxcom.h
- *
- * This routine indicates which interfaces this object supports. If a given
- * interface is supported, the object's reference count is incremented, and
- * a reference to that interface is returned. Otherwise a NULL object and
- * error code are returned. This method is called by other objects to
- * discover the functionality of this object.
- */
- STDMETHODIMP CAudioRenderer::QueryInterface(REFIID riid, void** ppvObj)
- {
- QInterfaceList qiList[] =
- {
- { GET_IIDHANDLE(IID_IHXInterruptSafe), (IHXInterruptSafe*)this},
- { GET_IIDHANDLE(IID_IHXDryNotification), (IHXDryNotification*)this},
- { GET_IIDHANDLE(IID_IUnknown), (IUnknown*)(IHXPlugin*) this},
- { GET_IIDHANDLE(IID_IHXPlugin), (IHXPlugin*)this},
- { GET_IIDHANDLE(IID_IHXRenderer), (IHXRenderer*)this},
- #if defined(HELIX_FEATURE_STATS)
- { GET_IIDHANDLE(IID_IHXStatistics), (IHXStatistics*)this},
- #endif // HELIX_FEATURE_STATS
- };
- return ::QIFind(qiList, QILISTSIZE(qiList), riid, ppvObj);
- }
- /****************************************************************************
- * IUnknown::AddRef ref: hxcom.h
- *
- * This routine increases the object reference count in a thread safe
- * manner. The reference count is used to manage the lifetime of an object.
- * This method must be explicitly called by the user whenever a new
- * reference to an object is used.
- */
- STDMETHODIMP_(ULONG32) CAudioRenderer::AddRef()
- {
- return InterlockedIncrement(&m_lRefCount);
- }
- /****************************************************************************
- * IUnknown::Release ref: hxcom.h
- *
- * This routine decreases the object reference count in a thread safe
- * manner, and deletes the object if no more references to it exist. It must
- * be called explicitly by the user whenever an object is no longer needed.
- */
- STDMETHODIMP_(ULONG32) CAudioRenderer::Release()
- {
- if (InterlockedDecrement(&m_lRefCount) > 0)
- {
- return m_lRefCount;
- }
- delete this;
- return 0;
- }
- /************************************************************************
- * 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
- CAudioRenderer::StartStream
- (
- IHXStream* pStream,
- IHXPlayer* pPlayer
- )
- {
- HX_RESULT retVal = HXR_OK;
- m_pStream = pStream;
- if (m_pStream)
- {
- m_pStream->AddRef();
- IHXStreamSource* pSource = 0;
- if (m_pStream->GetSource(pSource) == HXR_OK)
- {
- /* It is OK if the source does not support backchannel. Reasons:
- *
- * 1. This stream may not be coming from h261 fileformat.
- * It may instead be merged into a container fileformat which
- * may be does not support BackChannel.
- *
- * 2. The protocol used to serve this stream may not support
- * BackChannel.
- */
- pSource->QueryInterface(IID_IHXBackChannel, (void**) &m_pBackChannel);
- pSource->Release();
- }
- }
- IHXAudioPushdown2 * pAudioPushdown2 = NULL;
- // get interface to audio player
- if (pPlayer)
- {
- retVal = pPlayer->QueryInterface(IID_IHXAudioPlayer,
- (void**) &m_pAudioPlayer);
- #ifdef HELIX_CONFIG_MIN_PCM_PUSHDOWN_BYTES
- if( m_pAudioPlayer )
- {
- m_pAudioPlayer->QueryInterface(IID_IHXAudioPushdown2, (void**) &pAudioPushdown2);
- if( pAudioPushdown2 )
- {
- pAudioPushdown2->SetAudioPushdown( MINIMAL_AUDIO_PUSHDOWN );
- pAudioPushdown2->Release();
- }
- }
- #endif // HELIX_CONFIG_MIN_PCM_PUSHDOWN_BYTES
- }
- return retVal;
- }
- /////////////////////////////////////////////////////////////////////////
- // Method:
- // IHXRenderer::EndStream
- // Purpose:
- // Called by client engine to inform the renderer that the stream
- // is was rendering is closed.
- //
- STDMETHODIMP CAudioRenderer::EndStream()
- {
- if (m_pMutex)
- {
- m_pMutex->Lock();
- }
- m_bDoneWritingPackets = TRUE;
- m_PlayState = stopped;
- if (m_pMutex)
- {
- m_pMutex->Unlock();
- }
- if (m_pAudioFormat)
- {
- m_pAudioFormat->Release();
- m_pAudioFormat = NULL;
- }
- HX_RELEASE(m_pStream);
- HX_RELEASE(m_pBackChannel);
- HX_RELEASE(m_pAudioPlayer);
- for (UINT32 i = 0; i < m_ulNumAudioStreams; i++)
- {
- HX_RELEASE(m_ppAudioStream[i]);
- }
- HX_VECTOR_DELETE(m_ppAudioStream);
- m_ulNumAudioStreams = 0;
- 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
- CAudioRenderer::OnHeader(IHXValues* pHeader)
- {
- HX_RESULT retVal = HXR_OK;
- UINT32 ulTrackStartTime = NO_TIME_SET;
- UINT32 ulTrackEndTime = NO_TIME_SET;
- #if defined(HELIX_FEATURE_AUTOUPGRADE)
- // check the stream versions
- pHeader->AddRef();
- retVal = CheckStreamVersions(pHeader);
- pHeader->Release();
- #endif /* #if defined(HELIX_FEATURE_AUTOUPGRADE) */
- if (SUCCEEDED(retVal))
- {
- pHeader->GetPropertyULONG32("Preroll", m_ulPreroll);
- pHeader->GetPropertyULONG32("Duration", m_ulDuration);
- pHeader->GetPropertyULONG32("Delay", m_ulDelay);
- pHeader->GetPropertyULONG32("TrackStartTime", ulTrackStartTime);
- pHeader->GetPropertyULONG32("TrackEndTime", ulTrackEndTime);
- }
- if (SUCCEEDED(retVal))
- {
- m_pAudioFormat = CreateFormatObject(pHeader);
- retVal = HXR_OUTOFMEMORY;
- if (m_pAudioFormat)
- {
- m_pAudioFormat->AddRef();
- retVal = HXR_OK;
- }
- }
- if (SUCCEEDED(retVal))
- {
- retVal = m_pAudioFormat->Init(pHeader);
- #if defined(HELIX_FEATURE_AUTOUPGRADE)
- if (FAILED(retVal) && retVal == HXR_REQUEST_UPGRADE)
- {
- AddToAutoUpgradeCollection(m_pAudioFormat->GetAutoUpgradeString(),
- m_pContext);
- }
- #endif /* #if defined(HELIX_FEATURE_AUTOUPGRADE) */
- }
- if (SUCCEEDED(retVal))
- {
- retVal = InitAudioStream(pHeader, &m_ppAudioStream[m_ulCurAudioStream]);
- }
- // Setup preroll
- if (SUCCEEDED(retVal))
- {
- // check that stream header preroll value is not too big
- ULONG32 ulMaxPreroll = m_pAudioFormat->GetMaximumPreroll(pHeader);
- if (m_ulPreroll > ulMaxPreroll)
- {
- m_ulPreroll = ulMaxPreroll;
- }
- else
- // check that stream header preroll value is set
- if (m_ulPreroll == 0)
- {
- // preload is not set for this stream - assume default
- m_ulPreroll = m_pAudioFormat->GetDefaultPreroll(pHeader);
- }
- // note that we are not enforcing any minimum preroll here
- if (m_ulPreroll > 0)
- {
- pHeader->SetPropertyULONG32( "Preroll", m_ulPreroll );
- }
- // Set the flag saying whether or not the audio
- // stream parameters can change on the fly
- m_bCanChangeAudioStream = m_pAudioFormat->CanChangeAudioStream();
- // Save the stream header
- HX_RELEASE(m_pHeader);
- m_pHeader = pHeader;
- m_pHeader->AddRef();
- }
- return retVal;
- }
- /////////////////////////////////////////////////////////////////////////////
- // Method:
- // CAudioRenderer::CheckStreamVersions
- // copied from CRealAudioRenderer
- HX_RESULT CAudioRenderer::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);
- ULONG32 ulThisMajorVersion = STREAM_MAJOR_VERSION;
- ULONG32 ulThisMinorVersion = STREAM_MINOR_VERSION;
- GetStreamVersion(ulThisMajorVersion, ulThisMinorVersion);
- if((ulMajorVersion > ulThisMajorVersion) ||
- ((ulMinorVersion > ulThisMinorVersion) &&
- (ulMajorVersion == ulThisMajorVersion)))
- {
- bVersionOK = FALSE;
- }
- }
- if(bVersionOK &&
- (HXR_OK == pHeader->GetPropertyULONG32("ContentVersion",
- ulContentVersion)))
- {
- UINT32 ulMajorVersion = HX_GET_MAJOR_VERSION(ulContentVersion);
- UINT32 ulMinorVersion = HX_GET_MINOR_VERSION(ulContentVersion);
- ULONG32 ulThisMajorVersion = CONTENT_MAJOR_VERSION;
- ULONG32 ulThisMinorVersion = CONTENT_MINOR_VERSION;
- GetContentVersion(ulThisMajorVersion, ulThisMinorVersion);
- if((ulMajorVersion > ulThisMajorVersion) ||
- ((ulMinorVersion > ulThisMinorVersion) &&
- (ulMajorVersion == ulMajorVersion)))
- {
- bVersionOK = FALSE;
- }
- }
- if(!bVersionOK)
- {
- AddToAutoUpgradeCollection(GetUpgradeMimeType(), m_pContext);
- pnr = HXR_FAIL;
- }
- #endif /* #if defined(HELIX_FEATURE_AUTOUPGRADE) */
- return pnr;
- }
- /////////////////////////////////////////////////////////////////////////
- // 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
- CAudioRenderer::OnPacket(IHXPacket* pPacket, LONG32 lTimeOffset)
- {
- HX_RESULT retVal = HXR_OK;
- UINT16 uStreamForThisPacket = 0;
- /* Ignore any pre-seek packets or NULL packets */
- if (m_bInSeekMode || pPacket == NULL)
- {
- return HXR_OK;
- }
- m_lTimeOffset = lTimeOffset;
- m_bProcessingPacket = TRUE;
- m_pMutex->Lock();
- m_bFirstPacket = FALSE;
- m_pAudioFormat->Enqueue(pPacket);
- if (m_PlayState != playing)
- {
- // Take this chance to write audio to audio services
- UINT32 ulAudioTime;
- DoAudio(ulAudioTime);
- }
- m_bProcessingPacket = FALSE;
- m_pMutex->Unlock();
- return retVal;
- }
- /////////////////////////////////////////////////////////////////////////
- // 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 CAudioRenderer::OnTimeSync(ULONG32 ulTime)
- {
- MLOG_MISCEX(m_pErrorMessages, "OTS(%lu)n", ulTime);
- // we never enter the play state on Mac so that we write audio
- // in both packet and timesync
- #ifndef _MACINTOSH
- // if we get a timesync we must be playing
- m_PlayState = playing;
- #endif
- m_pMutex->Lock();
- #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*/
- #if !defined(HELIX_CONFIG_MIN_PCM_PUSHDOWN_BYTES)
- // Write to AS
- UINT32 ulAudioTime;
- DoAudio(ulAudioTime);
- #endif
- #ifdef _MACINTOSH
- m_bProcessingPacket = FALSE;
- exit:
- #endif /*_MACINTOSH*/
- m_pMutex->Unlock();
- return HXR_OK;
- }
- /////////////////////////////////////////////////////////////////////////
- // 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 CAudioRenderer::OnPreSeek(ULONG32 ulOldTime,
- ULONG32 ulNewTime)
- {
- m_pMutex->Lock();
- m_PlayState = seeking;
- m_bEndOfPackets = FALSE;
- m_bDoneWritingPackets = FALSE;
- m_bInSeekMode = TRUE;
- m_bFirstPacket = TRUE;
- m_ulLastWriteTime = NO_TIME_SET;
- // get out of our buffering state if we are in one
- if (IsRebuffering())
- {
- EndRebuffer();
- }
- m_pAudioFormat->SetStartTime(ulNewTime);
- m_pAudioFormat->Reset();
- m_pMutex->Unlock();
- 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 CAudioRenderer::OnPostSeek(ULONG32 ulOldTime, ULONG32 ulNewTime)
- {
- 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 CAudioRenderer::OnPause(ULONG32 ulTime)
- {
- m_pMutex->Lock();
- m_PlayState = paused;
- m_pMutex->Unlock();
- 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 CAudioRenderer::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 CAudioRenderer::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 CAudioRenderer::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 CAudioRenderer::OnEndofPackets(void)
- {
- HX_RESULT pnr = HXR_OK;
- /* we should release any remaining sub-superblocks to audio services here*/
- m_bEndOfPackets = TRUE;
- if (IsRebuffering())
- {
- EndRebuffer();
- }
- m_pMutex->Lock();
- #ifdef _MACINTOSH
- // since we don't get as many time sync calls on the mac
- // and we want to make sure to write all of the packets
- // to audio services, make sure we have 2 seconds of
- // data buffered in audio services now.
- AttemptToSatisfyDryRequest(m_ulLastWriteTime + 2000);
- #endif
- 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 CAudioRenderer::OnDryNotification(UINT32 /*IN*/ ulCurrentStreamTime,
- UINT32 /*IN*/ ulMinimumDurationRequired)
- {
- MLOG_MISC(m_pErrorMessages, "ODN (%lu,%lu)n",
- ulCurrentStreamTime, 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;
- }
- if (NO_TIME_SET != m_ulLastWriteTime &&
- IsTimeGreater(ulCurrentStreamTime, m_ulLastWriteTime + 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
- m_ulLastWriteTime = ulCurrentStreamTime;
- }
- if (!m_bFirstPacket &&
- IsTimeGreater(ulCurrentStreamTime + m_ulPreroll, m_ulDelay) &&
- (NO_TIME_SET == m_ulLastWriteTime ||
- IsTimeGreater(ulCurrentStreamTime + TIME_FUDGE, m_ulLastWriteTime)))
- {
- // Try to write some audio to satisfy the audio stream
- HX_RESULT pnr = HXR_OK;
- UINT32 ulAudioWantedTime =
- (ulCurrentStreamTime + ulMinimumDurationRequired);
- pnr = AttemptToSatisfyDryRequest(ulAudioWantedTime);
- // 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) &&
- IsTimeLess(m_ulLastWriteTime, ulAudioWantedTime))
- {
- StartRebuffer(ulAudioWantedTime);
- }
- }
- exit:
- m_pMutex->Unlock();
- return HXR_OK;
- }
- /************************************************************************
- * IHXStatistics Methods
- */
- /************************************************************************
- * InitializeStatistics
- */
- STDMETHODIMP CAudioRenderer::InitializeStatistics(UINT32 ulRegistryID)
- {
- BOOL bCodecNameKnown = FALSE;
- char* pValue = NULL;
- HX_RESULT retVal = HXR_UNEXPECTED;
- m_ulRegistryID = ulRegistryID;
- #if defined(HELIX_FEATURE_STATS)
- if (m_pAudioStats)
- {
- retVal = HXR_OK;
- }
- if (SUCCEEDED(retVal))
- {
- pValue = (char*) GetCodecName();
- if (pValue != NULL)
- {
- ReportStat(AS_CODEC_NAME, pValue);
- bCodecNameKnown = TRUE;
- }
- }
- if (SUCCEEDED(retVal))
- {
- pValue = (char*) GetRendererName();
- if (pValue != NULL)
- {
- ReportStat(AS_REND_NAME, pValue);
- // If Codec name is unknown, use a more generic renderer name
- if (!bCodecNameKnown)
- {
- ReportStat(AS_CODEC_NAME, pValue);
- }
- }
- }
- if (SUCCEEDED(retVal))
- {
- pValue = (char*) GetCodecFourCC();
- if (pValue != NULL)
- {
- ReportStat(AS_CODEC_4CC, pValue);
- }
- }
- if (SUCCEEDED(retVal))
- {
- HXAudioFormat audioFmt;
- audioFmt.uChannels = 0;
- audioFmt.ulSamplesPerSec = 0;
- audioFmt.uBitsPerSample = 0;
- if (m_pAudioFormat)
- {
- m_pAudioFormat->GetAudioFormat(audioFmt);
- }
- ReportStat(AS_CHANNELS, (INT32) audioFmt.uChannels);
- ReportStat(AS_SAMPLING_RATE, (INT32) audioFmt.ulSamplesPerSec);
- ReportStat(AS_SAMPLE_SIZE, (INT32) audioFmt.uBitsPerSample);
- }
- if (SUCCEEDED(retVal))
- {
- retVal = m_pAudioStats->DisplayStats(m_ulRegistryID);
- }
- return retVal;
- #else
- return HXR_NOTIMPL;
- #endif /* HELIX_FEATURE_STATS */
- }
- /************************************************************************
- * UpdateStatistics
- */
- STDMETHODIMP CAudioRenderer::UpdateStatistics()
- {
- #if defined(HELIX_FEATURE_STATS)
- HX_RESULT retVal = HXR_UNEXPECTED;
- if (m_pAudioStats)
- {
- retVal = HXR_OK;
- }
- if (SUCCEEDED(retVal))
- {
- retVal = m_pAudioStats->DisplayStats(m_ulRegistryID);
- }
- return retVal;
- #else
- return HXR_NOTIMPL;
- #endif /* HELIX_FEATURE_STATS */
- }
- /****************************************************************************
- * Renderer's customizable fuctions - can be called any time
- */
- /****************************************************************************
- * GetStreamVersion
- */
- void CAudioRenderer::GetStreamVersion(ULONG32 &ulThisMajorVersion,
- ULONG32 &ulThisMinorVersion)
- {
- ulThisMajorVersion = STREAM_MAJOR_VERSION;
- ulThisMinorVersion = STREAM_MINOR_VERSION;
- }
- /****************************************************************************
- * GetContentVersion
- */
- void CAudioRenderer::GetContentVersion(ULONG32 &ulThisMajorVersion,
- ULONG32 &ulThisMinorVersion)
- {
- ulThisMajorVersion = CONTENT_MAJOR_VERSION;
- ulThisMinorVersion = CONTENT_MINOR_VERSION;
- }
- /****************************************************************************
- * GetUpgradeMimeType
- */
- const char* CAudioRenderer::GetUpgradeMimeType(void)
- {
- const char** pStreamMimeTypes = NULL;
- UINT32 ulInitialGranularity;
- GetRendererInfo(pStreamMimeTypes, ulInitialGranularity);
- if (pStreamMimeTypes)
- {
- return pStreamMimeTypes[0];
- }
- return NULL;
- }
- /****************************************************************************
- * GetRendererName
- */
- const char* CAudioRenderer::GetRendererName(void)
- {
- return BASE_AUDIO_RENDERER_NAME;
- }
- /****************************************************************************
- * GetCodecName
- */
- const char* CAudioRenderer::GetCodecName(void)
- {
- return NULL;
- }
- /****************************************************************************
- * GetCoGetCodecFourCCdec4CC
- */
- const char* CAudioRenderer::GetCodecFourCC(void)
- {
- return NULL;
- }
- /****************************************************************************
- * CreateFormatObject
- */
- CAudioFormat* CAudioRenderer::CreateFormatObject(IHXValues* pHeader)
- {
- return new CAudioFormat(m_pCommonClassFactory,
- this);
- }
- /////////////////////////////////////////////////////////////////////////////
- // Method:
- // CAudioRenderer::InitAudioStream
- HX_RESULT CAudioRenderer::InitAudioStream(IHXValues* pHeader,
- IHXAudioStream** ppAudioStream)
- {
- HX_RESULT retVal = HXR_OK;
- // init so we can HX_RELEASE on error.
- *ppAudioStream = NULL;
- retVal = m_pAudioPlayer->CreateAudioStream(ppAudioStream);
- if (SUCCEEDED(retVal))
- {
- IHXCommonClassFactory* pCommonClassFactory;
- if (HXR_OK == (*ppAudioStream)->QueryInterface(IID_IHXCommonClassFactory,
- (void**)&pCommonClassFactory))
- {
- m_pAudioFormat->OverrideFactory(pCommonClassFactory);
- pCommonClassFactory->Release();
- }
- HXAudioFormat audioFmt;
- m_pAudioFormat->GetAudioFormat(audioFmt);
- #if defined(HELIX_FEATURE_STATS)
- ReportStat(AS_CHANNELS, (INT32) audioFmt.uChannels);
- ReportStat(AS_SAMPLING_RATE, (INT32) audioFmt.ulSamplesPerSec);
- ReportStat(AS_SAMPLE_SIZE, (INT32) audioFmt.uBitsPerSample);
- #endif /* #if defined(HELIX_FEATURE_STATS) */
- /* 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.
- */
- IHXDryNotification* pDryNot = NULL;
- // Get my own DryNotification interface with an add
- QueryInterface(IID_IHXDryNotification, (void**)&pDryNot);
- retVal = (*ppAudioStream)->AddDryNotification(pDryNot);
- HX_ASSERT(SUCCEEDED(retVal));
- MLOG_MISC(m_pErrorMessages, "AS Init (%u,%u,%lu,%u)n",
- audioFmt.uChannels, audioFmt.uBitsPerSample,
- audioFmt.ulSamplesPerSec, audioFmt.uMaxBlockSize);
- retVal = (*ppAudioStream)->Init(&audioFmt, pHeader);
- HX_RELEASE(pDryNot);
- }
- if (HXR_OK != retVal)
- {
- HX_RELEASE((*ppAudioStream));
- }
- return retVal;
- }
- /////////////////////////////////////////////////////////////////////////////
- // Method:
- // CAudioRenderer::WriteToAudioServices
- HX_RESULT CAudioRenderer::WriteToAudioServices(HXAudioData* pAudioData)
- {
- HX_RESULT pnr = HXR_OK;
- BOOL bTryWrite = TRUE;
- // Can the audio stream change on the fly?
- // If so, then check for any change. If not,
- // then skip the check.
- if (m_bCanChangeAudioStream)
- {
- BOOL bAudioStreamChanged = FALSE;
- pnr = CheckForAudioStreamChange(bAudioStreamChanged);
- if (FAILED(pnr))
- {
- return pnr;
- }
- if (bAudioStreamChanged)
- {
- pAudioData->uAudioStreamType = TIMED_AUDIO;
- }
- }
- while (bTryWrite)
- {
- pnr = CheckAudioServices();
- if (FAILED(pnr))
- {
- return pnr;
- }
- MLOG_MISC(m_pErrorMessages, "AS Write (%lu,%lu,%lu) ms=%lu tick=%lun",
- (pAudioData->pData ? pAudioData->pData->GetSize() : 0),
- pAudioData->ulAudioTime,
- pAudioData->uAudioStreamType,
- m_pAudioFormat->ConvertBytesToMs((pAudioData->pData ? pAudioData->pData->GetSize() : 0)),
- HX_GET_BETTERTICKCOUNT());
- DEBUG_OUTF_IDX(m_ulCurAudioStream, AUDREND_FLOW_FILE,
- (s, "Audio Write: Time=%u, Bytes=%u, Duration=%u, %sn",
- pAudioData->ulAudioTime,
- (pAudioData->pData ? pAudioData->pData->GetSize() : 0),
- m_pAudioFormat->ConvertBytesToMs((pAudioData->pData ? pAudioData->pData->GetSize() : 0)),
- ((pAudioData->uAudioStreamType == STREAMING_AUDIO) ? "STREAMING" : "TIMED")
- ));
- // Write to AS
- if (m_ppAudioStream[m_ulCurAudioStream])
- pnr = m_ppAudioStream[m_ulCurAudioStream]->Write( pAudioData );
- if (SUCCEEDED(pnr))
- {
- CalculateMaxTimeStamp(pAudioData);
- bTryWrite = FALSE;
- }
- else
- {
- // we got an error on write, check what time the audio stream
- // expects data for
- HXAudioData audioData;
- audioData.pData = NULL;
- if (m_ppAudioStream[m_ulCurAudioStream])
- m_ppAudioStream[m_ulCurAudioStream]->Write( &audioData );
- 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;
- }
- else if (IsTimeGreater(audioData.ulAudioTime, pAudioData->ulAudioTime) &&
- IsTimeLessOrEqual(audioData.ulAudioTime, pAudioData->ulAudioTime +
- m_pAudioFormat->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_pAudioFormat->ClipAudioBuffer(pAudioData,
- audioData.ulAudioTime, TRUE);
- }
- else
- {
- // we are a lot behind and should tell this format to discard
- // data until the audio stream time.
- m_pAudioFormat->
- DiscardAudioUntil(audioData.ulAudioTime);
- // we don't want to try again with this data
- bTryWrite = FALSE;
- }
- }
- }
- // Handle exiting rebuffer started by OnDryNotification from
- // Audio Services
- // if we just wrote audio to audio services that is greater than
- // or equal to the audio wanted time from the dry notification
- // call then we can leave buffering
-
- if (IsRebuffering() &&
- IsTimeGreaterOrEqual(m_ulLastWriteTime, m_ulAudioWantedTime))
- {
- EndRebuffer();
- }
- return pnr;
- }
- /////////////////////////////////////////////////////////////////////////////
- // Method:
- // CAudioRenderer::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 CAudioRenderer::DoAudio(UINT32& ulAudioTime,
- AUDIO_STATE audioState)
- {
- HX_RESULT retVal;
- HXAudioData audioData;
- ULONG32 ulPreviousLastWriteTime;
- LONG32 lTimeDelta;
- audioData.pData = NULL;
- audioData.ulAudioTime = ulAudioTime = 0;
- // write the lowest stream to audio services
- ulPreviousLastWriteTime = m_ulLastWriteTime;
- do
- {
- retVal = m_pAudioFormat->CreateAudioFrame(
- audioData,
- (m_bEndOfPackets) ? AUDIO_END_OF_PACKETS : audioState);
- if (retVal == HXR_OK)
- {
- audioData.uAudioStreamType = TIMED_AUDIO;
- // Update the timestamp of the audio services write
- audioData.ulAudioTime = AdjustTimestamp(audioData.ulAudioTime, m_lTimeOffset);
- if (m_ulLastWriteTime != NO_TIME_SET)
- {
- lTimeDelta = audioData.ulAudioTime -
- m_ulLastWriteTime;
- HX_ASSERT(lTimeDelta >= (-TIME_FUDGE));
- if (lTimeDelta <= TIME_FUDGE)
- {
- audioData.uAudioStreamType = STREAMING_AUDIO;
- }
- #ifdef _AUDREND_FLOW_LOG
- else if (lTimeDelta < (-TIME_FUDGE))
- {
- DEBUG_OUTF_IDX(m_ulCurAudioStream, AUDREND_FLOW_FILE,
- (s, "Overlapping Audio: Time=%u, LastWriteTime=%u, Overlap=%dn",
- audioData.ulAudioTime,
- m_ulLastWriteTime,
- -lTimeDelta
- ));
- }
- #endif // _AUDREND_FLOW_LOG
- }
- retVal = WriteToAudioServices(&audioData);
- }
- else
- {
- break;
- }
- // do not loop here if writing to
- // satisfy dry notification
- } while (audioState != AUDIO_DRYNOTIFICATION &&
- ((m_ulLastWriteTime - ulPreviousLastWriteTime) <
- MAX_AUDIO_WRITE_TIME));
- // release the data buffer if we got one
- HX_RELEASE(audioData.pData);
- // update the out param
- ulAudioTime = audioData.ulAudioTime;
- return retVal;
- }
- HX_RESULT CAudioRenderer::AttemptToSatisfyDryRequest(UINT32 ulAudioWantedTime)
- {
- HX_RESULT pnr = HXR_OK;
- UINT32 ulAudioTime = 0;
- while (HXR_OK == pnr &&
- IsTimeGreaterOrEqual(ulAudioWantedTime, m_ulLastWriteTime))
- {
- pnr = DoAudio(ulAudioTime, AUDIO_DRYNOTIFICATION);
- }
- return pnr;
- }
- void
- CAudioRenderer::CalculateMaxTimeStamp(HXAudioData* pAudioData)
- {
- UINT32 ulTimestamp = pAudioData->ulAudioTime +
- m_pAudioFormat->ConvertBytesToMs(pAudioData->pData->GetSize());
- if (m_ulLastWriteTime == NO_TIME_SET ||
- IsTimeLess(m_ulLastWriteTime, ulTimestamp))
- {
- m_ulLastWriteTime = ulTimestamp;
- }
- }
- HX_RESULT CAudioRenderer::CheckForAudioStreamChange(REF(BOOL) rbAudioStreamChanged)
- {
- HX_RESULT retVal = HXR_FAIL;
- if (m_pAudioFormat)
- {
- retVal = HXR_OK;
- // Check to see if the audio format has changed
- if (HasAudioFormatChanged())
- {
- // Transfer the current audio stream to
- // a newly created audio stream
- retVal = IncrementAudioStream();
- rbAudioStreamChanged = SUCCEEDED(retVal);
- }
- }
- return retVal;
- }
- BOOL CAudioRenderer::HasAudioFormatChanged()
- {
- BOOL bRet = FALSE;
- if (m_pAudioFormat)
- {
- // Get the audio format from the CAudioFormat object
- HXAudioFormat cAudioFormat1;
- HX_RESULT retVal = m_pAudioFormat->GetAudioFormat(cAudioFormat1);
- if (SUCCEEDED(retVal))
- {
- // Get the audio format from the current IHXAudioStream object
- if (m_ppAudioStream &&
- m_ulCurAudioStream < m_ulNumAudioStreams &&
- m_ppAudioStream[m_ulCurAudioStream])
- {
- IHXAudioStream2* pStream2 = NULL;
- retVal = m_ppAudioStream[m_ulCurAudioStream]->QueryInterface(IID_IHXAudioStream2,
- (void**) &pStream2);
- if (SUCCEEDED(retVal))
- {
- HXAudioFormat cAudioFormat2;
- retVal = pStream2->GetAudioFormat(&cAudioFormat2);
- if (SUCCEEDED(retVal))
- {
- // Check if the formats are different
- if (cAudioFormat1.uChannels != cAudioFormat2.uChannels ||
- cAudioFormat1.uBitsPerSample != cAudioFormat2.uBitsPerSample ||
- cAudioFormat1.ulSamplesPerSec != cAudioFormat2.ulSamplesPerSec ||
- cAudioFormat1.uMaxBlockSize > cAudioFormat2.uMaxBlockSize)
- {
- bRet = TRUE;
- }
- }
- }
- HX_RELEASE(pStream2);
- }
- }
- }
- return bRet;
- }
- HX_RESULT CAudioRenderer::IncrementAudioStream()
- {
- HX_RESULT retVal = HXR_FAIL;
- if (m_ulCurAudioStream + 1 >= m_ulNumAudioStreams)
- {
- // We need to create a larger buffer to hold the
- // audio stream pointers
- UINT32 ulNewSize = m_ulNumAudioStreams * 2;
- IHXAudioStream** ppAudioStream = new IHXAudioStream* [ulNewSize];
- if (ppAudioStream)
- {
- // NULL out the buffer
- memset((void*) ppAudioStream, 0, ulNewSize * sizeof(IHXAudioStream*));
- // Copy the current pointers
- memcpy((void*) ppAudioStream, /* Flawfinder: ignore */
- (const void*) m_ppAudioStream,
- m_ulNumAudioStreams * sizeof(IHXAudioStream*));
- // Delete the old array
- HX_VECTOR_DELETE(m_ppAudioStream);
- // Assign the new one
- m_ppAudioStream = ppAudioStream;
- // Assign the new size
- m_ulNumAudioStreams = ulNewSize;
- }
- }
- if (m_ulCurAudioStream + 1 < m_ulNumAudioStreams)
- {
- // Remove the dry notification from the old stream
- if (m_ppAudioStream[m_ulCurAudioStream])
- {
- IHXAudioStream2* pStream2 = NULL;
- m_ppAudioStream[m_ulCurAudioStream]->QueryInterface(IID_IHXAudioStream2,
- (void**) &pStream2);
- if (pStream2)
- {
- // Get our own IHXDryNotification interface
- IHXDryNotification* pDryNot = NULL;
- QueryInterface(IID_IHXDryNotification, (void**) &pDryNot);
- if (pDryNot)
- {
- pStream2->RemoveDryNotification(pDryNot);
- }
- HX_RELEASE(pDryNot);
- }
- HX_RELEASE(pStream2);
- }
- // Init the new stream
- retVal = InitAudioStream(m_pHeader, &m_ppAudioStream[m_ulCurAudioStream + 1]);
- if (SUCCEEDED(retVal))
- {
- // Increment the current audio stream index
- m_ulCurAudioStream += 1;
- }
- }
- return retVal;
- }
- BOOL CAudioRenderer::IsRebuffering() const
- {
- return (NO_TIME_SET != m_ulAudioWantedTime) ? TRUE : FALSE;
- }
- void CAudioRenderer::StartRebuffer(UINT32 ulAudioWantedTime)
- {
- if (m_pStream)
- {
- m_ulAudioWantedTime = ulAudioWantedTime;
- m_pStream->ReportRebufferStatus(1,0);
- }
- }
- void CAudioRenderer::EndRebuffer()
- {
- m_ulAudioWantedTime = NO_TIME_SET;
- if (m_pStream)
- {
- m_pStream->ReportRebufferStatus(1,1);
- }
- }