sl@0: // Copyright (c) 2001-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // sl@0: sl@0: #include "MmfBtAudioPolicy.h" sl@0: #include "MmfBtAudioPolicySession.h" sl@0: #include "MmfBtAudioPolicyServer.h" sl@0: #include "MdaBtHwInfo.h" sl@0: #include "MmfBtAudioPolicyRequest.h" sl@0: sl@0: CAudioPolicy::~CAudioPolicy() sl@0: { sl@0: delete iMdaHwInfo; sl@0: delete iAudioPolicyRequestArray; sl@0: } sl@0: sl@0: void CAudioPolicy::ConstructL() sl@0: { sl@0: // Create dynamic array for sessions list sl@0: iAudioPolicyRequestArray = new(ELeave)CArrayFixFlat(CAudioPolicy::EGranularity); sl@0: iMdaHwInfo = CMdaHwInfo::NewL(); sl@0: } sl@0: sl@0: EXPORT_C CAudioPolicy* CAudioPolicy::NewL(CMMFAudioPolicyServer* aAudioPolicyServer) sl@0: { sl@0: sl@0: CAudioPolicy* self = new(ELeave)CAudioPolicy(aAudioPolicyServer); sl@0: CleanupStack::PushL(self); sl@0: self->ConstructL(); sl@0: CleanupStack::Pop(); sl@0: return(self); sl@0: } sl@0: sl@0: CAudioPolicy::CAudioPolicy(CMMFAudioPolicyServer* aAudioPolicyServer) : sl@0: iAudioPolicyServer(aAudioPolicyServer) sl@0: { sl@0: } sl@0: sl@0: void CAudioPolicy::MakeRequest(CMMFAudioPolicyRequest* aAudioPolicyRequest) sl@0: { sl@0: //Make sure there is sufficient space in the array to avoid expansion in AppendL() sl@0: __ASSERT_ALWAYS(iAudioPolicyRequestArray->Count() < iAudioPolicyServer->PolicySessionCount(), Panic(EMMFAudioPolicyRequestArrayOverflow)); sl@0: TPolicyResponse responseValue; sl@0: iSessionToAlert = NULL; // Reset sl@0: sl@0: // Process Request by looking at priorities, preferences, special states... sl@0: responseValue = ProcessRequest(aAudioPolicyRequest); sl@0: sl@0: // Finally, check current profile settings (only if not denied thus far): sl@0: // CheckAgainstProfiles(aAudioPolicyRequest, responseValue); sl@0: if (responseValue == EDenied) sl@0: { sl@0: SetSessionToAlert(aAudioPolicyRequest->PolicySessionId(), sl@0: NULL, TMMFAudioPolicyEvent::EMMFAudioPolicyPriorityTooLow, sl@0: aAudioPolicyRequest->State()); sl@0: if(IsRegisteredNotification(aAudioPolicyRequest->PolicySessionId())) sl@0: { sl@0: TRAPD(err, iAudioPolicyRequestArray->AppendL(*aAudioPolicyRequest) ); sl@0: __ASSERT_ALWAYS(err==KErrNone, Panic(EMMFAudioPolicyRequestArrayOverflow) ); // we reserved space, so shouldn't hit this sl@0: } sl@0: } sl@0: sl@0: // If a client needs to be notified (either a previous session that was booted off or a new sl@0: // one that was denied) then send event for that session to the client: sl@0: // NB KErrInUse, KErrDied OR KErrAccessDenied may be used to indicate this. sl@0: if (iSessionToAlert != NULL) sl@0: { sl@0: //check the session is registered for notification of resource available sl@0: if(!IsRegisteredNotification(iSessionToAlert)) sl@0: { sl@0: RemoveFromList(iSessionToAlert); sl@0: } sl@0: iAudioPolicyEvent.iErrorCode = KErrInUse; sl@0: iAudioPolicyEvent.iState = aAudioPolicyRequest->State(); sl@0: iAudioPolicyServer->SendEventToClient(iSessionToAlert, iSessionToBeLaunched, iAudioPolicyEvent); sl@0: } sl@0: //Resume of a Audio of the notified client ,since it is already in the list sl@0: //no need to append and send response back to DevSound for request accepted. sl@0: if(responseValue == EResume) sl@0: { sl@0: iAudioPolicyServer->StopNotificationTimer(); sl@0: iAudioPolicyEvent.iErrorCode = KErrNone; sl@0: iAudioPolicyEvent.iEventType = TMMFAudioPolicyEvent::EMMFAudioPolicyNoEvent; sl@0: iAudioPolicyEvent.iState = aAudioPolicyRequest->State(); sl@0: iAudioPolicyServer->SendEventToClient(aAudioPolicyRequest->PolicySessionId(), NULL, iAudioPolicyEvent); sl@0: } sl@0: // Add new policy to list, and send response back to DevSound for request accepted sl@0: if (responseValue == EProceed) sl@0: { sl@0: //no possibility of expansion here as sufficient space for the array is reserved in advance during the creation of the policysession sl@0: TRAPD(err, iAudioPolicyRequestArray->AppendL(*aAudioPolicyRequest) ); sl@0: __ASSERT_ALWAYS(err==KErrNone,Panic(EMMFAudioPolicyRequestArrayOverflow) ); // we reserved space, so shouldn't hit this sl@0: iAudioPolicyEvent.iErrorCode = KErrNone; sl@0: iAudioPolicyEvent.iEventType = TMMFAudioPolicyEvent::EMMFAudioPolicyNoEvent; sl@0: iAudioPolicyEvent.iState = aAudioPolicyRequest->State(); sl@0: iAudioPolicyServer->SendEventToClient(aAudioPolicyRequest->PolicySessionId(), NULL, iAudioPolicyEvent); sl@0: } sl@0: if (responseValue == EStopThenProceed) // place on list, but dev Sound will launch request sl@0: { sl@0: //no possibility of expansion here as sufficient space for the array is reserved in advance during the creation of the policysession sl@0: TRAPD(err, iAudioPolicyRequestArray->AppendL(*aAudioPolicyRequest) ); sl@0: __ASSERT_ALWAYS(err==KErrNone,Panic(EMMFAudioPolicyRequestArrayOverflow) ); // we reserved space, so shouldn't hit this sl@0: } sl@0: } sl@0: sl@0: TPolicyResponse CAudioPolicy::ProcessRequest(CMMFAudioPolicyRequest* aAudioPolicyRequest) sl@0: { sl@0: TPolicyResponse responseValue(EProceed); sl@0: iSessionToAlert = NULL; // Reset sl@0: sl@0: // If there is no other item on list, return with proceed sl@0: if (!iAudioPolicyRequestArray->Count()) sl@0: return EProceed; sl@0: sl@0: // Handle Preferences, if any, otherwise just compare priorities: sl@0: // HandlePreferences(aAudioPolicyRequest, preference, responseValue); sl@0: if(IsNotified()) sl@0: { sl@0: return EResume; sl@0: } sl@0: responseValue = ComparePriorities(aAudioPolicyRequest); sl@0: sl@0: return responseValue; sl@0: } sl@0: sl@0: void CAudioPolicy::ModifyEntry(TInt aPolicySessionId, CMMFAudioPolicyRequest* aAudioPolicyRequest) sl@0: { sl@0: TMMFAudioPolicyState requestState = aAudioPolicyRequest->State(); sl@0: // If state is stopped or paused, remove item from list sl@0: if ((aAudioPolicyRequest->State() == EMMFStatePaused) || (aAudioPolicyRequest->State() == EMMFStateStopped) || (aAudioPolicyRequest->State() == EMMFStateCompleted)) sl@0: { sl@0: if(iSessionToBeLaunched == aPolicySessionId) sl@0: { sl@0: iSessionToBeLaunched = 0; sl@0: } sl@0: if((aAudioPolicyRequest->State() == EMMFStateStopped) && (!iSessionToBeLaunched)) sl@0: { sl@0: TInt sessionToNotify = CheckSessionToNotify(); sl@0: if(sessionToNotify) sl@0: { sl@0: iAudioPolicyServer->StartNotificationTimer(); sl@0: iAudioPolicyEvent.iErrorCode = KErrNone; sl@0: iAudioPolicyEvent.iEventType = TMMFAudioPolicyEvent::EMMFAudioPolicyResourceNotification; sl@0: iAudioPolicyServer->SendEventToClient(sessionToNotify, NULL, iAudioPolicyEvent); sl@0: } sl@0: } sl@0: if(aAudioPolicyRequest->NotificationEvent() != KMMFEventCategoryAudioResourceAvailable) sl@0: { sl@0: RemoveFromList(aPolicySessionId); sl@0: return; sl@0: } sl@0: } sl@0: sl@0: for (TInt index = 0; index < iAudioPolicyRequestArray->Count(); index++) sl@0: { sl@0: // Find correct entry to replace state sl@0: if ( ((*iAudioPolicyRequestArray)[index].PolicySessionId()) == aPolicySessionId) sl@0: { sl@0: (*iAudioPolicyRequestArray)[index].SetState(requestState); sl@0: break; sl@0: } sl@0: } sl@0: } sl@0: sl@0: void CAudioPolicy::RemoveFromList(TInt aPolicySessionId) sl@0: { sl@0: for (TInt index = 0; index < iAudioPolicyRequestArray->Count(); index++) sl@0: { sl@0: // Find correct entry to remove sl@0: if ( (*iAudioPolicyRequestArray)[index].PolicySessionId() == aPolicySessionId) sl@0: { sl@0: iAudioPolicyRequestArray->Delete(index); sl@0: break; sl@0: } sl@0: } sl@0: } sl@0: sl@0: TPolicyResponse CAudioPolicy::ComparePriorities(CMMFAudioPolicyRequest* aAudioPolicyRequest/*, TMMFAudioPolicyEvent& aEvent*/) sl@0: { sl@0: TPolicyResponse responseValue(EProceed); sl@0: TInt requestPriority = aAudioPolicyRequest->Priority(); sl@0: sl@0: TBool requestCaps = aAudioPolicyRequest->Capabilities(); sl@0: sl@0: // Iterate through list and compare priorities: sl@0: for (TInt index = 0; index < iAudioPolicyRequestArray->Count(); index++) sl@0: { sl@0: // If there's even one on the list w/ a higher priority deny request and leave: sl@0: sl@0: if ((*iAudioPolicyRequestArray)[index].Capabilities() > requestCaps) sl@0: { sl@0: responseValue = EDenied; sl@0: break; sl@0: } sl@0: else if((*iAudioPolicyRequestArray)[index].Capabilities() == requestCaps) sl@0: { sl@0: if((*iAudioPolicyRequestArray)[index].Priority() >= requestPriority) sl@0: { sl@0: responseValue = EDenied; sl@0: break; sl@0: } sl@0: } sl@0: sl@0: sl@0: // Otherwise have the one on the list removed: sl@0: SetSessionToAlert((*iAudioPolicyRequestArray)[index].PolicySessionId(), sl@0: aAudioPolicyRequest->PolicySessionId(), TMMFAudioPolicyEvent::EMMFAudioPolicyPriorityTooLow, aAudioPolicyRequest->State()); sl@0: responseValue = EStopThenProceed; sl@0: } sl@0: return responseValue; sl@0: } sl@0: sl@0: void CAudioPolicy::HandlePreferences(CMMFAudioPolicyRequest* /*aAudioPolicyRequest*/, TInt /*aPref*/, TPolicyResponse& /*aResponse*/) sl@0: { sl@0: } sl@0: sl@0: void CAudioPolicy::LaunchRequest() sl@0: { sl@0: if (iAudioPolicyEventToLaunch.iEventType == TMMFAudioPolicyEvent::EMMFAudioPolicySwitchToIdle) sl@0: iAudioPolicyServer->LaunchRequest(iSessionToBeLaunched, iAudioPolicyEventToLaunch); sl@0: } sl@0: sl@0: // Sets up session information for sending an event on a denied (or killed) request sl@0: void CAudioPolicy::SetSessionToAlert(TInt aSessionToAlert, TInt aSessionToBeLaunched, TMMFAudioPolicyEvent::TAudioPolicyEventType aEventType, TMMFAudioPolicyState aState ) sl@0: { sl@0: iSessionToAlert = aSessionToAlert; sl@0: iSessionToBeLaunched = aSessionToBeLaunched; sl@0: iAudioPolicyEvent.iEventType = aEventType; sl@0: sl@0: if (iSessionToBeLaunched != 0) // When currently playing item needs to be stopped sl@0: { sl@0: iAudioPolicyEventToLaunch.iEventType = TMMFAudioPolicyEvent::EMMFAudioPolicySwitchToIdle; sl@0: iAudioPolicyEventToLaunch.iState = aState; sl@0: } sl@0: } sl@0: sl@0: CArrayFixFlat* CAudioPolicy::AudioPolicyRequestArray() sl@0: { sl@0: return iAudioPolicyRequestArray; sl@0: } sl@0: sl@0: /** sl@0: @internalTechnology sl@0: sl@0: This function raises a panic sl@0: sl@0: @param aError sl@0: one of the several panics codes that may be raised by this dll sl@0: sl@0: @panic EMMFAudioPolicyRequestArrayOverflow is raised when policyrequest array is full sl@0: */ sl@0: GLDEF_C void Panic(TMMFAudioPolicyPanicCodes aPanicCode) sl@0: { sl@0: User::Panic(KMMFAudioPolicyPanicCategory, aPanicCode); sl@0: } sl@0: sl@0: // checks based on the session ,Is the session is registered for Notification sl@0: TBool CAudioPolicy::IsRegisteredNotification(TInt aSessionId) sl@0: { sl@0: TUid event; sl@0: for (TInt index = 0; index < iAudioPolicyRequestArray->Count(); index++) sl@0: { sl@0: if((*iAudioPolicyRequestArray)[index].PolicySessionId() == aSessionId) sl@0: { sl@0: event = (*iAudioPolicyRequestArray)[index].NotificationEvent(); sl@0: if (event == KMMFEventCategoryAudioResourceAvailable) sl@0: { sl@0: // only when the client is registered for KMMFEventCategoryAudioResourceAvailable event sl@0: return ETrue; sl@0: } sl@0: break; sl@0: } sl@0: } sl@0: return EFalse; sl@0: } sl@0: sl@0: // checks the state,whether any client is already send notification sl@0: TBool CAudioPolicy::IsNotified() sl@0: { sl@0: for (TInt index = 0; index < iAudioPolicyRequestArray->Count(); index++) sl@0: { sl@0: if((*iAudioPolicyRequestArray)[index].State() == EMMFStateNotified) sl@0: { sl@0: // In a instance only one client should have the state as EMMFStateNotified sl@0: return ETrue; sl@0: } sl@0: } sl@0: return EFalse; sl@0: } sl@0: sl@0: // get the next highest priority of the client to notify sl@0: TInt CAudioPolicy::CheckSessionToNotify() sl@0: { sl@0: TInt nextHighestPriority= -100; sl@0: TInt sessionToNotify = 0; sl@0: TInt notificationIdx = -1; sl@0: if(IsNotified()) sl@0: { sl@0: return sessionToNotify; sl@0: } sl@0: // get the max priority and set the Index sl@0: for (TInt index = 0; index < iAudioPolicyRequestArray->Count(); index++) sl@0: { sl@0: if((nextHighestPriority <= (*iAudioPolicyRequestArray)[index].Priority()) && ((*iAudioPolicyRequestArray)[index].NotificationEvent() != KNullUid) && (!(*iAudioPolicyRequestArray)[index].IsEventNotified())) sl@0: { sl@0: nextHighestPriority = (*iAudioPolicyRequestArray)[index].Priority(); sl@0: sessionToNotify = (*iAudioPolicyRequestArray)[index].PolicySessionId(); sl@0: notificationIdx = index; sl@0: } sl@0: } sl@0: // set the state as notified sl@0: if(notificationIdx != -1) sl@0: { sl@0: (*iAudioPolicyRequestArray)[notificationIdx].SetEventFlag(ETrue); sl@0: (*iAudioPolicyRequestArray)[notificationIdx].SetState(EMMFStateNotified); sl@0: } sl@0: return sessionToNotify; sl@0: } sl@0: sl@0: // send the message to the server sl@0: void CAudioPolicy::DoSendNotification() sl@0: { sl@0: ResetNotification(); sl@0: TInt sessionToNotify = CheckSessionToNotify(); sl@0: if(sessionToNotify) sl@0: { sl@0: iAudioPolicyEvent.iErrorCode = KErrNone; sl@0: iAudioPolicyEvent.iEventType = TMMFAudioPolicyEvent::EMMFAudioPolicyResourceNotification; sl@0: iAudioPolicyServer->SendEventToClient(sessionToNotify, NULL, iAudioPolicyEvent); sl@0: } sl@0: } sl@0: sl@0: // Set in the AudiopolicyRequestArray the uid registered sl@0: TInt CAudioPolicy::SetNotification(TInt aSessionId, TUid aEventType) sl@0: { sl@0: for (TInt index = 0; index < iAudioPolicyRequestArray->Count(); index++) sl@0: { sl@0: if((*iAudioPolicyRequestArray)[index].PolicySessionId() == aSessionId) sl@0: { sl@0: (*iAudioPolicyRequestArray)[index].SetNotificationEvent(aEventType); sl@0: return ETrue; sl@0: } sl@0: } sl@0: return EFalse; sl@0: } sl@0: sl@0: // cancel the state of the message notification to closed sl@0: void CAudioPolicy::ResetNotification() sl@0: { sl@0: for (TInt index = 0; index < iAudioPolicyRequestArray->Count(); index++) sl@0: { sl@0: if((*iAudioPolicyRequestArray)[index].State() == EMMFStateNotified) sl@0: { sl@0: (*iAudioPolicyRequestArray)[index].SetState(EMMFStateClosed); sl@0: } sl@0: } sl@0: } sl@0: