devsound/a3fdevsound/src/devsoundadaptor/cdevcommoncontrol.cpp
branchRCL_3
changeset 12 b74061f7f3d2
parent 11 d5f04de580b7
child 23 545d349d14da
--- a/devsound/a3fdevsound/src/devsoundadaptor/cdevcommoncontrol.cpp	Wed Mar 31 23:56:23 2010 +0300
+++ b/devsound/a3fdevsound/src/devsoundadaptor/cdevcommoncontrol.cpp	Wed Apr 14 17:32:53 2010 +0300
@@ -48,7 +48,7 @@
             err = iDevAudio->iAudioStream->Stop();
             if (err == KErrNone)
                 {
-                err = iDevAudio->iAudioContext->Commit();
+                err = iDevAudio->CommitAudioContext();
                 }
             if (err == KErrNone)
                 {
@@ -58,6 +58,17 @@
         case EDevSoundAdaptorGoingActive:
             iDevAudio->iActiveState = EDevSoundAdaptorStopping;
             break;
+        case EDevSoundAdaptorInitialised_Idle:
+        	{
+        	//If following condition is true, then we are here because of a
+        	//pre-emption clash in last Commit cycle started from
+        	//CDevCommonControl::ContextEventUpdateWithStateEventNoError.
+        	if(iDevAudio->iPreviousState == EDevSoundAdaptorUnloading)
+        		{
+				err = Unload();
+				break;
+        		}
+        	}
         default:
             break;
         }
@@ -79,7 +90,7 @@
     TInt err = iDevAudio->iAudioStream->Prime();
     if ( err == KErrNone)
         {
-        err = iDevAudio->iAudioContext->Commit();
+        err = iDevAudio->CommitAudioContext();
         }
     if (err == KErrNone)
         {
@@ -101,13 +112,28 @@
         err = KErrNotReady;
         }
 
+    //If following condition is true, then we are here because of a
+    //pre-emption clash in last Commit cycle started from
+    //CDevCommonControl::ContextEventUpdateWithStateEventAndError.
+    if(iDevAudio->iActiveState == EDevSoundAdaptorInitialised_Idle &&
+    		iDevAudio->iPreviousState == EDevSoundAdaptorUnloading)
+    	{
+		err = Unload();
+		DP0_RET(err,"%d");
+    	}
+
+    if(err == KErrNone)
+        {
+        // Populate gain and balance values set in the Paused state and being cached
+        err = iDevAudio->RequestGainAndBalance(this);
+        }
     if(err == KErrNone)
         {
         err = iDevAudio->iAudioStream->Activate();
         }
     if ( err == KErrNone)
         {
-        err = iDevAudio->iAudioContext->Commit();
+        err = iDevAudio->CommitAudioContext();
         }
     if (err == KErrNone)
         {
@@ -182,12 +208,26 @@
     // Can't "switch {...}" on UIDs unfortunately:
     if (aEvent == KUidA3FContextUpdateComplete)
         {
-        if(iBeingPreempted && iStateEventReceived)
+        if(iBeingPreempted)
             {
-            //use a sub state pattern to make premtion cycles like other cycles.
-            DP1(DLERR,"Preemption error=%d", aError);
-            iDevAudio->iActiveState = EDevSoundAdaptorBeingPreempted;
-            iBeingPreempted=EFalse;
+			if(iStateEventReceived)
+				{
+				//use a sub state pattern to make pre-emption cycles like other cycles.
+				DP1(DLERR,"Preemption error=%d", aError);
+				iDevAudio->iActiveState = EDevSoundAdaptorBeingPreempted;
+				if(iPreemptionClash)
+					{
+					// remove last request from front of queue without processing it
+					iAdaptationObserver->PreemptionClashWithStateChange();
+					iPreemptionClash=EFalse;
+					}
+				}
+            else if(!iStateEventReceived && iPreemptionClash)
+        		{
+				iIgnoreAsyncOpComplete=ETrue;
+				iPreemptionClash=EFalse;
+        		}
+			iBeingPreempted=EFalse;
             }
 		ContextEventUpdateComplete(aError);
         }
@@ -195,16 +235,18 @@
     else if ((aEvent == KUidA3FContextCommitUpdate))
         {
         iBeingPreempted=EFalse; // clear being preempted
+        iPreemptionClash=EFalse; // clear pre-emption clash flag
         TBool adaptorControlsContext = iAdaptationObserver->AdaptorControlsContext();
         iIgnoreAsyncOpComplete = !adaptorControlsContext;
             // if we don't control context, always send a PreemptionFinishedCallbackReceived()
 		iStateEventReceived=EFalse;
         }
 
-    else if ((aEvent == KUidA3FContextPreEmption) or (aEvent == KUidA3FContextPreEmptedCommit))
+    else if (aEvent == KUidA3FContextPreEmption)
         {
         // clear iBeingPreepted - will be set in ContextEventPreEmption if req
         iBeingPreempted=EFalse;
+        iPreemptionClash=EFalse; // clear pre-emption clash flag
         TBool adaptorControlsContext = iAdaptationObserver->AdaptorControlsContext();
 		iStateEventReceived=EFalse;
         iIgnoreAsyncOpComplete=EFalse; // clear being iIgnoreAsyncOpComplete
@@ -214,6 +256,26 @@
             iIgnoreAsyncOpComplete = ETrue; // if we don't control context never do AsyncOpComplete
             }
         }
+    else if (aEvent == KUidA3FContextPreEmptedCommit)
+        {
+		DP0(DLINFO,"KUidA3FContextPreEmptedCommit event received, thus clash with Pre-emption");
+        // clear iBeingPreepted - will be set in ContextEventPreEmption if req
+        iBeingPreempted=EFalse;
+        TBool adaptorControlsContext = iAdaptationObserver->AdaptorControlsContext();
+        if (adaptorControlsContext)
+        	{
+			// push current request that was being processed onto front of queue.
+        	iAdaptationObserver->PreemptionClash();
+        	iPreemptionClash=ETrue;
+        	}
+		iStateEventReceived=EFalse;
+        iIgnoreAsyncOpComplete=EFalse; // clear being iIgnoreAsyncOpComplete
+        ContextEventPreEmption(aEvent, aError);
+        if (!adaptorControlsContext)
+            {
+            iIgnoreAsyncOpComplete = ETrue; // if we don't control context never do AsyncOpComplete
+            }
+        }
 
     else if (aEvent == KUidA3FContextAbort)
         {
@@ -426,7 +488,7 @@
         return;
         }
     
-    err = iDevAudio->iAudioContext->Commit();
+    err = iDevAudio->CommitAudioContext();
     if (err)
         {
         ContextEventAsynchronousPlayCompletion(err);
@@ -564,6 +626,18 @@
         return;
         }
 
+    //If the Commit cycle when going into EDevSoundAdaptorRemovingProcessingUnits fails due to pre-emption
+    //clash then we re-apply the client request again.
+    if (iDevAudio->iActiveState == EDevSoundAdaptorRemovingProcessingUnits && iIgnoreAsyncOpComplete)
+    	{
+		//Pop front of queue to re-apply the request again via CMMFDevSoundSession::DequeueRequest
+		//from the callback into CMMFDevSoundSession below:
+		iAdaptationObserver->PreemptionFinishedCallbackReceived(ETrue);
+		iIgnoreAsyncOpComplete = EFalse;
+		DP_OUT();
+		return;
+    	}
+
     iDevAudio->iActiveState = EDevSoundAdaptorCreated_Uninitialised;
     
     if (iDevAudio->iReinitializing)
@@ -592,32 +666,78 @@
     {
     DP_CONTEXT(CDevCommonControl::ContextEventUpdateWithoutStateEventButWithError, CtxDevSound, DPLOCAL);
     DP_IN();
-    
-    // NOTE: We shouldn't actually be in any of the states below when calling this function.
-    //       But just in case we are we will rewind the state before dealing with the error. 
-    switch (iDevAudio->iActiveState)
-        {
-    case EDevSoundAdaptorInitialising:
-        iDevAudio->iActiveState = EDevSoundAdaptorCreated_Uninitialised;
-        ContextEventAsynchronousInitializeComplete(aError);
-        break;
-        
-    case EDevSoundAdaptorLoading:
-        iDevAudio->iActiveState = EDevSoundAdaptorInitialised_Initialised;
-        ContextEventAsynchronousPlayCompletion(aError);
-        break;
-        
-    case EDevSoundAdaptorActivating:
-        iDevAudio->iActiveState = EDevSoundAdaptorInitialised_Idle;
-        ContextEventAsynchronousPlayCompletion(aError);
-        break;
-        
-    default:
-        if(iBeingPreempted)
-            {
-            iAdaptationObserver->PreemptionFinishedCallbackReceived(ETrue); // notify client of end of cycle
-            }
-        }
+
+    //If flag is true below then it must be due to a stateless normal pre-emption or
+    //stateless pre-emption clash scenario.
+    if(iIgnoreAsyncOpComplete)
+    	{
+		//If we are in pre-emption clash then callback below will retry the client request again.
+		iAdaptationObserver->PreemptionFinishedCallbackReceived(ETrue); // notify client of end of cycle
+		iIgnoreAsyncOpComplete = EFalse;
+    	}
+    else
+    	{
+        TDevSoundAdaptorState previousState = iDevAudio->iPreviousState;
+
+        DP3(DLINFO,"Error with no state change, state %d, previous %d, error %d during Commit cycle",
+                    iDevAudio->iActiveState, previousState, aError);
+
+        // We can end up here for a number of reasons. For non "mid states", this is
+        // a standard error scenario. For some mid-states (e.g. Activating, Loading etc),
+        // when we try and "promote" the state, this happens when the promotion is rejected
+        // and we handle thus accordingly. For other mid-states the situation is less clear
+        // and we call AsynchronousOperationComplete() with the error assuming the parent
+        // session will deal with it. Whatever we don't want to stay in a mid-state, so
+        // rewind to the previous ("normal") one if we are in one.
+
+        // Longer term TODO. If the code were refactored so that the InitializeComplete(),
+        // PlayError() etc callback came from AsynchronousOperationComplete() then the
+        // following code might be simpler. Most of the time (at least) we get here because
+        // we are doing a session function, and we can use the function to determine what
+        // to do more easily than relying on the state. As it is, for some mid-states we
+        // try and work out what error code to generate. Not clear this covers 100% cases,
+        // although demotion transitions should not fail, so the problem cases might not occur.
+        //
+
+		//If we reach this condition then it is because of rejection/error during Commit cycle.
+		switch (iDevAudio->iActiveState)
+			{
+			case EDevSoundAdaptorInitialising:
+				{
+				iDevAudio->iActiveState = previousState;
+				ContextEventAsynchronousInitializeComplete(aError);
+				break;
+				}
+			case EDevSoundAdaptorLoading:
+				{
+				iDevAudio->iActiveState = previousState;
+				ContextEventAsynchronousPlayCompletion(aError);
+				break;
+				}
+			case EDevSoundAdaptorActivating:
+				{
+				iDevAudio->iActiveState = previousState;
+				ContextEventAsynchronousPlayCompletion(aError);
+				break;
+				}
+			case EDevSoundAdaptorRemovingProcessingUnits:
+			case EDevSoundAdaptorUninitialising:
+			case EDevSoundAdaptorUnloading:
+			case EDevSoundAdaptorStopping:
+			case EDevSoundAdaptorPausing:
+			    {
+                DP2(DLINFO,"Unexpected mid state [%d] when handling error [%d] during Commit cycle, workback", iDevAudio->iActiveState, aError);
+			    iDevAudio->iActiveState = previousState;
+                iAdaptationObserver->AsynchronousOperationComplete(aError, ETrue);
+			    break;
+			    }
+			default:
+				{
+				DP2(DLINFO,"Unexpected state [%d] when handling error [%d] during Commit cycle", iDevAudio->iActiveState, aError);
+		        iAdaptationObserver->AsynchronousOperationComplete(aError, ETrue);
+				}
+			}
+    	}
        
     DP_OUT();
     }
@@ -713,12 +833,15 @@
     
     iCallbackFromAdaptor = KCallbackNone;
     
-    if(iIgnoreAsyncOpComplete==EFalse)
+    if(!iIgnoreAsyncOpComplete)
         {
         iAdaptationObserver->AsynchronousOperationComplete(aError, ETrue);
         }
-    
-    iIgnoreAsyncOpComplete=EFalse;
+    else
+        {
+        iAdaptationObserver->PreemptionFinishedCallbackReceived(ETrue);
+        iIgnoreAsyncOpComplete=EFalse;
+        }
     
     DP_OUT();
     }