callcontinuity/vcc/src/tvccstatecalling.cpp
branchRCL_3
changeset 22 d38647835c2e
equal deleted inserted replaced
21:f742655b05bf 22:d38647835c2e
       
     1 /*
       
     2 * Copyright (c) 2007-2008 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:   Implementation for the VCC Calling state
       
    15 *
       
    16 */
       
    17 
       
    18 #include "tvccstatecalling.h"
       
    19 #include "cvccperformer.h"
       
    20 #include "rubydebug.h"
       
    21 
       
    22 
       
    23 // -----------------------------------------------------------------------------
       
    24 // c'tor
       
    25 // -----------------------------------------------------------------------------
       
    26 //
       
    27 TVccStateCalling::TVccStateCalling()
       
    28 	{
       
    29 	RUBY_DEBUG_BLOCK( "TVccStateCalling::TVccStateCalling" );	
       
    30 	} 
       
    31 
       
    32 // -----------------------------------------------------------------------------
       
    33 // Name
       
    34 // -----------------------------------------------------------------------------
       
    35 //	
       
    36 TUint TVccStateCalling::Name() const
       
    37 	{
       
    38 	RUBY_DEBUG_BLOCK( "TVccStateCalling::Name" );
       
    39 	return KVccStateCalling;
       
    40 	}
       
    41 
       
    42 // -----------------------------------------------------------------------------
       
    43 // LinkState
       
    44 // -----------------------------------------------------------------------------
       
    45 //
       
    46 void TVccStateCalling::LinkState(TVccState& aReleasing, 
       
    47                                 TVccState& aInit, 
       
    48                                 TVccState& aFailing )
       
    49 	{
       
    50 	RUBY_DEBUG_BLOCK( "TVccStateCalling::LinkState" );
       
    51 	iReleasing = &aReleasing;
       
    52 	iInit = &aInit;	
       
    53 	iFailing = &aFailing;
       
    54 	}
       
    55 	
       
    56 // -----------------------------------------------------------------------------
       
    57 // HangUp
       
    58 // -----------------------------------------------------------------------------
       
    59 //
       
    60 TInt TVccStateCalling::HangUp(CVccPerformer& aContext, MCCPCall& aCall)
       
    61 	{
       
    62     RUBY_DEBUG_BLOCK( "TVccStateCalling::HangUp" );
       
    63     
       
    64 	TInt err = KErrNotFound;
       
    65 	
       
    66 	__ASSERT_DEBUG(&aCall == aContext.PrimaryCall(), User::Invariant());
       
    67 	
       
    68 	//must release old leg and put old observer back aCall is the
       
    69 	// same as returned in the iContext.PrimaryCall()
       
    70 	aCall.RemoveObserver(aContext);
       
    71 	
       
    72 	//add new observer because the original call will be released and events 
       
    73 	//must be suppressed and performer does not have to be on the path for this 
       
    74 	//call anymore.
       
    75 	TRAP_IGNORE(aCall.AddObserverL(*aContext.CallObserver()));
       
    76 	
       
    77 	//now hangup old leg and forget about it - CCE will take of it.
       
    78 	//The performer will not be aware of the old leg release events.
       
    79 	err = aCall.HangUp();
       
    80 	
       
    81 	//must release new call leg as well and suppress the events 	
       
    82 	//new leg idle event should come in the releasing-state and
       
    83 	//it will be suppressed.
       
    84 	__ASSERT_DEBUG(aContext.SecondaryCall() != NULL, User::Invariant());
       
    85 	aContext.SecondaryCall()->HangUp();
       
    86 	
       
    87 	//signal the performer for the "idle call", so it can stop the trigger
       
    88 	//move to the releasing state
       
    89 	aContext.SetState(*iReleasing);
       
    90 	
       
    91 	//stop trigger since call becomes not active
       
    92 	aContext.ActivateTrigger( EFalse );
       
    93 	
       
    94 	//notify UI about hangup, hangup rejects HO but it is not failure
       
    95 	//no need to show the "ho failed note"
       
    96 	TRAP_IGNORE( aContext.Notifier().NotifySubscriberL(EVccCsToPsHoSuccessful, KErrNone) );
       
    97 	
       
    98 	return err;
       
    99 	
       
   100 	}
       
   101 	
       
   102 // -----------------------------------------------------------------------------
       
   103 // CallStateChanged
       
   104 // -----------------------------------------------------------------------------
       
   105 //	
       
   106 void TVccStateCalling::CallStateChanged( CVccPerformer& aContext, 
       
   107                                 const MCCPCallObserver::TCCPCallState aState,
       
   108                                 MCCPCall* aCall )
       
   109 	{
       
   110 	RUBY_DEBUG_BLOCK( "TVccStateCalling::CallStateChanged" );
       
   111 	
       
   112 	__ASSERT_DEBUG( aContext.SecondaryCall() != NULL, User::Invariant());
       
   113     __ASSERT_DEBUG( aContext.PrimaryCall() != NULL, User::Invariant() );
       
   114     
       
   115 	if ( aState == MCCPCallObserver::ECCPStateConnected && 
       
   116          aContext.SecondaryCall() == aCall)
       
   117 		{
       
   118         RUBY_DEBUG0( "TVccStateCalling::CallStateChanged - swap the calls" );
       
   119         
       
   120 		aContext.SetCall(aContext.SecondaryCall());
       
   121 		
       
   122 		if ( aContext.Parameters().CallType() == CCPCall::ECallTypePS )
       
   123             {
       
   124             TRAP_IGNORE( aContext.Notifier().NotifySubscriberL( EVccCsToPsHoInprogress, 
       
   125                                                    KErrNone ) );
       
   126                   
       
   127             RUBY_DEBUG0( "TVccStateCalling::CallStateChanged - call are swapped so hang up CS call now" );
       
   128             ReleaseCall( aContext, *aContext.SecondaryCall(), *iInit, KVccHoOk );
       
   129             return;
       
   130             }
       
   131         else
       
   132             {
       
   133             TRAP_IGNORE( aContext.Notifier().NotifySubscriberL( EVccPsToCsHoInprogress, 
       
   134                                                        KErrNone ) );
       
   135             }
       
   136 		//-> Set Next State - if the call is idle just destroy call object and 
       
   137 		//go to init-state
       
   138 		__ASSERT_DEBUG( aContext.SecondaryCall() != NULL, 
       
   139 		                User::Invariant());
       
   140 		
       
   141 		if ( aContext.SecondaryCall()->State() == 
       
   142 		     MCCPCallObserver::ECCPStateIdle)
       
   143 			{
       
   144             RUBY_DEBUG0( "TVccStateCalling::CallStateChanged -\
       
   145                          release the old leg" );
       
   146             
       
   147 			//delete the actuall call object and move to Init-state
       
   148             ReleaseCall( aContext, *aContext.SecondaryCall(), *iInit, 
       
   149                          KVccHoOk );
       
   150 			}
       
   151 		else
       
   152 			{
       
   153             RUBY_DEBUG0( "TVccStateCalling::CallStateChanged -\
       
   154                           set state to iReleasing" );
       
   155                     
       
   156 			//must wait for old leg to be released
       
   157 			aContext.SetState( *iReleasing );	
       
   158 			}				
       
   159         }
       
   160     else 
       
   161         {
       
   162         InspectChangedStates( aContext, 
       
   163                               aState, 
       
   164                               aCall, 
       
   165                               aContext.CallObserver(), 
       
   166                               &MCCPCallObserver::CallStateChanged );
       
   167         }
       
   168     }
       
   169 // -----------------------------------------------------------------------------
       
   170 // CallStateChangedWithInband
       
   171 // -----------------------------------------------------------------------------
       
   172 //  
       
   173 void TVccStateCalling::CallStateChangedWithInband( CVccPerformer& aContext, 
       
   174                                 const MCCPCallObserver::TCCPCallState aState,
       
   175                                 MCCPCall* aCall )
       
   176     {
       
   177     RUBY_DEBUG_BLOCK( "TVccStateCalling::CallStateChangedWithInband" );
       
   178     __ASSERT_DEBUG( aContext.SecondaryCall() != NULL, User::Invariant() );
       
   179     __ASSERT_DEBUG( aContext.PrimaryCall() != NULL, User::Invariant() );
       
   180     InspectChangedStates(aContext, 
       
   181                         aState, 
       
   182                         aCall, 
       
   183                         aContext.CallObserver(), 
       
   184                         &MCCPCallObserver::CallStateChangedWithInband);
       
   185 
       
   186     }
       
   187 
       
   188 // -----------------------------------------------------------------------------
       
   189 // From MCCPCallObserver
       
   190 // -----------------------------------------------------------------------------
       
   191 //
       
   192 void TVccStateCalling::ErrorOccurred( CVccPerformer& aContext, 
       
   193                                 const TCCPError aError,
       
   194                                 MCCPCall* aCall )
       
   195     {
       
   196     RUBY_DEBUG_BLOCK( "TVccStateCalling::ErrorOccurred" );
       
   197     RUBY_DEBUG1( "TVccStateCalling::ErrorOccurred - error: %d", aError );
       
   198     
       
   199     __ASSERT_DEBUG( aContext.CallObserver()!=NULL, User::Invariant() );
       
   200     __ASSERT_DEBUG(aContext.PrimaryCall()!=NULL, User::Invariant());
       
   201     __ASSERT_DEBUG(aCall != NULL, User::Invariant());
       
   202     
       
   203     if ( aCall == aContext.SecondaryCall() &&
       
   204          aContext.PrimaryCall()->State() == 
       
   205          MCCPCallObserver::ECCPStateConnected )
       
   206     	{
       
   207     	RUBY_DEBUG0( "TVccStateCalling::ErrorOccurred - set state to iFailing" );
       
   208     	        
       
   209     	aContext.SetState( *iFailing );
       
   210     	}
       
   211     else if( aCall == aContext.SecondaryCall() &&
       
   212             aContext.PrimaryCall()->State() != 
       
   213             MCCPCallObserver::ECCPStateConnected )
       
   214     	{
       
   215     //	RUBY_DEBUG0( "TVccStateCalling::ErrorOccurred - forward the error to CCE" );
       
   216     	//aContext.CallObserver()->ErrorOccurred( aError, 
       
   217     	  //                                      aContext.PrimaryCall() );
       
   218     	}
       
   219   		
       
   220     //Update PS key to notify handover failure
       
   221     TRAP_IGNORE( aContext.Notifier().NotifySubscriberL( EVccCsToPsHoFailure, 
       
   222                                                         aError ) );
       
   223     
       
   224     }
       
   225 
       
   226 // -----------------------------------------------------------------------------
       
   227 // From MCCPCallObserver
       
   228 // -----------------------------------------------------------------------------
       
   229 //
       
   230 void TVccStateCalling::CallEventOccurred(CVccPerformer& aContext, 
       
   231                                 const MCCPCallObserver::TCCPCallEvent aEvent,
       
   232                                 MCCPCall* aCall )
       
   233     {
       
   234     RUBY_DEBUG_BLOCK( "TVccStateCalling::CallEventOccurred" ); 
       
   235     
       
   236 	__ASSERT_DEBUG(aContext.CallObserver()!=NULL, User::Invariant());
       
   237 	__ASSERT_DEBUG(aCall != NULL, User::Invariant());
       
   238 	
       
   239 	//in successful HO case ECCPRemoteTerminated is also received when server
       
   240 	//disconnects the original leg
       
   241 	if ( aEvent == MCCPCallObserver::ECCPRemoteTerminated &&
       
   242 	     aCall == aContext.SecondaryCall()  &&
       
   243 	     aContext.PrimaryCall()->State() != MCCPCallObserver::ECCPStateConnected )
       
   244 		{
       
   245 		RUBY_DEBUG1( "TVccStateCalling::CallEventOccurred -\
       
   246 		             forward the call event to CCE: %d", aEvent );
       
   247 		        
       
   248 	 	aContext.CallObserver()->CallEventOccurred( aEvent, 
       
   249 	                                                aContext.PrimaryCall());
       
   250 	 	    
       
   251 		}
       
   252 	else if( aEvent == MCCPCallObserver::ECCPRemoteTerminated &&
       
   253          aCall == aContext.SecondaryCall()  &&
       
   254          aContext.PrimaryCall()->State() == MCCPCallObserver::ECCPStateConnected )
       
   255 	    {
       
   256 	    RUBY_DEBUG0( "TVccStateCalling::CallEventOccurred - set state to iFailing" );
       
   257 	            
       
   258 	    aContext.SetState( *iFailing );
       
   259 	    }
       
   260 	//if remote end holds the call HO is not allowed at this end either
       
   261 	else if( aEvent == MCCPCallObserver::ECCPRemoteHold )
       
   262 	    {
       
   263 	    //Trigger is informed that automatic HO is not allowed. 
       
   264 	    aContext.ActivateTrigger( EFalse );
       
   265 	    //for manual HO PS key needs to be updated
       
   266 	    aContext.AllowHo( EFalse );
       
   267 	    aContext.CallObserver()->CallEventOccurred( aEvent, 
       
   268 	                                                aContext.PrimaryCall());    
       
   269 	    }
       
   270 	else if( aEvent == MCCPCallObserver::ECCPRemoteResume )
       
   271 	    {
       
   272 	    //HO is allowed again
       
   273 	    aContext.ActivateTrigger( ETrue );
       
   274 	    //for manual HO PS key needs to be updated
       
   275 	    aContext.AllowHo( ETrue );
       
   276 	    aContext.CallObserver()->CallEventOccurred( aEvent, 
       
   277 	                                                aContext.PrimaryCall());                    
       
   278 	    }
       
   279 	}
       
   280 
       
   281 
       
   282 // -----------------------------------------------------------------------------
       
   283 // InspectChangedStates
       
   284 // -----------------------------------------------------------------------------
       
   285 //
       
   286 void TVccStateCalling::InspectChangedStates (CVccPerformer& aContext, 
       
   287                                 const MCCPCallObserver::TCCPCallState aState,
       
   288                                 MCCPCall* aCall,
       
   289                                 MCCPCallObserver* aCallee,
       
   290                                 void (MCCPCallObserver::*aCallback)
       
   291                                 (const MCCPCallObserver::TCCPCallState, MCCPCall*))
       
   292 
       
   293                                 
       
   294     {
       
   295     //Remote party has disconnected the call - the events might arrive
       
   296     //to the new leg first. The event must be issued on the old leg as
       
   297     //all previous events are suppressed.
       
   298     //
       
   299     if( (aState == MCCPCallObserver::ECCPStateDisconnecting ||
       
   300             aState == MCCPCallObserver::ECCPStateIdle) &&
       
   301             aCall == aContext.SecondaryCall() &&
       
   302             aContext.PrimaryCall()->State() != MCCPCallObserver::ECCPStateIdle &&
       
   303             aContext.PrimaryCall()->State() != MCCPCallObserver::ECCPStateConnected )
       
   304         {
       
   305         RUBY_DEBUG1( "TVccStateCalling::InspectChangedStates -\
       
   306                 forward the events on the old leg, suppress from new one: %d", aState );
       
   307         //remove progress bar from UI
       
   308         TRAP_IGNORE( aContext.Notifier().NotifySubscriberL( EVccCsToPsHoFailure, KErrGeneral ) );
       
   309         (aCallee->*aCallback)( aState, aContext.PrimaryCall());
       
   310         }
       
   311     //old leg is released in remote disconnect or other abnormal case, this should never
       
   312     //happen in the successfull HO case.
       
   313     
       
   314     else if( aState == MCCPCallObserver::ECCPStateIdle &&
       
   315                     aCall == aContext.PrimaryCall() )
       
   316         {       
       
   317         RUBY_DEBUG1( "TVccStateCalling::InspectChangedStates - shouldnt happen in normal HO case,\
       
   318                       MT disconnected the call, or some other abnormal case: %d", aState );
       
   319                 
       
   320         //remove progress bar from UI
       
   321         TRAP_IGNORE( aContext.Notifier().NotifySubscriberL( EVccCsToPsHoFailure, KErrGeneral ) );
       
   322         (aCallee->*aCallback)( aState, aContext.PrimaryCall() );
       
   323         aContext.SetState( *iInit );
       
   324         }
       
   325     }