devsound/devsoundrefplugin/src/server/Policy/MmfAudioPolicy.cpp
changeset 0 40261b775718
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/devsound/devsoundrefplugin/src/server/Policy/MmfAudioPolicy.cpp	Tue Feb 02 01:56:55 2010 +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;
+	}
+
+
+