upnpmpxplugins/upnpplaybackplugins/src/upnpmusicplayer.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Thu, 17 Dec 2009 08:52:00 +0200
changeset 0 7f85d04be362
permissions -rw-r--r--
Revision: 200947 Kit: 200951

/*
* 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;
            }
        }
    }