--- /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;
+ }
+
+
+