os/mm/devsound/devsoundrefplugin/src/server/Policy/MmfAudioPolicy.cpp
changeset 0 bde4ae8d615e
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/os/mm/devsound/devsoundrefplugin/src/server/Policy/MmfAudioPolicy.cpp	Fri Jun 15 03:10:57 2012 +0200
     1.3 @@ -0,0 +1,429 @@
     1.4 +// Copyright (c) 2001-2009 Nokia Corporation and/or its subsidiary(-ies).
     1.5 +// All rights reserved.
     1.6 +// This component and the accompanying materials are made available
     1.7 +// under the terms of "Eclipse Public License v1.0"
     1.8 +// which accompanies this distribution, and is available
     1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
    1.10 +//
    1.11 +// Initial Contributors:
    1.12 +// Nokia Corporation - initial contribution.
    1.13 +//
    1.14 +// Contributors:
    1.15 +//
    1.16 +// Description:
    1.17 +//
    1.18 +
    1.19 +#include "MmfAudioPolicy.h"
    1.20 +#include "MmfAudioPolicySession.h"	
    1.21 +#include "MmfAudioPolicyServer.h"
    1.22 +#include "MdaHwInfo.h"	
    1.23 +#include "MmfAudioPolicyRequest.h"
    1.24 +
    1.25 +/**
    1.26 +*@internalTechnology
    1.27 +*@return if a client owns or wish to own audio resource
    1.28 +*/
    1.29 +inline TBool IsActiveState(TMMFAudioPolicyState aState)
    1.30 +	{
    1.31 +	return (aState < EMMFStateStopped || aState==EMMFStateNotified || aState==EMMFStatePlayDualTone);
    1.32 +	}
    1.33 +
    1.34 +CAudioPolicy::~CAudioPolicy()
    1.35 +	{
    1.36 +	delete iMdaHwInfo;
    1.37 +	delete iAudioPolicyRequestArray;
    1.38 +	}
    1.39 +
    1.40 +void CAudioPolicy::ConstructL()
    1.41 +	{
    1.42 +	// Create dynamic array for sessions list
    1.43 +	iAudioPolicyRequestArray = new(ELeave) CPolicyReqPtrArray(CAudioPolicy::EGranularity);
    1.44 +	iMdaHwInfo = CMdaHwInfo::NewL();
    1.45 +	}
    1.46 +
    1.47 +EXPORT_C CAudioPolicy* CAudioPolicy::NewL(CMMFAudioPolicyServer* aAudioPolicyServer)
    1.48 +	{	
    1.49 +
    1.50 +	CAudioPolicy* self = new(ELeave)CAudioPolicy(aAudioPolicyServer);
    1.51 +	CleanupStack::PushL(self);
    1.52 +	self->ConstructL();
    1.53 +	CleanupStack::Pop();
    1.54 +	return(self);
    1.55 +	}
    1.56 +
    1.57 +CAudioPolicy::CAudioPolicy(CMMFAudioPolicyServer* aAudioPolicyServer) :
    1.58 +	iAudioPolicyServer(aAudioPolicyServer),
    1.59 +	iNotifiedSessionId(KErrNotFound),
    1.60 +	iSessionIdAwaitingForDevsound(KErrNotFound),
    1.61 +	iStopHandledFromSessId(KErrNotFound)
    1.62 +	{
    1.63 +	}
    1.64 +
    1.65 +void CAudioPolicy::MakeRequest(CMMFAudioPolicyRequest* aAudioPolicyRequest)
    1.66 +	{
    1.67 +// since we have a FIFO q, then remove request and re-add it.
    1.68 +	RemoveFromList(aAudioPolicyRequest->PolicySessionId(), EFalse); 
    1.69 +	if (iStopHandledFromSessId==aAudioPolicyRequest->PolicySessionId())
    1.70 +		{
    1.71 +		iStopHandledFromSessId=KErrNotFound;
    1.72 +		}
    1.73 +// Process Request by looking at priorities, preferences, special states...
    1.74 +	TPolicyResponse responseValue = ProcessRequest(aAudioPolicyRequest);
    1.75 +#if defined(ALLOW_POLICY_DEBUG)
    1.76 +	RDebug::Print(_L("Sess ID=%d, Priority=%d"),aAudioPolicyRequest->PolicySessionId(),aAudioPolicyRequest->Priority());
    1.77 +#endif	
    1.78 +	switch (responseValue)
    1.79 +		{
    1.80 +		case EDenied:
    1.81 +			{
    1.82 +			TMMFAudioPolicyEvent responseEvent(TMMFAudioPolicyEvent::EMMFAudioPolicyPriorityTooLow, KErrInUse,EMMFStateWaitingForResource);
    1.83 +			// the client won't be notified until he has request so, so we can set its state anyway
    1.84 +			aAudioPolicyRequest->SetState( EMMFStateWaitingForResource ); 
    1.85 +			iAudioPolicyServer->SendEventToClient(aAudioPolicyRequest->PolicySessionId(), responseEvent);
    1.86 +			}
    1.87 +			break;
    1.88 +		case EProceed:
    1.89 +			{
    1.90 +			iAudioPolicyServer->StopNotificationTimer();
    1.91 +			TMMFAudioPolicyEvent responseEvent(TMMFAudioPolicyEvent::EMMFAudioPolicyNoEvent, KErrNone, aAudioPolicyRequest->State());
    1.92 +			iAudioPolicyServer->SendEventToClient(aAudioPolicyRequest->PolicySessionId(), responseEvent);
    1.93 +			}
    1.94 +			break;
    1.95 +		case EStopThenProceed:
    1.96 +			{
    1.97 +			iAudioPolicyServer->StopNotificationTimer(); 
    1.98 +			iSessionIdAwaitingForDevsound=aAudioPolicyRequest->PolicySessionId();
    1.99 +			// we have to wait for devsound to stop client(s), then notify that one
   1.100 +			}
   1.101 +			break;
   1.102 +		case EResume:
   1.103 +		case EMix:
   1.104 +		default:
   1.105 +			ASSERT(EFalse);
   1.106 +		}
   1.107 +	TRAPD(err, iAudioPolicyRequestArray->AppendL(aAudioPolicyRequest) );
   1.108 +	__ASSERT_ALWAYS(err==KErrNone, Panic(EMMFAudioPolicyRequestArrayOverflow) ); // we reserved space, so shouldn't hit this
   1.109 +	}
   1.110 +
   1.111 +TPolicyResponse CAudioPolicy::ProcessRequest(CMMFAudioPolicyRequest* aAudioPolicyRequest)
   1.112 +	{
   1.113 +	// If there is no other item on list, return with proceed
   1.114 +	if (iAudioPolicyRequestArray->Count()==0)
   1.115 +		{
   1.116 +		return EProceed;
   1.117 +		}
   1.118 +		
   1.119 +	TPolicyResponse responseValue(EProceed);
   1.120 +	TInt requestPriority = aAudioPolicyRequest->Priority();
   1.121 +	
   1.122 +	TBool requestCaps = aAudioPolicyRequest->Capabilities();
   1.123 +
   1.124 +	// Iterate through list and compare priorities:
   1.125 +	// QUEST: state checking shall be done as well?
   1.126 +	for (TInt index = 0; index < iAudioPolicyRequestArray->Count(); index++)
   1.127 +		{
   1.128 +		CMMFAudioPolicyRequest& currentReq=*(*iAudioPolicyRequestArray)[index];
   1.129 +		if (!IsActiveState(currentReq.State()) ) // this request is inactive
   1.130 +			{
   1.131 +			continue;
   1.132 +			}
   1.133 +			// If there's even one on the list w/ a higher priority deny request and leave:
   1.134 +
   1.135 +		if (currentReq.Capabilities() > requestCaps)
   1.136 +			{
   1.137 +			responseValue = EDenied;
   1.138 +			break;
   1.139 +			}
   1.140 +		else if(currentReq.Capabilities() == requestCaps) 
   1.141 +			{
   1.142 +			if(currentReq.Priority() >= requestPriority)
   1.143 +				{
   1.144 +				responseValue = EDenied;
   1.145 +				break;
   1.146 +				}
   1.147 +			}
   1.148 +		if (currentReq.State()==EMMFStateWaitingForResource || currentReq.State()==EMMFStatePreempted)
   1.149 +			{
   1.150 +			continue;
   1.151 +			}
   1.152 +		// we need to stop active client since new request is of higher priority
   1.153 +		TMMFAudioPolicyEvent freezeEvent(TMMFAudioPolicyEvent::EMMFAudioPolicyPriorityTooLow, KErrInUse, EMMFStatePaused);
   1.154 +#if defined(ALLOW_POLICY_DEBUG)	
   1.155 +		RDebug::Print(_L("Sess ID=%d, State=%d Has been preempted"),currentReq.PolicySessionId(),currentReq.State());
   1.156 +#endif			
   1.157 +		currentReq.SetState( EMMFStatePreempted );
   1.158 +		currentReq.SetEventFlag(EFalse);
   1.159 +		iAudioPolicyServer->SendEventToClient(currentReq.PolicySessionId(), freezeEvent);
   1.160 +		responseValue = EStopThenProceed;
   1.161 +		}
   1.162 +
   1.163 +	return responseValue;
   1.164 +	}
   1.165 +
   1.166 +void CAudioPolicy::ModifyEntry(TInt aPolicySessionId,const TMMFAudioPolicyState aNewState)
   1.167 +	{
   1.168 +	CMMFAudioPolicyRequest* sessionEntry=FindPolicyRequestById(aPolicySessionId);
   1.169 +#if defined(ALLOW_POLICY_DEBUG)	
   1.170 +	RDebug::Print(_L("Sess ID=%d, Old State=%d New State=%d"),aPolicySessionId,sessionEntry?sessionEntry->State():-1, aNewState);
   1.171 +#endif	
   1.172 +	// some client took over resource, so update its state and cancel timer
   1.173 +	if (IsActiveState(aNewState))
   1.174 +		{
   1.175 +		if (sessionEntry)
   1.176 +			{
   1.177 +			sessionEntry->SetState(aNewState);	
   1.178 +			sessionEntry->SetEventFlag(EFalse);
   1.179 +			}
   1.180 +		iAudioPolicyServer->StopNotificationTimer();
   1.181 +		iNotifiedSessionId	=KErrNotFound;
   1.182 +		ASSERT(iSessionIdAwaitingForDevsound==KErrNotFound); // we shouldn't have a client waiting to be notified
   1.183 +		if (iStopHandledFromSessId==aPolicySessionId)
   1.184 +			{
   1.185 +			iStopHandledFromSessId=KErrNotFound;
   1.186 +			}
   1.187 +		return;
   1.188 +		}
   1.189 +	if (iNotifiedSessionId==aPolicySessionId) // if client that was notified, then stop timer.
   1.190 +		{
   1.191 +		iAudioPolicyServer->StopNotificationTimer();
   1.192 +		}
   1.193 +	if (sessionEntry==NULL) // to cope with erroneous behaviour of devsound
   1.194 +		{
   1.195 +		return;
   1.196 +		}
   1.197 +	// we have update from the client, if we have other clients waiting we should notify them
   1.198 +	if ( (aNewState == EMMFStatePaused || (aNewState == EMMFStateStopped && iStopHandledFromSessId!=aPolicySessionId) )
   1.199 +			&& sessionEntry->State()!=EMMFStateStopped && sessionEntry->State()!=EMMFStateWaitingForResource)
   1.200 +		{
   1.201 +		if (aNewState == EMMFStateStopped) // to eliminate duplicate stop events
   1.202 +			{
   1.203 +			iStopHandledFromSessId=aPolicySessionId;
   1.204 +			}
   1.205 +		if (sessionEntry->State()==EMMFStatePreempted)
   1.206 +			{
   1.207 +			sessionEntry->SetState(EMMFStateWaitingForResource);
   1.208 +			}
   1.209 +			
   1.210 +		if (iSessionIdAwaitingForDevsound==aPolicySessionId)
   1.211 +			{
   1.212 +			iSessionIdAwaitingForDevsound=KErrNotFound;
   1.213 +			}
   1.214 +			
   1.215 +		if (aNewState == EMMFStatePaused || aNewState == EMMFStateStopped) // devsound should free, so notify waiting client
   1.216 +			{
   1.217 +			if (iSessionIdAwaitingForDevsound!=KErrNotFound) // we have a client waiting for Devsound, so notify it
   1.218 +				{
   1.219 +				NotifySessionWithTimeout(iSessionIdAwaitingForDevsound, TMMFAudioPolicyEvent::EMMFAudioPolicyNoEvent);
   1.220 +				iSessionIdAwaitingForDevsound=KErrNotFound;
   1.221 +				}
   1.222 +			else if (!iAudioPolicyServer->IsTimerActive()) // do not try to notify if we're still waiting for response
   1.223 +				{
   1.224 +				const TInt sessionIdToNotify = CheckSessionToNotify();
   1.225 +				if(sessionIdToNotify != KErrNotFound)
   1.226 +					{
   1.227 +					// set the state as notified
   1.228 +					NotifySessionWithTimeout(sessionIdToNotify, TMMFAudioPolicyEvent::EMMFAudioPolicyResourceNotification);
   1.229 +					}				
   1.230 +				}
   1.231 +			}
   1.232 +		}
   1.233 +	// we update state to passive only if the client hasn't been stopped by us, so as not loose its waiting indication
   1.234 +	if (sessionEntry->State()!=EMMFStateWaitingForResource)
   1.235 +		{
   1.236 +		sessionEntry->SetState(aNewState);
   1.237 +		}
   1.238 +	}
   1.239 +	
   1.240 +void CAudioPolicy::NotifySessionWithTimeout(TInt aPolicySessionId, TMMFAudioPolicyEvent::TAudioPolicyEventType aEvent)
   1.241 +	{
   1.242 +	CMMFAudioPolicyRequest* sessionEntry=FindPolicyRequestById(aPolicySessionId);
   1.243 +	ASSERT(sessionEntry);
   1.244 +#if defined(ALLOW_POLICY_DEBUG)	
   1.245 +	RDebug::Print(_L("Sending timed not. ID=%d, State=%d Event=%d"),aPolicySessionId,sessionEntry->State(), aEvent);
   1.246 +#endif
   1.247 +	const TMMFAudioPolicyEvent eventToSend(aEvent, KErrNone, sessionEntry->State());
   1.248 +	sessionEntry->SetEventFlag(ETrue);
   1.249 +	iAudioPolicyServer->StartNotificationTimer();
   1.250 +	iNotifiedSessionId 	= aPolicySessionId;
   1.251 +	iAudioPolicyServer->SendEventToClient(aPolicySessionId, eventToSend);
   1.252 +	}
   1.253 +
   1.254 +void CAudioPolicy::RemoveFromList(TInt aPolicySessionId, TBool aAllowTimerRestart)
   1.255 +	{
   1.256 +	if (aPolicySessionId==KErrNotFound)
   1.257 +		{
   1.258 +		return;
   1.259 +		}
   1.260 +	for (TInt index = iAudioPolicyRequestArray->Count(); index-- ;)
   1.261 +		{
   1.262 +		// Find correct entry to remove	
   1.263 +		if ( (*iAudioPolicyRequestArray)[index]->PolicySessionId() == aPolicySessionId)
   1.264 +			{
   1.265 +			if (iSessionIdAwaitingForDevsound==aPolicySessionId)
   1.266 +				{
   1.267 +				iSessionIdAwaitingForDevsound=KErrNotFound;
   1.268 +				}			
   1.269 +			if (iNotifiedSessionId==aPolicySessionId && iAudioPolicyServer->IsTimerActive()) 
   1.270 +				{
   1.271 +				iNotifiedSessionId=KErrNotFound;
   1.272 +				// the session we were waiting for disconnected so try to immediately notify another one
   1.273 +				iAudioPolicyServer->StopNotificationTimer();
   1.274 +				if (iAudioPolicyRequestArray->Count() > 1 && aAllowTimerRestart)
   1.275 +					{
   1.276 +					iAudioPolicyServer->StartNotificationTimer(ETrue);
   1.277 +					}
   1.278 +				}			
   1.279 +			else if(!iAudioPolicyServer->IsTimerActive())
   1.280 +				{
   1.281 +				if (iAudioPolicyRequestArray->Count() > 1 && aAllowTimerRestart)
   1.282 +					{
   1.283 +					iAudioPolicyServer->StartNotificationTimer(ETrue);
   1.284 +					}
   1.285 +				}
   1.286 +			iAudioPolicyRequestArray->Delete(index);
   1.287 +			return;
   1.288 +			}
   1.289 +		}
   1.290 +	}
   1.291 +	
   1.292 +void CAudioPolicy::HandlePreferences(CMMFAudioPolicyRequest* /*aAudioPolicyRequest*/, TInt /*aPref*/, TPolicyResponse& /*aResponse*/)
   1.293 +	{
   1.294 +	}
   1.295 +
   1.296 +// this is weird, but devsound 
   1.297 +// does Stop() if a client is denied access to resource
   1.298 +// then calls this routine to indicate that resource became available
   1.299 +void CAudioPolicy::LaunchRequest(TInt aSessionId)
   1.300 +	{
   1.301 +	ASSERT(iSessionIdAwaitingForDevsound!=aSessionId);
   1.302 +	ModifyEntry(aSessionId, EMMFStateStopped);
   1.303 +	}
   1.304 +
   1.305 +void CAudioPolicy::ReserveClientNumL(TInt aNum)
   1.306 +	{
   1.307 +	iAudioPolicyRequestArray->SetReserveL(aNum);
   1.308 +	}
   1.309 +
   1.310 +/**
   1.311 +@internalTechnology
   1.312 +
   1.313 +This function raises a panic
   1.314 +
   1.315 +@param	aError
   1.316 +		one of the several panics codes that may be raised by this dll
   1.317 +
   1.318 +@panic	EMMFAudioPolicyRequestArrayOverflow is raised when policyrequest array is full
   1.319 +*/
   1.320 +GLDEF_C void Panic(TMMFAudioPolicyPanicCodes aPanicCode)
   1.321 +	{
   1.322 +	User::Panic(KMMFAudioPolicyPanicCategory, aPanicCode);
   1.323 +	}
   1.324 +
   1.325 +// checks based on the session ,Is the session is registered for Notification 
   1.326 +TBool CAudioPolicy::IsRegisteredNotification(TInt aSessionId) const
   1.327 +	{
   1.328 +	TUid event;
   1.329 + 	for (TInt index = 0; index < iAudioPolicyRequestArray->Count(); index++)
   1.330 + 		{
   1.331 + 		if((*iAudioPolicyRequestArray)[index]->PolicySessionId() == aSessionId)
   1.332 + 			{
   1.333 + 			event = (*iAudioPolicyRequestArray)[index]->NotificationEvent();
   1.334 + 			if (event  == KMMFEventCategoryAudioResourceAvailable)
   1.335 + 				{
   1.336 + 				// only when the client is registered for KMMFEventCategoryAudioResourceAvailable event
   1.337 + 				return ETrue; 
   1.338 + 				}
   1.339 + 			break;	
   1.340 + 			} 
   1.341 + 		} 
   1.342 + 	return EFalse;
   1.343 +	}
   1.344 +
   1.345 +// get the next highest priority of the client to notify 	
   1.346 +TInt CAudioPolicy::CheckSessionToNotify()
   1.347 +	{
   1.348 +	TInt nextHighestPriority= -100;
   1.349 +	TInt sessionToNotify = KErrNotFound;
   1.350 +
   1.351 +	// get the max priority and set the Index
   1.352 +	for (TInt attempt=2; attempt-- && sessionToNotify==KErrNotFound;)
   1.353 +		{
   1.354 +		
   1.355 +		for (TInt index = 0; index < iAudioPolicyRequestArray->Count(); ++index)
   1.356 +	 		{
   1.357 +	 		CMMFAudioPolicyRequest& currentReq=*(*iAudioPolicyRequestArray)[index];
   1.358 +	 		if((nextHighestPriority <= currentReq.Priority())
   1.359 +	 					&& (currentReq.NotificationEvent() == KMMFEventCategoryAudioResourceAvailable) 
   1.360 +	 					&& (!currentReq.IsEventNotified())
   1.361 +	 					&& currentReq.State()==EMMFStateWaitingForResource)
   1.362 +	 			{
   1.363 +	 			nextHighestPriority = currentReq.Priority();
   1.364 +	 			sessionToNotify = currentReq.PolicySessionId();
   1.365 +	 			}
   1.366 +	 		}
   1.367 +	 	// we tried to notify every session once, so reset flag and try again.
   1.368 +	 	if (sessionToNotify==KErrNotFound)
   1.369 +	 		{
   1.370 +	 		for (TInt i=iAudioPolicyRequestArray->Count(); i--;)
   1.371 +	 			{
   1.372 +	 			(*iAudioPolicyRequestArray)[i]->SetEventFlag(EFalse);
   1.373 +	 			}
   1.374 +	 		}
   1.375 + 		}
   1.376 +  	return sessionToNotify;	
   1.377 +	}
   1.378 +
   1.379 +// send the message to the server 
   1.380 +void CAudioPolicy::NotifyNextClient()
   1.381 +	{
   1.382 +	const TInt sessionIdToNotify = CheckSessionToNotify();
   1.383 +#if defined(ALLOW_POLICY_DEBUG)	
   1.384 +	RDebug::Print(_L("Sess ID %d didn't continue within timeout, Next ID=%d"), iNotifiedSessionId, sessionIdToNotify);
   1.385 +#endif	
   1.386 +	iNotifiedSessionId = KErrNotFound;
   1.387 +	if(sessionIdToNotify != KErrNotFound)
   1.388 +		{
   1.389 +		NotifySessionWithTimeout(sessionIdToNotify, TMMFAudioPolicyEvent::EMMFAudioPolicyResourceNotification);
   1.390 +		}	
   1.391 +	}
   1.392 +
   1.393 +// Set in the AudiopolicyRequestArray the uid registered
   1.394 +TInt CAudioPolicy::SetNotification(TInt aSessionId, TUid aEventType)
   1.395 +	{
   1.396 +	if (KMMFEventCategoryAudioResourceAvailable!=aEventType)
   1.397 +		{
   1.398 +		return EFalse;
   1.399 +		}
   1.400 +	for (TInt index = iAudioPolicyRequestArray->Count(); index-- ; )
   1.401 + 		{
   1.402 + 		CMMFAudioPolicyRequest& currentReq=*(*iAudioPolicyRequestArray)[index];
   1.403 + 		if(currentReq.PolicySessionId() == aSessionId)
   1.404 + 			{
   1.405 + 			currentReq.SetNotificationEvent(aEventType);
   1.406 +#if defined(ALLOW_POLICY_DEBUG)
   1.407 +			RDebug::Print(_L("Sess ID %d state=%d requested resource notification"), aSessionId, currentReq.State());
   1.408 +#endif			 			 			
   1.409 + 			if (!IsActiveState(currentReq.State()))
   1.410 + 				{
   1.411 + 				currentReq.SetState(EMMFStateWaitingForResource);
   1.412 + 				}
   1.413 + 			return ETrue;	
   1.414 + 			}
   1.415 + 		}
   1.416 + 	return EFalse;
   1.417 +	}
   1.418 +
   1.419 +CMMFAudioPolicyRequest* CAudioPolicy::FindPolicyRequestById(TInt aSessionId) const
   1.420 +	{
   1.421 +	for (TInt index = iAudioPolicyRequestArray->Count(); index-- ; )
   1.422 + 		{
   1.423 + 		if((*iAudioPolicyRequestArray)[index]->PolicySessionId() == aSessionId)
   1.424 + 			{
   1.425 + 			return (*iAudioPolicyRequestArray)[index];
   1.426 + 			}
   1.427 + 		}
   1.428 +	return NULL;
   1.429 +	}
   1.430 +
   1.431 +
   1.432 +