diff -r 000000000000 -r bde4ae8d615e os/mm/devsound/devsoundrefplugin/src/server/Policy/MmfAudioPolicy.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/os/mm/devsound/devsoundrefplugin/src/server/Policy/MmfAudioPolicy.cpp Fri Jun 15 03:10:57 2012 +0200 @@ -0,0 +1,429 @@ +// Copyright (c) 2001-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 "MmfAudioPolicy.h" +#include "MmfAudioPolicySession.h" +#include "MmfAudioPolicyServer.h" +#include "MdaHwInfo.h" +#include "MmfAudioPolicyRequest.h" + +/** +*@internalTechnology +*@return if a client owns or wish to own audio resource +*/ +inline TBool IsActiveState(TMMFAudioPolicyState aState) + { + return (aState < EMMFStateStopped || aState==EMMFStateNotified || aState==EMMFStatePlayDualTone); + } + +CAudioPolicy::~CAudioPolicy() + { + delete iMdaHwInfo; + delete iAudioPolicyRequestArray; + } + +void CAudioPolicy::ConstructL() + { + // Create dynamic array for sessions list + iAudioPolicyRequestArray = new(ELeave) CPolicyReqPtrArray(CAudioPolicy::EGranularity); + iMdaHwInfo = CMdaHwInfo::NewL(); + } + +EXPORT_C CAudioPolicy* CAudioPolicy::NewL(CMMFAudioPolicyServer* aAudioPolicyServer) + { + + CAudioPolicy* self = new(ELeave)CAudioPolicy(aAudioPolicyServer); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(); + return(self); + } + +CAudioPolicy::CAudioPolicy(CMMFAudioPolicyServer* aAudioPolicyServer) : + iAudioPolicyServer(aAudioPolicyServer), + iNotifiedSessionId(KErrNotFound), + iSessionIdAwaitingForDevsound(KErrNotFound), + iStopHandledFromSessId(KErrNotFound) + { + } + +void CAudioPolicy::MakeRequest(CMMFAudioPolicyRequest* aAudioPolicyRequest) + { +// since we have a FIFO q, then remove request and re-add it. + RemoveFromList(aAudioPolicyRequest->PolicySessionId(), EFalse); + if (iStopHandledFromSessId==aAudioPolicyRequest->PolicySessionId()) + { + iStopHandledFromSessId=KErrNotFound; + } +// Process Request by looking at priorities, preferences, special states... + TPolicyResponse responseValue = ProcessRequest(aAudioPolicyRequest); +#if defined(ALLOW_POLICY_DEBUG) + RDebug::Print(_L("Sess ID=%d, Priority=%d"),aAudioPolicyRequest->PolicySessionId(),aAudioPolicyRequest->Priority()); +#endif + switch (responseValue) + { + case EDenied: + { + TMMFAudioPolicyEvent responseEvent(TMMFAudioPolicyEvent::EMMFAudioPolicyPriorityTooLow, KErrInUse,EMMFStateWaitingForResource); + // the client won't be notified until he has request so, so we can set its state anyway + aAudioPolicyRequest->SetState( EMMFStateWaitingForResource ); + iAudioPolicyServer->SendEventToClient(aAudioPolicyRequest->PolicySessionId(), responseEvent); + } + break; + case EProceed: + { + iAudioPolicyServer->StopNotificationTimer(); + TMMFAudioPolicyEvent responseEvent(TMMFAudioPolicyEvent::EMMFAudioPolicyNoEvent, KErrNone, aAudioPolicyRequest->State()); + iAudioPolicyServer->SendEventToClient(aAudioPolicyRequest->PolicySessionId(), responseEvent); + } + break; + case EStopThenProceed: + { + iAudioPolicyServer->StopNotificationTimer(); + iSessionIdAwaitingForDevsound=aAudioPolicyRequest->PolicySessionId(); + // we have to wait for devsound to stop client(s), then notify that one + } + break; + case EResume: + case EMix: + default: + ASSERT(EFalse); + } + TRAPD(err, iAudioPolicyRequestArray->AppendL(aAudioPolicyRequest) ); + __ASSERT_ALWAYS(err==KErrNone, Panic(EMMFAudioPolicyRequestArrayOverflow) ); // we reserved space, so shouldn't hit this + } + +TPolicyResponse CAudioPolicy::ProcessRequest(CMMFAudioPolicyRequest* aAudioPolicyRequest) + { + // If there is no other item on list, return with proceed + if (iAudioPolicyRequestArray->Count()==0) + { + return EProceed; + } + + TPolicyResponse responseValue(EProceed); + TInt requestPriority = aAudioPolicyRequest->Priority(); + + TBool requestCaps = aAudioPolicyRequest->Capabilities(); + + // Iterate through list and compare priorities: + // QUEST: state checking shall be done as well? + for (TInt index = 0; index < iAudioPolicyRequestArray->Count(); index++) + { + CMMFAudioPolicyRequest& currentReq=*(*iAudioPolicyRequestArray)[index]; + if (!IsActiveState(currentReq.State()) ) // this request is inactive + { + continue; + } + // If there's even one on the list w/ a higher priority deny request and leave: + + if (currentReq.Capabilities() > requestCaps) + { + responseValue = EDenied; + break; + } + else if(currentReq.Capabilities() == requestCaps) + { + if(currentReq.Priority() >= requestPriority) + { + responseValue = EDenied; + break; + } + } + if (currentReq.State()==EMMFStateWaitingForResource || currentReq.State()==EMMFStatePreempted) + { + continue; + } + // we need to stop active client since new request is of higher priority + TMMFAudioPolicyEvent freezeEvent(TMMFAudioPolicyEvent::EMMFAudioPolicyPriorityTooLow, KErrInUse, EMMFStatePaused); +#if defined(ALLOW_POLICY_DEBUG) + RDebug::Print(_L("Sess ID=%d, State=%d Has been preempted"),currentReq.PolicySessionId(),currentReq.State()); +#endif + currentReq.SetState( EMMFStatePreempted ); + currentReq.SetEventFlag(EFalse); + iAudioPolicyServer->SendEventToClient(currentReq.PolicySessionId(), freezeEvent); + responseValue = EStopThenProceed; + } + + return responseValue; + } + +void CAudioPolicy::ModifyEntry(TInt aPolicySessionId,const TMMFAudioPolicyState aNewState) + { + CMMFAudioPolicyRequest* sessionEntry=FindPolicyRequestById(aPolicySessionId); +#if defined(ALLOW_POLICY_DEBUG) + RDebug::Print(_L("Sess ID=%d, Old State=%d New State=%d"),aPolicySessionId,sessionEntry?sessionEntry->State():-1, aNewState); +#endif + // some client took over resource, so update its state and cancel timer + if (IsActiveState(aNewState)) + { + if (sessionEntry) + { + sessionEntry->SetState(aNewState); + sessionEntry->SetEventFlag(EFalse); + } + iAudioPolicyServer->StopNotificationTimer(); + iNotifiedSessionId =KErrNotFound; + ASSERT(iSessionIdAwaitingForDevsound==KErrNotFound); // we shouldn't have a client waiting to be notified + if (iStopHandledFromSessId==aPolicySessionId) + { + iStopHandledFromSessId=KErrNotFound; + } + return; + } + if (iNotifiedSessionId==aPolicySessionId) // if client that was notified, then stop timer. + { + iAudioPolicyServer->StopNotificationTimer(); + } + if (sessionEntry==NULL) // to cope with erroneous behaviour of devsound + { + return; + } + // we have update from the client, if we have other clients waiting we should notify them + if ( (aNewState == EMMFStatePaused || (aNewState == EMMFStateStopped && iStopHandledFromSessId!=aPolicySessionId) ) + && sessionEntry->State()!=EMMFStateStopped && sessionEntry->State()!=EMMFStateWaitingForResource) + { + if (aNewState == EMMFStateStopped) // to eliminate duplicate stop events + { + iStopHandledFromSessId=aPolicySessionId; + } + if (sessionEntry->State()==EMMFStatePreempted) + { + sessionEntry->SetState(EMMFStateWaitingForResource); + } + + if (iSessionIdAwaitingForDevsound==aPolicySessionId) + { + iSessionIdAwaitingForDevsound=KErrNotFound; + } + + if (aNewState == EMMFStatePaused || aNewState == EMMFStateStopped) // devsound should free, so notify waiting client + { + if (iSessionIdAwaitingForDevsound!=KErrNotFound) // we have a client waiting for Devsound, so notify it + { + NotifySessionWithTimeout(iSessionIdAwaitingForDevsound, TMMFAudioPolicyEvent::EMMFAudioPolicyNoEvent); + iSessionIdAwaitingForDevsound=KErrNotFound; + } + else if (!iAudioPolicyServer->IsTimerActive()) // do not try to notify if we're still waiting for response + { + const TInt sessionIdToNotify = CheckSessionToNotify(); + if(sessionIdToNotify != KErrNotFound) + { + // set the state as notified + NotifySessionWithTimeout(sessionIdToNotify, TMMFAudioPolicyEvent::EMMFAudioPolicyResourceNotification); + } + } + } + } + // we update state to passive only if the client hasn't been stopped by us, so as not loose its waiting indication + if (sessionEntry->State()!=EMMFStateWaitingForResource) + { + sessionEntry->SetState(aNewState); + } + } + +void CAudioPolicy::NotifySessionWithTimeout(TInt aPolicySessionId, TMMFAudioPolicyEvent::TAudioPolicyEventType aEvent) + { + CMMFAudioPolicyRequest* sessionEntry=FindPolicyRequestById(aPolicySessionId); + ASSERT(sessionEntry); +#if defined(ALLOW_POLICY_DEBUG) + RDebug::Print(_L("Sending timed not. ID=%d, State=%d Event=%d"),aPolicySessionId,sessionEntry->State(), aEvent); +#endif + const TMMFAudioPolicyEvent eventToSend(aEvent, KErrNone, sessionEntry->State()); + sessionEntry->SetEventFlag(ETrue); + iAudioPolicyServer->StartNotificationTimer(); + iNotifiedSessionId = aPolicySessionId; + iAudioPolicyServer->SendEventToClient(aPolicySessionId, eventToSend); + } + +void CAudioPolicy::RemoveFromList(TInt aPolicySessionId, TBool aAllowTimerRestart) + { + if (aPolicySessionId==KErrNotFound) + { + return; + } + for (TInt index = iAudioPolicyRequestArray->Count(); index-- ;) + { + // Find correct entry to remove + if ( (*iAudioPolicyRequestArray)[index]->PolicySessionId() == aPolicySessionId) + { + if (iSessionIdAwaitingForDevsound==aPolicySessionId) + { + iSessionIdAwaitingForDevsound=KErrNotFound; + } + if (iNotifiedSessionId==aPolicySessionId && iAudioPolicyServer->IsTimerActive()) + { + iNotifiedSessionId=KErrNotFound; + // the session we were waiting for disconnected so try to immediately notify another one + iAudioPolicyServer->StopNotificationTimer(); + if (iAudioPolicyRequestArray->Count() > 1 && aAllowTimerRestart) + { + iAudioPolicyServer->StartNotificationTimer(ETrue); + } + } + else if(!iAudioPolicyServer->IsTimerActive()) + { + if (iAudioPolicyRequestArray->Count() > 1 && aAllowTimerRestart) + { + iAudioPolicyServer->StartNotificationTimer(ETrue); + } + } + iAudioPolicyRequestArray->Delete(index); + return; + } + } + } + +void CAudioPolicy::HandlePreferences(CMMFAudioPolicyRequest* /*aAudioPolicyRequest*/, TInt /*aPref*/, TPolicyResponse& /*aResponse*/) + { + } + +// this is weird, but devsound +// does Stop() if a client is denied access to resource +// then calls this routine to indicate that resource became available +void CAudioPolicy::LaunchRequest(TInt aSessionId) + { + ASSERT(iSessionIdAwaitingForDevsound!=aSessionId); + ModifyEntry(aSessionId, EMMFStateStopped); + } + +void CAudioPolicy::ReserveClientNumL(TInt aNum) + { + iAudioPolicyRequestArray->SetReserveL(aNum); + } + +/** +@internalTechnology + +This function raises a panic + +@param aError + one of the several panics codes that may be raised by this dll + +@panic EMMFAudioPolicyRequestArrayOverflow is raised when policyrequest array is full +*/ +GLDEF_C void Panic(TMMFAudioPolicyPanicCodes aPanicCode) + { + User::Panic(KMMFAudioPolicyPanicCategory, aPanicCode); + } + +// checks based on the session ,Is the session is registered for Notification +TBool CAudioPolicy::IsRegisteredNotification(TInt aSessionId) const + { + TUid event; + for (TInt index = 0; index < iAudioPolicyRequestArray->Count(); index++) + { + if((*iAudioPolicyRequestArray)[index]->PolicySessionId() == aSessionId) + { + event = (*iAudioPolicyRequestArray)[index]->NotificationEvent(); + if (event == KMMFEventCategoryAudioResourceAvailable) + { + // only when the client is registered for KMMFEventCategoryAudioResourceAvailable event + return ETrue; + } + break; + } + } + return EFalse; + } + +// get the next highest priority of the client to notify +TInt CAudioPolicy::CheckSessionToNotify() + { + TInt nextHighestPriority= -100; + TInt sessionToNotify = KErrNotFound; + + // get the max priority and set the Index + for (TInt attempt=2; attempt-- && sessionToNotify==KErrNotFound;) + { + + for (TInt index = 0; index < iAudioPolicyRequestArray->Count(); ++index) + { + CMMFAudioPolicyRequest& currentReq=*(*iAudioPolicyRequestArray)[index]; + if((nextHighestPriority <= currentReq.Priority()) + && (currentReq.NotificationEvent() == KMMFEventCategoryAudioResourceAvailable) + && (!currentReq.IsEventNotified()) + && currentReq.State()==EMMFStateWaitingForResource) + { + nextHighestPriority = currentReq.Priority(); + sessionToNotify = currentReq.PolicySessionId(); + } + } + // we tried to notify every session once, so reset flag and try again. + if (sessionToNotify==KErrNotFound) + { + for (TInt i=iAudioPolicyRequestArray->Count(); i--;) + { + (*iAudioPolicyRequestArray)[i]->SetEventFlag(EFalse); + } + } + } + return sessionToNotify; + } + +// send the message to the server +void CAudioPolicy::NotifyNextClient() + { + const TInt sessionIdToNotify = CheckSessionToNotify(); +#if defined(ALLOW_POLICY_DEBUG) + RDebug::Print(_L("Sess ID %d didn't continue within timeout, Next ID=%d"), iNotifiedSessionId, sessionIdToNotify); +#endif + iNotifiedSessionId = KErrNotFound; + if(sessionIdToNotify != KErrNotFound) + { + NotifySessionWithTimeout(sessionIdToNotify, TMMFAudioPolicyEvent::EMMFAudioPolicyResourceNotification); + } + } + +// Set in the AudiopolicyRequestArray the uid registered +TInt CAudioPolicy::SetNotification(TInt aSessionId, TUid aEventType) + { + if (KMMFEventCategoryAudioResourceAvailable!=aEventType) + { + return EFalse; + } + for (TInt index = iAudioPolicyRequestArray->Count(); index-- ; ) + { + CMMFAudioPolicyRequest& currentReq=*(*iAudioPolicyRequestArray)[index]; + if(currentReq.PolicySessionId() == aSessionId) + { + currentReq.SetNotificationEvent(aEventType); +#if defined(ALLOW_POLICY_DEBUG) + RDebug::Print(_L("Sess ID %d state=%d requested resource notification"), aSessionId, currentReq.State()); +#endif + if (!IsActiveState(currentReq.State())) + { + currentReq.SetState(EMMFStateWaitingForResource); + } + return ETrue; + } + } + return EFalse; + } + +CMMFAudioPolicyRequest* CAudioPolicy::FindPolicyRequestById(TInt aSessionId) const + { + for (TInt index = iAudioPolicyRequestArray->Count(); index-- ; ) + { + if((*iAudioPolicyRequestArray)[index]->PolicySessionId() == aSessionId) + { + return (*iAudioPolicyRequestArray)[index]; + } + } + return NULL; + } + + +