os/mm/devsound/devsoundrefplugin/src/server/Policy/MmfAudioPolicy.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 // Copyright (c) 2001-2009 Nokia Corporation and/or its subsidiary(-ies).
     2 // All rights reserved.
     3 // This component and the accompanying materials are made available
     4 // under the terms of "Eclipse Public License v1.0"
     5 // which accompanies this distribution, and is available
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 //
    15 
    16 #include "MmfAudioPolicy.h"
    17 #include "MmfAudioPolicySession.h"	
    18 #include "MmfAudioPolicyServer.h"
    19 #include "MdaHwInfo.h"	
    20 #include "MmfAudioPolicyRequest.h"
    21 
    22 /**
    23 *@internalTechnology
    24 *@return if a client owns or wish to own audio resource
    25 */
    26 inline TBool IsActiveState(TMMFAudioPolicyState aState)
    27 	{
    28 	return (aState < EMMFStateStopped || aState==EMMFStateNotified || aState==EMMFStatePlayDualTone);
    29 	}
    30 
    31 CAudioPolicy::~CAudioPolicy()
    32 	{
    33 	delete iMdaHwInfo;
    34 	delete iAudioPolicyRequestArray;
    35 	}
    36 
    37 void CAudioPolicy::ConstructL()
    38 	{
    39 	// Create dynamic array for sessions list
    40 	iAudioPolicyRequestArray = new(ELeave) CPolicyReqPtrArray(CAudioPolicy::EGranularity);
    41 	iMdaHwInfo = CMdaHwInfo::NewL();
    42 	}
    43 
    44 EXPORT_C CAudioPolicy* CAudioPolicy::NewL(CMMFAudioPolicyServer* aAudioPolicyServer)
    45 	{	
    46 
    47 	CAudioPolicy* self = new(ELeave)CAudioPolicy(aAudioPolicyServer);
    48 	CleanupStack::PushL(self);
    49 	self->ConstructL();
    50 	CleanupStack::Pop();
    51 	return(self);
    52 	}
    53 
    54 CAudioPolicy::CAudioPolicy(CMMFAudioPolicyServer* aAudioPolicyServer) :
    55 	iAudioPolicyServer(aAudioPolicyServer),
    56 	iNotifiedSessionId(KErrNotFound),
    57 	iSessionIdAwaitingForDevsound(KErrNotFound),
    58 	iStopHandledFromSessId(KErrNotFound)
    59 	{
    60 	}
    61 
    62 void CAudioPolicy::MakeRequest(CMMFAudioPolicyRequest* aAudioPolicyRequest)
    63 	{
    64 // since we have a FIFO q, then remove request and re-add it.
    65 	RemoveFromList(aAudioPolicyRequest->PolicySessionId(), EFalse); 
    66 	if (iStopHandledFromSessId==aAudioPolicyRequest->PolicySessionId())
    67 		{
    68 		iStopHandledFromSessId=KErrNotFound;
    69 		}
    70 // Process Request by looking at priorities, preferences, special states...
    71 	TPolicyResponse responseValue = ProcessRequest(aAudioPolicyRequest);
    72 #if defined(ALLOW_POLICY_DEBUG)
    73 	RDebug::Print(_L("Sess ID=%d, Priority=%d"),aAudioPolicyRequest->PolicySessionId(),aAudioPolicyRequest->Priority());
    74 #endif	
    75 	switch (responseValue)
    76 		{
    77 		case EDenied:
    78 			{
    79 			TMMFAudioPolicyEvent responseEvent(TMMFAudioPolicyEvent::EMMFAudioPolicyPriorityTooLow, KErrInUse,EMMFStateWaitingForResource);
    80 			// the client won't be notified until he has request so, so we can set its state anyway
    81 			aAudioPolicyRequest->SetState( EMMFStateWaitingForResource ); 
    82 			iAudioPolicyServer->SendEventToClient(aAudioPolicyRequest->PolicySessionId(), responseEvent);
    83 			}
    84 			break;
    85 		case EProceed:
    86 			{
    87 			iAudioPolicyServer->StopNotificationTimer();
    88 			TMMFAudioPolicyEvent responseEvent(TMMFAudioPolicyEvent::EMMFAudioPolicyNoEvent, KErrNone, aAudioPolicyRequest->State());
    89 			iAudioPolicyServer->SendEventToClient(aAudioPolicyRequest->PolicySessionId(), responseEvent);
    90 			}
    91 			break;
    92 		case EStopThenProceed:
    93 			{
    94 			iAudioPolicyServer->StopNotificationTimer(); 
    95 			iSessionIdAwaitingForDevsound=aAudioPolicyRequest->PolicySessionId();
    96 			// we have to wait for devsound to stop client(s), then notify that one
    97 			}
    98 			break;
    99 		case EResume:
   100 		case EMix:
   101 		default:
   102 			ASSERT(EFalse);
   103 		}
   104 	TRAPD(err, iAudioPolicyRequestArray->AppendL(aAudioPolicyRequest) );
   105 	__ASSERT_ALWAYS(err==KErrNone, Panic(EMMFAudioPolicyRequestArrayOverflow) ); // we reserved space, so shouldn't hit this
   106 	}
   107 
   108 TPolicyResponse CAudioPolicy::ProcessRequest(CMMFAudioPolicyRequest* aAudioPolicyRequest)
   109 	{
   110 	// If there is no other item on list, return with proceed
   111 	if (iAudioPolicyRequestArray->Count()==0)
   112 		{
   113 		return EProceed;
   114 		}
   115 		
   116 	TPolicyResponse responseValue(EProceed);
   117 	TInt requestPriority = aAudioPolicyRequest->Priority();
   118 	
   119 	TBool requestCaps = aAudioPolicyRequest->Capabilities();
   120 
   121 	// Iterate through list and compare priorities:
   122 	// QUEST: state checking shall be done as well?
   123 	for (TInt index = 0; index < iAudioPolicyRequestArray->Count(); index++)
   124 		{
   125 		CMMFAudioPolicyRequest& currentReq=*(*iAudioPolicyRequestArray)[index];
   126 		if (!IsActiveState(currentReq.State()) ) // this request is inactive
   127 			{
   128 			continue;
   129 			}
   130 			// If there's even one on the list w/ a higher priority deny request and leave:
   131 
   132 		if (currentReq.Capabilities() > requestCaps)
   133 			{
   134 			responseValue = EDenied;
   135 			break;
   136 			}
   137 		else if(currentReq.Capabilities() == requestCaps) 
   138 			{
   139 			if(currentReq.Priority() >= requestPriority)
   140 				{
   141 				responseValue = EDenied;
   142 				break;
   143 				}
   144 			}
   145 		if (currentReq.State()==EMMFStateWaitingForResource || currentReq.State()==EMMFStatePreempted)
   146 			{
   147 			continue;
   148 			}
   149 		// we need to stop active client since new request is of higher priority
   150 		TMMFAudioPolicyEvent freezeEvent(TMMFAudioPolicyEvent::EMMFAudioPolicyPriorityTooLow, KErrInUse, EMMFStatePaused);
   151 #if defined(ALLOW_POLICY_DEBUG)	
   152 		RDebug::Print(_L("Sess ID=%d, State=%d Has been preempted"),currentReq.PolicySessionId(),currentReq.State());
   153 #endif			
   154 		currentReq.SetState( EMMFStatePreempted );
   155 		currentReq.SetEventFlag(EFalse);
   156 		iAudioPolicyServer->SendEventToClient(currentReq.PolicySessionId(), freezeEvent);
   157 		responseValue = EStopThenProceed;
   158 		}
   159 
   160 	return responseValue;
   161 	}
   162 
   163 void CAudioPolicy::ModifyEntry(TInt aPolicySessionId,const TMMFAudioPolicyState aNewState)
   164 	{
   165 	CMMFAudioPolicyRequest* sessionEntry=FindPolicyRequestById(aPolicySessionId);
   166 #if defined(ALLOW_POLICY_DEBUG)	
   167 	RDebug::Print(_L("Sess ID=%d, Old State=%d New State=%d"),aPolicySessionId,sessionEntry?sessionEntry->State():-1, aNewState);
   168 #endif	
   169 	// some client took over resource, so update its state and cancel timer
   170 	if (IsActiveState(aNewState))
   171 		{
   172 		if (sessionEntry)
   173 			{
   174 			sessionEntry->SetState(aNewState);	
   175 			sessionEntry->SetEventFlag(EFalse);
   176 			}
   177 		iAudioPolicyServer->StopNotificationTimer();
   178 		iNotifiedSessionId	=KErrNotFound;
   179 		ASSERT(iSessionIdAwaitingForDevsound==KErrNotFound); // we shouldn't have a client waiting to be notified
   180 		if (iStopHandledFromSessId==aPolicySessionId)
   181 			{
   182 			iStopHandledFromSessId=KErrNotFound;
   183 			}
   184 		return;
   185 		}
   186 	if (iNotifiedSessionId==aPolicySessionId) // if client that was notified, then stop timer.
   187 		{
   188 		iAudioPolicyServer->StopNotificationTimer();
   189 		}
   190 	if (sessionEntry==NULL) // to cope with erroneous behaviour of devsound
   191 		{
   192 		return;
   193 		}
   194 	// we have update from the client, if we have other clients waiting we should notify them
   195 	if ( (aNewState == EMMFStatePaused || (aNewState == EMMFStateStopped && iStopHandledFromSessId!=aPolicySessionId) )
   196 			&& sessionEntry->State()!=EMMFStateStopped && sessionEntry->State()!=EMMFStateWaitingForResource)
   197 		{
   198 		if (aNewState == EMMFStateStopped) // to eliminate duplicate stop events
   199 			{
   200 			iStopHandledFromSessId=aPolicySessionId;
   201 			}
   202 		if (sessionEntry->State()==EMMFStatePreempted)
   203 			{
   204 			sessionEntry->SetState(EMMFStateWaitingForResource);
   205 			}
   206 			
   207 		if (iSessionIdAwaitingForDevsound==aPolicySessionId)
   208 			{
   209 			iSessionIdAwaitingForDevsound=KErrNotFound;
   210 			}
   211 			
   212 		if (aNewState == EMMFStatePaused || aNewState == EMMFStateStopped) // devsound should free, so notify waiting client
   213 			{
   214 			if (iSessionIdAwaitingForDevsound!=KErrNotFound) // we have a client waiting for Devsound, so notify it
   215 				{
   216 				NotifySessionWithTimeout(iSessionIdAwaitingForDevsound, TMMFAudioPolicyEvent::EMMFAudioPolicyNoEvent);
   217 				iSessionIdAwaitingForDevsound=KErrNotFound;
   218 				}
   219 			else if (!iAudioPolicyServer->IsTimerActive()) // do not try to notify if we're still waiting for response
   220 				{
   221 				const TInt sessionIdToNotify = CheckSessionToNotify();
   222 				if(sessionIdToNotify != KErrNotFound)
   223 					{
   224 					// set the state as notified
   225 					NotifySessionWithTimeout(sessionIdToNotify, TMMFAudioPolicyEvent::EMMFAudioPolicyResourceNotification);
   226 					}				
   227 				}
   228 			}
   229 		}
   230 	// we update state to passive only if the client hasn't been stopped by us, so as not loose its waiting indication
   231 	if (sessionEntry->State()!=EMMFStateWaitingForResource)
   232 		{
   233 		sessionEntry->SetState(aNewState);
   234 		}
   235 	}
   236 	
   237 void CAudioPolicy::NotifySessionWithTimeout(TInt aPolicySessionId, TMMFAudioPolicyEvent::TAudioPolicyEventType aEvent)
   238 	{
   239 	CMMFAudioPolicyRequest* sessionEntry=FindPolicyRequestById(aPolicySessionId);
   240 	ASSERT(sessionEntry);
   241 #if defined(ALLOW_POLICY_DEBUG)	
   242 	RDebug::Print(_L("Sending timed not. ID=%d, State=%d Event=%d"),aPolicySessionId,sessionEntry->State(), aEvent);
   243 #endif
   244 	const TMMFAudioPolicyEvent eventToSend(aEvent, KErrNone, sessionEntry->State());
   245 	sessionEntry->SetEventFlag(ETrue);
   246 	iAudioPolicyServer->StartNotificationTimer();
   247 	iNotifiedSessionId 	= aPolicySessionId;
   248 	iAudioPolicyServer->SendEventToClient(aPolicySessionId, eventToSend);
   249 	}
   250 
   251 void CAudioPolicy::RemoveFromList(TInt aPolicySessionId, TBool aAllowTimerRestart)
   252 	{
   253 	if (aPolicySessionId==KErrNotFound)
   254 		{
   255 		return;
   256 		}
   257 	for (TInt index = iAudioPolicyRequestArray->Count(); index-- ;)
   258 		{
   259 		// Find correct entry to remove	
   260 		if ( (*iAudioPolicyRequestArray)[index]->PolicySessionId() == aPolicySessionId)
   261 			{
   262 			if (iSessionIdAwaitingForDevsound==aPolicySessionId)
   263 				{
   264 				iSessionIdAwaitingForDevsound=KErrNotFound;
   265 				}			
   266 			if (iNotifiedSessionId==aPolicySessionId && iAudioPolicyServer->IsTimerActive()) 
   267 				{
   268 				iNotifiedSessionId=KErrNotFound;
   269 				// the session we were waiting for disconnected so try to immediately notify another one
   270 				iAudioPolicyServer->StopNotificationTimer();
   271 				if (iAudioPolicyRequestArray->Count() > 1 && aAllowTimerRestart)
   272 					{
   273 					iAudioPolicyServer->StartNotificationTimer(ETrue);
   274 					}
   275 				}			
   276 			else if(!iAudioPolicyServer->IsTimerActive())
   277 				{
   278 				if (iAudioPolicyRequestArray->Count() > 1 && aAllowTimerRestart)
   279 					{
   280 					iAudioPolicyServer->StartNotificationTimer(ETrue);
   281 					}
   282 				}
   283 			iAudioPolicyRequestArray->Delete(index);
   284 			return;
   285 			}
   286 		}
   287 	}
   288 	
   289 void CAudioPolicy::HandlePreferences(CMMFAudioPolicyRequest* /*aAudioPolicyRequest*/, TInt /*aPref*/, TPolicyResponse& /*aResponse*/)
   290 	{
   291 	}
   292 
   293 // this is weird, but devsound 
   294 // does Stop() if a client is denied access to resource
   295 // then calls this routine to indicate that resource became available
   296 void CAudioPolicy::LaunchRequest(TInt aSessionId)
   297 	{
   298 	ASSERT(iSessionIdAwaitingForDevsound!=aSessionId);
   299 	ModifyEntry(aSessionId, EMMFStateStopped);
   300 	}
   301 
   302 void CAudioPolicy::ReserveClientNumL(TInt aNum)
   303 	{
   304 	iAudioPolicyRequestArray->SetReserveL(aNum);
   305 	}
   306 
   307 /**
   308 @internalTechnology
   309 
   310 This function raises a panic
   311 
   312 @param	aError
   313 		one of the several panics codes that may be raised by this dll
   314 
   315 @panic	EMMFAudioPolicyRequestArrayOverflow is raised when policyrequest array is full
   316 */
   317 GLDEF_C void Panic(TMMFAudioPolicyPanicCodes aPanicCode)
   318 	{
   319 	User::Panic(KMMFAudioPolicyPanicCategory, aPanicCode);
   320 	}
   321 
   322 // checks based on the session ,Is the session is registered for Notification 
   323 TBool CAudioPolicy::IsRegisteredNotification(TInt aSessionId) const
   324 	{
   325 	TUid event;
   326  	for (TInt index = 0; index < iAudioPolicyRequestArray->Count(); index++)
   327  		{
   328  		if((*iAudioPolicyRequestArray)[index]->PolicySessionId() == aSessionId)
   329  			{
   330  			event = (*iAudioPolicyRequestArray)[index]->NotificationEvent();
   331  			if (event  == KMMFEventCategoryAudioResourceAvailable)
   332  				{
   333  				// only when the client is registered for KMMFEventCategoryAudioResourceAvailable event
   334  				return ETrue; 
   335  				}
   336  			break;	
   337  			} 
   338  		} 
   339  	return EFalse;
   340 	}
   341 
   342 // get the next highest priority of the client to notify 	
   343 TInt CAudioPolicy::CheckSessionToNotify()
   344 	{
   345 	TInt nextHighestPriority= -100;
   346 	TInt sessionToNotify = KErrNotFound;
   347 
   348 	// get the max priority and set the Index
   349 	for (TInt attempt=2; attempt-- && sessionToNotify==KErrNotFound;)
   350 		{
   351 		
   352 		for (TInt index = 0; index < iAudioPolicyRequestArray->Count(); ++index)
   353 	 		{
   354 	 		CMMFAudioPolicyRequest& currentReq=*(*iAudioPolicyRequestArray)[index];
   355 	 		if((nextHighestPriority <= currentReq.Priority())
   356 	 					&& (currentReq.NotificationEvent() == KMMFEventCategoryAudioResourceAvailable) 
   357 	 					&& (!currentReq.IsEventNotified())
   358 	 					&& currentReq.State()==EMMFStateWaitingForResource)
   359 	 			{
   360 	 			nextHighestPriority = currentReq.Priority();
   361 	 			sessionToNotify = currentReq.PolicySessionId();
   362 	 			}
   363 	 		}
   364 	 	// we tried to notify every session once, so reset flag and try again.
   365 	 	if (sessionToNotify==KErrNotFound)
   366 	 		{
   367 	 		for (TInt i=iAudioPolicyRequestArray->Count(); i--;)
   368 	 			{
   369 	 			(*iAudioPolicyRequestArray)[i]->SetEventFlag(EFalse);
   370 	 			}
   371 	 		}
   372  		}
   373   	return sessionToNotify;	
   374 	}
   375 
   376 // send the message to the server 
   377 void CAudioPolicy::NotifyNextClient()
   378 	{
   379 	const TInt sessionIdToNotify = CheckSessionToNotify();
   380 #if defined(ALLOW_POLICY_DEBUG)	
   381 	RDebug::Print(_L("Sess ID %d didn't continue within timeout, Next ID=%d"), iNotifiedSessionId, sessionIdToNotify);
   382 #endif	
   383 	iNotifiedSessionId = KErrNotFound;
   384 	if(sessionIdToNotify != KErrNotFound)
   385 		{
   386 		NotifySessionWithTimeout(sessionIdToNotify, TMMFAudioPolicyEvent::EMMFAudioPolicyResourceNotification);
   387 		}	
   388 	}
   389 
   390 // Set in the AudiopolicyRequestArray the uid registered
   391 TInt CAudioPolicy::SetNotification(TInt aSessionId, TUid aEventType)
   392 	{
   393 	if (KMMFEventCategoryAudioResourceAvailable!=aEventType)
   394 		{
   395 		return EFalse;
   396 		}
   397 	for (TInt index = iAudioPolicyRequestArray->Count(); index-- ; )
   398  		{
   399  		CMMFAudioPolicyRequest& currentReq=*(*iAudioPolicyRequestArray)[index];
   400  		if(currentReq.PolicySessionId() == aSessionId)
   401  			{
   402  			currentReq.SetNotificationEvent(aEventType);
   403 #if defined(ALLOW_POLICY_DEBUG)
   404 			RDebug::Print(_L("Sess ID %d state=%d requested resource notification"), aSessionId, currentReq.State());
   405 #endif			 			 			
   406  			if (!IsActiveState(currentReq.State()))
   407  				{
   408  				currentReq.SetState(EMMFStateWaitingForResource);
   409  				}
   410  			return ETrue;	
   411  			}
   412  		}
   413  	return EFalse;
   414 	}
   415 
   416 CMMFAudioPolicyRequest* CAudioPolicy::FindPolicyRequestById(TInt aSessionId) const
   417 	{
   418 	for (TInt index = iAudioPolicyRequestArray->Count(); index-- ; )
   419  		{
   420  		if((*iAudioPolicyRequestArray)[index]->PolicySessionId() == aSessionId)
   421  			{
   422  			return (*iAudioPolicyRequestArray)[index];
   423  			}
   424  		}
   425 	return NULL;
   426 	}
   427 
   428 
   429