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

📄 chxclientsink.cpp

📁 linux下的一款播放器
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/* ***** BEGIN LICENSE BLOCK ***** * Source last modified: $Id: CHXClientSink.cpp,v 1.18.2.4 2004/07/09 01:49:47 hubbe Exp $ *  * Portions Copyright (c) 1995-2004 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 (the "RPSL") available at * http://www.helixcommunity.org/content/rpsl unless you have licensed * the file under the current version of the RealNetworks Community * Source License (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. *  * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the * "GPL") in which case the provisions of the GPL are applicable * instead of those above. If you wish to allow use of your version of * this file only under the terms of the GPL, and not to allow others * to use your version of this file under the terms of either the RPSL * or RCSL, indicate your decision by deleting the provisions above * and replace them with the notice and other provisions required by * the GPL. If you do not delete the provisions above, a recipient may * use your version of this file under the terms of any one of the * RPSL, the RCSL or the GPL. *  * 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 ***** */#include "CHXClientSink.h"#include "CHXClientDebug.h"#include "enter_hx_headers.h"#include "hxerror.h"#include "hxcore.h"#include "ihxpckts.h"#include "hxsmartptr.h"HX_SMART_POINTER_INLINE( SPIHXBuffer, IHXBuffer );HX_SMART_POINTER_INLINE( SPIHXValues, IHXValues );HX_SMART_POINTER_INLINE( SPIHXPersistentComponentManager, IHXPersistentComponentManager );HX_SMART_POINTER_INLINE( SPIHXPersistentComponent, IHXPersistentComponent );HX_SMART_POINTER_INLINE( SPIHXAudioPlayer, IHXAudioPlayer );HX_SMART_POINTER_INLINE( SPIHXErrorSinkControl, IHXErrorSinkControl );HX_SMART_POINTER_INLINE( SPIHXErrorMessages, IHXErrorMessages );HX_SMART_POINTER_INLINE( SPIHXScheduler, IHXScheduler );#ifdef HELIX_FEATURE_REGISTRY#include "hxcomm.h"  // IHXRegistryID#include "hxmon.h"   // IHXRegistryHX_SMART_POINTER_INLINE( SPIHXRegistry, IHXRegistry );HX_SMART_POINTER_INLINE( SPIHXRegistryID, IHXRegistryID );#endif#include "exit_hx_headers.h"#include "HXClientConstants.h"#include "hlxclib/stdlib.h"#include "hlxclib/string.h"UINT32 const kInvalidSeekPosition = 0xFFFFFFFF;static const char* const kURLPropertyName    = "url";static const char* const kSourcePropertyName = "src";static const char* const kPersistentComponentIDPropertyName = "PersistentComponentID";#pragma mark -static intUnhex( char c ){	return (c >= '0' && c <= '9' ? c - '0'	    : c >= 'A' && c <= 'F' ? c - 'A' + 10	    : c - 'a' + 10 );}static voidUnescapeURL( char* s ){/* * Remove URL hex escapes from s... done in place.  The basic concept for * this routine is borrowed from the WWW library HTUnEscape() routine. */	char* p = NULL;	bool bProcessingOptionsPastQuestionMark = false;	for ( p = s; *s != '\0'; ++s )	{		if ( ( !bProcessingOptionsPastQuestionMark ) && ( *s == '%' ) )		{			if ( *++s != '\0' ) 			{				*p = Unhex( *s ) << 4;			}			if ( *++s != '\0' ) 			{				*p++ += Unhex( *s );			}		} 		else 		{			if ( *s == '?' )			{				bProcessingOptionsPastQuestionMark = true;			}			*p++ = *s;		}	}	*p = '\0';}CHXClientSink::~CHXClientSink( void ){	delete [] m_pRPURLTarget;	delete [] m_pRPURL;	delete [] m_pContextURL;	delete [] m_pTrackURL;	delete [] m_pMetafileURL;	delete [] m_pTitle;}CHXClientSink::CHXClientSink( IHXPlayer* pIHXPlayer, void* userInfo, const HXClientCallbacks* pClientCallbacks )	: m_UserInfo( userInfo )	, m_pClientCallbacks( pClientCallbacks )	, m_pIHXCorePlayer( pIHXPlayer )	, m_hScheduler( 0 )#ifdef HELIX_FEATURE_REGISTRY	, m_TitlePropID( 0 )	, m_ClipBandwidthPropID( 0 )#endif	, m_TitleSize( 0 )	, m_pTitle( NULL )	, m_pMetafileURL( NULL )	, m_pTrackURL( NULL )	, m_pContextURL( NULL )	, m_pRPURL( NULL )	, m_pRPURLTarget( NULL )	, m_ClipBandwidth( 0 )	, m_ContentState( kContentStateStopped ) // If this object is loaded, kContentStateNotLoaded is not applicable	, m_BufferPercent( 100 )	, m_Position( 0 )	, m_Length( 0 )	, m_OnPlayingPositionThreshold( 0 )	, m_PendingBeginPosition( kInvalidSeekPosition )	, m_IsLive( false )	, m_IsGroupsListDirty( false )	, m_HasContentBegun( false ){	CHXASSERT( m_pClientCallbacks ); // What's the point in observing if we cannot tell anyone about it.	CHXASSERT( m_pIHXCorePlayer ); // Need a valid core player.}BEGIN_INTERFACE_LIST_NOCREATE( CHXClientSink )    INTERFACE_LIST_ENTRY_SIMPLE( IHXClientAdviseSink )    INTERFACE_LIST_ENTRY_SIMPLE( IHXGroupSink )    INTERFACE_LIST_ENTRY_SIMPLE( IHXVolumeAdviseSink )#ifdef HELIX_FEATURE_REGISTRY    INTERFACE_LIST_ENTRY_SIMPLE( IHXPropWatchResponse )#endif	INTERFACE_LIST_ENTRY_SIMPLE( IHXErrorSink )    INTERFACE_LIST_ENTRY_SIMPLE( IHXCallback )END_INTERFACE_LISTvoidCHXClientSink::Init( void ){	SetUpPropWatcher();		SPIHXAudioPlayer spAudioPlayer = m_pIHXCorePlayer;	if ( spAudioPlayer.IsValid() )	{		IHXVolume* pIClientVolume = spAudioPlayer->GetDeviceVolume();		if ( pIClientVolume )		{			pIClientVolume->AddAdviseSink( this );			pIClientVolume->Release();		}	}	SPIHXErrorSinkControl spErrorSinkControl = m_pIHXCorePlayer;	if ( spErrorSinkControl.IsValid() )	{		spErrorSinkControl->AddErrorSink( this, HXLOG_EMERG, HXLOG_INFO );	}}voidCHXClientSink::Destroy( void ){	if ( m_hScheduler != 0 )	{		SPIHXScheduler spScheduler = m_pIHXCorePlayer;		if ( spScheduler.IsValid() )		{			m_hScheduler = spScheduler->Remove( m_hScheduler );		}	}	SPIHXErrorSinkControl spErrorSinkControl = m_pIHXCorePlayer;	if ( spErrorSinkControl.IsValid() )	{		spErrorSinkControl->RemoveErrorSink( this );	}	SPIHXAudioPlayer spAudioPlayer = m_pIHXCorePlayer;	if ( spAudioPlayer.IsValid() )	{		IHXVolume* pIClientVolume = spAudioPlayer->GetDeviceVolume();		if ( pIClientVolume )		{			pIClientVolume->RemoveAdviseSink( this );			pIClientVolume->Release();		}	}	DestroyPropWatcher();}#pragma mark -voidCHXClientSink::SetBeginPosition( UINT32 beginPosition ){	if ( m_ContentState == kContentStateStopped )	{		// XXXSEH: This has issues with various pieces of content including http clips and complex clips whose timeline is not known at the beginning.		// m_PendingBeginPosition = beginPosition; // Need to wait for an OnBegin() callback before we can change the clip's position.	}	else	{		m_PendingBeginPosition = kInvalidSeekPosition;		( void ) m_pIHXCorePlayer->Seek( beginPosition );	}}voidCHXClientSink::DoGroupsListUpdate( void ){	// we defer calling OnGroupsChanged until a playback transition, since at the times	// the group changes really occur, the information about the track names isn't yet	// available	if ( m_IsGroupsListDirty )	{		m_IsGroupsListDirty = false;		if ( m_pClientCallbacks->OnGroupsChanged )		{			m_pClientCallbacks->OnGroupsChanged( m_UserInfo );		}	}}voidCHXClientSink::UpdateContentState( int newContentState ){	if ( m_ContentState != newContentState )	{		if ( m_ContentState == kContentStateContacting )		{			if ( m_pClientCallbacks->OnContacting )			{				m_pClientCallbacks->OnContacting( m_UserInfo, NULL );			}		}		int oldContentState = m_ContentState;		m_ContentState = newContentState;		if ( m_pClientCallbacks->OnContentStateChanged )		{			m_pClientCallbacks->OnContentStateChanged( m_UserInfo, oldContentState, m_ContentState );		}	}}STDMETHODIMPCHXClientSink::OnPresentationOpened( void ){	return HXR_OK;}STDMETHODIMPCHXClientSink::OnBegin( ULONG32 ulTime ){	m_HasContentBegun = true;	m_Position = ulTime;	m_OnPlayingPositionThreshold = ulTime;	DoGroupsListUpdate();  // updates group information for second and later clip		if ( m_PendingBeginPosition != kInvalidSeekPosition )	{		UINT32 beginPosition = m_PendingBeginPosition;		m_PendingBeginPosition = kInvalidSeekPosition;		( void ) m_pIHXCorePlayer->Seek( beginPosition );	}	return HXR_OK;}STDMETHODIMPCHXClientSink::OnContacting( const char* pHostName ){	UpdateContentState( kContentStateContacting );	if ( m_pClientCallbacks->OnContacting )	{		m_pClientCallbacks->OnContacting( m_UserInfo, pHostName );	}	return HXR_OK;}STDMETHODIMPCHXClientSink::OnBuffering( ULONG32 ulFlags, UINT16 unPercentComplete ){	if ( m_BufferPercent != unPercentComplete )	{		m_OnPlayingPositionThreshold = m_pIHXCorePlayer->GetCurrentPlayTime();		m_BufferPercent = unPercentComplete;		if ( m_BufferPercent < 100 )		{			DoGroupsListUpdate(); // update information on first clip						// I've noticed that this callback is being made even when the content is paused,			// so let's prevent the content state from changing in this case.			if ( m_HasContentBegun )			{				UpdateContentState( kContentStateLoading );			}		}		if ( m_pClientCallbacks->OnBuffering )		{			m_pClientCallbacks->OnBuffering( m_UserInfo, ulFlags, m_BufferPercent );		}	}	return HXR_OK;}STDMETHODIMPCHXClientSink::OnPosLength( UINT32 ulPosition, UINT32 ulLength ){	bool wasLive = m_IsLive;	m_Position = ulPosition;	m_IsLive = ( 0 != m_pIHXCorePlayer->IsLive() );	if ( ( m_Length != ulLength ) || ( !wasLive != !m_IsLive ) )	{		m_Length = ulLength;		if ( m_pClientCallbacks->OnLengthChanged )		{			m_pClientCallbacks->OnLengthChanged( m_UserInfo, m_Length );		}	}	if ( m_Position > m_OnPlayingPositionThreshold )	{		DoGroupsListUpdate(); // update information on first clip		m_OnPlayingPositionThreshold = 0xFFFFFFFF;		UpdateContentState( kContentStatePlaying );	}	return HXR_OK;}STDMETHODIMPCHXClientSink::OnPause( ULONG32 ulTime ){	m_HasContentBegun = false;		m_Position = ulTime;	m_OnPlayingPositionThreshold = ulTime;	UpdateContentState( kContentStatePaused );	return HXR_OK;}	STDMETHODIMPCHXClientSink::OnStop( void ){	m_HasContentBegun = false;		m_Position = 0; // XXXSEH: Might be nice to retain the last position.	m_OnPlayingPositionThreshold = 0;	return HXR_OK;}STDMETHODIMPCHXClientSink::OnPresentationClosed( void ){	if ( m_ContentState != kContentStateStopped )	{		// I'd prefer to send this out in OnStop(), but unfortunately it and this callback are called		// prior to Helix being ready to immediately accept a new url for playback.		// This kludge solves this problem, providing support for custom playlist managers for example.		if ( m_hScheduler == 0 )		{			SPIHXScheduler spScheduler = m_pIHXCorePlayer;			if ( spScheduler.IsValid() )			{				m_hScheduler = spScheduler->RelativeEnter( this, 0 );			}			// Couldn't schedule the callback to update the state, so let's do it now.			// Not ideal, but better than never altering the state to stopped.			if ( m_hScheduler == 0 )			{				UpdateContentState( kContentStateStopped );			}		}	}	return HXR_OK;}voidCHXClientSink::ProcessPendingStateChange( void ){	if ( m_hScheduler != 0 )	{		SPIHXScheduler spScheduler = m_pIHXCorePlayer;		if ( spScheduler.IsValid() )		{			m_hScheduler = spScheduler->Remove( m_hScheduler );		}		UpdateContentState( kContentStateStopped );	}}STDMETHODIMPCHXClientSink::Func( void ){	m_hScheduler = 0;		UpdateContentState( kContentStateStopped );	if ( m_pClientCallbacks->OnContentConcluded )	{		m_pClientCallbacks->OnContentConcluded( m_UserInfo );	}	return HXR_OK;}STDMETHODIMPCHXClientSink::OnStatisticsChanged( void ){	return HXR_OK;}STDMETHODIMPCHXClientSink::OnPreSeek( ULONG32 ulOldTime, ULONG32 ulNewTime ){	m_Position = ulNewTime;	return HXR_OK;}STDMETHODIMPCHXClientSink::OnPostSeek( ULONG32 ulOldTime, ULONG32 ulNewTime ){	m_Position = ulNewTime;	m_OnPlayingPositionThreshold = ulNewTime;	return HXR_OK;}#pragma mark -voidCHXClientSink::GetURLsFromTrackProperties( IHXValues* pTrackProperties ){	delete [] m_pMetafileURL;	m_pMetafileURL = NULL;	delete [] m_pTrackURL;	m_pTrackURL = NULL;		if ( pTrackProperties )	{		SPIHXBuffer spTrackURLBuffer;		pTrackProperties->GetPropertyCString( kURLPropertyName, *spTrackURLBuffer.AsInOutParam() );		if ( !spTrackURLBuffer.IsValid() )		{			pTrackProperties->GetPropertyCString( kSourcePropertyName, *spTrackURLBuffer.AsInOutParam() );		}		if ( spTrackURLBuffer.IsValid() )		{

⌨️ 快捷键说明

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