upnpmpxplugins/upnpplaybackplugins/src/upnpmusicplayer.cpp
changeset 0 7f85d04be362
--- /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;
+            }
+        }
+    }
+
+ 
+