diff -r 6369bfd1b60d -r 08b5eae9f9ff upnpmpxplugins/upnpplaybackplugins/src/upnpplaybackstatemachine.cpp --- a/upnpmpxplugins/upnpplaybackplugins/src/upnpplaybackstatemachine.cpp Mon Nov 01 13:44:24 2010 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,796 +0,0 @@ -/* -* 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: Class for retrieving and selecting media renderers -* -*/ - - - - - - -// INCLUDES -#include -#include -#include "upnpavrenderingsession.h" -#include "upnpavrenderingsessionobserver.h" -#include "upnpavdevice.h" - -#include "upnpmusicplayer.h" // for parent.Observer() -#include "upnptrack.h" // for TrackDuration -#include "upnpvaluestatemachine.h" // -#include "upnpplaybackstatemachine.h" // myself -#include "upnppluginserrortranslation.h" - -_LIT( KComponentLogfile, "musicplugins.txt"); -#include "upnplog.h" - -// CONSTANTS -_LIT( KStateStoppedText, "Stopped" ); -_LIT( KStatePlayingText, "Playing" ); -_LIT( KStatePausedText, "Paused" ); -_LIT( KStateUnknownText, "Unknown" ); - -const TInt KDurationErrorMargin = 500; // 0.5 seconds -const TInt KPlaybackInfoTimeOut = 1000000; // 1s wait until device is ready -const TInt KPlaybackInfoTimeOutEnd = 2000000; // 2s wait check whether - //the playing is ended - -// ======== MEMBER FUNCTIONS ======== - -// -------------------------------------------------------------------------- -// CUPnPPlaybackStateMachine::NewL -// 1st phase constructor. -// -------------------------------------------------------------------------- -// -CUPnPPlaybackStateMachine* CUPnPPlaybackStateMachine::NewL( - CUPnPMusicPlayer& aParent, - MUPnPAVRenderingSession& aRenderingSession ) - { - __LOG( "PlaybackStateMachine::NewL" ); - CUPnPPlaybackStateMachine* self = - new(ELeave) CUPnPPlaybackStateMachine( - aParent, aRenderingSession ); - CleanupStack::PushL( self ); - self->ConstructL(); - CleanupStack::Pop( self ); - return self; - } - -// -------------------------------------------------------------------------- -// CUPnPPlaybackStateMachine::CUPnPPlaybackStateMachine -// Default constructor. -// -------------------------------------------------------------------------- -// -CUPnPPlaybackStateMachine::CUPnPPlaybackStateMachine( - CUPnPMusicPlayer& aParent, - MUPnPAVRenderingSession& aRenderingSession ) - :iParent( aParent ) - ,iRendererSession( aRenderingSession ) - ,iState( EStateStopped ) - ,iCurrentOperation( EOperationNone ) - { - } - -// -------------------------------------------------------------------------- -// CUPnPPlaybackStateMachine::ConstructL -// -------------------------------------------------------------------------- -// -void CUPnPPlaybackStateMachine::ConstructL() - { - __LOG( "CUPnPPlaybackStateMachine::ConstructL" ); - - // Create timer for observing duration query time out. - TInt64 iTime = 0; - iPlayMark = TTime( iTime ); - iPauseMark = TTime( iTime ); - iPeriodizer = CUPnPMusicPeriodizer::NewL( *this, KPlaybackInfoTimeOut ); - iPeriodizerEnd = CUPnPMusicPeriodizer::NewL( *this, - KPlaybackInfoTimeOutEnd ); - } - -// -------------------------------------------------------------------------- -// CUPnPPlaybackStateMachine::~CUPnPPlaybackStateMachine -// Destructor. -// -------------------------------------------------------------------------- -// -CUPnPPlaybackStateMachine::~CUPnPPlaybackStateMachine() - { - __LOG( "PlaybackStateMachine destructor" ); - iOperationQueue.Close(); - delete iPeriodizer; - delete iPeriodizerEnd; - } - -// -------------------------------------------------------------------------- -// CUPnPPlaybackStateMachine::CommandL -// Executes a command on the selected song. -// -------------------------------------------------------------------------- -// -void CUPnPPlaybackStateMachine::CommandL( TMPXPlaybackCommand aCmd ) - { - if ( aCmd == EPbCmdClose ) - { - // close can be handled parallel to other commands - HandleCloseL(); - return; - } - - if ( !iCurrentOperation.None() ) - { - __LOG( "PlaybackStateMachine::CommandL - Append to queue" ); - iOperationQueue.AppendL( aCmd ); - return; - } - - switch( aCmd ) - { - case EPbCmdPlay: - { - if( iState == EStatePlaying ) - { - // already playing - ignore - CheckOperationInQueueL(); - } - else - { - __LOG( "PlaybackStateMachine: command play" ); - iCurrentOperation = aCmd; - iRendererSession.PlayL(); - } - } - break; - case EPbCmdPause: - { - // Check if pause is supported by device - if( iParent.UsedRendererDevice().PauseCapability() ) - { - if( iState == EStatePaused ) - { - // already paused - ignore - CheckOperationInQueueL(); - } - else - { - __LOG( "PlaybackStateMachine: command pause" ); - iCurrentOperation = aCmd; - iRendererSession.PauseL(); - } - } - else - { - __LOG( "PlaybackStateMachine: Pause is not supported by \ - device!" ); - iParent.Observer().HandlePluginEvent( - MMPXPlaybackPluginObserver::EPPaused, 0, - KErrNotSupported ); - } - } - break; - case EPbCmdStop: - { - if( iState == EStateStopped ) - { - // already stopped - ignore - CheckOperationInQueueL(); - } - else - { - __LOG( "PlaybackStateMachine: command stop" ); - iCurrentOperation = aCmd; - iRendererSession.StopL(); - } - } - break; - case EPbCmdReplay: - { - iCurrentOperation = aCmd; - __LOG( "PlaybackStateMachine: command replay" ); - if( iState == EStatePlaying || iState == EStatePaused ) - { - // playing -must stop first - iRendererSession.StopL(); - } - else - { - // just play - iRendererSession.PlayL(); - } - } - break; - default: // Given command is not supported - { - __LOG( "PlaybackStateMachine: command default?" ); - CheckOperationInQueueL(); - User::Leave( KErrNotSupported ); - break; - } - } - } - -// -------------------------------------------------------------------------- -// CUPnPPlaybackStateMachine::PositionL -// Changes the position within the currently playing track -// -------------------------------------------------------------------------- -// -void CUPnPPlaybackStateMachine::PositionL( TInt aPosition ) - { - - // Ignore if already called. - if( iCurrentOperation == EOperationPositionToZero ) - { - __LOG( "PlaybackStateMachine::PositionL - \ - EOperationPositionToZero called twice -> ignored" ); - return; - } - - if ( !iCurrentOperation.None() ) - { - __LOG( "PlaybackStateMachine::PositionL - Append to queue" ); - iOperationQueue.AppendL( EOperationPositionToZero ); - return; - } - if ( aPosition != 0 ) - { - CheckOperationInQueueL(); - User::Leave( KErrNotSupported ); - } - - // handle Position(0) - if ( iState == EStatePlaying ) - { - __LOG( "PlaybackStateMachine: position(0) while playing" ); - iCurrentOperation = EOperationPositionToZero; - iRendererSession.StopL(); - } - else if ( iState == EStatePaused ) - { - __LOG( "PlaybackStateMachine: PositionL(0) while paused" ); - iCurrentOperation = EOperationPositionToZeroDuringPause; - iRendererSession.StopL(); - } - else if ( iState == EStateStopped ) - { - __LOG( "PlaybackStateMachine: PositionL(0) while stopped" ); - CheckOperationInQueueL(); - - // immediate response ! - iParent.Observer().HandlePluginEvent( - MMPXPlaybackPluginObserver::EPSetComplete, - EPbPropertyPosition, KErrNone ); - - } - } - -// -------------------------------------------------------------------------- -// CUPnPPlaybackStateMachine::SilentStopL -// Stops playback, does not provide any ACK event -// -------------------------------------------------------------------------- -// -void CUPnPPlaybackStateMachine::SilentStopL() - { - if ( !iCurrentOperation.None() ) - { - __LOG( "PlaybackStateMachine::SilentStopL - Append to queue" ); - iOperationQueue.AppendL( EOperationSilentStop ); - return; - } - - // handle stop - __LOG( "PlaybackStateMachine: SilentStopL" ); - if( iState == EStateStopped ) - { - // already stopped - ignore - CheckOperationInQueueL(); - } - else - { - iCurrentOperation = EOperationSilentStop; - iRendererSession.StopL(); - } - } - -// -------------------------------------------------------------------------- -// CUPnPPlaybackStateMachine::Cancel -// -------------------------------------------------------------------------- -// -void CUPnPPlaybackStateMachine::Cancel() - { - // reset current operation and empty the queue -> no callbacks. - iCurrentOperation.Reset(); - iOperationQueue.Reset(); - } - -// -------------------------------------------------------------------------- -// CUPnPPlaybackStateMachine::HandleCloseL -// Handles the close command -// -------------------------------------------------------------------------- -// -void CUPnPPlaybackStateMachine::HandleCloseL() - { - if ( iCurrentOperation == EPbCmdStop ) - { - // Stop pending - it can't be completed -> fake callback. - iParent.Observer().HandlePluginEvent( - MMPXPlaybackPluginObserver::EPStopped, - KErrNone, KErrNone ); - } - - iParent.Observer().HandlePluginEvent( - MMPXPlaybackPluginObserver::EPClosed, - KErrNone, KErrNone ); - } - - -// -------------------------------------------------------------------------- -// CUPnPPlaybackStateMachine::InteractOperationComplete -// Response for interaction operation (play, stop, etc.). -// -------------------------------------------------------------------------- -// -void CUPnPPlaybackStateMachine::InteractOperationComplete( TInt aErrorCode, - TUPnPAVInteractOperation aOperation ) - { - __LOG1( "CUPnPPlaybackStateMachine::InteractOperationComplete: err:[%d]", - aErrorCode ); - aErrorCode = TUpnpPluginsErrorTranslation::ErrorTranslate( aErrorCode ); - switch( aOperation ) - { - case EUPnPAVPlayUser: - { - __LOG1( "PlaybackStateMachine: event play user, state[%d]",iState ); - - if ( aErrorCode == KErrNone ) - { - if ( iState == EStatePaused ) - { - TimeContinue(); - ChangeState( EStatePlaying ); - iParent.Observer().HandlePluginEvent( - MMPXPlaybackPluginObserver::EPPlaying, KErrNone, - aErrorCode ); - if( iCurrentOperation == EPbCmdPlay ) - { - iCurrentOperation.Reset(); - TRAP_IGNORE( CheckOperationInQueueL() ); - } - } - else if ( iState == EStatePlaying ) - { - iPeriodizer->Stop(); - iParent.HandlePlayStarted(); - } - else if ( iState == EStateStopped ) - { - if ( iCurrentOperation == EPbCmdPlay || - iCurrentOperation == EPbCmdReplay ) - { - TimePlay(); - iParent.HandlePlayStarted(); - ChangeState( EStatePlaying ); - iCurrentOperation.Reset(); - TRAP_IGNORE( CheckOperationInQueueL() ); - iParent.Observer().HandlePluginEvent( - MMPXPlaybackPluginObserver::EPPlaying, KErrNone, - aErrorCode ); - } - else - { - // spontaneous change to PLAYING state -> ignore - } - } - - } - else - { - ChangeState( EStateUnknown ); - } - break; - } - case EUPnPAVPlay: - { - if ( iState == EStatePlaying ) - { - __LOG( "PlaybackStateMachine: event play ignored" ); - break; - } - - __LOG( "PlaybackStateMachine: event play" ); - - if ( aErrorCode == KErrNone ) - { - if ( iState == EStateStopped ) - { - TimePlay(); - iPeriodizer->Start(); - iPeriodizerEnd->Start(); - } - else if ( iState == EStatePaused ) - { - TimeContinue(); - iPeriodizer->Stop(); - iPeriodizer->Start(); - iPeriodizerEnd->Stop(); - iPeriodizerEnd->Start(); - } - ChangeState( EStatePlaying ); - } - else - { - ChangeState( EStateUnknown ); - } - - iCurrentOperation.Reset(); - TRAP_IGNORE( CheckOperationInQueueL() ); - break; - } - case EUPnPAVPauseUser: - { - if ( !iCurrentOperation.None() || - iState == EStatePaused ) - { - __LOG( "PlaybackStateMachine: event pause user ignored" ); - break; - } - __LOG( "PlaybackStateMachine: event pause user" ); - - if( aErrorCode == KErrNone ) - { - TimePause(); - ChangeState( EStatePaused ); - iPeriodizerEnd->Stop(); - } - else - { - ChangeState( EStateUnknown ); - } - - // Call callback - iParent.Observer().HandlePluginEvent( - MMPXPlaybackPluginObserver::EPPaused, KErrNone, - aErrorCode ); - break; - } - - case EUPnPAVPause: - { - __LOG( "PlaybackStateMachine: event pause" ); - - TInt err = aErrorCode; - if( aErrorCode == KErrNone ) - { - TimePause(); - ChangeState( EStatePaused ); - iPeriodizerEnd->Stop(); - } - else if( aErrorCode == KErrNotSupported ) - { - // Pause is supported (pause capability checked in CommandL ) - // but device is not ready. - err = KErrNotReady; - } - else - { - ChangeState( EStateUnknown ); - } - - if ( iCurrentOperation == EPbCmdPause ) - { - iCurrentOperation.Reset(); - TRAP_IGNORE( CheckOperationInQueueL() ); - iParent.Observer().HandlePluginEvent( - MMPXPlaybackPluginObserver::EPPaused, KErrNone, - err ); - } - else - { - iCurrentOperation.Reset(); - TRAP_IGNORE( CheckOperationInQueueL() ); - } - break; - } - case EUPnPAVStopUser: - { - iPeriodizerEnd->Stop(); - if ( !iCurrentOperation.None() || - iState == EStateStopped ) - { - __LOG( "PlaybackStateMachine: event stop user ignored" ); - break; - } - __LOG( "PlaybackStateMachine: event stop user" ); - - TBool trackComplete = TimeStop(); - if ( aErrorCode == KErrNone ) - { - ChangeState( EStateStopped ); - iParent.HandlePlayComplete(); - } - else - { - ChangeState( EStateUnknown ); - } - - // Call callback - if ( trackComplete ) - { - __LOG( "PlaybackStateMachine: play complete event to user" ); - iParent.Observer().HandlePluginEvent( - MMPXPlaybackPluginObserver::EPPlayComplete, KErrNone, - aErrorCode ); - } - else - { - __LOG( "PlaybackStateMachine: play stopped event to user" ); - iParent.Observer().HandlePluginEvent( - MMPXPlaybackPluginObserver::EPStopped, KErrNone, - aErrorCode ); - } - break; - } - case EUPnPAVStop: - { - iPeriodizerEnd->Stop(); - if ( iState == EStateStopped ) - { - // already in this state - ignore - break; - } - __LOG( "PlaybackStateMachine: event stop" ); - - if ( aErrorCode == KErrNone ) - { - ChangeState( EStateStopped ); - } - else - { - ChangeState( EStateUnknown ); - } - - if ( iCurrentOperation == EPbCmdStop ) - { - iCurrentOperation.Reset(); - TRAP_IGNORE( CheckOperationInQueueL() ); - // Call callback - iParent.Observer().HandlePluginEvent( - MMPXPlaybackPluginObserver::EPStopped, KErrNone, - aErrorCode ); - } - else if ( iCurrentOperation == EPbCmdReplay || - iCurrentOperation == EOperationPositionToZero ) - { - // continue with play - TRAP_IGNORE( iRendererSession.PlayL() ); - } - else if ( iCurrentOperation == - EOperationPositionToZeroDuringPause ) - { - // position zero complete - iCurrentOperation.Reset(); - TRAP_IGNORE( CheckOperationInQueueL() ); - - iParent.Observer().HandlePluginEvent( - MMPXPlaybackPluginObserver::EPSetComplete, - EPbPropertyPosition, aErrorCode ); - } - else - { - // Note: covers also EOperationSilentStop - iCurrentOperation.Reset(); - TRAP_IGNORE( CheckOperationInQueueL() ); - } - break; - } - default: - { - __LOG( "PlaybackStateMachine: event default?" ); - __PANICD( __FILE__, __LINE__ ); - break; - } - } - } - -// -------------------------------------------------------------------------- -// CUPnPPlaybackStateMachine::CheckOperationInQueueL -// Checks if operations are in the queue, and executes -// -------------------------------------------------------------------------- -// -void CUPnPPlaybackStateMachine::CheckOperationInQueueL() - { - if ( !iCurrentOperation.None() ) - { - // check operation though a current operation exists! - __PANICD( __FILE__, __LINE__ ); - return; - } - - if ( iOperationQueue.Count() > 0 ) - { - TOperation op = iOperationQueue[0]; - iOperationQueue.Remove(0); - if ( op == EOperationCommand ) - { - CommandL( op.iCmd ); - } - else if ( op == EOperationPositionToZero ) - { - PositionL( 0 ); - } - else - { - __PANICD( __FILE__, __LINE__ ); - } - } - } - -// -------------------------------------------------------------------------- -// CUPnPPlaybackStateMachine::TimePlay -// -------------------------------------------------------------------------- -// -void CUPnPPlaybackStateMachine::TimePlay() - { - iPlayMark.UniversalTime(); - iPausetime = 0; - } - -// -------------------------------------------------------------------------- -// CUPnPPlaybackStateMachine::TimePause -// -------------------------------------------------------------------------- -// -void CUPnPPlaybackStateMachine::TimePause() - { - iPauseMark.UniversalTime(); - } - -// -------------------------------------------------------------------------- -// CUPnPPlaybackStateMachine::TimeContinue -// -------------------------------------------------------------------------- -// -void CUPnPPlaybackStateMachine::TimeContinue() - { - TTime continueMark; - continueMark.UniversalTime(); - TTimeIntervalMicroSeconds paused = - continueMark.MicroSecondsFrom( iPauseMark ); - iPausetime += ( paused.Int64() / 1000 ); - } - - -// -------------------------------------------------------------------------- -// CUPnPPlaybackStateMachine::TimeStop -// -------------------------------------------------------------------------- -// -TBool CUPnPPlaybackStateMachine::TimeStop() - { - TBool isCompleted = ETrue; - if ( !iPlayMark.Int64() ) - { - isCompleted = EFalse; - return isCompleted; - } - TTime stopMark; - stopMark.UniversalTime(); - TTimeIntervalMicroSeconds played = - stopMark.MicroSecondsFrom( iPlayMark ); - - TInt duration = iParent.Track().TrackDuration(); - TInt playtime = ( played.Int64() / 1000 ) - iPausetime; - __LOG3("PlaybackStateMachine: playtime=%d duration=%d (pausetime=%d)", - playtime/1000, duration/1000, iPausetime/1000 ); - - if ( playtime >= 0 && - playtime < duration - KDurationErrorMargin ) - { - // [0 - duration-margin] - isCompleted= EFalse; - } - else if ( playtime >= duration - KDurationErrorMargin && - playtime <= duration + KDurationErrorMargin ) - { - // [duration-margin - duration+margin] - isCompleted= ETrue; - } - else - { - // position either negative or greater than duration ?? - __LOG2("Time ERROR: play=%d duration=%d ?", playtime, duration ); - isCompleted= ETrue; - } - - return isCompleted; - } - - -// -------------------------------------------------------------------------- -// CUPnPPlaybackStateMachine::ChangeState -// Changes the class state -// -------------------------------------------------------------------------- -// -void CUPnPPlaybackStateMachine::ChangeState( TState aNewState ) - { - __LOG2( "PlaybackStateMachine: STATE %S -> %S", - State( iState ), State( aNewState ) ); - iState = aNewState; - } - -// -------------------------------------------------------------------------- -// CUPnPPlaybackStateMachine::State -// -------------------------------------------------------------------------- -// -const TDesC* CUPnPPlaybackStateMachine::State( TState aState ) - { - switch( aState ) - { - case EStateStopped: - return &KStateStoppedText; - case EStatePlaying: - return &KStatePlayingText; - case EStatePaused: - return &KStatePausedText; - default: - return &KStateUnknownText; - } - } - -// -------------------------------------------------------------------------- -// CUPnPPlaybackStateMachine::HandlePeriod -// Action when timer has expired. -// -------------------------------------------------------------------------- -// -void CUPnPPlaybackStateMachine::HandlePeriod() - { - __LOG( "CUPnPPlaybackStateMachine::HandlePeriod" ); - - // Remote device is ready for give playback information. - iPeriodizer->Stop(); - iParent.HandlePlayStarted(); - } - -// -------------------------------------------------------------------------- -// CUPnPPlaybackStateMachine::HandlePeriodForEnd -// Action when timer has expired. -// -------------------------------------------------------------------------- -// -void CUPnPPlaybackStateMachine::HandlePeriodForEnd() - { - TBool trackComplete = TimeStop(); - if ( trackComplete ) - { - iPeriodizerEnd->Stop(); - PlayOvertimeEnd(); - } - else - { - iPeriodizerEnd->Start(); - } - } - -// -------------------------------------------------------------------------- -// CUPnPPlaybackStateMachine::PlayOvertimeEnd -// Stoping the playing song. -// -------------------------------------------------------------------------- -// - void CUPnPPlaybackStateMachine::PlayOvertimeEnd() - { - if ( !iCurrentOperation.None() || - iState == EStateStopped || iState == EStateUnknown) - { - return; - } - ChangeState( EStateStopped ); - iParent.HandlePlayComplete(); - iParent.Observer().HandlePluginEvent( - MMPXPlaybackPluginObserver::EPPlayComplete, KErrNone, - KErrNone ); - } -