--- 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 <mpxplaybackplugin.h>
-#include <mpxplaybackpluginobserver.h>
-#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 );
- }
-