sipvoipprovider/svphold/src/svpholdcontroller.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Thu, 19 Aug 2010 09:45:22 +0300
branchRCL_3
changeset 20 65a3ef1d5bd0
parent 0 a4daefaec16c
permissions -rw-r--r--
Revision: 201031 Kit: 201033

/*
* Copyright (c) 2006-2010 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:  Hold controller, interface class to SVP sessions
*
*/
 

#include    <mcesession.h>
#include    <mcemediastream.h>
#include    <mceaudiostream.h>

#include    "svpholdcontroller.h"
#include    "svpholdmediahandler.h"
#include    "svpholdobserver.h"
#include    "svpsessionbase.h"
#include    "svpsipconsts.h"
#include    "svpconsts.h"
#include    "svplogger.h"


// ---------------------------------------------------------------------------
// CSVPHoldController::CSVPHoldController
// ---------------------------------------------------------------------------
//
CSVPHoldController::CSVPHoldController() :
        iContext( NULL ),
        iPreviousHoldState( ESVPHoldConnected ),
        iHoldRequestCompleted( EFalse ),
        iHoldRequest( ESVPHoldNoRequest ),
        iReinviteCrossover( EFalse )
    {
    }

// ---------------------------------------------------------------------------
// CSVPHoldController::ConstructL
// ---------------------------------------------------------------------------
//
void CSVPHoldController::ConstructL( 
                            CMceSession& aSession,
                            TMceTransactionDataContainer& aContainer,
                            MSVPHoldObserver* aObserver,
                            TBool aIsMobileOriginated )
    {
    iContext = CSVPHoldContext::NewL( aSession, aContainer, aObserver,
                                      aIsMobileOriginated );
    }

// -----------------------------------------------------------------------------
// CSVPHoldController::NewL
// -----------------------------------------------------------------------------
//
CSVPHoldController* CSVPHoldController::NewL( 
                            CMceSession& aSession,
                            TMceTransactionDataContainer& aContainer,
                            MSVPHoldObserver* aObserver,
                            TBool aIsMobileOriginated )
    {    
    CSVPHoldController* self = new ( ELeave ) CSVPHoldController();
    
    CleanupStack::PushL( self );
    self->ConstructL( aSession, aContainer, aObserver,
                      aIsMobileOriginated );
                      
    CleanupStack::Pop( self );

    return self;
    }

// ---------------------------------------------------------------------------
// CSVPHoldController::NewLC
// ---------------------------------------------------------------------------
//
CSVPHoldController* CSVPHoldController::NewLC( 
                            CMceSession& aSession,
                            TMceTransactionDataContainer& aContainer,
                            MSVPHoldObserver* aObserver,
                            TBool aIsMobileOriginated )
    {
    CSVPHoldController* self = new ( ELeave ) CSVPHoldController();
    CleanupStack::PushL( self );
    self->ConstructL( aSession, aContainer, aObserver,
                      aIsMobileOriginated );

    return self;
    }


// ---------------------------------------------------------------------------
// CSVPHoldController::~CSVPHoldController
// ---------------------------------------------------------------------------
//
CSVPHoldController::~CSVPHoldController()
    {
    delete iContext;
    SVPDEBUG1( "CSVPHoldController::~CSVPHoldController Done" );
    }

// ---------------------------------------------------------------------------
// CSVPHoldController::RetryHoldRequest
// ---------------------------------------------------------------------------
//
TInt CSVPHoldController::RetryHoldRequest( CMceSession* aSession )
    {
    SVPDEBUG1( "CSVPHoldController::RetryHoldRequest -- IN" );
    TInt err = KErrNone;
    switch ( iHoldRequest )
        {
        case ESVPHoldToHold:
            {
            SVPDEBUG1( "CSVPHoldController::RetryHoldRequest -- Hold" );
            err = HoldSession( aSession );
            break;
            }
            
        case ESVPHoldToResume:
            {
            SVPDEBUG1( "CSVPHoldController::RetryHoldRequest -- Resume" );
            err = ResumeSession( aSession );
            break;
            }
        
        default:
            {
            SVPDEBUG1( "CSVPHoldController::RetryHoldRequest -- No request!!" );
            err = KErrNotFound;
            break;
            }
        }
    
    iHoldRequest = ESVPHoldNoRequest;
    SVPDEBUG1( "CSVPHoldController::RetryHoldRequest -- OUT" );
    return err;
    }

// ---------------------------------------------------------------------------
// CSVPHoldController::HoldSession
// ---------------------------------------------------------------------------
//
TInt CSVPHoldController::HoldSession( CMceSession* aSession )
    {
    SVPDEBUG1( "CSVPHoldController::HoldSession -- IN" );

    if ( HoldAllowed() )
        {
        iHoldRequest = ESVPHoldToHold;
        iHoldRequestCompleted = EFalse;
        SVPDEBUG1( "CSVPHoldController::HoldSession -- Allowed" );
        TInt err = KErrNone;
        iContext->SetSessionObject( aSession );

        TRAP( err, iContext->ApplyCurrentStateL( aSession,
                                                 ESVPHoldToHold ) );
        
        SVPDEBUG2(
        "CSVPHoldController::HoldSession -- ApplyCurrentState done, err = %i",
         err );
         
        switch ( err )
            {                
            case KErrSVPHoldLocalOldwayholdNeeded:
                {
                SVPDEBUG1(
                "CSVPHoldController::HoldSession: Oldway hold needed" );
                
                iContext->SetFirstAttempt( EFalse ); // Clearing the flag                
                TRAP( err, iContext->ApplyCurrentStateL( aSession,
                                                         ESVPHoldToHold ) );
                return err;
                }
                
            default:
                {
                SVPDEBUG2(
                "CSVPHoldController::HoldSession - default, err: %i", err );
                return err;
                }
            }        
        }
        
    else
        {
        return KErrSVPHoldInProgress;
        }
    }

// ---------------------------------------------------------------------------
// CSVPHoldController::ResumeSession
// ---------------------------------------------------------------------------
//
TInt CSVPHoldController::ResumeSession( CMceSession* aSession )
    {
    if ( ResumeAllowed() )
        {
        iHoldRequest = ESVPHoldToResume;
        iHoldRequestCompleted = EFalse;
        TInt err = KErrNone;
        iContext->SetSessionObject( aSession );
        TRAP( err, iContext->ApplyCurrentStateL( aSession,
                                                 ESVPHoldToResume ) );
        return err;
        }
    else
        {
        return KErrSVPHoldResumeInProgress;
        }
    }

// ---------------------------------------------------------------------------
// CSVPHoldController::TimedOut
// ---------------------------------------------------------------------------
//
void CSVPHoldController::TimedOut()
    {
    iContext->TimedOut();
    }

// ---------------------------------------------------------------------------
// CSVPHoldController::IncomingRequest
// ---------------------------------------------------------------------------
//
TInt CSVPHoldController::IncomingRequest( CMceSession* aSession )
    {
    SVPDEBUG1( "CSVPHoldController::IncomingRequest IN" )
    if ( IncomingRequestAllowed() )
        {
        SVPDEBUG1( "CSVPHoldController::IncomingRequest allowed" )
        
        iHoldRequestCompleted = EFalse;
        iContext->SetSessionObject( aSession );
        TInt err = KErrNone;
        TRAP( err, iContext->ApplyCurrentStateL( aSession,
                                                 ESVPHoldIncoming ) );
        
        if ( KErrSVPHoldNotHoldRequest == err )
            {
            iHoldRequestCompleted = ETrue;
            }
        
        return err;            
        }
        
    else
        {
        SVPDEBUG1( "CSVPHoldController::IncomingRequest not allowed!" )
        
        return KErrSVPHoldRequestPending;
        }    
    }

// ---------------------------------------------------------------------------
// CSVPHoldController::IncomingResponse
// ---------------------------------------------------------------------------
//
TInt CSVPHoldController::IncomingResponse( 
                            CMceSession* aSession, 
                            TInt aStatusCode )
    {
    if ( IncomingResponseAllowed() )
        {
        SVPDEBUG1( "CSVPHoldController::IncomingResponse - Allowed" );
        iContext->SetSessionObject( aSession );
        iContext->SetResponseStatusCode( aStatusCode );
        TInt err = KErrNone;
        TRAP( err, iContext->ApplyCurrentStateL() );
        iContext->SetResponseStatusCode( KErrNotFound );
                                                 
        SVPDEBUG2( "CSVPHoldController::IncomingResponse - Error = %i", err );                                         
        return err;            
        }
        
    else
        {
        SVPDEBUG1( "CSVPHoldController::IncomingResponse - not Allowed!" );
        return KErrSVPHoldRequestPending;
        }        
    }

// ---------------------------------------------------------------------------
// CSVPHoldController::HoldInProgress
// ---------------------------------------------------------------------------
//
TBool CSVPHoldController::HoldInProgress() const
    {
    return !iHoldRequestCompleted;
    }

// ---------------------------------------------------------------------------
// CSVPHoldController::HoldRolledBack
// ---------------------------------------------------------------------------
//
TBool CSVPHoldController::HoldRolledBack() const
    {
    return iContext->HoldRolledBack();
    }

// ---------------------------------------------------------------------------
// CSVPHoldController::HoldFailed
// ---------------------------------------------------------------------------
//
TBool CSVPHoldController::HoldFailed()
    {
    return iContext->HoldFailed();    
    }

// ---------------------------------------------------------------------------
// CSVPHoldController::ResumeFailed
// ---------------------------------------------------------------------------
//
TBool CSVPHoldController::ResumeFailed()
    {
    return iContext->ResumeFailed();    
    }

// ---------------------------------------------------------------------------
// CSVPHoldController::ContinueHoldProcessing
// ---------------------------------------------------------------------------
//
TInt CSVPHoldController::ContinueHoldProcessing( CMceSession& aSession )
    {
    SVPDEBUG1( "CSVPHoldController::ContinueHoldProcessing - IN" );
    iReinviteCrossover = EFalse;
    TInt err = KErrNone;
    iContext->SetSessionObject( &aSession );

    TRAP( err, iContext->ApplyCurrentStateL() );
    
    iHoldRequestCompleted = ETrue;
    SVPDEBUG2( "CSVPHoldController::ContinueHoldProcessing - Ready, err = %i",
                err );
    return err;
    }

// ---------------------------------------------------------------------------
// CSVPHoldController::RequestFailed
// ---------------------------------------------------------------------------
//
TInt CSVPHoldController::RequestFailed( CMceSession& aSession, 
                                        TInt aStatusCode, 
                                        CSVPSessionBase& aBase )
    {
    SVPDEBUG1( "CSVPHoldController::RequestFailed - IN" );


    aBase.StopTimers();
    
    // If 491 received first time, try it once more. No need to enable /
    // disable audios
    if ( KSVPRequestPendingVal == aStatusCode )
        {
        SVPDEBUG1( "CSVPHoldController::RequestFailed - 491 received" )
        if ( !iReinviteCrossover )
            {
            // First 491 received              
            iReinviteCrossover = ETrue;
            iContext->CrossOver( ETrue );                
            }
        else
            {
            // Second 491; hold/resume request failed
            iReinviteCrossover = EFalse;
            iContext->CrossOver( EFalse );
            }
        }
    
    if ( 0 == aStatusCode && ESVPEstablishing == HoldState() )
        {
        SVPDEBUG1( "CSVPHoldController::RequestFailed - status 0 received" )
        
        iReinviteCrossover = EFalse;
        iContext->CrossOver( EFalse );
        
        SVPDEBUG1( "CSVPHoldController::RequestFailed - set status code 400" )
        aStatusCode = KSVPBadRequestVal;
        }

    TInt err = KErrNone;
    if ( iReinviteCrossover )
        {
        TRAP( err, aBase.StartTimerL( aBase.ReinviteCrossoverTime(),
                                       KSVPReInviteTimerExpired ) );
        if ( err )
            {
            SVPDEBUG2("CSVPHoldController::RequestFailed - Timer, err %i",
                       err )
            }
        }

    iContext->SetCallRequestFailed( ETrue );
    err = IncomingResponse( &aSession, aStatusCode );
    iContext->SetCallRequestFailed( EFalse );
    SVPDEBUG1( "CSVPHoldController::RequestFailed - OUT" );
    return err;
    }


// ---------------------------------------------------------------------------
// CSVPHoldController::CheckCrossOver
// ---------------------------------------------------------------------------
//
void CSVPHoldController::CheckCrossOver( CSVPSessionBase& aBase )
    {
    SVPDEBUG1( "CSVPHoldController::CheckCrossOver - IN" );
    if ( iReinviteCrossover )
        {
        SVPDEBUG1("CSVPHoldController::CheckCrossOver - True");

        aBase.StopTimers();
        iReinviteCrossover = EFalse;
        iContext->CrossOver( EFalse );
 
        TSVPHoldRequestType previousRequest = HoldRequest();
        
        if ( ESVPLocalHold == previousRequest ||
             ESVPLocalDoubleHold == previousRequest )
            {
            aBase.HoldRequestFailed();
            }
        
        else if ( ESVPLocalResume == previousRequest ||
                  ESVPLocalDoubleHoldResume == previousRequest )
            {
            aBase.ResumeRequestFailed();
            }
        
        else
            {
            // This case should never happen
            SVPDEBUG2( "CSVPHoldController::CheckCrossOver - Error,  = %i",
                        previousRequest );
            }
        }
    
    SVPDEBUG1( "CSVPHoldController::CheckCrossOver - OUT" );
    }

// ---------------------------------------------------------------------------
// CSVPHoldController::HoldState
// Returns the hold state.
// ---------------------------------------------------------------------------
//
TSVPSessionHoldState CSVPHoldController::HoldState() const
    {
    SVPDEBUG1( "CSVPHoldController::HoldState" );
    
    TSVPHoldStateIndex currentState = iContext->CurrentState();
    
    
    if ( KSVPHoldConnectedStateIndex == currentState )
        {
        SVPDEBUG1( "CSVPHoldController::HoldState - CONNECTED" );
        return ESVPConnected;
        }
        
    else if ( KSVPHoldEstablishingStateIndex == currentState )
        {
        SVPDEBUG1( "CSVPHoldController::HoldState - ESTABLISHING" );
        return ESVPEstablishing;
        }
        
    else
        {
        SVPDEBUG1( "CSVPHoldController::HoldState - ONHOLD" );
        return ESVPOnHold;
        }
    }

// ---------------------------------------------------------------------------
// CSVPHoldController::HoldRequest
// Returns the hold request type.
// ---------------------------------------------------------------------------
//
TSVPHoldRequestType CSVPHoldController::HoldRequest() const
    {
    SVPDEBUG1( "CSVPHoldController::HoldRequest" );
    return iContext->HoldRequest();
    }

// ---------------------------------------------------------------------------
// CSVPHoldController::HoldAllowed
// ---------------------------------------------------------------------------
//
TBool CSVPHoldController::HoldAllowed()
    {
    TSVPHoldStateIndex currentState = iContext->CurrentState();
    
    if ( KSVPHoldOutStateIndex == currentState ||
         KSVPHoldEstablishingStateIndex == currentState ||
         KSVPHoldDHStateIndex == currentState )
        {
        SVPDEBUG1( "CSVPHoldController::HoldAllowed - EFalse" );
        return EFalse;
        }
    else
        {
        SVPDEBUG1( "CSVPHoldController::HoldAllowed - ETrue" );
        return ETrue;
        }
    }

// ---------------------------------------------------------------------------
// CSVPHoldController::ResumeAllowed
// ---------------------------------------------------------------------------
//   
TBool CSVPHoldController::ResumeAllowed()
    {
    TSVPHoldStateIndex currentState = iContext->CurrentState();
    if ( KSVPHoldInStateIndex == currentState ||
         KSVPHoldEstablishingStateIndex == currentState ||
         KSVPHoldConnectedStateIndex == currentState )
        {
        return EFalse;
        }
    else
        {
        SVPDEBUG1( "CSVPHoldController::ResumeAllowed" );
        return ETrue;
        }    
    }

// ---------------------------------------------------------------------------
// CSVPHoldController::Muted
// ---------------------------------------------------------------------------
//
void CSVPHoldController::Muted( TBool aMuted )
    {
    iContext->Muted( aMuted );
    }

// ---------------------------------------------------------------------------
// CSVPHoldController::IncomingRequestAllowed
// ---------------------------------------------------------------------------
//   
TBool CSVPHoldController::IncomingRequestAllowed()
    {
    if ( KSVPHoldEstablishingStateIndex == iContext->CurrentState() )
        {
        return EFalse;
        }
    else
        {
        SVPDEBUG1( "CSVPHoldController::IncomingRequestAllowed" );
        
        return ETrue;
        }        
    }
    
// ---------------------------------------------------------------------------
// CSVPHoldController::IncomingResponseAllowed
// ---------------------------------------------------------------------------
//   
TBool CSVPHoldController::IncomingResponseAllowed()
    {
    if ( KSVPHoldEstablishingStateIndex == iContext->CurrentState() )
        {
        SVPDEBUG1( "CSVPHoldController::IncomingResponseAllowed" );
        return ETrue;
        }
    else
        {
        return EFalse;
        }        
    }

// ---------------------------------------------------------------------------
// CSVPHoldController::HoldEvent
// ---------------------------------------------------------------------------
//
MCCPCallObserver::TCCPCallEvent CSVPHoldController::HoldEvent()
    {
    return iContext->HoldEvent();
    }

// ---------------------------------------------------------------------------
// CSVPHoldController::RefreshHoldStateL
// ---------------------------------------------------------------------------
//
void CSVPHoldController::RefreshHoldStateL()
    {
    SVPDEBUG1( "CSVPHoldController::RefreshHoldStateL - In" );

    CMceSession* session = iContext->SessionObject();
    const RPointerArray< CMceMediaStream >& streams = session->Streams();
    CMceMediaStream* mediaStream = NULL;

    TInt streamCount = streams.Count();
    for ( TInt i = 0; i < streamCount; i++ )
        {
        mediaStream = streams[ i ];
        TMceMediaType mediaType = mediaStream->Type();
        if ( KMceAudio == mediaType )
            {
            SVPDEBUG1( "CSVPHoldController::RefreshHoldStateL - Stream found" );
            mediaStream = streams[ i ];
            RefreshL( *mediaStream );
            break;
            }
        }
       
    SVPDEBUG1( "CSVPHoldController::RefreshHoldStateL - Out" );
    }

// ---------------------------------------------------------------------------
// CSVPHoldController::RefreshL
// ---------------------------------------------------------------------------
//
void CSVPHoldController::RefreshL( CMceMediaStream& aMediaStream )
    {
    if ( &aMediaStream )
        {
        switch ( iContext->CurrentState() )
            {
            case KSVPHoldOutStateIndex:
                {
                iContext->MediaHandler().PerformMediaActionL(
                        aMediaStream, ESVPLocalHold );
                break;
                }
                
            case KSVPHoldInStateIndex:
                {
                iContext->MediaHandler().PerformMediaActionL(
                        aMediaStream, ESVPRemoteHold );
                break;
                }
                
            case KSVPHoldDHStateIndex:
                {
                iContext->MediaHandler().PerformMediaActionL(
                        aMediaStream, ESVPLocalDoubleHold );
                break;
                }
            
            case KSVPHoldConnectedStateIndex:
                {
                // Special case here; for enablingIOP: audio is lost on Snom M3 when it unholds the call
                SVPDEBUG1( "CSVPHoldController::RefreshL -> Refresh audio" );
                iContext->MediaHandler().EnableAudioL( *iContext );
                SVPDEBUG1( "CSVPHoldController::RefreshL <- Refresh audio done" );
                break;
                }
                
            case KSVPHoldEstablishingStateIndex:
                {
                SVPDEBUG1( "CSVPHoldController::RefreshL - Not needed" );
                break;
                }
            }
        }

    SVPDEBUG1( "CSVPHoldController::RefreshL - Out" );
    }