--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/upnpavcontroller/upnprenderingstatemachine/src/upnprenderingstatemachine.cpp Wed Nov 03 11:45:09 2010 +0200
@@ -0,0 +1,1690 @@
+/*
+* Copyright (c) 2007,2009 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: Implementation of generic upnp remote rendering state machine
+*
+*/
+
+// INCLUDES
+// dlnasrv / mediaserver api
+#include <upnpitem.h>
+
+// dlnasrv / avcontroller api
+#include "upnpavrenderingsession.h"
+#include "upnpavdevice.h"
+#include "upnpitemutility.h"
+#include "upnpconstantdefs.h"
+#include "upnprenderingstatemachineconstants.h"
+#include "upnprenderingstatemachineobserver.h"
+
+// dlnasrv / component internal
+#include "upnprenderingoperation.h"
+#include "upnprenderingplaytimecalculator.h"
+#include "upnpretraces.h"
+#include "upnprenderingstatemachine.h"
+#include "upnpavcontrollerglobals.h"
+
+_LIT( KComponentLogfile, "upnprenderingstatemachine.txt");
+#include "upnplog.h"
+
+// CONSTANTS
+const TInt64 KMicrosecondsInMillisecond = 1000;
+const TInt KSeekThresholdTime = 2000; //ms
+
+// ======== MEMBER FUNCTIONS ========
+
+// --------------------------------------------------------------------------
+// CUpnpRenderingStateMachine::NewL
+// Static constructor.
+// --------------------------------------------------------------------------
+//
+EXPORT_C CUpnpRenderingStateMachine* CUpnpRenderingStateMachine::NewL(
+ MUPnPAVRenderingSession& aSession )
+ {
+ CUpnpRenderingStateMachine* self =
+ new (ELeave) CUpnpRenderingStateMachine( aSession );
+ CleanupStack::PushL( self );
+ self->ConstructL();
+ CleanupStack::Pop( self );
+ return self;
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpRenderingStateMachine::CUpnpRenderingStateMachine
+// default constructor
+// --------------------------------------------------------------------------
+//
+CUpnpRenderingStateMachine::CUpnpRenderingStateMachine(
+ MUPnPAVRenderingSession& aSession )
+ : iSession( aSession )
+ {
+ iState = Upnp::EOffSync;
+ iObserver = NULL;
+ iOptions = 0;
+ iSelector = 0;
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpRenderingStateMachine::ConstructL
+// 2nd phase constructor
+// --------------------------------------------------------------------------
+//
+void CUpnpRenderingStateMachine::ConstructL()
+ {
+ __LOG( "RenderingStateMachine::ConstructL" );
+ iPlaytimeCalculator = new(ELeave) CUpnpRenderingPlaytimeCalculator();
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpRenderingStateMachine::~CUpnpRenderingStateMachine
+// destructor
+// --------------------------------------------------------------------------
+//
+EXPORT_C CUpnpRenderingStateMachine::~CUpnpRenderingStateMachine()
+ {
+ __LOG( "RenderingStateMachine: ~CUpnpRenderingStateMachine" );
+ delete iPlaytimeCalculator;
+ iQueue.Close();
+ iObserver = NULL;
+ __LOG( "RenderingStateMachine: ~CUpnpRenderingStateMachine end" );
+ }
+
+
+
+// --------------------------------------------------------------------------
+// CUpnpRenderingStateMachine::SetOptions
+// sets the option flags for this state machine
+// --------------------------------------------------------------------------
+//
+EXPORT_C void CUpnpRenderingStateMachine::SetOptions( TInt aOptions )
+ {
+ iOptions = aOptions;
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpRenderingStateMachine::Options
+// --------------------------------------------------------------------------
+//
+EXPORT_C TInt CUpnpRenderingStateMachine::Options() const
+ {
+ return iOptions;
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpRenderingStateMachine::SetObserver
+// --------------------------------------------------------------------------
+//
+EXPORT_C void CUpnpRenderingStateMachine::SetObserver(
+ MUpnpRenderingStateMachineObserver& aObserver )
+ {
+ iObserver = &aObserver;
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpRenderingStateMachine::RemoveObserver
+// --------------------------------------------------------------------------
+//
+EXPORT_C void CUpnpRenderingStateMachine::RemoveObserver()
+ {
+ iObserver = NULL;
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpRenderingStateMachine::SetResourceSelector
+// custom selection for resource inside item
+// selects which resource is used in SetAvTransportUri
+// --------------------------------------------------------------------------
+//
+EXPORT_C void CUpnpRenderingStateMachine::SetResourceSelector(
+ MUPnPResourceSelector& aSelector )
+ {
+ __LOG( "RenderingStateMachine: SetResourceSelector" );
+ iSelector = &aSelector;
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpRenderingStateMachine::SyncL
+// synchronises the state machine with renderer
+// --------------------------------------------------------------------------
+//
+EXPORT_C void CUpnpRenderingStateMachine::SyncL()
+ {
+ __LOG( "CUpnpRenderingStateMachine::SyncL" );
+ __ASSERT( !IsInSync(), __FILE__, __LINE__ );
+ __ASSERT( !IsBusy(), __FILE__, __LINE__ );
+ if ( IsInSync() )
+ {
+ User::Leave( KErrGeneral );
+ }
+ if ( IsBusy() )
+ {
+ User::Leave( KErrServerBusy );
+ }
+ TUpnpRenderingOperation sync(
+ Upnp::ESync );
+ PushAndExecuteL( sync );
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpRenderingStateMachine::SetOffSync
+// sets this state machine off sync
+// --------------------------------------------------------------------------
+//
+EXPORT_C void CUpnpRenderingStateMachine::SetOffSync()
+ {
+ __LOG( "CUpnpRenderingStateMachine::SetOffSync" );
+ __ASSERT( !IsBusy(), __FILE__, __LINE__ );
+ iState = Upnp::EOffSync;
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpRenderingStateMachine::IsInSync
+// --------------------------------------------------------------------------
+//
+EXPORT_C TBool CUpnpRenderingStateMachine::IsInSync() const
+ {
+ return (iState & Upnp::EStateMaskInSync) != 0;
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpRenderingStateMachine::Command
+// Issues a command to the renderer through the state machine
+// --------------------------------------------------------------------------
+//
+EXPORT_C void CUpnpRenderingStateMachine::CommandL(
+ Upnp::TCommand aCommand,
+ TInt aCommandParameter,
+ const CUpnpItem* aMedia )
+ {
+ __LOG1( "CUpnpRenderingStateMachine::CommandL cmd = %d",aCommand );
+ TUpnpRenderingOperation cmd(
+ aCommand, aCommandParameter, aMedia );
+ PushAndExecuteL( cmd );
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpRenderingStateMachine::IsBusy
+// --------------------------------------------------------------------------
+//
+EXPORT_C TBool CUpnpRenderingStateMachine::IsBusy() const
+ {
+ return !IsFree();
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpRenderingStateMachine::State
+// --------------------------------------------------------------------------
+//
+EXPORT_C Upnp::TState CUpnpRenderingStateMachine::State() const
+ {
+ return iState;
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpRenderingStateMachine::Duration
+// --------------------------------------------------------------------------
+//
+EXPORT_C TInt CUpnpRenderingStateMachine::Duration() const
+ {
+ __LOG( "CUpnpRenderingStateMachine::Duration" );
+ __ASSERT( iState & Upnp::EStateMaskActive,
+ __FILE__, __LINE__ );
+ __ASSERT( iPlaytimeCalculator, __FILE__, __LINE__ );
+ return iPlaytimeCalculator->Duration();
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpRenderingStateMachine::Position
+// --------------------------------------------------------------------------
+//
+EXPORT_C TInt CUpnpRenderingStateMachine::Position() const
+ {
+ __LOG( "CUpnpRenderingStateMachine::Position" );
+ __ASSERT( iState & Upnp::EStateMaskActive,
+ __FILE__, __LINE__ );
+ __ASSERT( iPlaytimeCalculator, __FILE__, __LINE__ );
+ return iPlaytimeCalculator->Position();
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpRenderingStateMachine::HasPauseCapability
+// --------------------------------------------------------------------------
+//
+EXPORT_C TBool CUpnpRenderingStateMachine::HasPauseCapability() const
+ {
+ return iSession.Device().PauseCapability();
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpRenderingStateMachine::InteractOperationComplete
+// --------------------------------------------------------------------------
+//
+EXPORT_C void CUpnpRenderingStateMachine::InteractOperationComplete(
+ TInt aError, TUPnPAVInteractOperation aOperation )
+ {
+ __LOG( "CUpnpRenderingStateMachine::InteractOperationComplete" );
+ Process(
+ CUpnpRenderingStateMachine::EInteractOperationComplete,
+ aError, &aOperation );
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpRenderingStateMachine::PositionInfoResult
+// --------------------------------------------------------------------------
+//
+EXPORT_C void CUpnpRenderingStateMachine::PositionInfoResult(
+ TInt aError, const TDesC8& aPosition, const TDesC8& aLength )
+ {
+ __LOG( "CUpnpRenderingStateMachine::PositionInfoResult" );
+ Process(
+ CUpnpRenderingStateMachine::EPositionInfo,
+ aError, (TAny*)&aPosition, (TAny*)&aLength );
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpRenderingStateMachine::SetURIResult
+// --------------------------------------------------------------------------
+//
+EXPORT_C void CUpnpRenderingStateMachine::SetURIResult( TInt aError )
+ {
+ __LOG( "CUpnpRenderingStateMachine::SetURIResult" );
+ Process(
+ CUpnpRenderingStateMachine::ESetUriResult,
+ aError );
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpRenderingStateMachine::SetNextURIResult
+// --------------------------------------------------------------------------
+//
+EXPORT_C void CUpnpRenderingStateMachine::SetNextURIResult( TInt /*aError*/ )
+ {
+ __LOG( "CUpnpRenderingStateMachine::SetNextURIResult" );
+ __PANIC( __FILE__, __LINE__ );
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpRenderingStateMachine::ReportSyncReady
+// --------------------------------------------------------------------------
+//
+void CUpnpRenderingStateMachine::ReportSyncReady(
+ TInt aError, Upnp::TState aNewState )
+ {
+ __LOG3( "RenderingStateMachine: SyncReady err=%i %s->%s",
+ aError, StateName( iState ), StateName( aNewState ) );
+ iState = aNewState;
+ if ( iObserver )
+ {
+ iObserver->RendererSyncReady( aError, iState );
+ }
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpRenderingStateMachine::ReportStateChanged
+// --------------------------------------------------------------------------
+//
+void CUpnpRenderingStateMachine::ReportStateChanged(
+ TInt aError, Upnp::TState aNewState,
+ TBool aActionResponse, TInt aStateParam )
+ {
+ __LOG3( "RenderingStateMachine: StateChanged err=%i %s->%s",
+ aError, StateName( iState ), StateName( aNewState ) );
+ iState = aNewState;
+ if ( iObserver )
+ {
+ iObserver->RenderingStateChanged(
+ aError, iState, aActionResponse, aStateParam );
+ }
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpRenderingStateMachine::ReportPositionSync
+// --------------------------------------------------------------------------
+//
+void CUpnpRenderingStateMachine::ReportPositionSync( TInt aError,
+ Upnp::TPositionMode aMode,
+ TInt aDuration, TInt aPosition )
+ {
+ __LOG1( "RenderingStateMachine: PositionSync %i", aError );
+ if ( iObserver )
+ {
+ iObserver->PositionSync( aError, aMode, aDuration, aPosition );
+ }
+ }
+
+
+
+/*****************************************
+ ** State machine states implementation **
+ *****************************************/
+
+// --------------------------------------------------------------------------
+// CUpnpRenderingStateMachine::ExecuteOperationL
+// --------------------------------------------------------------------------
+//
+MUpnpRenderingOperationExecutor::TResult
+CUpnpRenderingStateMachine::ExecuteOperationL(
+ const TUpnpRenderingOperation& aOperation,
+ const TUpnpRenderingOperation& aCurrent )
+ {
+ __LOG1( "RenderingStateMachine: ExecuteOperationL (operation=%d)",
+ aOperation.Command() );
+ MUpnpRenderingOperationExecutor::TResult ret(ECompleted);
+ switch( aOperation.Command() )
+ {
+ case Upnp::ESync:
+ {
+ ret = ExecuteOperationSyncL( aOperation, aCurrent );
+ break;
+ }
+ case Upnp::EPlay:
+ {
+ ret = ExecuteOperationPlayL( aOperation, aCurrent );
+ break;
+ }
+ case Upnp::EStop:
+ {
+ ret = ExecuteOperationStopL( aOperation, aCurrent );
+ break;
+ }
+ case Upnp::EPause:
+ {
+ ret = ExecuteOperationPauseL( aOperation, aCurrent );
+ break;
+ }
+ case Upnp::EResume:
+ {
+ ret = ExecuteOperationResumeL( aOperation, aCurrent );
+ break;
+ }
+ case Upnp::ERestart:
+ {
+ ret = ExecuteOperationRestartL( aOperation, aCurrent );
+ break;
+ }
+ case Upnp::ESeek:
+ {
+ ret = ExecuteOperationSeekL( aOperation, aCurrent );
+ break;
+ }
+ case Upnp::ECalibrate:
+ {
+ ret = ExecuteOperationCalibrateL( aOperation, aCurrent );
+ break;
+ }
+ case Upnp::ESetUri:
+ {
+ ret = ExecuteOperationSetUriL( aOperation, aCurrent );
+ break;
+ }
+ default:
+ __PANIC( __FILE__, __LINE__ );
+ }
+ return ret;
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpRenderingStateMachine::ProcessOperationL
+// --------------------------------------------------------------------------
+//
+MUpnpRenderingOperationExecutor::TResult
+CUpnpRenderingStateMachine::ProcessOperationL(
+ const TUpnpRenderingOperation& aOperation, TInt aEvent,
+ TInt aError, const TAny* aParam1, const TAny* aParam2 )
+ {
+ __LOG2( "RenderingStateMachine: ProcessOperationL (event=%d) (aError=%d)",
+ aEvent, aError );
+
+ MUpnpRenderingOperationExecutor::TResult ret(ECompleted);
+ switch( aEvent )
+ {
+ case EInteractOperationComplete:
+ {
+ TUPnPAVInteractOperation op =
+ *(TUPnPAVInteractOperation*)aParam1;
+ if ( op == EUPnPAVPlay
+ || op == EUPnPAVPlayUser
+ || op == EUPnPAVStop
+ || op == EUPnPAVStopUser
+ || op == EUPnPAVPause
+ || op == EUPnPAVPauseUser
+ || op == EUPnPAVSeek )
+ {
+ ret = ProcessAVEvents( aOperation, op, aError );
+ }
+ else if ( op == EUPnPAVTransition )
+ {
+ ret = EContinue;
+ __LOG1( "RenderingStateMachine: Transition %d", aError );
+ }
+ else
+ {
+ __PANIC( __FILE__, __LINE__ );
+ }
+ break;
+ }
+ case EPositionInfo:
+ {
+ const TDesC8& pos = *(const TDesC8*)aParam1;
+ const TDesC8& len = *(const TDesC8*)aParam2;
+ ret = ProcessPositionInfo( aOperation, aError, pos, len );
+ break;
+ }
+ case ESetUriResult:
+ {
+ ret = ProcessSetURIResultL( aOperation, aError );
+ break;
+ }
+ default:
+ {
+ __PANIC( __FILE__, __LINE__ );
+ }
+ }
+ return ret;
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpRenderingStateMachine::HandleAsyncError
+// cancels the ongoing operation
+// --------------------------------------------------------------------------
+//
+void CUpnpRenderingStateMachine::HandleAsyncError(
+ const TUpnpRenderingOperation& aOperation, TInt aError )
+ {
+ __LOG( "RenderingStateMachine: HandleAsyncError" );
+ switch ( aOperation.Command() )
+ {
+ case Upnp::ESync:
+ {
+ ReportSyncReady( aError, State() );
+ break;
+ }
+ case Upnp::EPlay:
+ {
+ if ( aOperation.IsUserOriented() )
+ {
+ ReportStateChanged( aError,
+ Upnp::EStopped, ETrue );
+ }
+ break;
+ }
+ case Upnp::EStop:
+ {
+ if ( aOperation.IsUserOriented() )
+ {
+ ReportStateChanged( aError, State(), ETrue );
+ }
+ break;
+ }
+ case Upnp::EPause:
+ {
+ if ( aOperation.IsUserOriented() )
+ {
+ ReportStateChanged( aError, State(), ETrue );
+ }
+ break;
+ }
+ case Upnp::ECalibrate:
+ {
+ // do nothing
+ break;
+ }
+ case Upnp::ESeek:
+ {
+ TInt seekCode = Upnp::EPositionChanged;
+ ReportStateChanged( aError,
+ State(), ETrue, seekCode );
+ break;
+ }
+ default:
+ // __PANICD( __FILE__, __LINE__ );
+ break;
+ }
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpRenderingStateMachine::ExecuteOperationSyncL
+// --------------------------------------------------------------------------
+//
+MUpnpRenderingOperationExecutor::TResult
+CUpnpRenderingStateMachine::ExecuteOperationSyncL(
+ const TUpnpRenderingOperation& /*aOperation*/,
+ const TUpnpRenderingOperation& /*aCurrent*/ )
+ {
+ __LOG( "RenderingStateMachine: ExecuteOperationSyncL" );
+ // GetRendererState() method to be implemented in AVController
+ // 1. if renderer has already sent its first state event, it will be
+ // returned immediately.
+ // 2. if not (SUBSCRIBE just sent) there will be a small wait loop to
+ // wait for the initial event
+ // 3. if the initial even does not arrive
+ // 3.1 Request the state from the renderer (optional)
+ // 3.2 Assume it is in stopped state. (maybe enough)
+
+ TUPnPAVInteractOperation op = iSession.GetRendererStateL();
+ __LOG1( "RenderingStateMachine: ExecuteOperationSyncL \
+current op = %d" ,op );
+ Upnp::TState state = Upnp::EPlaying;
+ if( op == EUPnPAVStopUser )
+ {
+ state = Upnp::EStopped;
+ }
+ ReportSyncReady( KErrNone , state );
+ return ECompleted;
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpRenderingStateMachine::ExecuteOperationPlayL
+// --------------------------------------------------------------------------
+//
+MUpnpRenderingOperationExecutor::TResult
+CUpnpRenderingStateMachine::ExecuteOperationPlayL(
+ const TUpnpRenderingOperation& aOperation,
+ const TUpnpRenderingOperation& aCurrent )
+ {
+ __LOG( "RenderingStateMachine: ExecuteOperationPlayL" );
+ MUpnpRenderingOperationExecutor::TResult ret(ECompleted);
+ if ( aCurrent == Upnp::EPlay )
+ {
+ __LOG( "RenderingStateMachine: ExecuteOperationPlayL \
+aCurrent == Upnp::EPlay " );
+ // Play request repeats. Compare content.
+ const CUpnpItem* item = static_cast<const CUpnpItem*>(
+ aOperation.Data() );
+ if ( ResourceFromL( *item ).Value() != iCurrentUri )
+ {
+ ret = EQueue;
+ }
+ }
+ else if ( aCurrent != Upnp::ENone )
+ {
+ __LOG( "RenderingStateMachine: ExecuteOperationPlayL \
+aCurrent == Upnp::ENone " );
+ ret = EQueue;
+ }
+ else
+ {
+ switch( State() )
+ {
+ case Upnp::EPaused:
+ {
+ __LOG( "RenderingStateMachine: ExecuteOperationPlayL \
+aCurrent == Upnp::EPaused " );
+
+ const CUpnpItem* item =
+ static_cast<const CUpnpItem*>( aOperation.Data() );
+ if ( item && ResourceFromL( *item ).Value() != iCurrentUri )
+ {
+ // track changed during pause -> stop paused and start
+ // playing the new
+ TUpnpRenderingOperation stop( Upnp::EStop );
+ stop.SetUserOriented( EFalse );
+ PushL( stop );
+ TUpnpRenderingOperation play( aOperation );
+ PushL( play );
+ }
+ else
+ {
+ iSession.PlayL();
+ ret = EContinue;
+ }
+ break;
+ }
+ case Upnp::EPlaying:
+ case Upnp::EStopped:
+ {
+ __LOG( "RenderingStateMachine: ExecuteOperationPlayL aCurrent == Upnp::EStopped " );
+
+ // start play sequence
+ const CUpnpItem* item = static_cast<const CUpnpItem*>(
+ aOperation.Data() );
+
+ __LOG1( "RenderingStateMachine: ExecuteOperationPlayL item 0x%x ", item );
+
+ if ( item )
+ {
+ // improvements !!!
+ // check if user requests playing the same track that was
+ // previously playing. In that case we just call Play().
+ // Much faster.
+ const TDesC8& httpuri = ResourceFromL( *item ).Value();
+
+ __LOG( "RenderingStateMachine: ExecuteOperationPlayL current:" );
+ __LOG8( iCurrentUri );
+ __LOG( "RenderingStateMachine: ExecuteOperationPlayL new:" );
+ __LOG8( httpuri );
+ if( iCurrentUri == httpuri )
+ {
+ iSession.PlayL();
+ }
+ else
+ {
+ SetUriL( aOperation );
+ }
+ }
+ else
+ {
+ // uri not available
+ User::Leave( KErrArgument );
+ }
+ ret = EContinue;
+ break;
+ }
+ case Upnp::EOffSync:
+ case Upnp::EBusy:
+ case Upnp::EDead:
+ case Upnp::EBuffering:
+ case Upnp::EStateMaskInSync:
+ case Upnp::EStateMaskActive:
+ case Upnp::EStateMaskRendering:
+ default:
+ {
+ User::Leave( KErrNotReady );
+ }
+ }
+ }
+ return ret;
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpRenderingStateMachine::ExecuteOperationSetUriL
+// --------------------------------------------------------------------------
+//
+MUpnpRenderingOperationExecutor::TResult
+CUpnpRenderingStateMachine::ExecuteOperationSetUriL(
+ const TUpnpRenderingOperation& aOperation,
+ const TUpnpRenderingOperation& /*aCurrent*/ )
+ {
+ __LOG( "RenderingStateMachine: ExecuteOperationSetUriL" );
+
+ iStateBeforeSetUri = State();
+ SetUriL( aOperation );
+
+ return EContinue;
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpRenderingStateMachine::SetUriL
+// --------------------------------------------------------------------------
+//
+void CUpnpRenderingStateMachine::SetUriL(
+ const TUpnpRenderingOperation& aOperation )
+ {
+ __LOG( "RenderingStateMachine: ExecuteOperationSetUriL" );
+
+ const CUpnpItem* item = static_cast<const CUpnpItem*>(
+ aOperation.Data() );
+
+ __LOG1( "RenderingStateMachine: SetUriL item 0x%x ", item );
+
+ if ( item )
+ {
+ const TDesC8& httpuri = ResourceFromL( *item ).Value();
+
+ __LOG( "RenderingStateMachine: SetUriL current:" );
+ __LOG8( iCurrentUri );
+ __LOG( "RenderingStateMachine: SetUriL new:" );
+ __LOG8( httpuri );
+
+ __LOG( "RenderingStateMachine: SetUriL iSession.SetURIL" );
+
+ iSession.SetURIL( httpuri, *item );
+ iCurrentUri.Copy( httpuri );
+ ReportStateChanged( KErrNone, Upnp::EBuffering );
+ }
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpRenderingStateMachine::ExecuteOperationStopL
+// --------------------------------------------------------------------------
+//
+MUpnpRenderingOperationExecutor::TResult
+CUpnpRenderingStateMachine::ExecuteOperationStopL(
+ const TUpnpRenderingOperation& /*aOperation*/,
+ const TUpnpRenderingOperation& aCurrent )
+ {
+ __LOG( "RenderingStateMachine: ExecuteOperationStopL" );
+ MUpnpRenderingOperationExecutor::TResult ret(ECompleted);
+ if ( aCurrent == Upnp::EStop )
+ {
+ // already stopping, no need to stop twice
+ }
+ else if ( aCurrent != Upnp::ENone )
+ {
+ ret = EQueue;
+ }
+ else
+ {
+ switch( State() )
+ {
+ case Upnp::EPlaying:
+ case Upnp::EPaused:
+ {
+ iSession.StopL();
+ ret = EContinue;
+ break;
+ }
+ case Upnp::EStopped:
+ {
+ ReportStateChanged( KErrNone, State() );
+ break;
+ }
+ case Upnp::EOffSync:
+ case Upnp::EBusy:
+ case Upnp::EDead:
+ case Upnp::EBuffering:
+ case Upnp::EStateMaskInSync:
+ case Upnp::EStateMaskActive:
+ case Upnp::EStateMaskRendering:
+ default:
+ {
+ User::Leave( KErrNotReady );
+ }
+ }
+ }
+ return ret;
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpRenderingStateMachine::ExecuteOperationPauseL
+// --------------------------------------------------------------------------
+//
+MUpnpRenderingOperationExecutor::TResult
+CUpnpRenderingStateMachine::ExecuteOperationPauseL(
+ const TUpnpRenderingOperation& /*aOperation*/,
+ const TUpnpRenderingOperation& aCurrent )
+ {
+ __LOG( "RenderingStateMachine: ExecuteOperationPauseL" );
+ MUpnpRenderingOperationExecutor::TResult ret(ECompleted);
+ if ( aCurrent == Upnp::EPause )
+ {
+ // pause during pause request
+ }
+ else if ( aCurrent != Upnp::ENone )
+ {
+ ret = EQueue;
+ }
+ else
+ {
+ switch( State() )
+ {
+ case Upnp::EPlaying:
+ {
+ iSession.PauseL();
+ ret = EContinue;
+ break;
+ }
+ case Upnp::EPaused:
+ {
+ ReportStateChanged( KErrNone, State() );
+ ret = ECompleted;
+ break;
+ }
+ case Upnp::EOffSync:
+ case Upnp::EBusy:
+ case Upnp::EDead:
+ case Upnp::EStopped:
+ case Upnp::EBuffering:
+ case Upnp::EStateMaskInSync:
+ case Upnp::EStateMaskActive:
+ case Upnp::EStateMaskRendering:
+ default:
+ {
+ User::Leave( KErrNotReady );
+ }
+ }
+ }
+ return ret;
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpRenderingStateMachine::ExecuteOperationResumeL
+// --------------------------------------------------------------------------
+//
+MUpnpRenderingOperationExecutor::TResult
+CUpnpRenderingStateMachine::ExecuteOperationResumeL(
+ const TUpnpRenderingOperation& /*aOperation*/,
+ const TUpnpRenderingOperation& aCurrent )
+ {
+ __LOG( "RenderingStateMachine: ExecuteOperationResumeL" );
+ MUpnpRenderingOperationExecutor::TResult ret(ECompleted);
+ if ( aCurrent == Upnp::EPlay )
+ {
+ // resume during play
+ }
+ else if ( aCurrent != Upnp::ENone )
+ {
+ ret = EQueue;
+ }
+ else
+ {
+ switch( State() )
+ {
+ case Upnp::EPlaying:
+ {
+ ReportStateChanged( KErrNone, State() );
+ break;
+ }
+ case Upnp::EPaused:
+ {
+ iSession.PlayL();
+ ret = EContinue;
+ break;
+ }
+ case Upnp::EOffSync:
+ case Upnp::EBusy:
+ case Upnp::EDead:
+ case Upnp::EStopped:
+ case Upnp::EBuffering:
+ case Upnp::EStateMaskInSync:
+ case Upnp::EStateMaskActive:
+ case Upnp::EStateMaskRendering:
+ default:
+ {
+ User::Leave( KErrNotReady );
+ }
+ }
+
+ }
+ return ret;
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpRenderingStateMachine::ExecuteOperationRestartL
+// --------------------------------------------------------------------------
+//
+MUpnpRenderingOperationExecutor::TResult
+CUpnpRenderingStateMachine::ExecuteOperationRestartL(
+ const TUpnpRenderingOperation& /*aOperation*/,
+ const TUpnpRenderingOperation& aCurrent )
+ {
+ __LOG( "RenderingStateMachine: ExecuteOperationRestartL" );
+ // handle parallel
+ MUpnpRenderingOperationExecutor::TResult ret(ECompleted);
+ if ( aCurrent != Upnp::ENone )
+ {
+ ret = EQueue;
+ }
+ else
+ {
+ switch( State() )
+ {
+ case Upnp::EPlaying:
+ {
+ TUpnpRenderingOperation stop(
+ Upnp::EStop );
+ stop.SetUserOriented( EFalse );
+ PushL( stop );
+ TUpnpRenderingOperation play(
+ Upnp::EPlay );
+ PushL( play );
+ break;
+ }
+ case Upnp::EPaused:
+ {
+ TUpnpRenderingOperation stop(
+ Upnp::EStop );
+ PushL( stop );
+ break;
+ }
+ case Upnp::EOffSync:
+ case Upnp::EBusy:
+ case Upnp::EDead:
+ case Upnp::EStopped:
+ case Upnp::EBuffering:
+ case Upnp::EStateMaskInSync:
+ case Upnp::EStateMaskActive:
+ case Upnp::EStateMaskRendering:
+ default:
+ {
+ User::Leave( KErrNotReady );
+ }
+ }
+
+ }
+ return ret;
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpRenderingStateMachine::ExecuteOperationSeekL
+// --------------------------------------------------------------------------
+//
+MUpnpRenderingOperationExecutor::TResult
+CUpnpRenderingStateMachine::ExecuteOperationSeekL(
+ const TUpnpRenderingOperation& aOperation,
+ const TUpnpRenderingOperation& aCurrent )
+ {
+ __LOG( "RenderingStateMachine: ExecuteOperationSeekL" );
+ MUpnpRenderingOperationExecutor::TResult ret(ECompleted);
+
+ TInt currentPosition = iPlaytimeCalculator->Position();
+ TInt seekPosition = aOperation.Param();
+ __LOG3( "RenderingStateMachine: state 0x%x, currentPosition %d, seekPosition %d",
+ State(), currentPosition, seekPosition );
+ if( seekPosition < currentPosition + KSeekThresholdTime &&
+ seekPosition > currentPosition - KSeekThresholdTime )
+ {
+ // ignore seek
+ }
+ else if ( aCurrent != Upnp::ENone )
+ {
+ ret = EQueue;
+ }
+ else if ( State() == Upnp::EStopped ||
+ State() == Upnp::EPlaying )
+ {
+ iSeekPostion = seekPosition;
+ TTime seekTime = (TInt64)iSeekPostion * KMicrosecondsInMillisecond;
+ iSession.SeekRelTimeL( seekTime );
+ ret = EContinue;
+ }
+ else if( State() == Upnp::EPaused )
+ {
+ TInt lastIndex( iQueue.Count() - 1 );
+ TBool found(EFalse);
+ for( TInt i(lastIndex); i > 0; i-- )
+ {
+ if( iQueue[i].Command() == Upnp::EPause )
+ {
+ break;
+ }
+ else if( iQueue[i].Command() == Upnp::EPlay ||
+ iQueue[i].Command() == Upnp::EResume )
+ {
+ __LOG( "RenderingStateMachine: ExecuteOperationSeekL \
+ play or resume found adding seek to queue" );
+ TUpnpRenderingOperation seek( aOperation );
+ PushL( seek );
+ found = ETrue;
+ break;
+ }
+ }
+ /**
+ * if play or resume was not found it is
+ * illigal to execute seek in renderer
+ */
+ if ( !found )
+ {
+ User::Leave( KErrNotReady );
+ }
+ }
+ else
+ {
+ User::Leave( KErrNotReady );
+ }
+ return ret;
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpRenderingStateMachine::ExecuteOperationCalibrateL
+// --------------------------------------------------------------------------
+//
+MUpnpRenderingOperationExecutor::TResult
+CUpnpRenderingStateMachine::ExecuteOperationCalibrateL(
+ const TUpnpRenderingOperation& /*aOperation*/,
+ const TUpnpRenderingOperation& aCurrent )
+ {
+ __LOG( "RenderingStateMachine: ExecuteOperationCalibrateL" );
+ MUpnpRenderingOperationExecutor::TResult ret(ECompleted);
+ if ( aCurrent != Upnp::ENone )
+ {
+ ret = EQueue;
+ }
+ else if ( State() == Upnp::EPlaying ||
+ State() == Upnp::EPaused )
+ {
+ iGetPositionStartMark.UniversalTime();
+ iSession.GetPositionInfoL();
+ ret = EContinue;
+ }
+ else
+ {
+ User::Leave( KErrNotReady );
+ }
+ return ret;
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpRenderingStateMachine::ProcessEvents
+// --------------------------------------------------------------------------
+//
+MUpnpRenderingOperationExecutor::TResult
+CUpnpRenderingStateMachine::ProcessAVEvents(
+ const TUpnpRenderingOperation& aOperation,
+ const TUPnPAVInteractOperation aIntOp,
+ TInt aError )
+ {
+ MUpnpRenderingOperationExecutor::TResult ret(ECompleted);
+ if( !aError )
+ {
+ switch( aIntOp )
+ {
+ case EUPnPAVPlay:
+ {
+ if ( State() == Upnp::EPaused )
+ {
+ iPlaytimeCalculator->Resume();
+ }
+ else if ( !iPlaytimeCalculator->IsPlaying() )
+ {
+ iPlaytimeCalculator->Start();
+ }
+ ReportStateChanged( aError,
+ Upnp::EPlaying );
+ break;
+ }
+ case EUPnPAVPlayUser:
+ {
+ // spontaneous state change to playing
+ if ( State() == Upnp::EStopped )
+ {
+ iPlaytimeCalculator->Start();
+ }
+ else if ( State() == Upnp::EPaused )
+ {
+ iPlaytimeCalculator->Resume();
+ }
+ ReportStateChanged( aError,
+ Upnp::EPlaying, EFalse );
+ ret = EContinue;
+ break;
+ }
+ case EUPnPAVStop:
+ {
+ iPlaytimeCalculator->Stop();
+ ReportStateChanged( aError,
+ Upnp::EStopped , ETrue );
+ break;
+ }
+ case EUPnPAVStopUser:
+ {
+ // spontaneous state change to stopped
+ iPlaytimeCalculator->Stop();
+ TInt stopcode = Upnp::ENoMedia;
+ if( iPlaytimeCalculator->Duration() != KErrNotFound )
+ {
+ stopcode = ( iPlaytimeCalculator->IsTrackComplete() ?
+ Upnp::ETrackCompleted :
+ Upnp::EStopRequested );
+ }
+ ReportStateChanged( aError,
+ Upnp::EStopped, EFalse, stopcode );
+ ret = EContinue;
+ break;
+ }
+ case EUPnPAVPause:
+ {
+ iPlaytimeCalculator->Pause();
+ ReportStateChanged( aError,
+ Upnp::EPaused );
+ break;
+ }
+ case EUPnPAVPauseUser:
+ {
+ // spontaneous state change to paused
+ iPlaytimeCalculator->Pause();
+ ReportStateChanged( aError,
+ Upnp::EPaused, EFalse );
+ ret = EContinue;
+ break;
+ }
+ case EUPnPAVSeek:
+ {
+ iPlaytimeCalculator->RestartAt( iSeekPostion );
+ TInt seekCode = Upnp::EPositionChanged;
+ ReportStateChanged( aError,
+ State(), ETrue, seekCode );
+ break;
+ }
+ default:
+ {
+ __LOG2( "RenderingStateMachine: aIntOp = %d event during %s",
+ aIntOp , CommandName(aOperation.Command()) );
+ break;
+ }
+ }
+ }
+ else
+ {
+ ReportStateChanged( aError,
+ State() );
+ }
+ return ret;
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpRenderingStateMachine::ProcessPositionInfo
+// --------------------------------------------------------------------------
+//
+MUpnpRenderingOperationExecutor::TResult
+CUpnpRenderingStateMachine::ProcessPositionInfo(
+ const TUpnpRenderingOperation& aOperation,
+ TInt aError, const TDesC8& aPosition, const TDesC8& aLength )
+ {
+ __LOG( "RenderingStateMachine: ProcessPositionInfo" );
+ __ASSERT( aOperation == Upnp::ECalibrate,
+ __FILE__, __LINE__ );
+
+ TInt duration = 0;
+ TInt position = 0;
+ if ( aError == KErrNone )
+ {
+ aError = UPnPItemUtility::UPnPDurationAsMilliseconds(
+ aLength, duration );
+ }
+ if ( aError == KErrNone )
+ {
+ aError = UPnPItemUtility::UPnPDurationAsMilliseconds(
+ aPosition, position );
+ }
+ if ( aError == KErrNone )
+ {
+ //Incorporate the delay in receiving the response.
+ TTime posStopMark; posStopMark.UniversalTime();
+ TTimeIntervalMicroSeconds delay =
+ posStopMark.MicroSecondsFrom( iGetPositionStartMark );
+ TInt delayInMSec = ( delay.Int64() / KMicrosecondsInMillisecond );
+ position += (delayInMSec/2);
+ if ( position > duration )
+ {
+ position = duration;
+ }
+ __LOG2( "RenderingStateMachine: ProcessPositionInfo added delay(%d) \
+position(%d)", delayInMSec/2, position);
+ iPlaytimeCalculator->AcknowledgePositionInfo(
+ duration, position );
+ }
+ // response
+ // trick states
+ ReportPositionSync( aError,
+ Upnp::EPlayingNormally,
+ iPlaytimeCalculator->Duration(),
+ iPlaytimeCalculator->Position() );
+ return ECompleted;
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpRenderingStateMachine::ProcessSetURIResultL
+// --------------------------------------------------------------------------
+//
+MUpnpRenderingOperationExecutor::TResult
+CUpnpRenderingStateMachine::ProcessSetURIResultL(
+ const TUpnpRenderingOperation& aOperation,
+ TInt aError )
+ {
+ __LOG( "RenderingStateMachine: ProcessSetURIResultL" );
+ TBool validOp( aOperation == Upnp::EPlay || aOperation == Upnp::ESetUri );
+ __ASSERT( validOp, __FILE__, __LINE__ );
+ MUpnpRenderingOperationExecutor::TResult ret(ECompleted);
+ if ( aError == KErrNone )
+ {
+ // get duration from item and write to playtime calculator
+ const CUpnpItem* item = static_cast<const CUpnpItem*>(
+ aOperation.Data() );
+ const CUpnpAttribute* attr =
+ UPnPItemUtility::FindAttributeByName(
+ ResourceFromL( *item ), KAttributeDuration );
+ if ( attr )
+ {
+ TInt ms = 0;
+ if ( UPnPItemUtility::UPnPDurationAsMilliseconds(
+ attr->Value(), ms ) == KErrNone )
+ {
+ iPlaytimeCalculator->SetDuration( ms );
+ }
+ }
+ if( aOperation.Command() == Upnp::EPlay )
+ {
+ iSession.PlayL();
+ ret = EContinue;
+ }
+ else
+ {
+ ReportStateChanged( KErrNone, Upnp::EBuffering, EFalse, ETrue );
+ iState = iStateBeforeSetUri;
+ ret = ECompleted;
+ }
+ }
+ //if seturi failed send first stop in that case!
+ else if( aError == KErrAccessDenied || aError == KErrLocked )
+ {
+ iCurrentUri.Zero();
+ iQueue.Remove( 0 ); // removes play from queue
+ TUpnpRenderingOperation stop( Upnp::EStop );
+ stop.SetUserOriented( EFalse );
+ PushL( stop ); // add stop
+ iSession.StopL();
+ ret = EContinue; // continue = waits for operation to complete
+ TUpnpRenderingOperation play( aOperation );
+ PushL( play );
+ }
+ else
+ {
+ HandleAsyncError( aOperation, aError );
+ }
+ return ret;
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpRenderingStateMachine::ResourceFrom
+// --------------------------------------------------------------------------
+//
+const CUpnpElement& CUpnpRenderingStateMachine::ResourceFromL(
+ const CUpnpItem& aItem )
+ {
+ const CUpnpElement* element( NULL );
+ if ( iSelector )
+ {
+ element = &iSelector->SelectResourceL( aItem );
+ }
+ else
+ {
+ element = &iDefaultSelector.SelectResourceL( aItem );
+ }
+ return *element;
+ }
+
+
+/**************************
+ ** Queue implementation **
+ **************************/
+
+// --------------------------------------------------------------------------
+// CUpnpRenderingStateMachine::Size
+// --------------------------------------------------------------------------
+//
+TInt CUpnpRenderingStateMachine::Size() const
+ {
+ __LOG1( "CUpnpRenderingStateMachine::Size(%d)", iQueue.Count() );
+ return iQueue.Count();
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpRenderingStateMachine::IsFree
+// Checks if the queue is free for new operations
+// --------------------------------------------------------------------------
+//
+TBool CUpnpRenderingStateMachine::IsFree() const
+ {
+ return Size() == 0;
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpRenderingStateMachine::PushL
+// push operation to queue. Don't try to execute it yet.
+// --------------------------------------------------------------------------
+//
+void CUpnpRenderingStateMachine::PushL(
+ const TUpnpRenderingOperation& aOperation )
+ {
+ __LOG( "CUpnpRenderingStateMachine::PushL" );
+ iQueue.AppendL( aOperation );
+ CompressQueueL();
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpRenderingStateMachine::PushAndExecuteL
+// push operation to queue and execute it immediately
+// --------------------------------------------------------------------------
+//
+void CUpnpRenderingStateMachine::PushAndExecuteL(
+ const TUpnpRenderingOperation& aOperation )
+ {
+ __LOG( "CUpnpRenderingStateMachine::PushAndExecuteL" );
+ if ( IsFree() )
+ {
+ PushL( aOperation );
+ ExecuteRecursivelyL();
+ }
+ else
+ {
+ ExecuteParallelL( aOperation );
+ }
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpRenderingAlgorithms::Execute
+// Runs an operation in queue
+// --------------------------------------------------------------------------
+//
+void CUpnpRenderingStateMachine::Execute()
+ {
+ __LOG( "CUpnpRenderingStateMachine::Execute" );
+ TUpnpRenderingOperation op = Current();
+ if ( op.IsValid() )
+ {
+ __LOG1( "OperationQueue: Executing %s",
+ CommandName(op.Command()) );
+ MUpnpRenderingOperationExecutor::TResult result = ECompleted;
+ TRAPD( leave, result = ExecuteOperationL( op,
+ Upnp::ENone ) );
+ __LOG1( "OperationQueue: leave code(%d) ", leave );
+
+ if ( leave != KErrNone )
+ {
+ __LOG1( "OperationQueue: %s failed while executing",
+ CommandName(op.Command()) );
+ iQueue.Reset();
+ HandleAsyncError( op, leave );
+ }
+ else if ( result == ECompleted )
+ {
+ __LOG1( "OperationQueue: %s completed while executing",
+ CommandName(op.Command()) );
+ if( iQueue.Count() > 0 )
+ {
+ iQueue.Remove( 0 );
+ Execute(); // recur
+ }
+ }
+ else if ( result == EContinue )
+ {
+ // operation continues
+ }
+ else
+ {
+ // illegal answer
+ __PANIC( __FILE__, __LINE__ );
+ }
+ }
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpRenderingStateMachine::Process
+// Abstract process of an operation
+// --------------------------------------------------------------------------
+//
+void CUpnpRenderingStateMachine::Process(
+ TInt aEvent,
+ TInt aError, const TAny* aParam1, const TAny* aParam2 )
+ {
+ __LOG( "CUpnpRenderingStateMachine::Process" );
+ TUpnpRenderingOperation op = Current();
+ MUpnpRenderingOperationExecutor::TResult result = ECompleted;
+ __LOG2( "OperationQueue: Processing %s with event %d",
+ CommandName(op.Command()), aEvent );
+ __LOG( "CUpnpRenderingStateMachine::Process - call ProcessOperationL" );
+ TRAPD( leave,
+ result = ProcessOperationL( op, aEvent,
+ aError, aParam1, aParam2 ) );
+ if ( leave != KErrNone )
+ {
+ __LOG1( "OperationQueue: %s failed while processing",
+ CommandName(op.Command()) );
+ iQueue.Reset();
+ HandleAsyncError( op, leave );
+ }
+ else if ( result == ECompleted )
+ {
+ __LOG2(
+ "OperationQueue: %s completed while processing iQueue count = %d"
+ ,CommandName(op.Command()) , iQueue.Count() );
+ if( iQueue.Count() > 0 )
+ {
+ iQueue.Remove( 0 );
+ Execute(); // pop new
+ }
+ }
+ else if ( result == EContinue )
+ {
+ // operation continues
+ }
+ else
+ {
+ // illegal answer
+ __PANIC( __FILE__, __LINE__ );
+ }
+ }
+
+void CUpnpRenderingStateMachine::CompressQueueL()
+ {
+ TInt queueCount( iQueue.Count() );
+
+ if( queueCount > 1 )
+ {
+ TInt lastIndex( queueCount - 1 );
+
+ switch( iQueue[lastIndex].Command() )
+ {
+ case Upnp::EStop:
+ {
+ /*
+
+ TODO : check how to do later!!
+
+ TInt removeStartIndex( 0 );
+
+ if( iQueue[0] == Upnp::EStop )
+ {
+ // remove all except current ongoing stop command
+ removeStartIndex = lastIndex ;
+ }
+ else
+ {
+ // remove all except current ongoing command and last stop
+ // command
+ removeStartIndex = lastIndex - 1;
+ }
+
+ for( TInt i = removeStartIndex; i > 0; i-- )
+ {
+ __LOG2( "OperationQueue: Removing %s from queue index %d",
+ CommandName( iQueue[i].Command() ), i );
+ iQueue.Remove( i );
+ } */
+
+ break;
+ }
+ case Upnp::EPlay:
+ {
+ /*
+
+ TODO : check how to do later!!
+
+ TInt removeStartIndex( 0 );
+
+ const CUpnpItem* item = static_cast<const CUpnpItem*>(
+ iQueue[lastIndex].Data() );
+
+ if( iQueue[0] == Upnp::EPlay &&
+ item &&
+ ResourceFromL( *item ).Value() == iCurrentUri )
+ {
+ // remove all except current ongoing play command
+ removeStartIndex = lastIndex;
+ }
+ else
+ {
+ // remove all except current ongoing command and
+ // (last stop and) play command
+ if( queueCount > 2 &&
+ iQueue[lastIndex - 1] == Upnp::EStop )
+ {
+ // stop found before last play command
+ removeStartIndex = lastIndex - 2;
+ }
+ else
+ {
+ removeStartIndex = lastIndex - 1;
+ }
+ }
+
+ for( TInt i = removeStartIndex; i > 0; i-- )
+ {
+ __LOG2( "OperationQueue: Removing %s from queue index %d",
+ CommandName( iQueue[i].Command() ), i );
+ iQueue.Remove( i );
+ }
+ */
+ break;
+ }
+ case Upnp::ECalibrate:
+ {
+ RemoveAllDublicateCommands( iQueue[lastIndex].Command() );
+ break;
+ }
+ case Upnp::ERestart:
+ case Upnp::EPause:
+ case Upnp::ESeek:
+ case Upnp::EResume:
+ case Upnp::ENone:
+ case Upnp::ESync:
+ case Upnp::EClose:
+ case Upnp::ENext:
+ case Upnp::EPrev:
+ case Upnp::EBack:
+ case Upnp::EJump:
+ default:
+ {
+ //not implemented -> do nothing
+ break;
+ }
+ }
+ }
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpRenderingStateMachine::RemoveAllDublicateCommands
+// --------------------------------------------------------------------------
+//
+void CUpnpRenderingStateMachine::RemoveAllDublicateCommands(
+Upnp::TCommand aCommand )
+ {
+ __LOG1( "CUpnpRenderingStateMachine::RemoveAllDublicateCommands \
+ command = %d" , aCommand );
+ TInt lastIndex( iQueue.Count() - 1 );
+
+ for( TInt i(lastIndex-1); i > 0; i-- )
+ {
+ if( iQueue[i].Command() == aCommand )
+ {
+ __LOG1( "CUpnpRenderingStateMachine::RemoveAllDublicateCommands \
+ found dublicate command index = %d",i);
+ // remove dublicate command
+ iQueue.Remove( i );
+ }
+ }
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpRenderingStateMachine::Current
+// --------------------------------------------------------------------------
+//
+TUpnpRenderingOperation CUpnpRenderingStateMachine::Current() const
+ {
+ __LOG( "CUpnpRenderingStateMachine::Current" );
+ return ( iQueue.Count() > 0 ) ? iQueue[0] : Upnp::ENone;
+ }
+
+// --------------------------------------------------------------------------
+// ResetArray
+// --------------------------------------------------------------------------
+//
+void ResetArray( TAny* iParam )
+ {
+ __LOG( "CUpnpRenderingStateMachine::ResetArray" );
+ RArray<TUpnpRenderingOperation>* array =
+ static_cast< RArray<TUpnpRenderingOperation>* >( iParam );
+ array->Reset();
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpRenderingStateMachine::ExecuteRecursivelyL
+// Runs an operation first in the queue. If during the operation there
+// were more operations added to queue, continues running recursively.
+// --------------------------------------------------------------------------
+//
+void CUpnpRenderingStateMachine::ExecuteRecursivelyL()
+ {
+ __LOG( "CUpnpRenderingStateMachine::ExecuteRecursivelyL" );
+ TUpnpRenderingOperation op = Current();
+ if ( op.IsValid() )
+ {
+ __LOG1( "OperationQueue: Executing %s",
+ CommandName(op.Command()) );
+ // if the operation fails, OperationArrayClose method will
+ // clean up the entire operations queue !
+ CleanupStack::PushL( TCleanupItem(
+ ResetArray, &iQueue ) );
+ MUpnpRenderingOperationExecutor::TResult result =
+ ExecuteOperationL( op,
+ Upnp::ENone );
+ CleanupStack::Pop();
+ switch( result )
+ {
+ case ECompleted:
+ {
+ __LOG1( "OperationQueue: %s completed while executing",
+ CommandName(op.Command()) );
+ if( iQueue.Count() > 0 )
+ {
+ iQueue.Remove( 0 );
+ ExecuteRecursivelyL(); // recur
+ }
+ break;
+ }
+ case EContinue:
+ {
+ // operation continues
+ break;
+ }
+ case EQueue:
+ default:
+ {
+ // illegal answer
+ __PANIC( __FILE__, __LINE__ );
+ }
+ }
+ }
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpRenderingStateMachine::ExecuteParallelL
+// Runs an operation that was requested to put to queue. Checks if it
+// completes right away or if it should wait for its turn to run.
+// --------------------------------------------------------------------------
+//
+void CUpnpRenderingStateMachine::ExecuteParallelL(
+ const TUpnpRenderingOperation& aOperation )
+ {
+ __LOG( "CUpnpRenderingStateMachine::ExecuteParallelL" );
+ TUpnpRenderingOperation current = Current();
+ __LOG1( "OperationQueue: Executing %s",
+ CommandName(aOperation.Command()) );
+ MUpnpRenderingOperationExecutor::TResult result =
+ ExecuteOperationL( aOperation, current );
+ switch( result )
+ {
+ case ECompleted:
+ {
+ __LOG1( "OperationQueue: %s completed while executing",
+ CommandName(aOperation.Command()) );
+ break;
+ }
+ case EQueue:
+ {
+ PushL( aOperation );
+ __LOG1( "OperationQueue: %s added to queue",
+ CommandName(aOperation.Command()) );
+ break;
+ }
+ case EContinue:
+ default:
+ {
+ // illegal answer
+ __PANIC( __FILE__, __LINE__ );
+ }
+ }
+ }
+
+// end of file