multimediacommscontroller/mmcccontroller/src/mccresourceitem.cpp
changeset 0 1bce908db942
child 11 2a28ef775f15
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/multimediacommscontroller/mmcccontroller/src/mccresourceitem.cpp	Tue Feb 02 01:04:58 2010 +0200
@@ -0,0 +1,817 @@
+/*
+* Copyright (c) 2006 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:    
+*
+*/
+
+
+
+// INCLUDE FILES
+#include "mccresourceitem.h"
+#include "mccuids.hrh"
+#include "mcccontrollerlogs.h"
+#include "mccmultiplexer.h"
+#include "mccinternaldef.h"
+#include "mcccamerahandler.h"
+
+#include <mmf/server/mmfaudioinput.h>
+#include <mmf/server/mmfaudiooutput.h>
+
+// EXTERNAL DATA STRUCTURES
+
+// EXTERNAL FUNCTION PROTOTYPES  
+
+// CONSTANTS
+const TInt KMccOneResourceUser = 1;
+
+// MACROS
+
+// LOCAL CONSTANTS AND MACROS
+
+// MODULE DATA STRUCTURES
+
+// LOCAL FUNCTION PROTOTYPES
+
+// FORWARD DECLARATIONS
+
+// ============================= LOCAL FUNCTIONS ===============================
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CMccResourceItem::NewLC
+// -----------------------------------------------------------------------------
+//
+CMccResourceItem* CMccResourceItem::NewLC(
+    TUint32 aCurrentUserStreamId,
+    MDataSink* aSink, 
+    MDataSource* aSource, 
+    TUint32 aEndpointId,
+    TBool aIsMultiplexer )
+    {
+    CMccResourceItem* self = 
+        new ( ELeave ) CMccResourceItem( aCurrentUserStreamId, 
+                                         aEndpointId, 
+                                         aIsMultiplexer );
+    CleanupStack::PushL( self );
+    self->ConstructL( aSink, aSource );
+    return self;
+    }
+
+// -----------------------------------------------------------------------------
+// CMccResourceItem::NewL
+// -----------------------------------------------------------------------------
+//
+CMccResourceItem* CMccResourceItem::NewL(
+    TUint32 aCurrentUserStreamId,
+    MDataSink* aSink, 
+    MDataSource* aSource, 
+    TUint32 aEndpointId,
+    TBool aIsMultiplexer )
+    {
+    CMccResourceItem* self = 
+        CMccResourceItem::NewLC( aCurrentUserStreamId,
+                                 aSink, 
+                                 aSource, 
+                                 aEndpointId, 
+                                 aIsMultiplexer );
+    CleanupStack::Pop( self );
+    return self;
+    } 
+    
+// -----------------------------------------------------------------------------
+// CMccResourceItem::~CMccResourceItem
+// -----------------------------------------------------------------------------
+//       
+CMccResourceItem::~CMccResourceItem()
+    {
+    __CONTROLLER( "CMccResourceItem::~CMccResourceItem" )
+    
+    delete iMultiplexerItem;
+    delete iMultiplexer;
+    iUsers.Reset();
+    iUsers.Close();
+    
+    iKeyFrameInfo.Close();
+        
+    __CONTROLLER( "CMccResourceItem::~CMccResourceItem, exit" )
+    }
+
+// -----------------------------------------------------------------------------
+// CMccResourceItem::IncreaseRefCount
+// -----------------------------------------------------------------------------
+//
+TInt CMccResourceItem::IncreaseRefCount( const TMccResourceParams& aUser )
+    {
+    __CONTROLLER( "CMccResourceItem::IncreaseRefCount" )
+    
+    TInt err = iUsers.Append( aUser );
+    if ( !err && iMultiplexerItem )
+        {
+        __CONTROLLER( "CMccResourceItem::IncreaseRefCount, call multiplexer" )
+        
+        // Inform also the multiplexer
+        err = iMultiplexerItem->IncreaseRefCount( aUser );
+        }
+    return err;
+    }
+
+// -----------------------------------------------------------------------------
+// CMccResourceItem::DecreaseRefCount
+// -----------------------------------------------------------------------------
+//        
+TBool CMccResourceItem::DecreaseRefCount( const TMccResourceParams& aUser )
+    {
+    __CONTROLLER( "CMccResourceItem::DecreaseRefCount" )
+    
+    TIdentityRelation<TMccResourceParams> comparison( UserMatch );
+    TInt index = iUsers.Find( aUser, comparison );
+    if ( index != KErrNotFound )
+        {
+        iUsers.Remove( index );
+        
+        // Inform also the multiplexer
+        if ( iMultiplexerItem )
+            {
+            __CONTROLLER( "CMccResourceItem::DecreaseRefCount, call multiplexer" )
+            
+            if ( iMultiplexerItem->DecreaseRefCount( aUser ) )
+                {
+                __CONTROLLER( "CMccResourceItem::DecreaseRefCount, delete multiplexer" )
+                
+                delete iMultiplexerItem;
+                iMultiplexerItem = 0;
+                }
+            }
+        }
+    // If no more users, resource item can be deleted
+    if ( iUsers.Count() == 0 )
+        {
+        __CONTROLLER( "CMccResourceItem::DecreaseRefCount, can be removed" )
+        
+        return ETrue;
+        }
+    
+    __CONTROLLER( "CMccResourceItem::DecreaseRefCount, cannot be removed" )
+    
+    iCurrentUserStreamId = iUsers[ 0 ].iStreamId;
+    return EFalse;
+    }
+
+// -----------------------------------------------------------------------------
+// CMccResourceItem::RefCount
+// -----------------------------------------------------------------------------
+//    
+TInt CMccResourceItem::RefCount() const
+    {
+    return iUsers.Count();
+    }
+    
+// -----------------------------------------------------------------------------
+// CMccResourceItem::EndpointId
+// -----------------------------------------------------------------------------
+//
+TUint32 CMccResourceItem::EndpointId() const
+    {
+    return iEndpointId;
+    }
+
+// -----------------------------------------------------------------------------
+// CMccResourceItem::IsNetworkResource
+// -----------------------------------------------------------------------------
+//    
+TBool CMccResourceItem::IsNetworkResource() const
+    {
+    TBool isNetworkResource = iSink ? 
+        iSink->DataSinkType().iUid == KImplUidRtpDataSink :
+        iSource->DataSourceType().iUid == KImplUidRtpDataSource;
+    
+    return isNetworkResource;
+    }
+
+// -----------------------------------------------------------------------------
+// CMccResourceItem::IsResourceActive
+// -----------------------------------------------------------------------------
+// 
+TBool CMccResourceItem::IsResourceActive() const
+    {
+    return ( iState == MMccResources::EPrepared || 
+             iState == MMccResources::EStarted );
+    }
+
+// -----------------------------------------------------------------------------
+// CMccResourceItem::IsSharedResource
+// -----------------------------------------------------------------------------
+//     
+TBool CMccResourceItem::IsSharedResource() const
+    {
+    TBool sharable = iIsMultiplexer || ( RefCount() > KMccOneResourceUser );
+    
+    return sharable;
+    }
+    
+// -----------------------------------------------------------------------------
+// CMccResourceItem::IsStandbyResource
+// -----------------------------------------------------------------------------
+//     
+TBool CMccResourceItem::IsStandbyResource() const
+    {
+    TBool standby( EFalse );
+    if ( iSink && iSink->DataSinkType() == KUidMmfAudioOutput )
+        {
+        for ( TInt i = 0; i < iUsers.Count() && !standby; i++ )
+            {
+            standby = iUsers[ i ].iIsStandby;
+            }
+        }
+    return standby;
+    }
+ 
+// -----------------------------------------------------------------------------
+// CMccResourceItem::NeedsCamera
+// -----------------------------------------------------------------------------
+// 
+TBool CMccResourceItem::NeedsCamera( CMccCameraHandler& aCameraHandler )
+    {
+    TBool needsCamera( EFalse );
+    if ( iState == MMccResources::EStarted )
+        {
+        needsCamera = ETrue;
+        }
+    else if ( iState == MMccResources::EPrepared )
+        {
+        needsCamera = aCameraHandler.IsViewFinderEnabled();
+        }
+    else
+        {
+        // NOP
+        }
+    return needsCamera;
+    }
+    
+// -----------------------------------------------------------------------------
+// CMccResourceItem::SetResourceStateL
+// -----------------------------------------------------------------------------
+//    
+TBool CMccResourceItem::SetResourceStateL( 
+    TUint32 aStreamId, 
+    MMccResources::TResourceState aState,
+    TBool aStandbyControl,
+    TBool aDtmfControl )
+    {
+    __CONTROLLER_INT1( "CMccResourceItem::SetResourceStateL, old state:", iState )
+    __CONTROLLER_INT1( "CMccResourceItem::SetResourceStateL, proposed state:", aState )
+
+    TBool effectiveStateChange = EFalse;
+    
+    if ( iMultiplexerItem )
+        {
+        __CONTROLLER( "CMccResourceItem::SetResourceStateL, multiplexer decision" )
+        
+        effectiveStateChange = 
+            iMultiplexerItem->SetResourceStateL( 
+                aStreamId, aState, aStandbyControl, aDtmfControl );
+        
+        // Actual resource follows multiplexer states
+        iState = iMultiplexerItem->CurrentState();
+        }
+    else
+        {
+        __CONTROLLER( "CMccResourceItem::SetResourceStateL, resource usage allowed" )
+        
+        // For shared resources, all resource state change operations should
+        // be passed further.
+        effectiveStateChange = IsSharedResource();
+        
+        TBool isStandbyResource = IsStandbyResource();
+        
+        if ( isStandbyResource || aDtmfControl )
+            {
+            // Special handling for standby resource and dtmf
+            SpecialStateChangeL( aStreamId, 
+                                 aState, 
+                                 aStandbyControl, 
+                                 aDtmfControl, 
+                                 effectiveStateChange );
+            }
+        else
+            {
+            TBool stateOK( EFalse );
+            
+            switch ( aState )
+                { 
+                case MMccResources::EPrepared:
+                    {
+                    if ( MMccResources::EConstructed == iState )
+                        {
+                        stateOK = ETrue;
+                        }
+                    else if ( iState == MMccResources::EStarted ||
+                              iState == MMccResources::EResourcePaused )
+                        {
+                        // Endpoint is already started by other user,
+                        // state is not "downgraded"
+                        aState = iState;
+                        stateOK = ETrue;
+                        }
+                    else
+                        {
+                        // NOP
+                        }
+                    break;
+                    }
+                case MMccResources::EStarted:
+                    {
+                    if ( MMccResources::EPrepared == iState || 
+                         MMccResources::EResourcePaused == iState )
+                        {
+                        stateOK = ETrue;
+                        }  
+                    break;
+                    }
+                case MMccResources::EResourcePaused:
+                    {
+                    if ( MMccResources::EStarted == iState )
+                        {
+                        stateOK = ETrue;
+                        }  
+                    break;
+                    }
+                case MMccResources::EResourceStopped:
+                    {
+                    // Endpoint cannot be stopped until all its users
+                    // want to stop it.
+                    if ( !UserStopL( aStreamId ) )
+                        {
+                        aState = iState;
+                        effectiveStateChange = EFalse;
+                        }
+                    stateOK = ETrue; 
+                    break;
+                    }
+                default:
+                    {
+                    break;
+                    }
+                }
+            
+            if ( aState != iState )
+                {
+                __ASSERT_ALWAYS( stateOK || effectiveStateChange, 
+                                 User::Leave( KErrNotReady ) );
+                
+                iState = aState;
+                
+                effectiveStateChange = ETrue;
+                }
+            }
+        }
+    
+    __CONTROLLER_INT1( "CMccResourceItem::SetResourceStateL, effective change:", 
+                       effectiveStateChange )
+    __CONTROLLER_INT1( "CMccResourceItem::SetResourceStateL, exit with state:", 
+                       iState )
+        
+    return effectiveStateChange;
+    }
+
+// -----------------------------------------------------------------------------
+// CMccResourceItem::IsSink
+// -----------------------------------------------------------------------------
+//
+TBool CMccResourceItem::IsSink() const
+    {
+    return ( iSink != 0 );
+    }
+
+// -----------------------------------------------------------------------------
+// CMccResourceItem::IsSource
+// -----------------------------------------------------------------------------
+//        
+TBool CMccResourceItem::IsSource() const
+    {
+    return ( iSource != 0 );
+    }
+
+// -----------------------------------------------------------------------------
+// CMccResourceItem::IsInternal
+// -----------------------------------------------------------------------------
+//        
+TBool CMccResourceItem::IsInternal() const
+    {
+    TBool isInternal = iSink ? IsInternal( iSink->DataSinkType().iUid ) :
+                               IsInternal( iSource->DataSourceType().iUid );
+    
+    return isInternal;
+    }
+
+// -----------------------------------------------------------------------------
+// CMccResourceItem::Source
+// -----------------------------------------------------------------------------
+//        
+MDataSource* CMccResourceItem::Source()
+    {
+    return iSource;
+    }
+
+// -----------------------------------------------------------------------------
+// CMccResourceItem::Sink
+// -----------------------------------------------------------------------------
+//       
+MDataSink* CMccResourceItem::Sink()
+    {
+    return iSink;
+    }
+
+// -----------------------------------------------------------------------------
+// CMccResourceItem::MultiplexerL
+// -----------------------------------------------------------------------------
+//
+CMccMultiplexer* CMccResourceItem::MultiplexerL()
+    {
+    if ( !iMultiplexerItem )
+        {
+        iMultiplexerItem = 
+            CMccResourceItem::NewL( iCurrentUserStreamId,
+                                    iSink, 
+                                    iSource, 
+                                    iEndpointId, 
+                                    ETrue );
+        
+        // Update ref count immediately
+        for ( TInt i = 0; i < iUsers.Count(); i++ )
+            {
+            User::LeaveIfError( 
+                iMultiplexerItem->IncreaseRefCount( iUsers[ i ] ) );
+            }
+        }
+    return iMultiplexerItem->GetMultiplexerL();
+    }
+ 
+// -----------------------------------------------------------------------------
+// CMccResourceItem::GetMultiplexerL
+// -----------------------------------------------------------------------------
+//   
+CMccMultiplexer* CMccResourceItem::GetMultiplexerL()
+    {
+    __ASSERT_ALWAYS( iMultiplexer, User::Leave( KErrNotReady ) );
+    
+    return iMultiplexer;
+    }
+    
+// -----------------------------------------------------------------------------
+// CMccResourceItem::UserSessionMatch
+// -----------------------------------------------------------------------------
+//     
+TBool CMccResourceItem::UserSessionMatch( 
+    const TMccResourceParams& aUser1, 
+    const TMccResourceParams& aUser2 )
+    {
+    return ( aUser1.iSessionId == aUser2.iSessionId );
+    }
+    
+// -----------------------------------------------------------------------------
+// CMccResourceItem::UserMatch
+// -----------------------------------------------------------------------------
+//     
+TBool CMccResourceItem::UserMatch( 
+    const TMccResourceParams& aUser1, 
+    const TMccResourceParams& aUser2 )
+    {
+    return ( aUser1.iStreamId == aUser2.iStreamId );
+    }
+    
+// -----------------------------------------------------------------------------
+// CMccResourceItem::UserMatchNotStrict
+// -----------------------------------------------------------------------------
+//     
+TBool CMccResourceItem::UserMatchNotStrict( 
+    const TMccResourceParams& aUser1, 
+    const TMccResourceParams& aUser2 )
+    {
+    if ( aUser1.iLinkId )
+        {
+        return ( aUser1.iLinkId == aUser2.iLinkId );
+        }
+    return UserMatch( aUser1, aUser2 );
+    }
+
+// -----------------------------------------------------------------------------
+// CMccResourceItem::UserMatchActive
+// -----------------------------------------------------------------------------
+//     
+TBool CMccResourceItem::UserMatchActive( 
+    const TMccResourceParams& /*aUser1*/, 
+    const TMccResourceParams& aUser2 )
+    {
+    // First argument is the search term, in this case it can be ignored
+    return ( !aUser2.iIsStopped );
+    }
+    
+// -----------------------------------------------------------------------------
+// CMccResourceItem::UsersInfoL
+// -----------------------------------------------------------------------------
+//   
+void CMccResourceItem::UsersInfoL( RArray<TMccResourceParams>& aUsers )
+    {
+    for ( TInt i = 0; i < iUsers.Count(); i++ )
+        {
+        aUsers.AppendL( iUsers[ i ] );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CMccResourceItem::CurrentState
+// -----------------------------------------------------------------------------
+//    
+MMccResources::TResourceState CMccResourceItem::CurrentState() const
+    {
+    return iState;
+    }
+
+// -----------------------------------------------------------------------------
+// CMccResourceItem::Match
+// -----------------------------------------------------------------------------
+//    
+TBool CMccResourceItem::Match( const TMccResourceParams& aUser ) const
+    {
+    TIdentityRelation<TMccResourceParams> comparison( UserMatchNotStrict );
+    TInt index = iUsers.Find( aUser, comparison );
+    return ( index != KErrNotFound );
+    }
+    
+// -----------------------------------------------------------------------------
+// CMccResourceItem::MatchSession
+// -----------------------------------------------------------------------------
+//    
+TBool CMccResourceItem::MatchSession( const TUint32 aSessionId ) const
+    {
+    TMccResourceParams searchTerm( aSessionId, 0, 0, 0, EFalse, 0 );
+    TIdentityRelation<TMccResourceParams> comparison( UserSessionMatch );
+    TInt index = iUsers.Find( searchTerm, comparison );
+    return ( index != KErrNotFound );
+    }
+	
+// -----------------------------------------------------------------------------
+// CMccResourceItem::StoreKeyFrameInfoL
+// -----------------------------------------------------------------------------
+//
+void CMccResourceItem::StoreKeyFrameInfoL( CMMFBuffer& aKeyFrame )
+    {
+    __CONTROLLER_INT1( "CMccResourceItem::StoreKeyFrameInfoL, timestamp:", 
+                       aKeyFrame.TimeToPlay().Int64() )
+                       
+    if ( iKeyFrameInfo.Count() >= KMccMaxNumKeyFrames )
+        {
+        iKeyFrameInfo.Remove( 0 );
+        iKeyFrameInfo.Compress();
+        }
+    TMccKeyFrameInfo info;
+    info.iSeqNum = aKeyFrame.FrameNumber();
+    info.iTimestamp = aKeyFrame.TimeToPlay().Int64();
+    iKeyFrameInfo.AppendL( info );
+    }
+
+// -----------------------------------------------------------------------------
+// CMccResourceItem::IsKeyFrame
+// -----------------------------------------------------------------------------
+//
+TBool CMccResourceItem::IsKeyFrame( CMMFBuffer& aBuffer )
+    {
+    TBool isKeyFrame( EFalse );
+    for ( TInt i = 0; i < iKeyFrameInfo.Count() && !isKeyFrame; i++ )
+        {
+        TMccKeyFrameInfo& info = iKeyFrameInfo[ i ];
+        isKeyFrame = ( info.iSeqNum == aBuffer.FrameNumber() && 
+                       info.iTimestamp == aBuffer.TimeToPlay().Int64() );
+        }
+    return isKeyFrame;
+    }
+        
+// -----------------------------------------------------------------------------
+// CMccResourceItem::IsCurrentUser
+// -----------------------------------------------------------------------------
+//
+TBool CMccResourceItem::IsCurrentUser( TUint32 aStreamId ) const
+    {
+    return ( iCurrentUserStreamId == aStreamId );
+    }
+    
+// -----------------------------------------------------------------------------
+// CMccResourceItem::NonSharableResource
+// -----------------------------------------------------------------------------
+//    
+TBool CMccResourceItem::NonSharableResource( TUid aUid ) const
+    {
+    // TBD! sharing audiooutput should be possible with multiplexer
+    return ( aUid == KUidMmfAudioInput ||
+             aUid == KUidMmfAudioOutput );
+    }
+    
+// -----------------------------------------------------------------------------
+// CMccResourceItem::IsInternal
+// -----------------------------------------------------------------------------
+//        
+TBool CMccResourceItem::IsInternal( TUint32 aUid ) const
+    {
+    return MCC_INTERNAL_ENDPOINT( aUid );
+    }
+
+// -----------------------------------------------------------------------------
+// CMccResourceItem::CMccResourceItem
+// -----------------------------------------------------------------------------
+//      
+CMccResourceItem::CMccResourceItem( 
+    TUint32 aCurrentUserStreamId, 
+    TUint32 aEndpointId,
+    TBool aIsMultiplexer ) :
+    iCurrentUserStreamId( aCurrentUserStreamId ),
+    iEndpointId( aEndpointId ),
+    iIsMultiplexer( aIsMultiplexer )
+    {
+    }
+
+// -----------------------------------------------------------------------------
+// CMccResourceItem::ConstructL
+// -----------------------------------------------------------------------------
+// 
+void CMccResourceItem::ConstructL( 
+    MDataSink* aSink, 
+    MDataSource* aSource )
+    {
+    __CONTROLLER( "CMccResourceItem::ConstructL" )
+    
+    // Resource item can contain sink OR source
+    
+    if ( aSink )
+        {
+        __ASSERT_ALWAYS( !aSource, User::Leave( KErrArgument ) );
+        iSink = aSink;
+        }
+    else if ( aSource )
+        {
+        __ASSERT_ALWAYS( !aSink, User::Leave( KErrArgument ) );
+        iSource = aSource;
+        }
+    else
+        {
+        User::Leave( KErrArgument );
+        }
+
+    if ( iIsMultiplexer )
+        {
+        __CONTROLLER( "CMccResourceItem::ConstructL, create real multiplexer" )
+        
+        __ASSERT_ALWAYS( iSource, User::Leave( KErrNotReady ) );
+        iMultiplexer = CMccMultiplexer::NewL( iSource );
+        }
+    
+    __CONTROLLER( "CMccResourceItem::ConstructL, exit" )
+    }
+
+// -----------------------------------------------------------------------------
+// CMccResourceItem::SpecialStateChangeL
+// -----------------------------------------------------------------------------
+//    
+void CMccResourceItem::SpecialStateChangeL( 
+    TUint32 aStreamId,
+    MMccResources::TResourceState aState,
+    TBool aStandbyControl,
+    TBool aDtmfControl,
+    TBool& aEffectiveStateChange )
+    {
+    __CONTROLLER( "CMccResourceItem::StandbyStateChangeL" )
+    __CONTROLLER_INT1( "CMccResourceItem::StandbyStateChangeL, paused by user:", 
+                       iPausedByUser )
+    __CONTROLLER_INT1( "CMccResourceItem::StandbyStateChangeL, standby control:",
+                       aStandbyControl )
+    
+    // For standby resource, pausing prepared resource is ok but it's not
+    // an effective state change as pause is not really needed. If standby
+    // resource has been paused by user, standby control will not have
+    // any effect. Additionally, user paused stream is not resumed if user
+    // tries to do it. Dtmf stream cannot pause its endpoints if others are
+    // using them.
+    
+    TBool stateOK( EFalse );
+    
+    TBool nonEffective = 
+        ( iPausedByUser && aStandbyControl ) || 
+        ( !aStandbyControl && !aDtmfControl && aState == MMccResources::EStarted ) ||
+        ( aDtmfControl && aStandbyControl && aState == MMccResources::EResourcePaused && 
+            ( RefCount() > KMccOneResourceUser ) );
+    
+    switch ( aState )
+        { 
+        case MMccResources::EPrepared:
+            {
+            if ( MMccResources::EConstructed == iState )
+                {
+                stateOK = ETrue;
+                }
+             else if ( iState == MMccResources::EStarted ||
+                       iState == MMccResources::EResourcePaused )
+                {
+                // Endpoint is already started by other user,
+                // state is not "downgraded"
+                aState = iState;
+                stateOK = ETrue;
+                }
+            else
+                {
+                // NOP
+                }
+            break;
+            }
+        case MMccResources::EStarted:
+            {
+            if ( MMccResources::EPrepared == iState || 
+                 MMccResources::EResourcePaused == iState )
+                {
+                stateOK = ETrue;
+                }  
+            break;
+            }
+        case MMccResources::EResourcePaused:
+            {
+            if ( MMccResources::EStarted == iState )
+                {
+                stateOK = ETrue;
+                }
+            else if ( MMccResources::EPrepared == iState )
+                {
+                stateOK = ETrue;
+                nonEffective = ETrue;
+                }
+            else
+                {
+                }
+            
+            break;
+            }
+        case MMccResources::EResourceStopped:
+            {
+            nonEffective = !UserStopL( aStreamId );
+            stateOK = ETrue; 
+            break;
+            }
+        default:
+            {
+            break;
+            }
+        }
+     
+    if ( aState != iState )
+        {
+        if ( !nonEffective )
+            {
+            __ASSERT_ALWAYS( stateOK, User::Leave( KErrNotReady ) );
+                    
+            iState = aState;
+            }
+        
+        aEffectiveStateChange = !nonEffective;
+        }
+           
+    if ( !aStandbyControl )
+        {
+        // Update paused by user info
+        iPausedByUser = ( MMccResources::EResourcePaused == aState ||
+                          MMccResources::EPrepared == aState );
+        }
+        
+    __CONTROLLER( "CMccResourceItem::StandbyStateChangeL, exit" )
+    }
+
+// -----------------------------------------------------------------------------
+// CMccResourceItem::UserStopL
+// -----------------------------------------------------------------------------
+// 
+TBool CMccResourceItem::UserStopL( TUint32 aStreamId )
+    {
+    TMccResourceParams searchTerm( 0, 0, aStreamId, 0, EFalse, 0 );
+    TIdentityRelation<TMccResourceParams> comparison( UserMatch );
+    TInt index = iUsers.Find( searchTerm, comparison );
+    __ASSERT_ALWAYS( index != KErrNotFound, User::Leave( KErrNotFound ) );
+    iUsers[ index ].iIsStopped = ETrue;
+    
+    TIdentityRelation<TMccResourceParams> comparison2( UserMatchActive );
+    index = iUsers.Find( searchTerm, comparison2 );
+    
+    // If didn't found any active ones, the resource can be stopped
+    return ( index == KErrNotFound );
+    }
+    
+// End of file
+