⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 audrend.cpp

📁 著名的 helix realplayer 基于手机 symbian 系统的 播放器全套源代码
💻 CPP
📖 第 1 页 / 共 3 页
字号:

    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))

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -