--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/upnpavcontroller/upnprenderingstatemachine/src/upnpvolumestatemachine.cpp Wed Nov 03 11:45:09 2010 +0200
@@ -0,0 +1,835 @@
+/*
+* 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 volume state machine
+*
+*/
+
+
+// INCLUDES
+// avcontroller api
+#include <upnpavrenderingsession.h>
+#include <upnpavdevice.h> // for device.VolumeCapability()
+// volume state machine
+#include "upnprenderingstatemachineconstants.h" // option flags
+#include "upnpvolumestatemachineobserver.h"
+#include "upnpvolumestatemachine.h"
+
+_LIT( KComponentLogfile, "upnprenderingengine.txt");
+#include "upnplog.h"
+
+// CONSTANTS
+const TInt KCancelTimeMaximum = 3000000;
+const TInt KCancelTimeResolution = 500000;
+
+// ======== MEMBER FUNCTIONS ========
+
+
+TUpnpVSMQueueItem::TUpnpVSMQueueItem(
+ const TUpnpVSMQueueItem::TPropertyType aProperty, const TInt aValue )
+ : iProperty( aProperty )
+ , iValue( aValue )
+ {
+ }
+
+TUpnpVSMQueueItem::TPropertyType TUpnpVSMQueueItem::Property() const
+ {
+ return iProperty;
+ }
+
+TInt TUpnpVSMQueueItem::Value() const
+ {
+ return iValue;
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpVolumeStateMachine::NewL
+// Static constructor.
+// --------------------------------------------------------------------------
+//
+EXPORT_C CUpnpVolumeStateMachine* CUpnpVolumeStateMachine::NewL(
+ MUPnPAVRenderingSession& aSession )
+ {
+ CUpnpVolumeStateMachine* self =
+ new (ELeave) CUpnpVolumeStateMachine( aSession );
+ // no 2nd phase construction needed
+ return self;
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpVolumeStateMachine::CUpnpVolumeStateMachine
+// Default constructor.
+// --------------------------------------------------------------------------
+//
+CUpnpVolumeStateMachine::CUpnpVolumeStateMachine(
+ MUPnPAVRenderingSession& aSession )
+ : iSession( aSession )
+ {
+ __LOG( "VolumeStateMachine: constructor" );
+ iVolumeCapability = iSession.Device().VolumeCapability();
+ iMuteCapability = iSession.Device().MuteCapability();
+ iState = EOffSync;
+ iCurrentVolume = KErrNotFound;
+ iVolumeToSetAfterMute = KErrNotFound;
+ iCurrentMute = KErrNotFound;
+ iMuteRequestedByClient = EFalse;
+ iCachedVolume = KErrNotFound;
+ iCachedMute = KErrNotFound;
+ }
+
+
+// --------------------------------------------------------------------------
+// CUpnpVolumeStateMachine::~CUpnpVolumeStateMachine
+// Destructor.
+// --------------------------------------------------------------------------
+//
+EXPORT_C CUpnpVolumeStateMachine::~CUpnpVolumeStateMachine()
+ {
+ __LOG( "VolumeStateMachine: destructor" );
+ }
+
+
+// --------------------------------------------------------------------------
+// CUpnpVolumeStateMachine::SetOptions
+// sets the option flags for this state machine
+// --------------------------------------------------------------------------
+//
+EXPORT_C void CUpnpVolumeStateMachine::SetOptions( TInt aOptions )
+ {
+ iOptions = aOptions;
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpVolumeStateMachine::Options
+// --------------------------------------------------------------------------
+//
+EXPORT_C TInt CUpnpVolumeStateMachine::Options() const
+ {
+ return iOptions;
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpVolumeStateMachine::SetObserver
+// --------------------------------------------------------------------------
+//
+EXPORT_C void CUpnpVolumeStateMachine::SetObserver(
+ MUpnpVolumeStateMachineObserver& aObserver )
+ {
+ iObserver = &aObserver;
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpVolumeStateMachine::RemoveObserver
+// --------------------------------------------------------------------------
+//
+EXPORT_C void CUpnpVolumeStateMachine::RemoveObserver()
+ {
+ iObserver = NULL;
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpVolumeStateMachine::SyncL
+// Synchronises this state machine with the renderer
+// --------------------------------------------------------------------------
+//
+EXPORT_C void CUpnpVolumeStateMachine::SyncL()
+ {
+ __LOG( "VolumeStateMachine: SyncL" );
+
+ if ( iState != EOffSync && iState != EIdle )
+ {
+ __LOG( "VolumeStateMachine: not synchronizing" );
+ return;
+ }
+
+ if ( !iVolumeCapability )
+ {
+ User::Leave( KErrNotSupported );
+ }
+
+ iSession.GetVolumeL();
+ iState = ESyncing;
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpVolumeStateMachine::SetOffSync
+// Forces the state machine off sync
+// --------------------------------------------------------------------------
+//
+EXPORT_C void CUpnpVolumeStateMachine::SetOffSync()
+ {
+ __ASSERTD( !IsBusy(), __FILE__, __LINE__ );
+ iState = EOffSync;
+ iCurrentVolume = KErrNotFound;
+ iVolumeToSetAfterMute = KErrNotFound;
+ iCurrentMute = KErrNotFound;
+ iMuteRequestedByClient = EFalse;
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpVolumeStateMachine::IsInSync
+// --------------------------------------------------------------------------
+//
+EXPORT_C TBool CUpnpVolumeStateMachine::IsInSync() const
+ {
+ return iState != EOffSync;
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpVolumeStateMachine::SetVolumeL
+// --------------------------------------------------------------------------
+//
+EXPORT_C void CUpnpVolumeStateMachine::SetVolumeL( TInt aVolume )
+ {
+ __LOG1( "VolumeStateMachine: SetVolumeL %d", aVolume );
+ __ASSERTD( IsInSync(), __FILE__, __LINE__ );
+ if ( !iVolumeCapability )
+ {
+ User::Leave( KErrNotSupported );
+ }
+
+ if ( IsBusy() )
+ {
+ PushIntoQueueL( TUpnpVSMQueueItem::EVolume, aVolume );
+ return;
+ }
+
+ // check volume is between given limits
+ aVolume = Max( aVolume, KVolumeMin );
+ aVolume = Min( aVolume, KVolumeMax );
+
+ if ( aVolume == KVolumeMin && iCurrentVolume > 0 &&
+ iMuteCapability && iCurrentMute == KMuteOff &&
+ iOptions & Upnp::EConvertVolumeZeroToMute )
+ {
+ // adjust volume to zero (using mute)
+ iSession.SetMuteL( ETrue );
+ iState = EAdjustingVolumeToZero;
+ }
+ else if ( aVolume == KVolumeMin && iCurrentMute == KMuteOn )
+ {
+ // no need to change volume. Call back directly.
+ if ( iObserver )
+ {
+ iObserver->VolumeChanged(
+ KErrNone, iCurrentVolume, ETrue );
+ }
+ }
+ else if ( aVolume > KVolumeMin && iCurrentMute == KMuteOn &&
+ !iMuteRequestedByClient )
+ {
+ // volume is at zero, and renderer is muted.
+ // unmute and after that change volume if needed
+ iVolumeToSetAfterMute = aVolume;
+ iSession.SetMuteL( EFalse );
+ iState = EAdjustingVolumeFromZero;
+ }
+ else if ( aVolume != iCurrentVolume )
+ {
+ // adjust volume normally
+ iSession.SetVolumeL( aVolume );
+ iState = EAdjustingVolume;
+ }
+ else
+ {
+ // no need to change volume. Call back directly.
+ if ( iObserver )
+ {
+ iObserver->VolumeChanged(
+ KErrNone, iCurrentVolume, ETrue );
+ }
+ }
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpVolumeStateMachine::Volume
+// --------------------------------------------------------------------------
+//
+EXPORT_C TInt CUpnpVolumeStateMachine::Volume() const
+ {
+ __ASSERTD( IsInSync(), __FILE__, __LINE__ );
+ TInt vol = iCurrentVolume;
+ if ( iCurrentMute && (iOptions & Upnp::EConvertVolumeZeroToMute) )
+ {
+ vol = KVolumeMin;
+ }
+ return vol;
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpVolumeStateMachine::SetMuteL
+// --------------------------------------------------------------------------
+//
+EXPORT_C void CUpnpVolumeStateMachine::SetMuteL( TBool aMuteState )
+ {
+ __LOG1( "VolumeStateMachine: SetMuteL", aMuteState );
+ __ASSERTD( IsInSync(), __FILE__, __LINE__ );
+ if ( !iMuteCapability )
+ {
+ // Could implement here FAKE MUTE SUPPORT by converting mute
+ // to Volume(0). However there is no need to that since no clients
+ // use the mute feature.
+ User::Leave( KErrNotSupported );
+ }
+ if ( IsBusy() )
+ {
+ PushIntoQueueL( TUpnpVSMQueueItem::EMute, aMuteState );
+ return;
+ }
+
+ // check mute state is between given limits
+ aMuteState = Max( aMuteState, KMuteOff );
+ aMuteState = Min( aMuteState, KMuteOn );
+
+ if ( aMuteState && !iCurrentMute )
+ {
+ // mute
+ iSession.SetMuteL( ETrue );
+ iState = EAdjustingMute;
+ }
+ else if ( !aMuteState && iCurrentMute )
+ {
+ // unmute
+ iSession.SetMuteL( EFalse );
+ iState = EAdjustingMute;
+ }
+ else
+ {
+ // no change in mute state. Call back directly.
+ if ( iObserver )
+ {
+ iObserver->MuteChanged(
+ KErrNone, iCurrentMute, ETrue );
+ }
+ }
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpVolumeStateMachine::Mute
+// --------------------------------------------------------------------------
+//
+EXPORT_C TBool CUpnpVolumeStateMachine::Mute() const
+ {
+ __ASSERTD( IsInSync(), __FILE__, __LINE__ );
+ return ( (iCurrentMute == KMuteOn) ? KMuteOn : KMuteOff );
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpVolumeStateMachine::IsBusy
+// --------------------------------------------------------------------------
+//
+EXPORT_C TBool CUpnpVolumeStateMachine::IsBusy() const
+ {
+ return iState != EIdle;
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpVolumeStateMachine::HasVolumeCapability
+// tests if renderer has volume capability
+// --------------------------------------------------------------------------
+//
+EXPORT_C TBool CUpnpVolumeStateMachine::HasVolumeCapability() const
+ {
+ return iVolumeCapability;
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpVolumeStateMachine::Cancel
+// --------------------------------------------------------------------------
+//
+EXPORT_C void CUpnpVolumeStateMachine::Cancel()
+ {
+ // actually we can not cancel anything, but providing the interface for
+ // future purposes
+ if ( iState != EIdle )
+ {
+ __LOG1( "VolumeStateMachine: Canceling in state %d", iState );
+ iState = ECancelled;
+ for ( TInt t = KCancelTimeMaximum;
+ t > 0 && iState != EIdle;
+ t -= KCancelTimeResolution )
+ {
+ User::After( TTimeIntervalMicroSeconds32(
+ KCancelTimeResolution ) );
+ }
+ __LOG1( "VolumeStateMachine: state after cancel: %d", iState );
+ }
+ }
+
+void CUpnpVolumeStateMachine::HandleVolumeResultInSyncState(
+ TInt aError, TInt aVolumeLevel, TBool /*aActionResponse*/ )
+ {
+ if ( aError == KErrNone )
+ {
+ iCurrentVolume = aVolumeLevel;
+ if ( iMuteCapability )
+ {
+ // continue to sync mute
+ TRAPD( muteError, iSession.GetMuteL() );
+ if ( muteError != KErrNone )
+ {
+ // error syncing mute - callback
+ iState = EIdle;
+ if ( iObserver )
+ {
+ iObserver->VolumeSyncReady( muteError );
+ }
+ }
+ }
+ else
+ {
+ // mute not needed - callback
+ iCurrentMute = KMuteOff; // assume always off
+ iState = EIdle;
+ // notify sync initially and volume if changed
+ if ( iObserver && iCachedVolume == KErrNotFound )
+ {
+ iObserver->VolumeSyncReady( KErrNone );
+ }
+ else if ( iObserver && iCachedVolume != iCurrentVolume )
+ {
+ iObserver->VolumeChanged(
+ aError, iCurrentVolume, EFalse );
+ }
+ }
+ }
+ else
+ {
+ // error callback
+ iState = EIdle;
+ if ( iObserver )
+ {
+ iObserver->VolumeSyncReady( aError );
+ }
+ }
+
+ }
+
+
+
+// --------------------------------------------------------------------------
+// CUpnpVolumeStateMachine::VolumeResult
+// --------------------------------------------------------------------------
+//
+EXPORT_C void CUpnpVolumeStateMachine::VolumeResult(
+ TInt aError, TInt aVolumeLevel, TBool aActionResponse )
+ {
+ __LOG3( "VolumeStateMachine: VolumeResult %d, %d state=%d",
+ aError, aVolumeLevel, iState );
+
+ //
+ // RESPONSE TO A REQUEST
+ //
+ if ( aActionResponse )
+ {
+ //
+ // SYNC
+ //
+ if( iState == ESyncing )
+ {
+ HandleVolumeResultInSyncState(aError, aVolumeLevel, aActionResponse);
+ }
+ //
+ // VOLUME ADJUST
+ //
+ else if ( iState == EAdjustingVolume ||
+ iState == EAdjustingVolumeFromZero )
+ {
+ if ( aError == KErrNone )
+ {
+ iCurrentVolume = aVolumeLevel;
+ }
+ iState = EIdle;
+ // volume adjust done, call back
+ if ( iObserver )
+ {
+ iObserver->VolumeChanged(
+ aError, iCurrentVolume, ETrue );
+ }
+ }
+ //
+ // CANCEL
+ //
+ else if( iState == ECancelled )
+ {
+ iState = EIdle;
+ }
+ }
+
+ //
+ // UNSOLICTED VOLUME EVENT
+ //
+ else
+ {
+ if ( iState == EIdle )
+ {
+ if ( aVolumeLevel != iCurrentVolume )
+ {
+ if ( iCurrentMute == KMuteOn )
+ {
+ __LOG("unsolicted volume event during muted");
+ }
+ iCurrentVolume = aVolumeLevel;
+ if ( iObserver )
+ {
+ iObserver->VolumeChanged(
+ KErrNone, iCurrentVolume, EFalse );
+ }
+ }
+ }
+ else
+ {
+ __LOG("ignoring unsolicted volume event in this state");
+ }
+ }
+
+ iCachedVolume = iCurrentVolume;
+ ProcessNextQueuedProperty();
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpVolumeStateMachine::MuteResult
+// --------------------------------------------------------------------------
+//
+EXPORT_C void CUpnpVolumeStateMachine::MuteResult(
+ TInt aError, TBool aMute, TBool aActionResponse )
+ {
+ __LOG3( "VolumeStateMachine: MuteResult %d, %d, %d",
+ aError, aMute, aActionResponse );
+ __LOG1( "VolumeStateMachine: MuteResult in state=%d", iState );
+
+ //
+ // RESPONSE TO A REQUEST
+ //
+ if( aActionResponse )
+ {
+ //
+ // SYNC
+ //
+ if ( iState == ESyncing )
+ {
+ if ( aError == KErrNone )
+ {
+ iCurrentMute = aMute;
+ iMuteRequestedByClient = EFalse;
+ }
+ iState = EIdle;
+ // notify sync initially and volume and mute if changed
+ if ( iObserver && iCachedMute == KErrNotFound )
+ {
+ iObserver->VolumeSyncReady( aError );
+ }
+ else if ( iObserver )
+ {
+ if( iCachedVolume != iCurrentVolume )
+ {
+ iObserver->VolumeChanged(
+ aError, iCurrentVolume, EFalse );
+ }
+ if( iCachedMute != iCurrentMute )
+ {
+ iObserver->MuteChanged(
+ aError, iCurrentMute, EFalse );
+ }
+ }
+ }
+ //
+ // MUTE ADJUST
+ //
+ if ( iState == EAdjustingMute )
+ {
+ if ( aError == KErrNone )
+ {
+ iCurrentMute = aMute;
+ iMuteRequestedByClient = aMute;
+ }
+ iState = EIdle;
+ if ( iObserver )
+ {
+ iObserver->MuteChanged(
+ aError, iCurrentMute, ETrue );
+ }
+ }
+ //
+ // VOLUME ADJUST -> 0
+ //
+ if ( iState == EAdjustingVolumeToZero )
+ {
+ if ( aError == KErrNone )
+ {
+ iCurrentMute = aMute;
+ iMuteRequestedByClient = EFalse;
+ }
+ iState = EIdle;
+ if ( iObserver )
+ {
+ iObserver->VolumeChanged(
+ aError, KVolumeMin, ETrue );
+ }
+ }
+ //
+ // VOLUME ADJUST 0 -> up
+ //
+ if ( iState == EAdjustingVolumeFromZero )
+ {
+ if ( aError == KErrNone )
+ {
+ iCurrentMute = aMute;
+ iMuteRequestedByClient = EFalse;
+ TRAP( aError, iSession.SetVolumeL(
+ iVolumeToSetAfterMute ) );
+ }
+ if ( aError != KErrNone )
+ {
+ // error callback
+ iVolumeToSetAfterMute = KErrNotFound;
+ iState = EIdle;
+ if ( iObserver )
+ {
+ iObserver->VolumeChanged(
+ aError, iCurrentVolume, ETrue );
+ }
+ }
+ }
+ //
+ // CANCEL
+ //
+ else if( iState == ECancelled )
+ {
+ iState = EIdle;
+ }
+ }
+
+ //
+ // UNSOLICITED MUTE EVENT
+ //
+ else
+ {
+ HandleUnsolicitedMuteEvent(aError, aMute, aActionResponse );
+ }
+
+ iCachedMute = iCurrentMute;
+ ProcessNextQueuedProperty();
+ }
+
+void CUpnpVolumeStateMachine::HandleUnsolicitedMuteEvent(
+ TInt aError, TBool aMute, TBool aActionResponse )
+ {
+ if ( iState == EIdle )
+ {
+ HandleUnsolicitedMuteEventInIdle(aError, aMute, aActionResponse);
+ }
+ else
+ {
+ __LOG("ignoring unsolicted mute event in this state");
+ }
+
+ }
+
+void CUpnpVolumeStateMachine::HandleUnsolicitedMuteEventInIdle(
+ TInt /*aError*/, TBool aMute, TBool /*aActionResponse*/ )
+ {
+ __LOG3( "VolumeStateMachine: HandleUnsolicitedMuteEventInIdle %d, %d, %d",
+ aMute, iCurrentMute, iMuteRequestedByClient );
+
+ if ( iCurrentMute && !aMute && iMuteRequestedByClient )
+ {
+ // client has requested mute, renderer unmuted
+ iCurrentMute = aMute;
+ // check if client has changed volume during mute
+ if ( iVolumeToSetAfterMute > 0 &&
+ iVolumeToSetAfterMute != iCurrentVolume )
+ {
+ TRAP_IGNORE(
+ iSession.SetVolumeL( iVolumeToSetAfterMute );
+ iVolumeToSetAfterMute = KErrNotFound;
+ iState = EAdjustingVolume;
+ );
+ }
+ // notify observer about mute state change
+ if ( iObserver )
+ {
+ iObserver->MuteChanged(
+ KErrNone, KMuteOff, EFalse );
+ }
+ }
+ else if ( iCurrentMute && !aMute ||
+ !iCurrentMute && aMute )
+ {
+ // renderer unmuted - notify volume state back
+ iCurrentMute = aMute;
+ // check if client has changed volume during mute
+ if ( iVolumeToSetAfterMute > 0 &&
+ iVolumeToSetAfterMute != iCurrentVolume &&
+ !aMute &&
+ ( ( (iOptions & Upnp::EConvertVolumeZeroToMute) == 0 ) ||
+ iMuteRequestedByClient ) )
+ {
+ __LOG2( "After unmute adjusting volume %d->%d",
+ iCurrentVolume, iVolumeToSetAfterMute );
+ TRAP_IGNORE(
+ iSession.SetVolumeL( iVolumeToSetAfterMute );
+ iVolumeToSetAfterMute = KErrNotFound;
+ iState = EAdjustingVolume;
+ );
+ }
+ // notify observer
+ if ( iObserver )
+ {
+ NotifyObserver(aMute);
+ }
+ }
+ else
+ {
+ // no need to report status change
+ }
+ }
+
+void CUpnpVolumeStateMachine::NotifyObserver(TBool aMute)
+ {
+ __LOG2( "VolumeStateMachine: NotifyObserver %d, %d",
+ aMute, iOptions );
+
+ if ( ( (iOptions & Upnp::EConvertVolumeZeroToMute) == 0 ) ||
+ iMuteRequestedByClient )
+ {
+ // client prefers to use mute, or client has
+ // explicitely requested this mute session.
+ iObserver->MuteChanged(
+ KErrNone, aMute, EFalse );
+ }
+ else
+ {
+ // convert mute signal to volume callback
+ TInt givenvol =
+ ( aMute ? KVolumeMin : iCurrentVolume );
+ iObserver->VolumeChanged(
+ KErrNone, givenvol, EFalse );
+ }
+ }
+
+
+
+// --------------------------------------------------------------------------
+// CUpnpVolumeStateMachine::CopyValues
+// --------------------------------------------------------------------------
+//
+EXPORT_C void CUpnpVolumeStateMachine::CopyValues(
+ const CUpnpVolumeStateMachine& aOther )
+ {
+ iCurrentVolume = aOther.Volume();
+ iCurrentMute = aOther.Mute();
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpVolumeStateMachine::PushIntoQueueL
+// --------------------------------------------------------------------------
+//
+void CUpnpVolumeStateMachine::PushIntoQueueL(
+ const TUpnpVSMQueueItem::TPropertyType aPropery, const TInt aValue )
+ {
+ __LOG( "VolumeStateMachine: PushIntoQueueL" );
+ TUpnpVSMQueueItem queued( aPropery, aValue );
+ iQueue.AppendL( queued );
+
+ CompressQueue();
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpVolumeStateMachine::CompressQueueL
+// --------------------------------------------------------------------------
+//
+void CUpnpVolumeStateMachine::CompressQueue()
+ {
+ TInt queueCount( iQueue.Count() );
+
+ if( queueCount > 1 )
+ {
+ __LOG1( "VolumeStateMachine: CompressQueue (queue count: %d)", queueCount );
+
+ TInt lastIndex( queueCount - 1 );
+
+ if( iQueue[lastIndex].Property() == TUpnpVSMQueueItem::EVolume )
+ {
+ // remove all other except the last 'set volume' request
+ for( TInt i( queueCount - 2 ); i >= 0; --i )
+ {
+ __LOG2( "VolumeStateMachine Queue: Removing %d from queue index %d",
+ iQueue[i].Property(), i );
+
+ iQueue.Remove( i );
+ }
+ }
+ else
+ {
+ // remove all other except (the last 'set volume' request and)
+ // the last 'set mute' request
+ TBool setVolumeFound( EFalse );
+ TBool setMuteFound( EFalse );
+ for( TInt i( queueCount - 1 ); i >= 0; --i )
+ {
+ if( iQueue[i].Property() == TUpnpVSMQueueItem::EVolume &&
+ !setVolumeFound )
+ {
+ setVolumeFound = ETrue;
+ }
+ else if( iQueue[i].Property() == TUpnpVSMQueueItem::EMute &&
+ !setMuteFound )
+ {
+ setMuteFound = ETrue;
+ }
+ else
+ {
+ __LOG2( "VolumeStateMachine Queue: Removing %d from queue index %d",
+ iQueue[i].Property(), i );
+
+ iQueue.Remove( i );
+ }
+ }
+ }
+ }
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpVolumeStateMachine::ProcessNextQueuedProperty
+// --------------------------------------------------------------------------
+//
+void CUpnpVolumeStateMachine::ProcessNextQueuedProperty()
+ {
+ if( iQueue.Count() > 0 )
+ {
+ __LOG( "VolumeStateMachine: ProcessNextQueuedPropertyL" );
+
+ TUpnpVSMQueueItem queuedItem( iQueue[0] );
+ iQueue.Remove( 0 );
+
+ if( queuedItem.Property() == TUpnpVSMQueueItem::EVolume )
+ {
+ TRAPD( err, SetVolumeL( queuedItem.Value() ) );
+ if( err )
+ {
+ iObserver->VolumeChanged( err, iCurrentVolume, ETrue );
+ }
+ }
+ else
+ {
+ TRAPD( err, SetMuteL( queuedItem.Value() ) );
+ if( err )
+ {
+ iObserver->MuteChanged( err, iCurrentMute, ETrue );
+ }
+ }
+ }
+ }
+
+// end of file