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 +