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".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
16 #include "MmfAudioPolicy.h"
17 #include "MmfAudioPolicySession.h"
18 #include "MmfAudioPolicyServer.h"
19 #include "MdaHwInfo.h"
20 #include "MmfAudioPolicyRequest.h"
24 *@return if a client owns or wish to own audio resource
26 inline TBool IsActiveState(TMMFAudioPolicyState aState)
28 return (aState < EMMFStateStopped || aState==EMMFStateNotified || aState==EMMFStatePlayDualTone);
31 CAudioPolicy::~CAudioPolicy()
34 delete iAudioPolicyRequestArray;
37 void CAudioPolicy::ConstructL()
39 // Create dynamic array for sessions list
40 iAudioPolicyRequestArray = new(ELeave) CPolicyReqPtrArray(CAudioPolicy::EGranularity);
41 iMdaHwInfo = CMdaHwInfo::NewL();
44 EXPORT_C CAudioPolicy* CAudioPolicy::NewL(CMMFAudioPolicyServer* aAudioPolicyServer)
47 CAudioPolicy* self = new(ELeave)CAudioPolicy(aAudioPolicyServer);
48 CleanupStack::PushL(self);
54 CAudioPolicy::CAudioPolicy(CMMFAudioPolicyServer* aAudioPolicyServer) :
55 iAudioPolicyServer(aAudioPolicyServer),
56 iNotifiedSessionId(KErrNotFound),
57 iSessionIdAwaitingForDevsound(KErrNotFound),
58 iStopHandledFromSessId(KErrNotFound)
62 void CAudioPolicy::MakeRequest(CMMFAudioPolicyRequest* aAudioPolicyRequest)
64 // since we have a FIFO q, then remove request and re-add it.
65 RemoveFromList(aAudioPolicyRequest->PolicySessionId(), EFalse);
66 if (iStopHandledFromSessId==aAudioPolicyRequest->PolicySessionId())
68 iStopHandledFromSessId=KErrNotFound;
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());
75 switch (responseValue)
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);
87 iAudioPolicyServer->StopNotificationTimer();
88 TMMFAudioPolicyEvent responseEvent(TMMFAudioPolicyEvent::EMMFAudioPolicyNoEvent, KErrNone, aAudioPolicyRequest->State());
89 iAudioPolicyServer->SendEventToClient(aAudioPolicyRequest->PolicySessionId(), responseEvent);
92 case EStopThenProceed:
94 iAudioPolicyServer->StopNotificationTimer();
95 iSessionIdAwaitingForDevsound=aAudioPolicyRequest->PolicySessionId();
96 // we have to wait for devsound to stop client(s), then notify that one
104 TRAPD(err, iAudioPolicyRequestArray->AppendL(aAudioPolicyRequest) );
105 __ASSERT_ALWAYS(err==KErrNone, Panic(EMMFAudioPolicyRequestArrayOverflow) ); // we reserved space, so shouldn't hit this
108 TPolicyResponse CAudioPolicy::ProcessRequest(CMMFAudioPolicyRequest* aAudioPolicyRequest)
110 // If there is no other item on list, return with proceed
111 if (iAudioPolicyRequestArray->Count()==0)
116 TPolicyResponse responseValue(EProceed);
117 TInt requestPriority = aAudioPolicyRequest->Priority();
119 TBool requestCaps = aAudioPolicyRequest->Capabilities();
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++)
125 CMMFAudioPolicyRequest& currentReq=*(*iAudioPolicyRequestArray)[index];
126 if (!IsActiveState(currentReq.State()) ) // this request is inactive
130 // If there's even one on the list w/ a higher priority deny request and leave:
132 if (currentReq.Capabilities() > requestCaps)
134 responseValue = EDenied;
137 else if(currentReq.Capabilities() == requestCaps)
139 if(currentReq.Priority() >= requestPriority)
141 responseValue = EDenied;
145 if (currentReq.State()==EMMFStateWaitingForResource || currentReq.State()==EMMFStatePreempted)
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());
154 currentReq.SetState( EMMFStatePreempted );
155 currentReq.SetEventFlag(EFalse);
156 iAudioPolicyServer->SendEventToClient(currentReq.PolicySessionId(), freezeEvent);
157 responseValue = EStopThenProceed;
160 return responseValue;
163 void CAudioPolicy::ModifyEntry(TInt aPolicySessionId,const TMMFAudioPolicyState aNewState)
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);
169 // some client took over resource, so update its state and cancel timer
170 if (IsActiveState(aNewState))
174 sessionEntry->SetState(aNewState);
175 sessionEntry->SetEventFlag(EFalse);
177 iAudioPolicyServer->StopNotificationTimer();
178 iNotifiedSessionId =KErrNotFound;
179 ASSERT(iSessionIdAwaitingForDevsound==KErrNotFound); // we shouldn't have a client waiting to be notified
180 if (iStopHandledFromSessId==aPolicySessionId)
182 iStopHandledFromSessId=KErrNotFound;
186 if (iNotifiedSessionId==aPolicySessionId) // if client that was notified, then stop timer.
188 iAudioPolicyServer->StopNotificationTimer();
190 if (sessionEntry==NULL) // to cope with erroneous behaviour of devsound
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)
198 if (aNewState == EMMFStateStopped) // to eliminate duplicate stop events
200 iStopHandledFromSessId=aPolicySessionId;
202 if (sessionEntry->State()==EMMFStatePreempted)
204 sessionEntry->SetState(EMMFStateWaitingForResource);
207 if (iSessionIdAwaitingForDevsound==aPolicySessionId)
209 iSessionIdAwaitingForDevsound=KErrNotFound;
212 if (aNewState == EMMFStatePaused || aNewState == EMMFStateStopped) // devsound should free, so notify waiting client
214 if (iSessionIdAwaitingForDevsound!=KErrNotFound) // we have a client waiting for Devsound, so notify it
216 NotifySessionWithTimeout(iSessionIdAwaitingForDevsound, TMMFAudioPolicyEvent::EMMFAudioPolicyNoEvent);
217 iSessionIdAwaitingForDevsound=KErrNotFound;
219 else if (!iAudioPolicyServer->IsTimerActive()) // do not try to notify if we're still waiting for response
221 const TInt sessionIdToNotify = CheckSessionToNotify();
222 if(sessionIdToNotify != KErrNotFound)
224 // set the state as notified
225 NotifySessionWithTimeout(sessionIdToNotify, TMMFAudioPolicyEvent::EMMFAudioPolicyResourceNotification);
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)
233 sessionEntry->SetState(aNewState);
237 void CAudioPolicy::NotifySessionWithTimeout(TInt aPolicySessionId, TMMFAudioPolicyEvent::TAudioPolicyEventType aEvent)
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);
244 const TMMFAudioPolicyEvent eventToSend(aEvent, KErrNone, sessionEntry->State());
245 sessionEntry->SetEventFlag(ETrue);
246 iAudioPolicyServer->StartNotificationTimer();
247 iNotifiedSessionId = aPolicySessionId;
248 iAudioPolicyServer->SendEventToClient(aPolicySessionId, eventToSend);
251 void CAudioPolicy::RemoveFromList(TInt aPolicySessionId, TBool aAllowTimerRestart)
253 if (aPolicySessionId==KErrNotFound)
257 for (TInt index = iAudioPolicyRequestArray->Count(); index-- ;)
259 // Find correct entry to remove
260 if ( (*iAudioPolicyRequestArray)[index]->PolicySessionId() == aPolicySessionId)
262 if (iSessionIdAwaitingForDevsound==aPolicySessionId)
264 iSessionIdAwaitingForDevsound=KErrNotFound;
266 if (iNotifiedSessionId==aPolicySessionId && iAudioPolicyServer->IsTimerActive())
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)
273 iAudioPolicyServer->StartNotificationTimer(ETrue);
276 else if(!iAudioPolicyServer->IsTimerActive())
278 if (iAudioPolicyRequestArray->Count() > 1 && aAllowTimerRestart)
280 iAudioPolicyServer->StartNotificationTimer(ETrue);
283 iAudioPolicyRequestArray->Delete(index);
289 void CAudioPolicy::HandlePreferences(CMMFAudioPolicyRequest* /*aAudioPolicyRequest*/, TInt /*aPref*/, TPolicyResponse& /*aResponse*/)
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)
298 ASSERT(iSessionIdAwaitingForDevsound!=aSessionId);
299 ModifyEntry(aSessionId, EMMFStateStopped);
302 void CAudioPolicy::ReserveClientNumL(TInt aNum)
304 iAudioPolicyRequestArray->SetReserveL(aNum);
310 This function raises a panic
313 one of the several panics codes that may be raised by this dll
315 @panic EMMFAudioPolicyRequestArrayOverflow is raised when policyrequest array is full
317 GLDEF_C void Panic(TMMFAudioPolicyPanicCodes aPanicCode)
319 User::Panic(KMMFAudioPolicyPanicCategory, aPanicCode);
322 // checks based on the session ,Is the session is registered for Notification
323 TBool CAudioPolicy::IsRegisteredNotification(TInt aSessionId) const
326 for (TInt index = 0; index < iAudioPolicyRequestArray->Count(); index++)
328 if((*iAudioPolicyRequestArray)[index]->PolicySessionId() == aSessionId)
330 event = (*iAudioPolicyRequestArray)[index]->NotificationEvent();
331 if (event == KMMFEventCategoryAudioResourceAvailable)
333 // only when the client is registered for KMMFEventCategoryAudioResourceAvailable event
342 // get the next highest priority of the client to notify
343 TInt CAudioPolicy::CheckSessionToNotify()
345 TInt nextHighestPriority= -100;
346 TInt sessionToNotify = KErrNotFound;
348 // get the max priority and set the Index
349 for (TInt attempt=2; attempt-- && sessionToNotify==KErrNotFound;)
352 for (TInt index = 0; index < iAudioPolicyRequestArray->Count(); ++index)
354 CMMFAudioPolicyRequest& currentReq=*(*iAudioPolicyRequestArray)[index];
355 if((nextHighestPriority <= currentReq.Priority())
356 && (currentReq.NotificationEvent() == KMMFEventCategoryAudioResourceAvailable)
357 && (!currentReq.IsEventNotified())
358 && currentReq.State()==EMMFStateWaitingForResource)
360 nextHighestPriority = currentReq.Priority();
361 sessionToNotify = currentReq.PolicySessionId();
364 // we tried to notify every session once, so reset flag and try again.
365 if (sessionToNotify==KErrNotFound)
367 for (TInt i=iAudioPolicyRequestArray->Count(); i--;)
369 (*iAudioPolicyRequestArray)[i]->SetEventFlag(EFalse);
373 return sessionToNotify;
376 // send the message to the server
377 void CAudioPolicy::NotifyNextClient()
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);
383 iNotifiedSessionId = KErrNotFound;
384 if(sessionIdToNotify != KErrNotFound)
386 NotifySessionWithTimeout(sessionIdToNotify, TMMFAudioPolicyEvent::EMMFAudioPolicyResourceNotification);
390 // Set in the AudiopolicyRequestArray the uid registered
391 TInt CAudioPolicy::SetNotification(TInt aSessionId, TUid aEventType)
393 if (KMMFEventCategoryAudioResourceAvailable!=aEventType)
397 for (TInt index = iAudioPolicyRequestArray->Count(); index-- ; )
399 CMMFAudioPolicyRequest& currentReq=*(*iAudioPolicyRequestArray)[index];
400 if(currentReq.PolicySessionId() == aSessionId)
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());
406 if (!IsActiveState(currentReq.State()))
408 currentReq.SetState(EMMFStateWaitingForResource);
416 CMMFAudioPolicyRequest* CAudioPolicy::FindPolicyRequestById(TInt aSessionId) const
418 for (TInt index = iAudioPolicyRequestArray->Count(); index-- ; )
420 if((*iAudioPolicyRequestArray)[index]->PolicySessionId() == aSessionId)
422 return (*iAudioPolicyRequestArray)[index];