--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/upnpmpxplugins/upnpplaybackplugins/src/upnpmusicplayer.cpp Thu Dec 17 08:52:00 2009 +0200
@@ -0,0 +1,1466 @@
+/*
+* Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: Plugin for playing files in a remote upnp renderer
+*
+*/
+
+
+
+
+
+
+// INCLUDES
+#include "upnpavcontrollerfactory.h"
+#include "upnpavcontroller.h"
+#include "upnpfileutility.h"
+#include "upnpavrenderingsession.h"
+#include "upnpavdevice.h"
+#include <mpxplaybackpluginobserver.h>
+
+#include "upnpmusicplayer.h"
+#include "upnpsingleton.h"
+#include "upnptrack.h"
+#include "upnpplaybackstatemachine.h"
+#include "upnpvaluestatemachine.h"
+#include "upnppluginserrortranslation.h"
+
+
+// CONSTANTS
+// ** a message to music player to complete an immediate exit
+const TInt KMusicPluginMessageExit = 3001;
+const TUid KMusicPlayerUid = { 0x200075D8 };
+
+_LIT( KStateUninitialized, "Uninitialised" );
+_LIT( KStateUninitialising, "Uninitialising" );
+_LIT( KStateInitializing, "Initializing" );
+_LIT( KStateActive, "Active" );
+_LIT( KStatePreInitializing, "PreInitializing" );
+_LIT( KStatePreInitialized, "PreInitialized" );
+_LIT( KStateWaiting, "Waiting" );
+_LIT( KStateActiveForceInit, "ActiveForceInit" );
+_LIT( KStateError, "Error" );
+_LIT( KStateUnknown, "Unknown" );
+
+
+_LIT( KComponentLogfile, "musicplugins.txt");
+#include "upnplog.h"
+
+// LOCAL FUNCTIONS
+
+ /*
+ * a template helper function to safely delete a pointer
+ * (make sure pointer becomes NULL before delete is called)
+ * 1. first copy the given pointer to a local temp variable
+ * 2. then allocate a local member, then nullify the given pointer
+ * 3. last, delete the temporary pointer
+ */
+ template <class T>
+ inline void SafeDelete( T*& aPointer )
+ {
+ // first, store the given object into a local temp variable
+ T* tempPointer = aPointer;
+ // nullify the given pointer
+ aPointer = 0;
+ // last, delete the given object
+ delete tempPointer;
+ }
+
+// --------------------------------------------------------------------------
+// Static members of CUPnPMusicPlayer
+// --------------------------------------------------------------------------
+//
+
+// Pointer to the plugin that is active at the time
+CUPnPMusicPlayer* CUPnPMusicPlayer::iActivePlugIn;
+
+// Pointer to the plugini that is waiting to activate (pre-initialized)
+CUPnPMusicPlayer* CUPnPMusicPlayer::iNextPlugIn;
+
+// ======== MEMBER FUNCTIONS ========
+
+// --------------------------------------------------------------------------
+// CUPnPMusicPlayer::NewL
+// 1st phase constructor.
+// --------------------------------------------------------------------------
+//
+CUPnPMusicPlayer* CUPnPMusicPlayer::NewL( MMPXPlaybackPluginObserver& aObs )
+ {
+ CUPnPMusicPlayer* p = new(ELeave) CUPnPMusicPlayer( aObs );
+ CleanupStack::PushL( p );
+ __LOG1( "CUPnPMusicPlayer::NewL [%d]", p );
+ p->ConstructL();
+ CleanupStack::Pop( p );
+ return p;
+ }
+
+// --------------------------------------------------------------------------
+// CUPnPMusicPlayer::CUPnPMusicPlayer
+// Default constructor.
+// --------------------------------------------------------------------------
+//
+CUPnPMusicPlayer::CUPnPMusicPlayer( MMPXPlaybackPluginObserver& aObs ) :
+ iSelectedRendererIndex( KErrNotFound ),
+ iPlayerState( EStateUninitialised ),
+ iIsReady( EFalse )
+ {
+ iObs = &aObs;
+ iTrack = NULL;
+ }
+
+// --------------------------------------------------------------------------
+// CUPnPMusicPlayer::ConstructL
+// --------------------------------------------------------------------------
+//
+void CUPnPMusicPlayer::ConstructL()
+ {
+ __LOG( "CUPnPMusicPlayer::ConstructL" );
+
+ // get a handle to the shared singleton
+ iSingleton = CUPnPSingleton::GetInstanceL();
+
+ // audio policy
+ iAudioPolicy = CUPnPAudioPolicy::NewL( *this );
+ }
+
+// --------------------------------------------------------------------------
+// CUPnPMusicPlayer::~CUPnPMusicPlayer
+// Destructor.
+// --------------------------------------------------------------------------
+//
+CUPnPMusicPlayer::~CUPnPMusicPlayer()
+ {
+ __LOG( "CUPnPMusicPlayer::~CUPnPMusicPlayer()" );
+ UninitialiseTrack( EStateNone );
+
+ if( iSingleton != NULL )
+ {
+ CUPnPSingleton::LoseInstance( iSingleton );
+ iSingleton = NULL;
+ }
+
+ delete iAudioPolicy;
+ iAudioPolicy = 0;
+ delete iSelectedRenderer;
+ }
+
+// --------------------------------------------------------------------------
+// CUPnPMusicPlayer::MatchRenderer
+// Compares renderers names
+// --------------------------------------------------------------------------
+//
+TBool CUPnPMusicPlayer::MatchRenderer(
+ const CUpnpAVDevice* aRenderer ) const
+ {
+ if( aRenderer == NULL )
+ {
+ // no renderer - using default renderer, which is always
+ // the same as previously selected renderer -> ALWAYS MATCH.
+ return ETrue;
+ }
+
+ if( iSelectedRenderer == NULL )
+ {
+ // Current renderer does not exist - this should never happen.
+ __PANICD( __FILE__, __LINE__ );
+ return ETrue;
+ }
+
+ // compare renderer pointer
+ if ( iSelectedRenderer == aRenderer )
+ {
+ return ETrue;
+ }
+
+ // Compare renderer UUID
+ if ( iSelectedRenderer->Uuid().Compare( aRenderer->Uuid() ) == 0 )
+ {
+ return ETrue;
+ }
+
+ return EFalse;
+ }
+
+
+// --------------------------------------------------------------------------
+// CUPnPMusicPlayer::UsedRendererDevice
+// Returns currently used renderer device
+// --------------------------------------------------------------------------
+//
+CUpnpAVDevice& CUPnPMusicPlayer::UsedRendererDevice() const
+ {
+ return *iSelectedRenderer;
+ }
+
+// --------------------------------------------------------------------------
+// CUPnPMusicPlayer::SetActive
+// Set Plugin state to active.
+// --------------------------------------------------------------------------
+//
+void CUPnPMusicPlayer::SetActive( TBool aForceInitialise )
+ {
+ __LOG( "CUPnPMusicPlayer::SetActive" );
+
+ if ( iActivePlugIn != 0 &&
+ iActivePlugIn->MatchRenderer( iSelectedRenderer ) )
+ {
+ // Continuing playback on the same renderer.
+ // copy some cached values
+ //
+ iValueStateMachine->CopyValues(
+ iActivePlugIn->ValueStateMachine() );
+ }
+
+ if( iPlayerState == EStatePreInitialized )
+ {
+ // Preinitialize is ready. Clear pointer from iNextPlugin and
+ // sets it to iActivePlugIn.
+ iActivePlugIn = this;
+ iNextPlugIn = NULL;
+ if( aForceInitialise )
+ {
+ ChangeState( EStateActiveForceInitialise );
+ TRAP_IGNORE( iAudioPolicy->PlayL() );
+ }
+ else
+ {
+ ChangeState( EStateActive );
+ TRAP_IGNORE( iAudioPolicy->PlayL() );
+ }
+ }
+ else if( iPlayerState == EStateWaiting )
+ {
+ // Used renderer does not support SetNextURI feature. Initialise
+ // track by SetURI after play command.
+ iActivePlugIn = this;
+ iNextPlugIn = NULL;
+ ChangeState( EStateActiveForceInitialise );
+ }
+ else if( iPlayerState == EStateActive )
+ {
+ // do nothing
+ iActivePlugIn = this;
+ iNextPlugIn = NULL;
+ ChangeState( EStateActive );
+ TRAP_IGNORE( iAudioPolicy->PlayL() );
+ }
+ else if( iPlayerState == EStatePreInitializing )
+ {
+ // Do nothing.
+ }
+ else
+ {
+ __LOG1( "CUPnPMusicPlayer::SetActive in wrong state %S",
+ State( iPlayerState ) );
+ __PANICD( __FILE__, __LINE__ );
+ }
+ }
+
+// --------------------------------------------------------------------------
+// CUPnPMusicPlayer::Observer
+// --------------------------------------------------------------------------
+//
+MMPXPlaybackPluginObserver& CUPnPMusicPlayer::Observer() const
+ {
+ __ASSERTD( iObs != 0, __FILE__, __LINE__ );
+ return *iObs;
+ }
+
+// --------------------------------------------------------------------------
+// CUPnPMusicPlayer::PlaybackStateMachine
+// --------------------------------------------------------------------------
+//
+const CUPnPPlaybackStateMachine&
+ CUPnPMusicPlayer::PlaybackStateMachine() const
+ {
+ __ASSERTD( iPlaybackStateMachine != 0, __FILE__, __LINE__ );
+ return *iPlaybackStateMachine;
+ }
+
+// --------------------------------------------------------------------------
+// CUPnPMusicPlayer::ValueStateMachine
+// --------------------------------------------------------------------------
+//
+const CUPnPValueStateMachine&
+ CUPnPMusicPlayer::ValueStateMachine() const
+ {
+ __ASSERTD( iValueStateMachine != 0, __FILE__, __LINE__ );
+ return *iValueStateMachine;
+ }
+
+// --------------------------------------------------------------------------
+// CUPnPMusicPlayer::Track
+// --------------------------------------------------------------------------
+//
+CUPnPTrack& CUPnPMusicPlayer::Track() const
+ {
+ __ASSERTD( iTrack != 0, __FILE__, __LINE__ );
+ return *iTrack;
+ }
+
+
+// --------------------------------------------------------------------------
+// CUPnPMusicPlayer::HandlePlayStarted
+// --------------------------------------------------------------------------
+//
+void CUPnPMusicPlayer::HandlePlayStarted()
+ {
+ __LOG( "CUPnPMusicPlayer::HandlePlayStarted" );
+
+ // Remote device is ready for give playback information
+ // (duration, position..)
+ iIsReady = ETrue;
+
+ // Inform user that playback is started
+ iObs->HandlePluginEvent( MMPXPlaybackPluginObserver::EPPlaying, 0,
+ KErrNone );
+
+ if( iValueStateMachine && iTrack )
+ {
+ // always query volume. Duration if not already exist or in
+ // case of remote track.
+ TRAP_IGNORE(
+ iValueStateMachine->VolumeQueryL();
+ if( iTrack->TrackDuration() == 0 || iTrack->IsRemote() )
+ {
+ iValueStateMachine->DurationQueryL();
+ }
+ )
+ }
+ }
+
+// --------------------------------------------------------------------------
+// CUPnPMusicPlayer::HandlePlayComplete
+// --------------------------------------------------------------------------
+//
+void CUPnPMusicPlayer::HandlePlayComplete()
+ {
+ __LOG( "CUPnPMusicPlayer::HandlePlayComplete" );
+
+ iAudioPolicy->Stop();
+
+ // If there is a next initialized plugin then active it
+ if( iActivePlugIn == this && iNextPlugIn != 0 )
+ {
+ // Set iActivePlugIn to null.
+ iNextPlugIn->SetActive( EFalse );
+ }
+ }
+
+
+// --------------------------------------------------------------------------
+// Methods from CMPXPlaybackPlugin
+// --------------------------------------------------------------------------
+
+// --------------------------------------------------------------------------
+// CUPnPMusicPlayer::InitialiseL( const TDesC& aSong )
+// Initializes a song for playback.
+// --------------------------------------------------------------------------
+//
+void CUPnPMusicPlayer::InitialiseL( const TDesC& aSong )
+ {
+ // Initialise song for play back.
+ InitialiseTrackL( aSong );
+ }
+
+// --------------------------------------------------------------------------
+// CUPnPMusicPlayer::InitialiseL( RFile& aSong )
+// Initializes a song for playback.
+// --------------------------------------------------------------------------
+//
+void CUPnPMusicPlayer::InitialiseL( RFile& aSong )
+ {
+ // At first get the song path from given resource file
+ HBufC* tempBuf = HBufC::NewL( KMaxFileName );
+ CleanupStack::PushL( tempBuf );
+ TPtr ptr = tempBuf->Des();
+ TInt err = aSong.FullName( ptr );
+
+ // Leave if any error
+ if( err != KErrNone )
+ {
+ User::Leave( KErrArgument );
+ }
+
+ // Initialise song for play back.
+ InitialiseTrackL( *tempBuf );
+ CleanupStack::PopAndDestroy( tempBuf );
+ }
+
+// --------------------------------------------------------------------------
+// CUPnPMusicPlayer::InitialiseTrackL
+// Initializes a remote or local song for playback
+// --------------------------------------------------------------------------
+//
+void CUPnPMusicPlayer::InitialiseTrackL( const TDesC& aSong )
+ {
+ __LOG1( "CUPnPMusicPlayer::InitialiseTrackL [%d]", this );
+ __ASSERTD( iPlayerState == EStateUninitialised, __FILE__, __LINE__ );
+
+ // some state checks
+ if ( iPlayerState != EStateUninitialised )
+ {
+ __LOG( "CUPnPMusicPlayer::InitialiseTrackL: In wrong state! " );
+ User::Leave( KErrNotReady );
+ }
+ if( ( iActivePlugIn != NULL ) && ( iNextPlugIn != NULL ) )
+ {
+ __LOG( "CUPnPMusicPlayer::InitialiseTrackL - \
+ More than two plugin initialisezed at the same time! " );
+ User::Leave( KErrNotReady );
+ }
+ if( iSelectedRenderer == 0 )
+ {
+ __LOG( "CUPnPMusicPlayer::InitialiseTrackL - \
+ Subplayer not selected " );
+ User::Leave( KErrNotReady );
+ }
+
+ if( aSong.Length() == 0 )
+ {
+ User::Leave( KErrNotSupported );
+ }
+
+ __LOG( "CUPnPMusicPlayer::InitialiseTrackL: Start rendering session" );
+ MUPnPAVRenderingSession* tempSession =
+ &iSingleton->AVC().StartRenderingSessionL( *iSelectedRenderer );
+
+ __LOG( "CUPnPMusicPlayer::InitialiseTrackL - \
+ Set Rendering session observer" );
+ // Set media observer
+ tempSession->SetObserver( *this );
+
+ // stop existing rendering session if exists
+ if( iRendererSession )
+ {
+ __LOG( "CUPnPMusicPlayer::InitialiseTrackL: Stop old session" );
+ // releasing local MS services is left to AVController
+ iSingleton->AVC().StopRenderingSession( *iRendererSession );
+ iRendererSession = 0;
+ }
+
+ iRendererSession = tempSession;
+
+ // Set plugin to active and call SetURI if there is no track
+ // playing currently or the track playing currently is in
+ // different renderer
+ if( iActivePlugIn == NULL )
+ {
+ // There is no track playing currently
+ iActivePlugIn = this; // Set Plugin to the active.
+ ChangeState( EStateInitializing );
+ }
+ else // Track is currently playing.
+ {
+ // Check if track is playing in different renderer
+ if( iActivePlugIn->MatchRenderer( iSelectedRenderer ) )
+ {
+ iNextPlugIn = this; // Set plugin to the next
+ ChangeState( EStatePreInitializing );
+ }
+ else
+ {
+ // Track is playing but different renderer
+ ChangeState( EStateInitializing );
+ }
+ }
+
+ // Create state machines
+ iPlaybackStateMachine = CUPnPPlaybackStateMachine::NewL(
+ *this, *iRendererSession );
+
+ iValueStateMachine = CUPnPValueStateMachine::NewL(
+ *this, *iRendererSession );
+
+ // Create track object to resolving URI
+ iTrack = CUPnPTrack::NewL( iSingleton->AVC() );
+ iTrack->ResolveURIL( aSong, *this, CUPnPTrack::EDirectionRemote );
+ }
+
+// --------------------------------------------------------------------------
+// CUPnPMusicPlayer::UninitialiseTrack
+// --------------------------------------------------------------------------
+//
+void CUPnPMusicPlayer::UninitialiseTrack( TPlayerState aToState )
+ {
+ __LOG1( "CUPnPMusicPlayer::UninitialiseTrack(%S)",
+ State( aToState ) );
+ ChangeState( EStateUninitialising );
+
+ if ( iAudioPolicy )
+ {
+ iAudioPolicy->Stop();
+ }
+
+ if ( iActivePlugIn == this )
+ {
+ iActivePlugIn = 0;
+ }
+ if ( iNextPlugIn == this )
+ {
+ iNextPlugIn = 0;
+ }
+
+ if( iPlaybackStateMachine )
+ {
+ delete iPlaybackStateMachine;
+ iPlaybackStateMachine = 0;
+ }
+
+ if( iValueStateMachine )
+ {
+ delete iValueStateMachine;
+ iValueStateMachine = 0;
+ }
+
+ // Rendering session is not cleared until destructor.
+ if( iRendererSession && aToState == EStateNone )
+ {
+ // releasing local MS services is left to AVController
+ iSingleton->AVC().StopRenderingSession( *iRendererSession );
+ iRendererSession = 0;
+ }
+
+ iSelectedRendererIndex = KErrNotFound;
+ iIsReady = EFalse;
+
+ if ( iTrack )
+ {
+ // request track to delete itself
+ CUPnPTrack* tempTrack = iTrack;
+ iTrack = NULL;
+ tempTrack->Delete();
+ }
+
+ ChangeState( aToState );
+ __LOG( "CUPnPMusicPlayer::UninitialiseTrack - End" );
+ }
+
+// --------------------------------------------------------------------------
+// CUPnPMusicPlayer::ResolveURIComplete
+// from MUPnPTrackObserver
+// --------------------------------------------------------------------------
+//
+void CUPnPMusicPlayer::ResolveURIComplete( TInt aError )
+ {
+ __LOG2( "CUPnPMusicPlayer::ResolveURIComplete in state %S [%d]",
+ State( iPlayerState ), this );
+
+ if ( aError == KErrNone )
+ {
+ // Check is local or remote
+ TRAPD( error, SetURIL() );
+ if ( error != KErrNone )
+ {
+ __LOG1("CUPnPMusicPlayer::ResolveURIComplete: leaves with %d",
+ error );
+ UninitialiseTrack();
+ error = TUpnpPluginsErrorTranslation::ErrorTranslate(
+ error );
+ iObs->HandlePluginEvent(
+ MMPXPlaybackPluginObserver::EPInitialised,
+ 0, error );
+ }
+ }
+ else
+ {
+ __LOG1("CUPnPMusicPlayer::ResolveURIComplete: error %d",
+ aError );
+ UninitialiseTrack();
+ aError = TUpnpPluginsErrorTranslation::ErrorTranslate(
+ aError );
+ iObs->HandlePluginEvent(
+ MMPXPlaybackPluginObserver::EPInitialised,
+ 0, aError );
+ }
+ }
+
+
+// --------------------------------------------------------------------------
+// CUPnPMusicPlayer::SetURIL
+// --------------------------------------------------------------------------
+//
+void CUPnPMusicPlayer::SetURIL()
+ {
+ __LOG( "CUPnPMusicPlayer::SetURIL" );
+
+ switch( iPlayerState )
+ {
+ case EStateInitializing: // flow through
+ case EStateActiveForceInitialise:
+ {
+ iRendererSession->SetURIL(
+ iTrack->UpnpURI(), iTrack->UpnpItem() );
+ }
+ break;
+ case EStatePreInitializing:
+ {
+ // Set NextUri if action is supported by used device
+ if( iSelectedRenderer->NextAVTransportUri() )
+ {
+ __LOG( "CUPnPMusicPlayer::SetURIL - \
+ Remote:SetNextURI" );
+
+ iRendererSession->SetNextURIL(
+ iTrack->UpnpURI(), iTrack->UpnpItem() );
+ }
+ else
+ {
+ __LOG( "CUPnPMusicPlayer::SetURI - \
+ SetNextURI is not supported by used device" );
+
+ // Used renderer does not support SetNextURI feature.
+ // Initialise track by SetURI after play is called.
+ ChangeState( EStateWaiting );
+ iObs->HandlePluginEvent(
+ MMPXPlaybackPluginObserver::EPInitialised,
+ iTrack->TrackDuration(), KErrNone );
+ if ( iPlayerState == EStateWaiting )
+ {
+ if( iTrack->IsRemote() )
+ {
+ iTrack->SendMediaChangedEventL( *iObs );
+ }
+ }
+ }
+ }
+ break;
+ case EStatePauseInActiveForceInitialise:
+ {
+ // This case happens when active plugin is paused and user
+ // skips to the next track from UI.
+ __LOG( "SetURI during EStatePauseInActiveForceInitialise" );
+ iRendererSession->SetURIL(
+ iTrack->UpnpURI(), iTrack->UpnpItem() );
+ }
+ break;
+ default:
+ {
+ __PANICD( __FILE__, __LINE__ );
+ }
+ break;
+ }
+
+ }
+
+// --------------------------------------------------------------------------
+// CUPnPMusicPlayer::CommandL
+// Executes a command on the selected song.
+// --------------------------------------------------------------------------
+//
+void CUPnPMusicPlayer::CommandL( TMPXPlaybackCommand aCmd, TInt aData )
+ {
+ __LOG3( "CUPnPMusicPlayer::CommandL(%d) in state %S [%d]",
+ aCmd, State( iPlayerState ), this );
+
+ switch( iPlayerState )
+ {
+ case EStateUninitialised: // fall through
+ case EStateUninitialising: // fall through
+ {
+ // ignore everything
+ }
+ case EStateError:
+ {
+ // Only Stop and Close will be handled.
+ // All other commands ignored.
+ if ( aCmd == EPbCmdStop )
+ {
+ iObs->HandlePluginEvent(
+ MMPXPlaybackPluginObserver::EPStopped,
+ KErrNone, KErrNone );
+ }
+ if ( aCmd == EPbCmdClose )
+ {
+ iObs->HandlePluginEvent(
+ MMPXPlaybackPluginObserver::EPClosed,
+ KErrNone, KErrNone );
+ }
+ break;
+ }
+ case EStateInitializing: // fall through
+ case EStatePreInitializing: // fall through
+ case EStatePreInitialized: // fall through
+ case EStateWaiting: // fall through
+ case EStateActiveForceInitialise:
+ {
+ if( aCmd == EPbCmdStop )
+ {
+ // answer directly to stopped message
+ iObs->HandlePluginEvent(
+ MMPXPlaybackPluginObserver::EPStopped,
+ KErrNone, KErrNone );
+ }
+ if( aCmd == EPbCmdPlay &&
+ ( iPlayerState == EStateActiveForceInitialise ) )
+ {
+ __LOG( "CUPnPMusicPlayer::Command(play)->SetURI" );
+ SetURIL();
+ }
+ if( aCmd == EPbCmdPlay && iPlayerState == EStateWaiting )
+ {
+ // This plugin has to be set active because track has forced
+ // to be skipped by user.
+ SetActive( ETrue );
+ SetURIL();
+ }
+ if( aCmd == EPbCmdPlay && iPlayerState == EStatePreInitialized )
+ {
+ // This plugin has to be set active because track has forced
+ // to be skipped by user.
+ SetActive( ETrue );
+ SetURIL();
+ }
+ if( aCmd == EPbCmdPause &&
+ ( iPlayerState == EStateActiveForceInitialise ||
+ iPlayerState == EStateWaiting ) )
+ {
+ // This case happens when active plugin is paused and user
+ // skips to the next track from UI -> next track must be
+ // switched to paused state.
+ __LOG( "Pause command during EStateActiveForceInitialise" );
+ iPlayerState = EStatePauseInActiveForceInitialise;
+ SetURIL();
+ }
+
+ if ( aCmd == EPbCmdClose )
+ {
+ UninitialiseTrack();
+ iObs->HandlePluginEvent(
+ MMPXPlaybackPluginObserver::EPClosed,
+ KErrNone, KErrNone );
+ }
+ break;
+ }
+ case EStateActive:
+ {
+ iPlaybackStateMachine->CommandL( aCmd );
+ if( aCmd == EPbCmdStop )
+ {
+ if ( this == iActivePlugIn && iNextPlugIn != 0 )
+ {
+ __LOG( "CommandL(stop)->SetActive()" );
+ iNextPlugIn->SetActive( ETrue );
+ }
+ }
+ if( aCmd == EPbCmdPause )
+ {
+ if ( this == iActivePlugIn && iNextPlugIn != 0 )
+ {
+ __LOG( "CommandL(pause)->SetActive()" );
+ iNextPlugIn->SetActive( EFalse );
+ }
+ }
+ if( aCmd == EPbCmdClose )
+ {
+ if ( this == iActivePlugIn && iNextPlugIn != 0 )
+ {
+ __LOG( "CommandL(close)->SetActive()" );
+ iNextPlugIn->SetActive( ETrue );
+ }
+ UninitialiseTrack();
+ }
+ break;
+ }
+ default:
+ {
+ __LOG( "CUPnPMusicPlayer::CommandL - Default" );
+ break;
+ }
+ }
+
+ // check for messages from upnp framework (aData param)
+ if ( aCmd == EPbCmdClose &&
+ aData == KMusicPluginMessageExit )
+ {
+ __LOG( "CommandL(Close, exit) -> cleanup and terminate" );
+
+ // cancel things that are ongoing
+ CancelRequest();
+ // clear resources
+ UninitialiseTrack( EStateError );
+
+ // Create event to user
+ iObs->HandlePluginEvent(
+ MMPXPlaybackPluginObserver::EPPlayerUnavailable,
+ 0, KErrDisconnected );
+ }
+
+ }
+
+// --------------------------------------------------------------------------
+// CUPnPMusicPlayer::SetL
+// Sets a property of the plugin.
+// --------------------------------------------------------------------------
+//
+void CUPnPMusicPlayer::SetL( TMPXPlaybackProperty aProperty, TInt aValue )
+ {
+ __LOG2( "CUPnPMusicPlayer::SetL in state %S [%d]",
+ State( iPlayerState ), this );
+
+ CUPnPValueStateMachine::TValidationResult result =
+ CUPnPValueStateMachine::ValidatePropertyInState(
+ aProperty, ETrue, iPlayerState, iIsReady );
+
+ if ( result == CUPnPValueStateMachine::EHandle )
+ {
+ if ( aProperty == EPbPropertyPosition )
+ {
+ // Position changes are handled in playback s.m.
+ iPlaybackStateMachine->PositionL( aValue );
+ }
+ else
+ {
+ // all other values in value s.m.
+ iValueStateMachine->SetL( aProperty, aValue );
+ }
+ }
+ else if ( result == CUPnPValueStateMachine::EHandleStatic )
+ {
+ iObs->HandlePluginEvent(
+ MMPXPlaybackPluginObserver::EPSetComplete,
+ (TInt)aProperty, KErrNone );
+ }
+ else if ( result == CUPnPValueStateMachine::EErrorNotReady )
+ {
+ iObs->HandlePluginEvent(
+ MMPXPlaybackPluginObserver::EPSetComplete,
+ (TInt)aProperty, KErrNotReady );
+ }
+ else if ( result == CUPnPValueStateMachine::EErrorNotSupported )
+ {
+ iObs->HandlePluginEvent(
+ MMPXPlaybackPluginObserver::EPSetComplete,
+ (TInt)aProperty, KErrNotSupported );
+ }
+ else if ( result == CUPnPValueStateMachine::EIgnore )
+ {
+ // do nothing
+ }
+ else
+ {
+ __PANICD( __FILE__, __LINE__ );
+ }
+ }
+
+// --------------------------------------------------------------------------
+// CUPnPMusicPlayer::ValueL
+// Gets a property of the plugin (async).
+// --------------------------------------------------------------------------
+//
+void CUPnPMusicPlayer::ValueL( TMPXPlaybackProperty aProperty ) const
+ {
+ __LOG2( "CUPnPMusicPlayer::ValueL in state %S [%d]",
+ State( iPlayerState ), this );
+
+ CUPnPValueStateMachine::TValidationResult result =
+ CUPnPValueStateMachine::ValidatePropertyInState(
+ aProperty, EFalse, iPlayerState, iIsReady );
+
+ if ( result == CUPnPValueStateMachine::EHandle )
+ {
+ iValueStateMachine->ValueL( aProperty );
+ }
+ else if ( result == CUPnPValueStateMachine::EHandleStatic )
+ {
+ CUPnPValueStateMachine::ValueStatic( aProperty, *iObs );
+ }
+ else if ( result == CUPnPValueStateMachine::EErrorNotReady )
+ {
+ iObs->HandleProperty( aProperty,
+ 0, KErrNotReady );
+ }
+ else if ( result == CUPnPValueStateMachine::EErrorNotSupported )
+ {
+ iObs->HandleProperty( aProperty,
+ 0, KErrNotSupported );
+ }
+ else if ( result == CUPnPValueStateMachine::EIgnore )
+ {
+ // do nothing
+ }
+ else
+ {
+ __PANICD( __FILE__, __LINE__ );
+ }
+
+ }
+
+// --------------------------------------------------------------------------
+// CUPnPMusicPlayer::SubPlayerNamesL
+// Gets a list of sub players (async).
+// --------------------------------------------------------------------------
+//
+void CUPnPMusicPlayer::SubPlayerNamesL()
+ {
+ __LOG1( "CUPnPMusicPlayer::SubPlayerNamesL [%d]", this );
+
+ // Get media renderers from renderer selector
+ iSingleton->GetRendererNamesL( *this );
+ }
+
+// --------------------------------------------------------------------------
+// CUPnPMusicPlayer::SelectSubPlayerL
+// Select a sub player.
+// --------------------------------------------------------------------------
+//
+void CUPnPMusicPlayer::SelectSubPlayerL( TInt aIndex )
+ {
+ __LOG1( "CUPnPMusicPlayer::SelectSubPlayerL [%d]", this );
+
+ // this method can only be called in uninitialized state
+ __ASSERTD( iPlayerState == EStateUninitialised ||
+ aIndex == iSelectedRendererIndex, __FILE__, __LINE__ );
+
+ // Select media renderer. Ignore if already selected.
+ if ( iSelectedRendererIndex != aIndex )
+ {
+ iSelectedRendererIndex = aIndex;
+ CUpnpAVDevice* tempDev = CUpnpAVDevice::NewL(
+ *iSingleton->SelectRendererByIndexL( aIndex ) );
+ delete iSelectedRenderer;
+ iSelectedRenderer = tempDev;
+ }
+ }
+
+// --------------------------------------------------------------------------
+// CUPnPMusicPlayer::SubPlayerName
+// Returns current sub player name
+// --------------------------------------------------------------------------
+//
+const TDesC& CUPnPMusicPlayer::SubPlayerName()
+ {
+ __LOG1( "CUPnPMusicPlayer::SubPlayerName [%d]", this );
+ if ( iSelectedRenderer )
+ {
+ iSelectedRendererName.Copy(
+ iSelectedRenderer->FriendlyName() );
+ }
+ else if ( iSingleton->DefaultDevice() )
+ {
+ iSelectedRendererName.Copy(
+ iSingleton->DefaultDevice()->FriendlyName() );
+ }
+ else
+ {
+ iSelectedRendererName.Copy( KNullDesC );
+ }
+ return iSelectedRendererName;
+ }
+
+// --------------------------------------------------------------------------
+// CUPnPMusicPlayer::SubPlayerIndex
+// Return current sub player index.
+// --------------------------------------------------------------------------
+//
+TInt CUPnPMusicPlayer::SubPlayerIndex() const
+ {
+ __LOG1( "CUPnPMusicPlayer::SubPlayerIndex [%d]", this );
+
+ // Get current sub player index
+ return iSelectedRendererIndex;
+ }
+
+// --------------------------------------------------------------------------
+// CUPnPMusicPlayer::MediaL
+// Extended properties of the current file (async).
+// --------------------------------------------------------------------------
+//
+void CUPnPMusicPlayer::MediaL( const TArray<TMPXAttribute>& aAttrs )
+ {
+ __LOG2( "CUPnPMusicPlayer::MediaL in state %S [%d]",
+ State( iPlayerState ), this );
+
+ // Get media if track is initialised
+ if( iTrack )
+ {
+ iTrack->GetMetaDataL( aAttrs, *iObs );
+ }
+ else
+ {
+ __LOG( "CUPnPMusicPlayer::MediaL - Wrong state!" );
+ User::Leave( KErrNotReady );
+ }
+ }
+
+// --------------------------------------------------------------------------
+// CUPnPMusicPlayer::CancelRequest
+// Cancel outstanding request.
+// --------------------------------------------------------------------------
+//
+void CUPnPMusicPlayer::CancelRequest()
+ {
+ __LOG2( "CUPnPMusicPlayer::CancelRequest in state %S [%d]",
+ State( iPlayerState ), this );
+
+ // If cancel is called during initialise
+ if( iPlayerState == EStateInitializing ||
+ iPlayerState == EStatePreInitializing ||
+ iPlayerState == EStateActiveForceInitialise ||
+ iPlayerState == EStateActive )
+ {
+ // Stop rendering session -> SetURI operation will be cancelled
+ UninitialiseTrack( EStateNone );
+ iPlayerState = EStateUninitialised;
+ }
+ else if( iPlayerState == EStateUninitialising )
+ {
+ // Ignore. Do not call state machines.
+ return;
+ }
+
+ if ( iSingleton != 0 )
+ {
+ iSingleton->CancelGetRendererNames();
+ }
+ if ( iPlaybackStateMachine )
+ {
+ iPlaybackStateMachine->Cancel();
+ }
+ if ( iValueStateMachine )
+ {
+ iValueStateMachine->Cancel();
+ }
+ }
+
+// --------------------------------------------------------------------------
+// Methods of MUPnPAVRenderingSessionObserver
+// --------------------------------------------------------------------------
+
+// --------------------------------------------------------------------------
+// CUPnPMusicPlayer::VolumeResult
+// Response for get/set volume property commands.
+// --------------------------------------------------------------------------
+//
+void CUPnPMusicPlayer::VolumeResult( TInt aError, TInt aVolumeLevel,
+ TBool aActionResponse )
+ {
+ __LOG2( "CUPnPMusicPlayer::VolumeResult in state %S [%d]",
+ State( iPlayerState ), this );
+
+ if( iValueStateMachine )
+ {
+ iValueStateMachine->VolumeResult( aError, aVolumeLevel,
+ aActionResponse );
+ }
+ }
+
+// --------------------------------------------------------------------------
+// CUPnPMusicPlayer::MuteResult
+// Response for get/set mute property commands.
+// --------------------------------------------------------------------------
+//
+void CUPnPMusicPlayer::MuteResult( TInt aError, TBool aMute,
+ TBool aActionResponse )
+ {
+ __LOG2( "CUPnPMusicPlayer::MuteResult in state %S [%d]",
+ State( iPlayerState ), this );
+
+ if( iValueStateMachine )
+ {
+ iValueStateMachine->MuteResult( aError, aMute, aActionResponse );
+ }
+ }
+
+// --------------------------------------------------------------------------
+// CUPnPMusicPlayer::InteractOperationComplete
+// Response for interaction operation (play, stop, etc.).
+// --------------------------------------------------------------------------
+//
+void CUPnPMusicPlayer::InteractOperationComplete( TInt aErrorCode,
+ TUPnPAVInteractOperation aOperation )
+ {
+ __LOG3( "CUPnPMusicPlayer::InteractOp.Comp(%d) in state %S [%d]",
+ aOperation, State( iPlayerState ), this );
+
+ if( iPlayerState == EStateActive )
+ {
+ if( iPlaybackStateMachine )
+ {
+ iPlaybackStateMachine->InteractOperationComplete( aErrorCode,
+ aOperation );
+ }
+ }
+ }
+
+// --------------------------------------------------------------------------
+// CUPnPMusicPlayer::PositionInfoResult
+// Response for position/duration requests.
+// --------------------------------------------------------------------------
+//
+void CUPnPMusicPlayer::PositionInfoResult( TInt aStatus,
+ const TDesC8& aTrackPosition, const TDesC8& aTrackLength )
+ {
+ __LOG2( "CUPnPMusicPlayer::PositionInfoResult in state %S [%d]",
+ State( iPlayerState ), this );
+
+ if( iValueStateMachine )
+ {
+ iValueStateMachine->PositionInfoResult( aStatus, aTrackPosition,
+ aTrackLength );
+ }
+ }
+
+// --------------------------------------------------------------------------
+// CUPnPMusicPlayer::SetURIResult
+// Response for SetURI.
+// --------------------------------------------------------------------------
+//
+void CUPnPMusicPlayer::SetURIResult( TInt aError )
+ {
+ __LOG3( "CUPnPMusicPlayer::SetURIResult in state %S err=%d [%d]",
+ State( iPlayerState ), aError, this );
+
+ if( iPlayerState == EStateInitializing )
+ {
+ // "Normal" response for SetURI
+ TInt duration(0);
+ if( aError == KErrNone )
+ {
+ // Set player state to active
+ ChangeState( EStateActive );
+ TRAP_IGNORE( iAudioPolicy->PlayL() );
+ duration = iTrack->TrackDuration();
+ }
+ else
+ {
+ UninitialiseTrack();
+ }
+ // if aError is KErrGeneral, the music player doesn't skip to
+ //the next song . translate to KErrCorrupt.
+ if( aError == KErrGeneral)
+ {
+ aError = KErrCorrupt;
+ }
+ else
+ {
+ aError = TUpnpPluginsErrorTranslation::ErrorTranslate( aError );
+ }
+ iObs->HandlePluginEvent(
+ MMPXPlaybackPluginObserver::EPInitialised, duration, aError );
+ if ( iPlayerState == EStateActive )
+ {
+ TRAP_IGNORE(
+ if( iTrack->IsRemote() )
+ {
+ iTrack->SendMediaChangedEventL( *iObs );
+ }
+ );
+ }
+ }
+ else if( iPlayerState == EStateActiveForceInitialise )
+ {
+ // Response for preinitialise that is failed because of
+ // used device does not support SetNextUri functionality.
+ if( aError == KErrNone )
+ {
+ __LOG( "SetURIResult,ActiveForceInitialise->Play" );
+ // Set player state to active
+ iPlayerState = EStateActive;
+ TRAP_IGNORE( iAudioPolicy->PlayL() );
+
+ // Play
+ TRAPD( error, CommandL( EPbCmdPlay, TInt(0) ) );
+ if ( error != KErrNone )
+ {
+ UninitialiseTrack();
+ // Send play event with error to user. Note play event
+ // because we are actually performing play command.
+ error = TUpnpPluginsErrorTranslation::ErrorTranslate( error );
+ iObs->HandlePluginEvent(
+ MMPXPlaybackPluginObserver::EPPlaying,
+ 0, error );
+ // Send event that device is not available.
+ iObs->HandlePluginEvent(
+ MMPXPlaybackPluginObserver::EPPlayerUnavailable,
+ 0, KErrNotFound );
+ }
+ }
+ else
+ {
+ UninitialiseTrack();
+ // Send play event with error to user. Note play event
+ // because weare actually performing play command.
+ aError = TUpnpPluginsErrorTranslation::ErrorTranslate( aError );
+ iObs->HandlePluginEvent(
+ MMPXPlaybackPluginObserver::EPPlaying,
+ 0, aError );
+ }
+ }
+ else if( iPlayerState == EStatePauseInActiveForceInitialise )
+ {
+ // This case happens when active plugin is paused and user
+ // skips to the next track from UI.
+ __LOG( "SetUriResult during EStatePauseInActiveForceInitialise" );
+
+ iPlayerState = EStateActive;
+ if( aError == KErrNone )
+ {
+ // Pause
+ TRAPD( error, CommandL( EPbCmdPause, TInt(0) ) );
+ if ( error != KErrNone )
+ {
+ UninitialiseTrack();
+ // Send pause event with error to user. Note pause event
+ // because we are actually performing pause command.
+ error = TUpnpPluginsErrorTranslation::ErrorTranslate( error );
+ iObs->HandlePluginEvent(
+ MMPXPlaybackPluginObserver::EPPaused,
+ 0, error );
+ }
+ }
+ else
+ {
+ UninitialiseTrack();
+ // Send pause event with error to user. Note pause event
+ // because we are actually performing pause command.
+ aError = TUpnpPluginsErrorTranslation::ErrorTranslate( aError );
+ iObs->HandlePluginEvent(
+ MMPXPlaybackPluginObserver::EPPaused, 0, aError );
+ }
+ }
+ else // Covers also if Cancel request is called during SetURI
+ {
+ __LOG( "CUPnPMusicPlayer::SetURIResult - Unknown state " );
+ }
+ }
+
+// --------------------------------------------------------------------------
+// CUPnPMusicPlayer::SetNextURIResult
+// Response for SetNextURI.
+// --------------------------------------------------------------------------
+//
+void CUPnPMusicPlayer::SetNextURIResult( TInt aError )
+ {
+ __LOG2( "CUPnPMusicPlayer::SetNextURIResult err=%d [%d]",
+ aError, this );
+
+ aError = TUpnpPluginsErrorTranslation::ErrorTranslate( aError );
+ if( iPlayerState == EStatePreInitializing )
+ {
+ TInt duration(0);
+ // Check if any error during SetNextURI call
+ if( aError == KErrNone )
+ {
+ // Set palyer state to preinitialized
+ ChangeState( EStatePreInitialized );
+ duration = iTrack->TrackDuration();
+ }
+ else
+ {
+ // Used renderer does not support SetNextURI feature.
+ // Initialise track by SetURI after play is called.
+ ChangeState( EStateWaiting );
+ }
+ iObs->HandlePluginEvent(
+ MMPXPlaybackPluginObserver::EPInitialised, duration, aError );
+ if ( iPlayerState == EStatePreInitialized )
+ {
+ TRAP_IGNORE(
+ if( iTrack->IsRemote() )
+ {
+ iTrack->SendMediaChangedEventL( *iObs );
+ }
+ );
+ }
+ }
+ else
+ {
+ __LOG( "CUPnPMusicPlayer::SetNextURIResult - Wrong state! " );
+ __PANICD( __FILE__, __LINE__ );
+ }
+ }
+
+// --------------------------------------------------------------------------
+// CUPnPMusicPlayer::MediaRendererDisappeared
+// Indication in case of renderer disappear
+// --------------------------------------------------------------------------
+//
+void CUPnPMusicPlayer::MediaRendererDisappeared(
+ TUPnPDeviceDisconnectedReason aReason )
+ {
+ __LOG1( "CUPnPMusicPlayer::MediaRendererDisappeared [%d]",
+ this );
+
+ if ( aReason == MUPnPAVSessionObserverBase::EWLANLost )
+ {
+ if( iTrack )
+ {
+ if ( iTrack->IsRemote() )
+ {
+ __LOG( "CUPnPMusicPlayer::MediaRendererDisappeared - \
+ WLAN disappeared while playing a REMOTE track " );
+ // WLAN disappeared while playing a REMOTE track
+ // stop rendering session and inform player
+ // Fixes ESLX-7KQERV
+ CancelRequest();
+ UninitialiseTrack( EStateError );
+ iObs->HandlePluginEvent(
+ MMPXPlaybackPluginObserver::EPPlayerUnavailable,
+ 0, KErrDisconnected );
+ }
+ else
+ {
+ __LOG( "CUPnPMusicPlayer::MediaRendererDisappeared - \
+ WLAN disappeared while playing a LOCAL track " );
+ // WLAN disappeared while playing a LOCAL track
+ // signal not available.
+ UninitialiseTrack( EStateError );
+ iObs->HandlePluginEvent(
+ MMPXPlaybackPluginObserver::EPPlayerUnavailable,
+ 0, KErrNone );
+ }
+ }
+ else // Track does not exist -> state is already uninitialised
+ {
+ iObs->HandlePluginEvent(
+ MMPXPlaybackPluginObserver::EPPlayerUnavailable,
+ 0, KErrNone );
+ }
+ }
+ else
+ {
+ // renderer disappeared
+ UninitialiseTrack( EStateUninitialised );
+ iObs->HandlePluginEvent(
+ MMPXPlaybackPluginObserver::EPPlayerUnavailable,
+ 0, KErrNotFound );
+ }
+ }
+
+// --------------------------------------------------------------------------
+// CUPnPMusicPlayer::ReserveLocalMSServicesCompleted
+// --------------------------------------------------------------------------
+//
+void CUPnPMusicPlayer::ReserveLocalMSServicesCompleted( TInt /*aError*/ )
+ {
+ __LOG1( "CUPnPMusicPlayer::ReserveMSCompleted!? [%d]", this );
+ // Implementation no needed.
+ }
+
+// --------------------------------------------------------------------------
+// CUPnPMusicPlayer::HandleSubPlayerNames
+// Response for GetSubplayerNames request.
+// --------------------------------------------------------------------------
+//
+void CUPnPMusicPlayer::HandleSubPlayerNames( const MDesCArray* aSubPlayers,
+ TBool aComplete, TInt aError )
+ {
+ __LOG2( "CUPnPMusicPlayer::HandleSubPlayerNames in state %S [%d]",
+ State( iPlayerState ), this );
+
+ aError = TUpnpPluginsErrorTranslation::ErrorTranslate( aError );
+ // Return subplayer names
+ iObs->HandleSubPlayerNames( KMusicPlayerUid, aSubPlayers,
+ aComplete, aError );
+ }
+
+// --------------------------------------------------------------------------
+// CUPnPMusicPlayer::RendererListChanged
+// Call back if reanderer list has changed.
+// --------------------------------------------------------------------------
+//
+void CUPnPMusicPlayer::RendererListChanged()
+ {
+ __LOG2( "CUPnPMusicPlayer::RendererListChanged in state %S [%d]",
+ State( iPlayerState ), this );
+
+ // Create EPSubPlayersChanged event
+ iObs->HandlePluginEvent(
+ MMPXPlaybackPluginObserver::EPSubPlayersChanged,
+ KErrNone, KErrNone );
+ }
+
+
+// --------------------------------------------------------------------------
+// CUPnPMusicPlayer::AudioConflict
+// --------------------------------------------------------------------------
+//
+void CUPnPMusicPlayer::AudioConflict( TInt /*aError*/ )
+ {
+
+ // stop playing
+ TRAP_IGNORE( iPlaybackStateMachine->SilentStopL() );
+
+ // notify framework
+ iObs->HandlePluginEvent(
+ MMPXPlaybackPluginObserver::EPStopped,
+ 0, KErrNone );
+ }
+
+// --------------------------------------------------------------------------
+// CUPnPMusicPlayer::ChangeState
+// --------------------------------------------------------------------------
+//
+void CUPnPMusicPlayer::ChangeState( TPlayerState aNewState )
+ {
+ __LOG3( "CUPnPMusicPlayer: STATE %S -> %S [%d]",
+ State( iPlayerState ), State( aNewState ), this );
+
+ iPlayerState = aNewState;
+ }
+
+
+// --------------------------------------------------------------------------
+// CUPnPMusicPlayer::State
+// --------------------------------------------------------------------------
+//
+const TDesC* CUPnPMusicPlayer::State( TPlayerState aState ) const
+ {
+ switch( aState )
+ {
+ case EStateUninitialised:
+ {
+ return &KStateUninitialized;
+ }
+ case EStateInitializing:
+ {
+ return &KStateInitializing;
+ }
+ case EStateUninitialising:
+ {
+ return &KStateUninitialising;
+ }
+ case EStateActive:
+ {
+ return &KStateActive;
+ }
+ case EStatePreInitializing:
+ {
+ return &KStatePreInitializing;
+ }
+ case EStatePreInitialized:
+ {
+ return &KStatePreInitialized;
+ }
+ case EStateWaiting:
+ {
+ return &KStateWaiting;
+ }
+ case EStateActiveForceInitialise:
+ {
+ return &KStateActiveForceInit;
+ }
+ case EStateError:
+ {
+ return &KStateError;
+ }
+ default:
+ {
+ return &KStateUnknown;
+ }
+ }
+ }
+
+
+