diff -r 000000000000 -r 79dd3e2336a0 mmresourcemgmt/mmresctrl/src/mmrcserver/mmrcservercontroller.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mmresourcemgmt/mmresctrl/src/mmrcserver/mmrcservercontroller.cpp Fri Oct 08 19:40:43 2010 +0100 @@ -0,0 +1,917 @@ +// 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: +// + +#include "mmrcservercontroller.h" +#include "mmrcerrorcodes.h" +#include "mmrcserversession.h" +#include "mmrcserverinfo.h" +#include "mmrcserverrulemanager.h" +#include "mmrcadaptationproxy.h" +#include "mlogicalchain.h" +#include + +/** +@internalComponent + +This class implements a timer. +*/ +class CARNNotificationObject : public CActive + { + +public: + static CARNNotificationObject* NewL(const TInt aPriority, CMMRCServerInfo& aMMRCServerInfo); + ~CARNNotificationObject(); + void After(TTimeIntervalMicroSeconds32 aInterval); + void Initialize(); + +protected: + void RunL(); + void DoCancel(); + +private: + CARNNotificationObject(const TInt aPriority); + void ConstructL(CMMRCServerInfo& aMMRCServerInfo); + +public: + TInt iIndex; + +protected: + RTimer iTimer; + CMMRCServerInfo* iMMRCServerInfo; + }; + +//------------------------------------------------------------------------------------ +// +//------------------------------------------------------------------------------------ + +/** + * Constructor + */ +CMMRCServerController::CMMRCServerController() + { + TRACE_CREATE(); + DP_CONTEXT(----> CMMRCServerController::CMMRCServerController *CD1*, CtxDevSound, DPLOCAL); + DP_IN(); + + DP_OUT(); + } + +/** + * Destructor + */ +CMMRCServerController::~CMMRCServerController() + { + DP_CONTEXT(----> CMMRCServerController::~CMMRCServerController *CD1*, CtxDevSound, DPLOCAL); + DP_IN(); + + delete iMMRCServerInfo; + delete iMMRCServerRuleManager; + delete iARNNotificationObject; + + DP_OUT(); + } + +/** + * Constructs, and returns a pointer to, a new CMMRCServerController object. + * Leaves on failure. + * @return CMMRCServerController* A pointer to newly created utlitly object. + */ +CMMRCServerController* CMMRCServerController::NewL() + { + DP_STATIC_CONTEXT(----> CMMRCServerController::NewL *CD1*, CtxDevSound, DPLOCAL); + DP_IN(); + + CMMRCServerController* self = NewLC(); + CleanupStack::Pop(self); + + DP0_RET(self, "self = 0x%x"); + } + +/** + * Constructs, leaves object on the cleanup stack, and returns a pointer + * to, a new CMMRCServerController object. + * Leaves on failure. + * @return CMMRCServerController* A pointer to newly created utlitly object. + */ +CMMRCServerController* CMMRCServerController::NewLC() + { + DP_STATIC_CONTEXT(----> CMMRCServerController::NewLC *CD1*, CtxDevSound, DPLOCAL); + DP_IN(); + + CMMRCServerController* self = new(ELeave) CMMRCServerController(); + CleanupStack::PushL(self); + self->ConstructL(); + + DP0_RET(self, "self = 0x%x"); + } + +/** + * CMMRCServerController::ConstructL + * Symbian 2nd phase constructor can leave. + */ +void CMMRCServerController::ConstructL() + { + DP_CONTEXT(----> CMMRCServerController::ConstructL *CD1*, CtxDevSound, DPLOCAL); + DP_IN(); + + iMMRCServerInfo = CMMRCServerInfo::NewL(*this); + iMMRCServerRuleManager = CMMRCServerRuleManager::NewL(*this); + iARNNotificationObject = CARNNotificationObject::NewL(0, *iMMRCServerInfo); //Check the value + + DP_OUT(); + } + +/** +* Process the request pointer by a specific session +* @param CMMRCServerSession& aServerSession +* @return KerrNone in case of success of the process +*/ +TInt CMMRCServerController::EnqueueRequestL(CMMRCServerSession& aServerSession) + { + DP_CONTEXT(----> CMMRCServerController::ProcessRequestL *CD1*, CtxDevSound, DPLOCAL); + DP_IN(); + + //add the request to the queue + iMMRCServerInfo->PushRequestL(aServerSession); + TInt err = ProcessNextRequestL(); + + DP0_RET(err, "err=%d"); + } + +/** + * Process the first request with the highest priority from the FIFO queue + * @return KerrNone in case of success of the process + */ + TInt CMMRCServerController::ProcessNextRequestL() + { + DP_CONTEXT(--------> CMMRCServerController::ProcessNextRequestL *CD1*, CtxDevSound, DPLOCAL); + DP_IN(); + + TInt err = KErrNone; + + TUint64 contextId; + TMMRCServerState serverState; + iMMRCServerInfo->ServerState(serverState, contextId); +#ifdef SYMBIAN_MULTIMEDIA_ENABLE_LOGGING + RDebug::Print(_L("serverState = %d"), serverState); + RDebug::Print(_L("size of message queue = %d"), iMMRCServerInfo->RequestsCount()); + RDebug::Print(_L("size of inprocess queue = %d"), iMMRCServerInfo->AllocatedResourceContextsCount()); + RDebug::Print(_L("size of paused queue = %d"), iMMRCServerInfo->AllocatedPausedContextsCount()); +#endif + if(EMMRCServerStateIdle != serverState) + { + DP0_RET(KErrNone, "%d"); + } + + CMMRCServerSession* serverSession = iMMRCServerInfo->PopAndRemoveFirstRequest(); //PopAndRemoveRequestFirstHighestPriority(); + //Pop the next next commited message with the highest priority + if( NULL == serverSession ) + { + DP0_RET(KErrNone, "%d"); + } + + if (!serverSession->HasUserEnvironmentCapability()) + { + /* Check to see if it's a record use case and in IDLE, Active, or PRIME. + // in which case you should refuse the request for reasons + KErrPermissionDenied + */ + MLogicalChain* requestedChange = serverSession->LogicalChainRequestedStack(); + if ((requestedChange!=NULL) && (requestedChange->StreamState() > EInitialized)) // trying to play + { + TInt count = requestedChange->AudioProcessingUnitsCount(); + for (TInt i=0; iAudioProcessingUnitUid(i)) + { + serverSession->NotifyClientOfError(KErrPermissionDenied); + // The following return value, doesn't actually make it back to the client + // We do however Notify the client above using NotifyClientOfError() + DP0_RET(KErrPermissionDenied, "%d"); + } + } + } + + } + + //Pop the last commited message in process = the current resource in use + CMMRCServerSession* serverSessionAllocatedResource = iMMRCServerInfo->PopFirstAllocatedResourceContext(); + //If no resource locked... + if( NULL == serverSessionAllocatedResource ) + { + + err = SendResourceRequest ( *serverSession ); + } + else //If a resource has been allocated or is used, possibly preemption + { + TAudioContextId contextId = serverSession->ContextId( ); + TAudioContextId contextIdAllocatedResource = serverSessionAllocatedResource->ContextId( ); + #ifdef SYMBIAN_MULTIMEDIA_ENABLE_LOGGING + RDebug::Print(_L("contextId = %d"), contextId.Id()); + RDebug::Print(_L("contextIdAllocatedResource = %d"), contextIdAllocatedResource.Id()); + #endif + + //in case of processing the same context, remove the last committed request from the queue + // of in-process request to avoid preemption within the same context. + if(contextId == contextIdAllocatedResource) + { + err = SendResourceRequest ( *serverSession ); + } + else // maybe preemption + { + //Pop the rule + + MLogicalChain* logicalChainUsingResource = serverSessionAllocatedResource->LogicalChainLastCommited(); + MLogicalChain* logicalChainNew = serverSession->LogicalChainRequestedStack(); + //Should not/cannot be null! + if( NULL==logicalChainUsingResource || NULL==logicalChainNew ) + { + #ifdef _DEBUG + RDebug::Print(_L("!!!!CMMRCServerController::ProcessNextRequestL - logicalChainUsingResource or logicalChainNew NULL")); + ASSERT(0); + #endif + User::Leave(EMMRCErrorLogicalChainNull); + } + + TAudioState audioStateAllocatedResource = logicalChainUsingResource->StreamState(); + TAudioState audioStateNew = logicalChainNew->StreamState ( ); + TMMRCRule rule = DecisionRule(audioStateAllocatedResource, audioStateNew); + //Process according to the rule + if( rule == EAlwaysProcess ) + { + err = SendResourceRequest( *serverSession ); + } + else // process only in case of higher priority + { + TInt currentClientPriority = logicalChainUsingResource->Priority(); + TInt newClientPriority = logicalChainNew->Priority(); + TBool currentClient_HasMMDD = serverSessionAllocatedResource->HasMultimediaCapability(); + TBool newClient_HasMMDD = serverSession->HasMultimediaCapability(); + + // If new client has multimedia capability and current doesn't have, + // priorities don't matter preempt the current client + + // But if both are equal competitors (both has MMDD capability or both hasn't) + // and the newcomer has higher priority preempt too + if ( (!currentClient_HasMMDD && newClient_HasMMDD) || + ( (currentClient_HasMMDD == newClient_HasMMDD) && + (newClientPriority > currentClientPriority) ) ) + { + //The process is delayed. First we have to preempt the current inprocess resource + // so puch back the request (its session) + iMMRCServerInfo->PushRequestL(*serverSession); + // + //send a premption message to the last commited message session + err = SendPreemptionRequest ( *serverSessionAllocatedResource ); + } + else + { + // Deny the resource + TAudioContextId iId = serverSession->ContextId( ); + TBool iIsOnPauseList = iMMRCServerInfo->IsOnPauseList(iId); + if(!iIsOnPauseList) + { + iMMRCServerInfo->PushPausedContextL(*serverSession); + } +// nothing pending, deny resources, and notify client. + serverSession->AdaptationRequestAcknowledgment(EMMRCAdaptationToServerResourceIncomplete, KErrInUse); +// Server is back to idle. + iMMRCServerInfo->SwitchServerState(EMMRCServerStateIdle, 0); + } + } + } + } + +#ifdef SYMBIAN_MULTIMEDIA_ENABLE_LOGGING + if(err != KErrNone) + { + RDebug::Print(_L("!!!!CMMRCServerController::ProcessNextRequestL - error = %d"), err); + } +#endif + + DP0_RET(err, "err=%d"); + } + +/** + * Pop the decision rule on the base of the current in-process request and a new committed request + * @param TAudioState aAudioStateAllocatedResource + * @param TAudioState aAudioStateRequiringProcess + * @return TMMRCRule + */ +TMMRCRule CMMRCServerController::DecisionRule(TAudioState aAudioStateAllocatedResource, TAudioState aAudioStateRequiringProcess) + { + DP_CONTEXT(----> CMMRCServerController::DecisionRule *CD1*, CtxDevSound, DPLOCAL); + DP_IN(); + + TMMRCRule rule = iMMRCServerRuleManager->DecisionRule(aAudioStateAllocatedResource, aAudioStateRequiringProcess); + + DP0_RET(rule, "rule=%d"); + } + +/** + * Pop the action reason on the base of the last committed request and the current one + * @param TAudioState aAudioStateLastCommitted + * @param TAudioState aAudioStateRequested + * @return TReason + */ +TReason CMMRCServerController::ActionReason(TAudioState aAudioStateLastCommitted, TAudioState aAudioStateRequested) + { + DP_CONTEXT(----> CMMRCServerController::ActionReason *CD1*, CtxDevSound, DPLOCAL); + DP_IN(); + + TReason reason = iMMRCServerRuleManager->ActionReason(aAudioStateLastCommitted, aAudioStateRequested); + + DP0_RET(reason, "reason=%d"); + } + +/** + * Send a resource request to the adaptation + * @param MLogicalChain* aOldChain + * @param MLogicalChain* aNewChain + * @return KerrNone in case of success of the process + */ +TInt CMMRCServerController::SendResourceRequest( CMMRCServerSession& aServerSession ) + { + DP_CONTEXT(----> CMMRCServerController::SendResourceRequest *CD1*, CtxDevSound, DPLOCAL); + DP_IN(); + + iMMRCServerInfo->SwitchServerState( EMMRCServerStateWaitResourceResponseFromAdaptation, aServerSession.ContextId() ); + +// if entering APR state, remove from Paused list. + TRAPD(err, aServerSession.StartProcessL()); + { + MLogicalChain* logicalChainNew = aServerSession.LogicalChainRequested(); + if (logicalChainNew) + { + TAudioState audioStateNew = logicalChainNew->StreamState(); + if ( + (audioStateNew == EActive ) || + (audioStateNew == EPrimed) || + (audioStateNew == EIdle) + + ) + { + TInt contextId = aServerSession.ContextId( ); + iMMRCServerInfo->PopAndRemovePausedContext(contextId); + } + } + } + if(err == KErrNone) + { + //Send request + if (!aServerSession.SendRequestToAdaptation(ENormalRequest)) + { +// TBD fail at current task. +// return server shutting down + } + } + +#ifdef SYMBIAN_MULTIMEDIA_ENABLE_LOGGING + if(err != KErrNone) + { + RDebug::Print(_L("!!!!CMMRCServerController::SendResourceRequest - error = %d"), err); + } +#endif + + DP0_RET(err, "err=%d"); + } + +/** + * Send a preemption request to the adaptation + * @param MLogicalChain* aOldChain + * @param MLogicalChain* aNewChain + * @return KerrNone in case of success of the process + */ +TInt CMMRCServerController::SendPreemptionRequest( CMMRCServerSession& aServerSession ) + { + DP_CONTEXT(----> CMMRCServerController::SendPreemptionRequest *CD1*, CtxDevSound, DPLOCAL); + DP_IN(); + + iMMRCServerInfo->SwitchServerState( EMMRCServerStateWaitPreemptionResponse, aServerSession.ContextId() ); + + //Update logical chains + TRAPD(err, aServerSession.StartPreemptionL()); + + + if(err == KErrNone) + { + //Send request + if (!aServerSession.SendRequestToAdaptation(EPreemptionRequest)) + { + // TBD fail at current task. + // return server shutting down/low memory where necessary + } + } + +#ifdef SYMBIAN_MULTIMEDIA_ENABLE_LOGGING + if(err != KErrNone) + { + RDebug::Print(_L("!!!!CMMRCServerController::SendPreemptionRequest - error = %d"), err); + } +#endif + + DP0_RET(err, "err=%d"); + } + +/** + * Callback from the adaptation + * @param MLogicalChain* aOldChain + * @param MLogicalChain* aNewChain + * @param TMMRCAdaptationToServerRequestResults aResult + */ +void CMMRCServerController::AdaptationRequestAcknowledgment(CMMRCServerSession& aServerSession, TMMRCAdaptationToServerRequestResults aResult, TInt /*aError*/) + { + DP_CONTEXT(--------> CMMRCServerController::AdaptationRequestAcknowledgment *CD1*, CtxDevSound, DPLOCAL); + DP_IN(); +#ifdef SYMBIAN_MULTIMEDIA_ENABLE_LOGGING + RDebug::Print(_L("size of message queue = %d"), iMMRCServerInfo->RequestsCount()); + RDebug::Print(_L("size of inprocess queue = %d"), iMMRCServerInfo->AllocatedResourceContextsCount()); + RDebug::Print(_L("size of paused queue = %d"), iMMRCServerInfo->AllocatedPausedContextsCount()); +#endif + + TUint64 contextId; + TMMRCServerState serverState; + TInt err = KErrNone; + iMMRCServerInfo->ServerState(serverState, contextId); + switch(serverState) + { + case EMMRCServerStateWaitPreemptionResponse: // here we process the response + { + switch(aResult) + { + case EMMRCAdaptationToServerResourceComplete: + { + //we remove the request in process from the queue + CMMRCServerSession* serverSession = iMMRCServerInfo->PopAndRemoveFirstAllocatedResourceContext(); + if(serverSession) + { + TRAP(err, iMMRCServerInfo->PushPausedContextL(*serverSession)); + DP1(DLERR,"EPushPauseContextLeft %d", err); + __ASSERT_DEBUG(err == KErrNone, Panic(EPushPauseContextLeft)); + } + //Do not wait for a client acknowledgment + iMMRCServerInfo->SwitchServerState(EMMRCServerStateIdle, 0); + } + break; + case EMMRCAdaptationToServerResourceTimeout: + default: + { + //jjpy TODO: What if the preemption request failed?! + // That will be specified/implemented during the integration with the resource manager + //we remove the request in process from the queue + iMMRCServerInfo->PopAndRemoveFirstAllocatedResourceContext(); + } + } // end switch(aResult) + } //end case EMMRCServerStateWaitPreemptionResponse + break; + case EMMRCServerStateWaitResourceResponseFromAdaptation: // here we process the response + { + switch(aResult) + { + case EMMRCAdaptationToServerResourceComplete: + { + CMMRCServerSession* serverSessionAllocatedResource = iMMRCServerInfo->PopFirstAllocatedResourceContext(); + if( serverSessionAllocatedResource ) //If some previously some context has allocated a resource + { + //check if same context, if not it might be an error + TAudioContextId contextId = aServerSession.ContextId( ); + TAudioContextId contextIdAllocatedResource = serverSessionAllocatedResource->ContextId( ); + #ifdef SYMBIAN_MULTIMEDIA_ENABLE_LOGGING + RDebug::Print(_L("contextId = %d"), contextId.Id()); + RDebug::Print(_L("contextIdAllocatedResource = %d"), contextIdAllocatedResource.Id()); + #endif + MLogicalChain* logicalChainNew = aServerSession.LogicalChainRequested(); + MLogicalChain* logicalChainOld = aServerSession.LogicalChainLastCommited(); + TAudioState audioStateNew = logicalChainNew->StreamState ( ); + if(contextId != contextIdAllocatedResource) + { + //it is ok if the rule said process always + MLogicalChain* logicalChainUsingResource = serverSessionAllocatedResource->LogicalChainLastCommited(); + TAudioState audioStateAllocatedResource = logicalChainUsingResource->StreamState(); + TAudioState audioStateNew = logicalChainNew->StreamState ( ); + TMMRCRule rule = DecisionRule(audioStateAllocatedResource, audioStateNew); + if( rule != EAlwaysProcess ) + { + //not possible in theory... this is an error + #ifdef SYMBIAN_MULTIMEDIA_ENABLE_LOGGING + RDebug::Print(_L("!!!!CMMRCServerController::AdaptationRequestAcknowledgment - contextId allocating a resource and new request different. Should be the same!"), iMMRCServerInfo->AllocatedResourceContextsCount()); + #endif + } + } + else //same context here, so check if the resource has been deallocated + { + // in case of stop etc. remove from in process request + //now check the reason + TAudioState audioStateOld = EUninitialized; + if(logicalChainOld) + { + audioStateOld = logicalChainOld->StreamState(); + } + TReason reason = ActionReason(audioStateOld, audioStateNew); + + if (reason == ELoad) + { + iARNNotificationObject->Cancel(); + iMMRCServerInfo->PopAndRemovePausedContext(contextId); + } + else if (reason == EUnload) + { + iARNNotificationObject->Initialize(); + iMMRCServerInfo->PopAndRemoveFirstAllocatedResourceContextByContextId(contextId); + } + } + } + else //no in process request locking a resource + { + MLogicalChain* logicalChainNew = aServerSession.LogicalChainRequested(); + MLogicalChain* logicalChainOld = aServerSession.LogicalChainLastCommited(); + TAudioState audioStateNew = logicalChainNew->StreamState ( ); + TAudioState audioStateOld = EUninitialized; + if(logicalChainOld) + { + audioStateOld = logicalChainOld->StreamState(); + } + TReason reason = ActionReason(audioStateOld, audioStateNew); + if( reason == ELoad || + reason == EPrimeReason || + reason == EActivate ) + { + TRAP(err, iMMRCServerInfo->PushAllocatedResourceContextL( aServerSession )); + DP1(DLERR,"EPushAllocatedResourceContextFailed %d", err); + __ASSERT_DEBUG(err == KErrNone, Panic(EPushAllocatedResourceContextFailed)); + } + } + iMMRCServerInfo->SwitchServerState(EMMRCServerStateIdle, 0); + } + break; + case EMMRCAdaptationToServerResourceTimeout: + default: + { + //Just switch the state + iMMRCServerInfo->SwitchServerState(EMMRCServerStateIdle, 0); + } + break; + } //end switch switch(aResult) + } // end case EMMRCServerStateWaitResourceResponseFromAdaptation + break; + case EMMRCServerStateIdle: //not possible.... + default: + break; + } + + TRAP(err, ProcessNextRequestL()); + DP1(DLERR,"EProcessNextRequestLeft %d", err); + __ASSERT_DEBUG(err == KErrNone, Panic(EProcessNextRequestLeft)); + DP_OUT(); + } + +/* + * + */ +void CMMRCServerController::NotifyPausedClientsResourceUnallocated() + { + DP_CONTEXT(----> CMMRCServerController::NotifyClientsResourceUnallocated *CD1*, CtxDevSound, DPLOCAL); + DP_IN(); + + CMMRCServerSession* serverSession = iMMRCServerInfo->PopAndRemoveFirstPausedContext( ); + while( serverSession ) + { + serverSession->NotifyClientResourceUnallocated(); + serverSession = iMMRCServerInfo->PopAndRemoveFirstPausedContext( ); + } + + DP_OUT(); + } + +/* + * + */ +void CMMRCServerController::CloseSessionByContextId(TInt32 aContextId) + { + DP_CONTEXT(----> CMMRCServerController::CloseSessionByContextId *CD1*, CtxDevSound, DPLOCAL); + DP_IN(); + + while( iMMRCServerInfo->PopAndRemoveFirstAllocatedResourceContextByContextId( aContextId ) ){} + while( iMMRCServerInfo->PopAndRemoveFirstRequestByContextId( aContextId ) ){} + while( iMMRCServerInfo->PopAndRemovePausedContext( aContextId ) ){} + while( iMMRCServerInfo->PopAndRemoveFirstAPRContextByContextId( aContextId ) ){} + TUint64 contextId; + TMMRCServerState serverState; + iMMRCServerInfo->ServerState(serverState, contextId); + if( contextId == aContextId) + { + iMMRCServerInfo->SwitchServerState(EMMRCServerStateIdle, 0); + } +#ifdef SYMBIAN_MULTIMEDIA_ENABLE_LOGGING + RDebug::Print(_L("size of message queue = %d"), iMMRCServerInfo->RequestsCount()); + RDebug::Print(_L("size of inprocess queue = %d"), iMMRCServerInfo->AllocatedResourceContextsCount()); + RDebug::Print(_L("size of paused queue = %d"), iMMRCServerInfo->AllocatedPausedContextsCount()); + RDebug::Print(_L("size of APR queue = %d"), iMMRCServerInfo->AllocatedAPRContextsCount()); +#endif + + DP_OUT(); + } + +/* + * + */ +void CMMRCServerController::ServerState(TMMRCServerState& aServerState, TUint64& aContextId) const + { + iMMRCServerInfo->ServerState(aServerState, aContextId); + } + +/** + +*/ +TInt CMMRCServerController::EnqueueRequestForAPRL(CMMRCServerSession& aServerSession) + { + DP_CONTEXT(----> CMMRCServerController::EnqueueRequestForAPRL *CD1*, CtxDevSound, DPLOCAL); + DP_IN(); + + //add the request to the queue + TInt err = KErrNone; + //if already there, should return KErrAlreadyExists + + if (iMMRCServerInfo->IsOnAPRList(aServerSession.ContextId())) + { + err = KErrAlreadyExists; + } + else + { + iMMRCServerInfo->PushAPRContextL(aServerSession); + } + DP0_RET(err, "err=%d"); + } + +/** + +*/ +TInt CMMRCServerController::RemoveRequestForAPR(CMMRCServerSession& aServerSession) + { + DP_CONTEXT(----> CMMRCServerController::RemoveRequestForAPR *CD1*, CtxDevSound, DPLOCAL); + DP_IN(); + + TInt err = KErrNone; + TInt32 iContextId = aServerSession.ContextId(); + TBool iIsOnAPRList = iMMRCServerInfo->IsOnAPRList(iContextId); + if(iIsOnAPRList) + { + + // Its possible that the remove request has occured whilst clients are being notified that the resource is available + // Check if a notification sequence is currently under way + if ( iARNNotificationObject->IsActive() ) + { + + // Iterate through each paused client + for ( TInt index = 0 ; index < iMMRCServerInfo->AllocatedPausedContextsCount() ; index++ ) + { + + // Find the client that has requested removal in the list + TAudioContextId id = iMMRCServerInfo->PausedContextByIndex(index)->ContextId(); + if ( aServerSession.ContextId() == id ) + { + // Object has already received a notification + if ( index < iARNNotificationObject->iIndex ) + { + // decrement the notification objects list index to account for the item that will be removed from the queue + --iARNNotificationObject->iIndex; + } + + // no action needs to be taken if + // index >= iMMRCServerInfo.iIndex + + break; + } + } + + } + + iMMRCServerInfo->PopAndRemoveFirstAPRContextByContextId(iContextId); + iMMRCServerInfo->PopAndRemovePausedContext(iContextId); //removing this session from the list of paused too. + } + else + { + err = KErrCancel; + } + + DP0_RET(err, "err=%d"); + } + +/** + +*/ +TInt CMMRCServerController::WillResumePlay() + { + DP_CONTEXT(----> CMMRCServerController::WillResumePlay *CD1*, CtxDevSound, DPLOCAL); + DP_IN(); + + TInt err = KErrNone; + iARNNotificationObject->Cancel(); + + + DP0_RET(err, "err=%d"); + } + + +//From CActive +/** + * Constructor. + */ +CARNNotificationObject::CARNNotificationObject(const TInt aPriority) +:CActive(aPriority) + { + TRACE_CREATE(); + DP_CONTEXT(----> CARNNotificationObject::CARNNotificationObject *CD1*, CtxDevSound, DPLOCAL); + DP_IN(); + + + DP_OUT(); + } + + +/** + * Destructor. + */ +CARNNotificationObject::~CARNNotificationObject() + { + DP_CONTEXT(----> CARNNotificationObject::~CARNNotificationObject *CD1*, CtxDevSound, DPLOCAL); + DP_IN(); + + Cancel(); + iTimer.Close(); + delete iMMRCServerInfo; + + DP_OUT(); + } + + +/** + CARNNotificationObject::ConstructL + Symbian 2nd phase constructor can leave. + */ +void CARNNotificationObject::ConstructL(CMMRCServerInfo& aMMRCServerInfo) + { + DP_CONTEXT(----> CARNNotificationObject::ConstructL *CD1*, CtxDevSound, DPLOCAL); + DP_IN(); + + iMMRCServerInfo = &aMMRCServerInfo; + CActiveScheduler::Add(this); + User::LeaveIfError(iTimer.CreateLocal()); + + + DP_OUT(); + } + +// --------------------------------------------------------------------------- +// CARNNotificationObject::NewL +// --------------------------------------------------------------------------- +CARNNotificationObject* CARNNotificationObject::NewL(const TInt aPriority, CMMRCServerInfo& aMMRCServerInfo) + { + DP_STATIC_CONTEXT(----> CARNNotificationObject::NewL *CD1*, CtxDevSound, DPLOCAL); + DP_IN(); + + CARNNotificationObject* self = new(ELeave)CARNNotificationObject(aPriority); + CleanupStack::PushL(self); + self->ConstructL(aMMRCServerInfo); + CleanupStack::Pop(self); + + DP0_RET(self, "0x%x"); + } + +// --------------------------------------------------------------------------- +// CARNNotificationObject::RunL +// --------------------------------------------------------------------------- +void CARNNotificationObject::RunL() + { + DP_CONTEXT(CARNNotificationObject::RunL *CD1*, CtxDevSound, DPLOCAL); + DP_IN(); + + #if defined(_DEBUG) && defined(__WINS__) + const TTimeIntervalMicroSeconds32 KTimer = 1.8*1000000; // 1.8 seconds + #else + const TTimeIntervalMicroSeconds32 KTimer = 800000; // 0.8 seconds + #endif + + TInt numPausedContext = iMMRCServerInfo->AllocatedPausedContextsCount(); + + // The list may have been modified whilst the AO was asleep, need to check that: + // 1) iIndex is still in range + // 2) the object at that location should still receive a notification + + if ( (iIndex > -1) && (iIndex < numPausedContext) ) + { + CMMRCServerSession* mmrcSession = iMMRCServerInfo->PausedContextByIndex(iIndex); + + TAudioContextId id = mmrcSession->ContextId( ); + TBool isOnAPRList = iMMRCServerInfo->IsOnAPRList(id); + if(isOnAPRList) + { + mmrcSession->NotifyClientResourceUnallocated(); + } + + + for(TInt aux = iIndex + 1; aux < numPausedContext ; aux++) + { + mmrcSession = iMMRCServerInfo->PausedContextByIndex(aux); + id = mmrcSession->ContextId( ); + isOnAPRList = iMMRCServerInfo->IsOnAPRList(id); + if(isOnAPRList) + { + iIndex = aux; + After(KTimer); + break; + } + } + } + + else + { + iIndex = 0; + } + + DP_OUT(); + } + +// --------------------------------------------------------------------------- +// CARNNotificationObject::After +// --------------------------------------------------------------------------- +void CARNNotificationObject::After(TTimeIntervalMicroSeconds32 aInterval) + { + DP_CONTEXT(CARNNotificationObject::After *CD1*, CtxDevSound, DPLOCAL); + DP_IN(); + + Cancel(); + iTimer.After(iStatus,aInterval); + SetActive(); + + DP_OUT(); + } + +// --------------------------------------------------------------------------- +// CARNNotificationObject::Initialize +// --------------------------------------------------------------------------- +void CARNNotificationObject::Initialize() + { + DP_CONTEXT(CARNNotificationObject::Initialize *CD1*, CtxDevSound, DPLOCAL); + DP_IN(); + + #if defined(_DEBUG) && defined(__WINS__) + const TTimeIntervalMicroSeconds32 KTimer = 1.8*1000000; // 1.8 seconds + #else + const TTimeIntervalMicroSeconds32 KTimer = 800000; // 0.8 seconds + #endif + + TInt numPausedContext = iMMRCServerInfo->AllocatedPausedContextsCount(); + iIndex = 0; + CMMRCServerSession* mmrcSession = NULL; + + if(numPausedContext) // don't bother if zero. + { + for(TInt i(0); iPausedContextByIndex(i); + TAudioContextId id = mmrcSession->ContextId( ); + TBool isOnAPRList = iMMRCServerInfo->IsOnAPRList(id); + if(isOnAPRList) + { + iIndex = i; + After(KTimer); + break; + } + } + } + + DP_OUT(); + } + +// --------------------------------------------------------------------------- +// CMMRCServer::DoCancel +// --------------------------------------------------------------------------- +void CARNNotificationObject::DoCancel() + { + DP_CONTEXT(CARNNotificationObject::DoCancel *CD1*, CtxDevSound, DPLOCAL); + DP_IN(); + + iTimer.Cancel(); + + DP_OUT(); + } + + +void CMMRCServerController::Panic(TMMRCServerControllerPanicCodes aCode) + { + User::Panic(KMMRCServerControllerPanicCategory, aCode); + } +//EOF