--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/upnpmpxplugins/upnpplaybackplugins/src/upnpvaluestatemachine.cpp Thu Dec 17 08:52:00 2009 +0200
@@ -0,0 +1,966 @@
+/*
+* 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 "upnpavdevice.h"
+#include "upnpitemutility.h" // for UPnPDurationToMilliseconds
+#include "upnpmusicplayer.h"
+#include "upnptrack.h" // for TrackDuration
+#include "upnpvaluestatemachine.h"
+#include "upnppluginserrortranslation.h"
+
+_LIT( KComponentLogfile, "musicplugins.txt");
+#include "upnplog.h"
+
+// CONSTANT
+const TInt KDefaultMaxVolume = 100;
+const TInt KDefaultMinVolume = 0;
+
+// ======== MEMBER FUNCTIONS ========
+
+// --------------------------------------------------------------------------
+// CUPnPValueStateMachine::NewL
+// 1st phase constructor.
+// --------------------------------------------------------------------------
+//
+CUPnPValueStateMachine* CUPnPValueStateMachine::NewL(
+ CUPnPMusicPlayer& aParent,
+ MUPnPAVRenderingSession& aRenderingSession )
+ {
+ __LOG( "ValueStateMachine: NewL" );
+ CUPnPValueStateMachine* self = new(ELeave)
+ CUPnPValueStateMachine( aParent, aRenderingSession );
+ return self;
+ }
+
+// --------------------------------------------------------------------------
+// CUPnPValueStateMachine::CUPnPValueStateMachine
+// Default constructor.
+// --------------------------------------------------------------------------
+//
+CUPnPValueStateMachine::CUPnPValueStateMachine(
+ CUPnPMusicPlayer& aParent,
+ MUPnPAVRenderingSession& aRenderingSession ) :
+ iParent( aParent ),
+ iRendererSession( aRenderingSession ),
+ iCurrentOperation( EOperationNone ),
+ iRendererVolume( KErrNotFound ),
+ iRendererMuted( KErrNotFound )
+ {
+ }
+
+
+// --------------------------------------------------------------------------
+// CUPnPValueStateMachine::~CUPnPValueStateMachine
+// Destructor.
+// --------------------------------------------------------------------------
+//
+CUPnPValueStateMachine::~CUPnPValueStateMachine()
+ {
+ __LOG( "ValueStateMachine: destructor" );
+ iOperationQueue.Close();
+ }
+
+// --------------------------------------------------------------------------
+// CUPnPValueStateMachine::CopyValues
+// copies renderer-specific cached values from another instance
+// --------------------------------------------------------------------------
+//
+void CUPnPValueStateMachine::CopyValues(
+ const CUPnPValueStateMachine& aOther )
+ {
+ iRendererVolume = aOther.iRendererVolume;
+ iRendererMuted = aOther.iRendererMuted;
+ }
+
+// --------------------------------------------------------------------------
+// CUPnPValueStateMachine::ValidatePropertyInState
+// defines the rules of getting / setting in different states
+// --------------------------------------------------------------------------
+//
+CUPnPValueStateMachine::TValidationResult
+ CUPnPValueStateMachine::ValidatePropertyInState(
+ TMPXPlaybackProperty aProperty,
+ TBool aSetting,
+ TInt aPlayerState,
+ TBool aIsReady )
+ {
+ switch( aProperty )
+ {
+ case EPbPropertyMaxVolume: // fall through
+ case EPbPropertyRemote: // fall through
+ case EPbPropertySupportedFeatures:
+ {
+ // allow getting in all states,
+ // trying to set will result to error
+ if ( !aSetting )
+ {
+ return EHandleStatic;
+ }
+ else
+ {
+ return EErrorNotSupported;
+ }
+ }
+ case EPbPropertyVolume: // fall through
+ case EPbPropertyMute:
+ {
+ // allow volume get/set after initialisation when remote device
+ // is ready. In other states respond with error
+ if ( aPlayerState ==
+ CUPnPMusicPlayer::EStateActive )
+ {
+ if( !aIsReady )
+ {
+ return EErrorNotReady;
+ }
+ else
+ {
+ return EHandle;
+ }
+ }
+ else if ( aPlayerState ==
+ CUPnPMusicPlayer::EStatePreInitialized ||
+ aPlayerState ==
+ CUPnPMusicPlayer::EStateWaiting ||
+ aPlayerState ==
+ CUPnPMusicPlayer::EStateActiveForceInitialise )
+ {
+ return EHandle;
+ }
+ else
+ {
+ return EErrorNotReady;
+ }
+ }
+ case EPbPropertyDuration:
+ {
+ // duration setting is not allowed
+ // getting is allowed after initialised, but will result
+ // to returning plain zero in other states except active
+ // when it is actually asked from the device
+ if ( aSetting )
+ {
+ return EErrorNotSupported;
+ }
+ else if ( aPlayerState ==
+ CUPnPMusicPlayer::EStateActive )
+ {
+ if( aIsReady )
+ {
+ return EHandle;
+ }
+ else
+ {
+ // On active state but device is not ready ->
+ // Use initial values.
+ return EHandleStatic;
+ }
+ }
+ else if ( aPlayerState ==
+ CUPnPMusicPlayer::EStatePreInitialized ||
+ aPlayerState ==
+ CUPnPMusicPlayer::EStateWaiting ||
+ aPlayerState ==
+ CUPnPMusicPlayer::EStateActiveForceInitialise )
+ {
+ return EHandleStatic;
+ }
+ else
+ {
+ return EErrorNotReady;
+ }
+ }
+ case EPbPropertyPosition:
+ {
+ // position get/set is allowed after init when remote device
+ // is ready. Only active state it will result to real action
+ if ( aPlayerState ==
+ CUPnPMusicPlayer::EStateActive )
+ {
+ if( aIsReady )
+ {
+ return EHandle;
+ }
+ else
+ {
+ // On active state but device is not ready ->
+ // Use initial values.
+ return EHandleStatic;
+ }
+ }
+ else if ( aPlayerState ==
+ CUPnPMusicPlayer::EStatePreInitialized ||
+ aPlayerState ==
+ CUPnPMusicPlayer::EStateWaiting ||
+ aPlayerState ==
+ CUPnPMusicPlayer::EStateActiveForceInitialise )
+ {
+ return EHandleStatic;
+ }
+ else
+ {
+ return EErrorNotReady;
+ }
+ }
+ default:
+ {
+ // unsupported property
+ return EErrorNotSupported;
+ }
+ }
+ }
+
+
+// --------------------------------------------------------------------------
+// CUPnPValueStateMachine::SetL
+// --------------------------------------------------------------------------
+//
+void CUPnPValueStateMachine::SetL( TMPXPlaybackProperty aProperty,
+ TInt aValue )
+ {
+ // Check if volume or mute is supported by device
+ if( ( aProperty == EPbPropertyVolume &&
+ !iParent.UsedRendererDevice().VolumeCapability() ) ||
+ ( aProperty == EPbPropertyMute &&
+ !iParent.UsedRendererDevice().MuteCapability() )
+ )
+ {
+ __LOG( "ValueStateMachine::SetL - \
+ Request is not supported by device" );
+ iParent.Observer().HandlePluginEvent(
+ MMPXPlaybackPluginObserver::EPSetComplete,
+ (TInt)aProperty, KErrNotSupported );
+
+ return;
+ }
+
+ // Check from queue if alredy requested.
+ if( FoundFromQueue( aProperty ) )
+ {
+ __LOG( "ValueStateMachine::SetL: Volume query Ignored!" );
+ // Ignore
+ return;
+ }
+
+ if ( !iCurrentOperation.None() )
+ {
+ __LOG( "ValueStateMachine::SetL - Append to queue" );
+ iOperationQueue.AppendL( TOperation( aProperty, aValue ) );
+ return;
+ }
+
+ switch( aProperty )
+ {
+ case EPbPropertyVolume:
+ {
+ __LOG1( "ValueStateMachine: SetVolume(%d)",
+ aValue );
+ // Set the volume, do a sanity check
+ if( aValue < KDefaultMinVolume || aValue > KDefaultMaxVolume )
+ {
+ // Given value out of range
+ CheckOperationInQueueL();
+ iParent.Observer().HandlePluginEvent(
+ MMPXPlaybackPluginObserver::EPSetComplete,
+ aProperty, KErrArgument );
+ }
+ else if ( aValue == iRendererVolume )
+ {
+ // re-setting the same volume
+ if ( iRendererMuted )
+ {
+ MuteRequestL( 0 );
+ }
+ iParent.Observer().HandlePluginEvent(
+ MMPXPlaybackPluginObserver::EPSetComplete,
+ aProperty, KErrNone );
+ }
+ else
+ {
+ iCurrentOperation.Set( aProperty, aValue );
+ iRendererSession.SetVolumeL( aValue );
+ if ( iRendererMuted )
+ {
+ // unmute after volume has been adjusted
+ MuteRequestL( 0 );
+ }
+ }
+ break;
+ }
+ case EPbPropertyMute:
+ {
+ __LOG1( "ValueStateMachine: SetMute(%d)",
+ aValue );
+ if( aValue != 0 && iRendererMuted != 1 )
+ {
+ // set mute on
+ iCurrentOperation.Set( aProperty, 1 );
+ iRendererSession.SetMuteL( ETrue );
+ }
+ else if ( aValue == 0 && iRendererMuted != 0 )
+ {
+ // set mute off
+ iCurrentOperation.Set( aProperty, 0 );
+ iRendererSession.SetMuteL( EFalse );
+ }
+ else
+ {
+ // mute is already in requested state
+ CheckOperationInQueueL();
+ iParent.Observer().HandlePluginEvent(
+ MMPXPlaybackPluginObserver::EPSetComplete,
+ aProperty, KErrNone );
+ }
+ break;
+ }
+ default: // Given property is not supported
+ {
+ __LOG( "ValueStateMachine: Set - default" );
+ CheckOperationInQueueL();
+ iParent.Observer().HandlePluginEvent(
+ MMPXPlaybackPluginObserver::EPSetComplete,
+ aProperty, KErrNotSupported );
+ break;
+ }
+ }
+
+ }
+
+// --------------------------------------------------------------------------
+// CUPnPValueStateMachine::ValueL
+// --------------------------------------------------------------------------
+//
+void CUPnPValueStateMachine::ValueL( TMPXPlaybackProperty aProperty )
+ {
+ // Check if volume or mute is supported by device
+ if( ( aProperty == EPbPropertyVolume &&
+ !iParent.UsedRendererDevice().VolumeCapability() ) ||
+ ( aProperty == EPbPropertyMute &&
+ !iParent.UsedRendererDevice().MuteCapability() )
+ )
+ {
+ __LOG( "ValueStateMachine::ValueL - \
+ Request is not supported by device" );
+ iParent.Observer().HandlePluginEvent(
+ MMPXPlaybackPluginObserver::EPSetComplete,
+ (TInt)aProperty, KErrNotSupported );
+
+ return;
+ }
+
+ if ( !iCurrentOperation.None() )
+ {
+ __LOG( "ValueStateMachine::ValueL - Append to queue" );
+ iOperationQueue.AppendL( TOperation( aProperty ) );
+ return;
+ }
+
+ switch( aProperty )
+ {
+ case EPbPropertyVolume:
+ {
+ __LOG( "ValueStateMachine: Value(volume)" );
+ iRendererSession.GetVolumeL();
+ iCurrentOperation.Set( aProperty );
+ break;
+ }
+ case EPbPropertyMute:
+ {
+ __LOG( "ValueStateMachine: Value(mute)" );
+ iRendererSession.GetMuteL();
+ iCurrentOperation.Set( aProperty );
+ break;
+ }
+ case EPbPropertyDuration:
+ {
+ __LOG( "ValueStateMachine: Value(duration)" );
+ if ( iParent.Track().TrackDuration() > 0 )
+ {
+ // duration found in cache
+ CheckOperationInQueueL();
+ iParent.Observer().HandleProperty( aProperty,
+ iParent.Track().TrackDuration(), KErrNone );
+ }
+ else
+ {
+ iRendererSession.GetPositionInfoL();
+ iCurrentOperation.Set( aProperty );
+ }
+ break;
+ }
+ case EPbPropertyPosition:
+ {
+ __LOG( "ValueStateMachine: Value(position)" );
+ iRendererSession.GetPositionInfoL();
+ iCurrentOperation.Set( aProperty );
+ break;
+ }
+ default:
+ {
+ __PANICD( __FILE__, __LINE__ );
+ break;
+ }
+ }
+ }
+
+
+// --------------------------------------------------------------------------
+// CUPnPValueStateMachine::ValueStatic
+// --------------------------------------------------------------------------
+//
+void CUPnPValueStateMachine::ValueStatic(
+ TMPXPlaybackProperty aProperty,
+ MMPXPlaybackPluginObserver& aPlaybackObs )
+ {
+ switch( aProperty )
+ {
+ case EPbPropertyMaxVolume:
+ {
+ __LOG( "ValueStateMachine: ValueStatic(max volume)" );
+ aPlaybackObs.HandleProperty( aProperty,
+ KDefaultMaxVolume, KErrNone );
+ break;
+ }
+ case EPbPropertyRemote:
+ {
+ __LOG( "ValueStateMachine: ValueStatic(remote)" );
+ aPlaybackObs.HandleProperty( aProperty,
+ (TInt)EFalse, KErrNone );
+ break;
+ }
+ case EPbPropertySupportedFeatures:
+ {
+ __LOG( "ValueStateMachine: ValueStatic(features)" );
+ // No support for any features
+ TInt supportedFeatures = 0;
+ aPlaybackObs.HandleProperty( aProperty,
+ supportedFeatures, KErrNone );
+ break;
+ }
+ case EPbPropertyDuration:
+ {
+ __LOG( "ValueStateMachine: ValueStatic(duration)" );
+ TInt initialDuration = 0;
+ aPlaybackObs.HandleProperty( aProperty,
+ initialDuration, KErrNone );
+ break;
+ }
+ case EPbPropertyPosition:
+ {
+ __LOG( "ValueStateMachine: ValueStatic(position)" );
+ TInt initialPosition = 1;
+ aPlaybackObs.HandleProperty( aProperty,
+ initialPosition, KErrNone );
+ break;
+ }
+ default:
+ {
+ __PANICD( __FILE__, __LINE__ );
+ break;
+ }
+ }
+ }
+
+// --------------------------------------------------------------------------
+// CUPnPValueStateMachine::DurationQueryL
+// --------------------------------------------------------------------------
+//
+void CUPnPValueStateMachine::DurationQueryL()
+ {
+ // here we could check if the duration is already present in
+ // iParent.track() however it was decided that we check the duration
+ // from renderer anyway and trust the renderer's duration more.
+ if ( !iCurrentOperation.None() )
+ {
+ __LOG( "ValueStateMachine::DurationQueryL - Append to queue" );
+ iOperationQueue.AppendL( EOperationDurationQuery );
+ return;
+ }
+
+ __LOG( "ValueStateMachine::DurationQueryL" );
+ iRendererSession.GetPositionInfoL();
+ iCurrentOperation = EOperationDurationQuery;
+ }
+
+// --------------------------------------------------------------------------
+// CUPnPValueStateMachine::PositionQueryL
+// --------------------------------------------------------------------------
+//
+void CUPnPValueStateMachine::PositionQueryL()
+ {
+ __LOG( "ValueStateMachine::PositionQueryL" );
+
+ if ( !iCurrentOperation.None() )
+ {
+ __LOG( "ValueStateMachine::PositionQueryL - Append to queue" );
+ iOperationQueue.AppendL( EOperationPositionQuery );
+ return;
+ }
+ iRendererSession.GetPositionInfoL();
+ iCurrentOperation = EOperationPositionQuery;
+ }
+
+// --------------------------------------------------------------------------
+// CUPnPValueStateMachine::VolumeQueryL
+// --------------------------------------------------------------------------
+//
+void CUPnPValueStateMachine::VolumeQueryL()
+ {
+ // Check if volume feature is supported by device.
+ if( iParent.UsedRendererDevice().VolumeCapability() )
+ {
+ if ( iRendererVolume != KErrNotFound )
+ {
+ // Volume query not required - already cached.
+ return;
+ }
+
+ if ( !iCurrentOperation.None() )
+ {
+ __LOG( "ValueStateMachine::VolumeQueryL - Append to queue" );
+ iOperationQueue.AppendL( EOperationVolumeQuery );
+ return;
+ }
+
+ __LOG( "ValueStateMachine::VolumeQueryL" );
+ iRendererSession.GetVolumeL();
+ iCurrentOperation = EOperationVolumeQuery;
+ }
+ else
+ {
+ // Get volume is not supported. Do nothing.
+ }
+ }
+
+// --------------------------------------------------------------------------
+// CUPnPValueStateMachine::MuteRequestL
+// --------------------------------------------------------------------------
+//
+void CUPnPValueStateMachine::MuteRequestL( TInt aMute )
+ {
+ if ( !iCurrentOperation.None() )
+ {
+ __LOG( "ValueStateMachine::MuteRequestL - Append to queue" );
+ iOperationQueue.AppendL( TOperation( EOperationMute, aMute ) );
+ return;
+ }
+
+ __LOG1( "ValueStateMachine: MuteRequest(%d)", aMute );
+ if( aMute != 0 && iRendererMuted != 1 )
+ {
+ // set mute on
+ iCurrentOperation = EOperationMute;
+ iRendererSession.SetMuteL( ETrue );
+ }
+ else if ( aMute == 0 && iRendererMuted != 0 )
+ {
+ // set mute off
+ iCurrentOperation = EOperationMute;
+ iRendererSession.SetMuteL( EFalse );
+ }
+ else
+ {
+ // mute is already in requested state
+ CheckOperationInQueueL();
+ }
+ }
+
+// --------------------------------------------------------------------------
+// CUPnPValueStateMachine::VolumeResult
+// --------------------------------------------------------------------------
+//
+void CUPnPValueStateMachine::VolumeResult( TInt aError, TInt aVolumeLevel,
+ TBool aActionResponse )
+ {
+ aError = TUpnpPluginsErrorTranslation::ErrorTranslate( aError );
+ // If response for get volume
+
+ if( aActionResponse )
+ {
+ if (aError == KErrNone)
+ {
+ iRendererVolume = aVolumeLevel;
+ }
+
+ if( iCurrentOperation.Compare( EOperationValue, EPbPropertyVolume ) )
+ {
+ __LOG( "ValueStateMachine::VolumeResult: Value resp." );
+
+ iCurrentOperation.Reset();
+ TRAP_IGNORE( CheckOperationInQueueL() );
+ iParent.Observer().HandleProperty( EPbPropertyVolume,
+ iRendererVolume, aError );
+ }
+ else if( iCurrentOperation.Compare( EOperationSet,
+ EPbPropertyVolume ) )
+ {
+ __LOG( "ValueStateMachine::VolumeResult: Set resp." );
+ iCurrentOperation.Reset();
+ TRAP_IGNORE( CheckOperationInQueueL() );
+ iParent.Observer().HandlePluginEvent(
+ MMPXPlaybackPluginObserver::EPSetComplete,
+ (TInt)EPbPropertyVolume, aError );
+ }
+ else if ( iCurrentOperation == EOperationVolumeQuery )
+ {
+ __LOG1("VolumeQueryResult: Volume query resp err=%d", aError );
+
+ if ( aError == KErrNone )
+ {
+ iParent.Observer().HandlePluginEvent(
+ MMPXPlaybackPluginObserver::EPVolumeChanged,
+ iRendererVolume, aError );
+ }
+
+ iCurrentOperation.Reset();
+ TRAP_IGNORE( CheckOperationInQueueL() );
+ }
+ else
+ {
+ iCurrentOperation.Reset();
+ __LOG( "ValueStateMachine::VolumeResult: no request?" );
+ }
+ }
+ else // Volume changed from device
+ {
+ // Ignore volume events from device if volume control
+ // is ongoing on handset.
+ if( iCurrentOperation.Compare( EOperationSet, EPbPropertyVolume ) )
+ {
+ return;
+ }
+
+ if (aError == KErrNone)
+ {
+ iRendererVolume = aVolumeLevel;
+ }
+
+ if ( !iRendererMuted )
+ {
+ __LOG1( "ValueStateMachine::VolumeResult: from device: (%d)",
+ aVolumeLevel );
+ iParent.Observer().HandlePluginEvent(
+ MMPXPlaybackPluginObserver::EPVolumeChanged,
+ iRendererVolume, aError );
+ }
+ else
+ {
+ __LOG( "ValueStateMachine::VolumeResult: from device (muted)" );
+ }
+ }
+ }
+
+// --------------------------------------------------------------------------
+// CUPnPValueStateMachine::MuteResult
+// --------------------------------------------------------------------------
+//
+void CUPnPValueStateMachine::MuteResult( TInt aError, TBool aMute,
+ TBool aActionResponse )
+ {
+ aError = TUpnpPluginsErrorTranslation::ErrorTranslate( aError );
+ // Response for set mute
+ if( aActionResponse )
+ {
+ if( iCurrentOperation.Compare( EOperationValue, EPbPropertyMute ) )
+ {
+ __LOG( "ValueStateMachine::MuteResult: Value resp." );
+ iRendererMuted = aMute;
+ iCurrentOperation.Reset();
+ TRAP_IGNORE( CheckOperationInQueueL() );
+ iParent.Observer().HandleProperty( EPbPropertyMute,
+ (TInt)aMute, aError );
+ }
+ else if ( iCurrentOperation.Compare( EOperationSet,
+ EPbPropertyMute ) )
+ {
+ __LOG( "ValueStateMachine::MuteResult: Set resp." );
+ iRendererMuted = aMute;
+ iCurrentOperation.Reset();
+ TRAP_IGNORE( CheckOperationInQueueL() );
+ iParent.Observer().HandlePluginEvent(
+ MMPXPlaybackPluginObserver::EPSetComplete,
+ (TInt)EPbPropertyMute, aError );
+ }
+ else if ( iCurrentOperation == EOperationMute )
+ {
+ // internal operation, no event.
+ iRendererMuted = aMute;
+ iCurrentOperation.Reset();
+ TRAP_IGNORE( CheckOperationInQueueL() );
+ }
+ else
+ {
+ iRendererMuted = aMute;
+ iCurrentOperation.Reset();
+ __LOG( "ValueStateMachine::MuteResult: no request?" );
+ }
+ }
+ else // Mute changed from device
+ {
+ __LOG( "ValueStateMachine::MuteResult: Mute changed from device" );
+
+ if( aMute )
+ {
+ iRendererMuted = ETrue;
+ iParent.Observer().HandlePluginEvent(
+ MMPXPlaybackPluginObserver::EPVolumeChanged,
+ 0, aError );
+ }
+ else
+ {
+ iRendererMuted = EFalse;
+ iParent.Observer().HandlePluginEvent(
+ MMPXPlaybackPluginObserver::EPVolumeChanged,
+ iRendererVolume, aError );
+ }
+ }
+ }
+
+// --------------------------------------------------------------------------
+// CUPnPValueStateMachine::PositionInfoResult
+// --------------------------------------------------------------------------
+//
+void CUPnPValueStateMachine::PositionInfoResult( TInt aStatus,
+ const TDesC8& aTrackPosition, const TDesC8& aTrackLength )
+ {
+ // Check if position info was asked
+ if( iCurrentOperation.Compare( EOperationValue, EPbPropertyPosition ) )
+ {
+ __LOG1( "Position response err=%d", aStatus );
+ TInt ms = 0;
+ if( aStatus == KErrNone )
+ {
+ // Convert the descriptor to integer value
+ aStatus = UPnPItemUtility::UPnPDurationAsMilliseconds(
+ aTrackPosition, ms );
+ __LOG2( "ValueStateMachine::PositionInfoResult position=%d err=%d",
+ ms, aStatus );
+ }
+ iCurrentOperation.Reset();
+ TRAP_IGNORE( CheckOperationInQueueL() );
+
+ // Use initial position value in case of errors or position 0.
+ // This will guarantee that in case of unpause, SetPosition
+ // is called with real value even if remote player does not
+ // return real value for getposition call. Note that
+ // SetPosition(0) is used when user really wants to move to
+ // track beginning.
+ if( aStatus != KErrNone )
+ {
+ // GetPositionInfo is not supported by used device.
+ iParent.Observer().HandleProperty( EPbPropertyPosition, 1,
+ KErrNotSupported );
+ }
+ else
+ {
+ if( ms == 0 )
+ {
+ ms = 1;
+ }
+ iParent.Observer().HandleProperty( EPbPropertyPosition, ms,
+ aStatus );
+ }
+ }
+ else if ( iCurrentOperation == EOperationPositionQuery )
+ {
+ __LOG1( "PositionQuery response err=%d", aStatus );
+ TInt ms = 0;
+ if( aStatus == KErrNone )
+ {
+ // Convert the descriptor to integer value
+ aStatus = UPnPItemUtility::UPnPDurationAsMilliseconds(
+ aTrackPosition, ms );
+ __LOG2( "ValueStateMachine::PositionInfoResult position=%d err=%d",
+ ms, aStatus );
+ }
+ iCurrentOperation.Reset();
+ TRAP_IGNORE( CheckOperationInQueueL() );
+
+ if( aStatus == KErrNone )
+ {
+ if( ms == 0 )
+ {
+ ms = 1;
+ }
+ //iParent.Observer().HandlePluginEvent(
+ //MMPXPlaybackPluginObserver::EPPositionChanged, ms, KErrNone );
+ }
+ }
+ // Check if duration info was asked
+ else if( iCurrentOperation.Compare( EOperationValue,
+ EPbPropertyDuration ) )
+ {
+ __LOG1( "Duration response err=%d", aStatus );
+ TInt ms = 0;
+ if( aStatus == KErrNone )
+ {
+ aStatus = UPnPItemUtility::UPnPDurationAsMilliseconds(
+ aTrackLength, ms );
+ __LOG2( "ValueStateMachine::PositionInfoResult -\
+ duration=%d err=%d", ms, aStatus );
+
+ if ( aStatus == KErrNone )
+ {
+ iParent.Track().SetTrackDuration( ms );
+ }
+ }
+ iCurrentOperation.Reset();
+ TRAP_IGNORE( CheckOperationInQueueL() );
+
+ if( aStatus == KErrNotSupported )
+ {
+ // GetDuration is not supported by used device.
+ // Use initial duration value (1). It will guarantee that in
+ // case of unpause, SetPosition is called with real value even
+ // if remote player does not return real value for getposition
+ // call. Note that SetPosition(0) is used when user really wants
+ // to move to track beginning.
+ iParent.Observer().HandleProperty( EPbPropertyDuration, 1,
+ KErrNone );
+ }
+ else
+ {
+ iParent.Observer().HandleProperty( EPbPropertyDuration,
+ ms, aStatus );
+ }
+ }
+ else if ( iCurrentOperation == EOperationDurationQuery )
+ {
+ __LOG1( "DurationQuery response err=%d", aStatus );
+ TInt ms = 0;
+ if( aStatus == KErrNone )
+ {
+ aStatus = UPnPItemUtility::UPnPDurationAsMilliseconds(
+ aTrackLength, ms );
+ __LOG2( "ValueStateMachine::PositionInfoResult - \
+ duration=%d err=%d",
+ ms, aStatus );
+ if ( aStatus == KErrNone )
+ {
+ iParent.Track().SetTrackDuration( ms );
+ }
+ }
+ iCurrentOperation.Reset();
+ TRAP_IGNORE( CheckOperationInQueueL() );
+
+ if ( iParent.Track().TrackDuration() > 0 && aStatus == KErrNone )
+ {
+ iParent.Observer().HandlePluginEvent(
+ MMPXPlaybackPluginObserver::EPDurationChanged,
+ iParent.Track().TrackDuration(), KErrNone );
+ }
+ }
+ else
+ {
+ __LOG( "ValueStateMachine::PositionInfoResult: no request?" );
+ }
+ }
+
+
+
+// --------------------------------------------------------------------------
+// CUPnPValueStateMachine::Cancel
+// --------------------------------------------------------------------------
+//
+void CUPnPValueStateMachine::Cancel()
+ {
+ // reset current operation and empty the queue -> no callbacks.
+ iCurrentOperation.Reset();
+ iOperationQueue.Reset();
+ }
+
+// --------------------------------------------------------------------------
+// CUPnPValueStateMachine::CheckOperationInQueueL
+// Checks if operations are in the queue, and executes
+// --------------------------------------------------------------------------
+//
+void CUPnPValueStateMachine::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 == EOperationValue )
+ {
+ ValueL( op.iProperty );
+ }
+ else if ( op == EOperationSet )
+ {
+ SetL( op.iProperty, op.iValue );
+ }
+ else if ( op == EOperationDurationQuery )
+ {
+ DurationQueryL();
+ }
+ else if ( op == EOperationVolumeQuery )
+ {
+ VolumeQueryL();
+ }
+ else if ( op == EOperationPositionQuery )
+ {
+ PositionQueryL();
+ }
+ else if ( op == EOperationMute )
+ {
+ MuteRequestL( op.iValue );
+ }
+ else
+ {
+ __PANICD( __FILE__, __LINE__ );
+ }
+ }
+ }
+
+// --------------------------------------------------------------------------
+// CUPnPValueStateMachine::FoundFromQueue
+// Checks if operations are in the queue
+// --------------------------------------------------------------------------
+//
+TBool CUPnPValueStateMachine::FoundFromQueue(TMPXPlaybackProperty aProperty)
+ {
+ TBool found = EFalse;
+ TInt count = iOperationQueue.Count();
+
+ for( TInt i = 0; i < count; i++ )
+ {
+ TOperation op = iOperationQueue[i];
+ if( op.iProperty == aProperty )
+ {
+ found = ETrue;
+ break;
+ }
+ }
+ return found;
+ }
+
+