sipvoipprovider/src/svpemergencysession.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Fri, 19 Feb 2010 22:44:34 +0200
branchRCL_3
changeset 6 fc8c25e5a2e8
parent 0 a4daefaec16c
permissions -rw-r--r--
Revision: 201003 Kit: 201007

/*
* Copyright (c) 2006-2008 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:  SVP Emergency Sesssion class. Handles emergency 
*                session methods.        
*
*/


#include <sip.h>
#include <sipprofile.h>
#include <sipprofileregistry.h>

#include <mceaudiostream.h>
#include <mcertpsource.h>
#include <mcertpsink.h>
#include <mcemicsource.h>
#include <mcespeakersink.h>
#include <mcetransactiondatacontainer.h>

#include "crcseprofileentry.h"
#include "crcseprofileregistry.h"

#include "svpemergencysession.h"
#include "svpuriparser.h"
#include "svputility.h"
#include "svpsipconsts.h"
#include "svpconsts.h"
#include "svppositioningprovider.h"
#include "svpemergencyconnection.h"
#include "svpholdcontroller.h"
#include "svpaudioutility.h"
#include "svpdtmfeventgenerator.h"

// ---------------------------------------------------------------------------
// CSVPEmergencySession::CSVPEmergencySession
// ---------------------------------------------------------------------------
//
CSVPEmergencySession::CSVPEmergencySession( 
    CSVPUtility& aSVPUtility, 
    CMceManager& aMceManager, 
    TBool aIsLastProfile, 
    TBool aIsDummy )
    : iSVPUtility( aSVPUtility ), 
      iMceManager( aMceManager ), 
      iSessionExpires( KSVPDefaultSessionExpires ), 
      iIsLastProfile( aIsLastProfile ), 
      iIsDummy( aIsDummy ), 
      iIsDialed( EFalse ), 
      iIsLIRequestReady( ETrue )
    {
    }

// ---------------------------------------------------------------------------
// CSVPEmergencySession::ConstructL
// ---------------------------------------------------------------------------
//
void CSVPEmergencySession::ConstructL( TUint32 aVoipProfileId, 
                                       const TDesC& aAddress, 
                                       const MCCPCallObserver& aObserver, 
                                       TBool aIsDummy )                                   
    {
    SVPDEBUG2("CSVPEmergencySession::ConstructL() IN, VoIP profile ID: %d", 
        aVoipProfileId)

    iEmergencyObserver = const_cast< MCCPCallObserver* >( &aObserver );
    iVoipProfileId = ( TInt )aVoipProfileId;

    // Start emergency timer, timeout 17 seconds
    StartTimerL( KSVPEmergencyTimeout, KSVPEmergencyExpired );

    if ( aIsDummy )
        {
        SVPDEBUG1("CSVPEmergencySession::ConstructL, dummy session")
        return;
        }

    // Initialize registries
    CRCSEProfileRegistry* reg = CRCSEProfileRegistry::NewLC(); // CS:1
    CSIP* sip = CSIP::NewLC( KSVPUid, *this ); // CS:2
    CSIPProfileRegistry* sipProfileRegistry = CSIPProfileRegistry::NewLC( 
        *sip, *this ); // CS:3

    // Find VoIP profile by its ID
    CRCSEProfileEntry* voipProfile = CRCSEProfileEntry::NewLC();  // CS:4
    reg->FindL( aVoipProfileId, *voipProfile );

    // Set Session Expires value
    iSessionExpires = ( TUint32 )voipProfile->iSIPSessionExpires;
    
    // There is only one (or zero) SIP profile per VoIP profile.
    // if profileId doesn't exist, report an error ( ECCPErrorGeneral ).
    if ( 0 == voipProfile->iIds.Count() )
        {
        SVPDEBUG1( "CSVPEmergencySession::ConstructL, no SIP profile, return" )
        CleanupStack::PopAndDestroy( 4, reg ); // CS:0
        ErrorOccurred( ECCPErrorGeneral );
        return;
        }
    CSIPProfile* sipProfile = sipProfileRegistry->ProfileL( 
        voipProfile->iIds[0].iProfileId );
    CleanupStack::PushL( sipProfile ); // CS:5

    // Get SIP profile ID
    User::LeaveIfError( 
        sipProfile->GetParameter( KSIPProfileId, iSipProfileId ) );
       
    // Get user AOR
    const TDesC8* userAor = NULL;
    User::LeaveIfError( sipProfile->GetParameter( KSIPUserAor, userAor ) );
    iUserAor = HBufC8::NewL( userAor->Length() );
    ( iUserAor->Des() ).Copy( *userAor );
    
    // Parse SIP URI
    HBufC8* recipient = HBufC8::NewLC( aAddress.Length() ); // CS:6
    ( recipient->Des() ).Copy( aAddress );
    CSVPUriParser* uriParser = CSVPUriParser::NewLC(); // CS:7
    iRecipientUri = uriParser->CompleteSipUriL( *recipient, *iUserAor, ETrue );
    CleanupStack::PopAndDestroy( 2, recipient ); // uriparser, recipient CS:5

    // Get registration status
    TBool registered( EFalse );
    sipProfile->GetParameter( KSIPProfileRegistered, registered );

    // Get SNAP ID
    TUint32 snapId( 0 );
    TInt errSnap = sipProfile->GetParameter( KSIPSnapId, snapId );

    // Define IAP ID
    if ( !registered && KErrNone == errSnap )
        {
        SVPDEBUG2("CSVPEmergencySession::ConstructL, snapId: %d", snapId)
        // Define IAP ID from SNAP ID, create WLAN connection
        iEmergencyConnection = CSVPEmergencyConnection::NewL( 
            CActive::EPriorityStandard, *this );
        iEmergencyConnection->ConnectWithSnapIdL( snapId );
        CleanupStack::PopAndDestroy( 5, reg );
        // reg, sip, sipProfileRegistry, voipProfile, sipProfile CS:0
        SVPDEBUG1("CSVPEmergencySession::ConstructL, return")
        return;
        }
    else
        {
        User::LeaveIfError( 
            sipProfile->GetParameter( KSIPAccessPointId, iIapId ) );
        }

    // Create MCE out session
    if ( registered )
        {
        SVPDEBUG1("CSVPEmergencySession::ConstructL, registered")
        iEmergencySession = CMceOutSession::NewL( 
            iMceManager, *sipProfile, *iRecipientUri );
        ConstructAudioStreamsL();
        }
    else
        {
        CreateUnregistedSessionL();
        }
    
    CleanupStack::PopAndDestroy( 5, reg ); 
    // CS:0 reg, sip, sipProfileRegistry, voipProfile, sipProfile

    // Request for position information
    RequestPosition( iIapId );

    SVPDEBUG1("CSVPEmergencySession::ConstructL() OUT")
    }

// ---------------------------------------------------------------------------
// CSVPEmergencySession::ConstructWithIapIdL
// ---------------------------------------------------------------------------
//
void CSVPEmergencySession::ConstructWithIapIdL( 
    TUint32 aIapId, 
    const TDesC& aAddress, 
    const MCCPCallObserver& aObserver, 
    TBool aIsDummy )                                   
    {
    SVPDEBUG2("CSVPEmergencySession::ConstructWithIapIdL() In, IAP ID: %d", 
        aIapId)

    iEmergencyObserver = const_cast< MCCPCallObserver* >( &aObserver );
    iVoipProfileId = KErrNotFound;
    iIapId = aIapId;
    
    // Copy recipient address
    iAddress = HBufC8::NewL( aAddress.Length() );
    ( iAddress->Des() ).Copy( aAddress );
    
    // Start emergency timer, timeout 17 seconds
    StartTimerL( KSVPEmergencyTimeout, KSVPEmergencyExpired );

    if ( aIsDummy )
        {
        SVPDEBUG1("CSVPEmergencySession::ConstructWithIapIdL, dummy session")
        return;
        }

    // Request for SIP proxy address
    SVPDEBUG1("CSVPEmergencySession::ConstructWithIapIdL, SIP proxy address")
    iEmergencyConnection = CSVPEmergencyConnection::NewL( 
        CActive::EPriorityStandard, *this );
    iEmergencyConnection->ConnectL( iIapId );
    
    SVPDEBUG1("CSVPEmergencySession::ConstructWithIapIdL() Out")
    }

// ---------------------------------------------------------------------------
// CSVPEmergencySession::ContinueConstructWithIapIdL
// ---------------------------------------------------------------------------
//
void CSVPEmergencySession::RequestSipProxyAddressL()
    {
    if ( NULL == iEmergencyConnection )
        {
        User::Leave( KErrGeneral );
        }

    iEmergencyConnection->RequestSipProxyAddressL( iIapId );
    }

// ---------------------------------------------------------------------------
// CSVPEmergencySession::ContinueConstructWithIapIdL
// ---------------------------------------------------------------------------
//
void CSVPEmergencySession::ContinueConstructWithIapIdL( 
    const TDesC16& aSipProxyAddress )
    {
    SVPDEBUG2("CSVPEmergencySession::ContinueConstructWithIapIdL(),\
        SIP proxy address: %S", &aSipProxyAddress)

    if ( 0 == aSipProxyAddress.Length() )
        {
        User::Leave( KErrNotFound );
        }

    // Parse user AOR
    iUserAor = HBufC8::NewL(
        KSVPSipPrefix().Length() + 
        KSVPAnonymous().Length() + 
        KSVPAt().Length() + 
        aSipProxyAddress.Length() );
    TPtr8 userAorPtr = iUserAor->Des();
    userAorPtr.Copy( KSVPSipPrefix );
    userAorPtr.Append( KSVPAnonymous );
    userAorPtr.Append( KSVPAt );
    userAorPtr.Append( aSipProxyAddress );

    // Parse SIP URI
    SVPDEBUG1("CSVPEmergencySession::ContinueConstructWithIapIdL,\
        parse SIP URI")
    CSVPUriParser* uriParser = CSVPUriParser::NewLC(); // CS:1
    iRecipientUri = uriParser->CompleteSipUriL( *iAddress, *iUserAor, ETrue );
    CleanupStack::PopAndDestroy( uriParser ); // CS:0

    // Create MCE session
    CreateUnregistedSessionL();

    // Request for position information
    RequestPosition( iIapId );
    
    SVPDEBUG1("CSVPEmergencySession::ContinueConstructWithIapIdL() Out")
    }

// ---------------------------------------------------------------------------
// CSVPEmergencySession::NewL
// ---------------------------------------------------------------------------
//
CSVPEmergencySession* CSVPEmergencySession::NewL(  
                                        CMceManager& aMceManager, 
                                        TUint32 aVoipProfileId, 
                                        const TDesC& aAddress, 
                                        const MCCPCallObserver& aObserver,
                                        CSVPUtility& aSVPUtility, 
                                        TBool aIsLastProfile, 
                                        TBool aIsDummy )
    {
    CSVPEmergencySession* self = new( ELeave ) CSVPEmergencySession( 
        aSVPUtility, aMceManager, aIsLastProfile, aIsDummy );
    CleanupStack::PushL( self );
    self->ConstructL( aVoipProfileId, aAddress, aObserver, aIsDummy );
    CleanupStack::Pop( self );
    return self;
    }

// ---------------------------------------------------------------------------
// CSVPEmergencySession::NewL
// ---------------------------------------------------------------------------
//
CSVPEmergencySession* CSVPEmergencySession::NewL(  
                                        CMceManager& aMceManager, 
                                        const TDesC& aAddress, 
                                        const MCCPCallObserver& aObserver,
                                        CSVPUtility& aSVPUtility, 
                                        TUint32 aIapId, 
                                        TBool aIsLastProfile, 
                                        TBool aIsDummy )
    {
    CSVPEmergencySession* self = new( ELeave ) CSVPEmergencySession( 
        aSVPUtility, aMceManager, aIsLastProfile, aIsDummy );
    CleanupStack::PushL( self );
    self->ConstructWithIapIdL( aIapId, aAddress, aObserver, aIsDummy );
    CleanupStack::Pop( self );
    return self;
    }

// ---------------------------------------------------------------------------
// CSVPEmergencySession::~CSVPEmergencySession
// ---------------------------------------------------------------------------
//
CSVPEmergencySession::~CSVPEmergencySession()
    {
    SVPDEBUG1("CSVPEmergencySession::~CSVPEmergencySession() In")

    StopTimers();  
    iTimers.Close();

    delete iEmergencySession;
    delete iFailedEmergencySession;
    
    delete iUserAor;
    delete iAddress;
    delete iRecipientUri;
    
    delete iPositionInformation;
    delete iPositioningProvider;
    
    delete iEmergencyConnection;
    
    delete iHoldController;
    
    delete iDTMFEventGenerator;
    
    delete iDtmfString;

    SVPDEBUG1("CSVPEmergencySession::~CSVPEmergencySession() Out")
    }

// ---------------------------------------------------------------------------
// CSVPEmergencySession::State
// ---------------------------------------------------------------------------
//
MCCPCallObserver::TCCPCallState CSVPEmergencySession::State() const
    {
    SVPDEBUG1("CSVPEmergencySession::State()")

    // ccpState can be safely initialized with StatusIdle
    MCCPCallObserver::TCCPCallState ccpState = 
        MCCPCallObserver::ECCPStateIdle;
    
    switch ( iEmergencySession->State() )
        {
        case CMceSession::EIdle:
            SVPDEBUG1("CSVPEmergencySession::State, MCE EIdle")
            ccpState = MCCPCallObserver::ECCPStateIdle;
            break;
       
        case CMceSession::EProceeding:
            SVPDEBUG1("CSVPEmergencySession::State, MCE EProceeding")
            ccpState = MCCPCallObserver::ECCPStateConnecting;
            break;
            
        case CMceSession::EEstablished:
            SVPDEBUG1("CSVPEmergencySession::State, MCE EEstablished")
            ccpState = MCCPCallObserver::ECCPStateConnected;
            break;
            
        case CMceSession::ECancelling:
            SVPDEBUG1("CSVPEmergencySession::State, MCE ECancelling")
            ccpState = MCCPCallObserver::ECCPStateIdle;  
            break;
            
        case CMceSession::ETerminating:
            SVPDEBUG1("CSVPEmergencySession::State, MCE ETerminating")
            ccpState = MCCPCallObserver::ECCPStateDisconnecting;
            break;
            
        case CMceSession::ETerminated:
            SVPDEBUG1("CSVPEmergencySession::State, MCE ETerminated")
            if ( MCCPCallObserver::ECCPStateDisconnecting == iSessionState )
                {
                ccpState = MCCPCallObserver::ECCPStateDisconnecting;
                }
            else
                {
                ccpState = MCCPCallObserver::ECCPStateIdle;     
                }
            break;
            
        default:
            SVPDEBUG1("CSVPEmergencySession::State, DEFAULT")
            // This block should never be reached.
            break;
        }

    return ccpState;
    }

// ---------------------------------------------------------------------------
// Traps SessionStateChangedL
// ---------------------------------------------------------------------------
//
void CSVPEmergencySession::SessionStateChanged( TInt aStatusCode )
    {
    TRAPD( err, SessionStateChangedL( aStatusCode ) )
    if ( err )
        {
        SVPDEBUG2("CSVPEmergencySession::SessionStateChanged, err: %d", err)
        }
    }

// ---------------------------------------------------------------------------
// Session connection state changed
// ---------------------------------------------------------------------------
//
void CSVPEmergencySession::SessionConnectionStateChanged(
    CMceSession& aSession, TBool aActive )
    {
    SVPDEBUG2("CSVPEmergencySession::SessionConnectionStateChanged - %d", 
        aActive)
    
    if ( iEmergencySession == &aSession && aActive )
        {
        ProceedDial();
        }
    }

// ---------------------------------------------------------------------------
// Stream state changed
// ---------------------------------------------------------------------------
//
void CSVPEmergencySession::StreamStateChanged( CMceMediaStream& aStream )
    {
    SVPDEBUG1("CSVPEmergencySession::StreamStateChanged()")
    
    if ( CMceMediaStream::EDisabled == aStream.State() &&
         CMceSession::EEstablished == aStream.Session()->State() )
        {
        // Remote end died
        iEmergencyObserver->CallStateChanged( 
            MCCPCallObserver::ECCPStateDisconnecting, NULL );
        TRAP_IGNORE( StartTimerL( 
            KSVPTerminatingTime, KSVPRemoteEndDiedExpired ) )
        }
    else if ( CMceMediaStream::EStreaming == aStream.State() )
        {
        SVPDEBUG1("CSVPEmergencySession::StreamStateChanged() - EStreaming")
        StopTimer( KSVPRemoteEndDiedExpired );
        }
    }

// ---------------------------------------------------------------------------
// Handle incoming request, i.e. hold
// ---------------------------------------------------------------------------
//
void CSVPEmergencySession::IncomingRequestL( 
    CMceInSession* aUpdatedSession, TMceTransactionDataContainer aContainer )
    {
    SVPDEBUG1("CSVPEmergencySession::IncomingRequest() In")

    if ( !aUpdatedSession )
        {
        User::Leave( KErrArgument );
        }

    // Create hold controller
    if ( NULL == iHoldController )
        {
        iHoldController = CSVPHoldController::NewL( 
            *iEmergencySession,
            aContainer,
            this,
            ETrue );
        }

    iEmergencySession = aUpdatedSession;

    User::LeaveIfError( iHoldController->IncomingRequest( aUpdatedSession ) );
    }

// ---------------------------------------------------------------------------
// Returns ETrue, if hold controller exists
// ---------------------------------------------------------------------------
//
TBool CSVPEmergencySession::HasHoldController() const
    {
    if ( iHoldController )
        {
        return ETrue;
        }
    else
        {
        return EFalse;
        }
    }

// ---------------------------------------------------------------------------
// Returns reference to hold controller
// ---------------------------------------------------------------------------
//    
CSVPHoldController& CSVPEmergencySession::HoldController() const
    {
    return *iHoldController;
    }

// ---------------------------------------------------------------------------
// Handles hold session state changes
// ---------------------------------------------------------------------------
//
void CSVPEmergencySession::HoldSessionStateChangedL( CMceSession& aSession )
    {
    SVPDEBUG1("CSVPEmergencySession::HoldSessionStateChangedL() In")
    
    if ( NULL == iHoldController )
        {
        User::Leave( KErrNotFound );
        }

    if ( iHoldController->HoldInProgress() )
        {
        SVPDEBUG1(
            "CSVPEmergencySession::HoldSessionStateChangedL, in progress")
        StopTimers();
        if ( iHoldController->ContinueHoldProcessing( aSession ) )
            {
            iEmergencyObserver->ErrorOccurred( ECCPLocalHoldFail, NULL );
            }
        }

    SVPDEBUG1("CSVPEmergencySession::HoldSessionStateChangedL() Out")
    }

// ---------------------------------------------------------------------------
// Returns DTMF observer
// ---------------------------------------------------------------------------
//
const MCCPDTMFObserver& CSVPEmergencySession::DtmfObserver()
    {
    return *iDtmfObserver;
    }

// ---------------------------------------------------------------------------
// Sets DTMF observer
// ---------------------------------------------------------------------------
//
void CSVPEmergencySession::SetDtmfObserver( 
    const MCCPDTMFObserver& aObserver )
    {
    SVPDEBUG1("CSVPEmergencySession::SetDtmfObserver()")
    
    iDtmfObserver = const_cast<MCCPDTMFObserver*>( &aObserver );
    }

// ---------------------------------------------------------------------------
// Starts DTMF tone
// ---------------------------------------------------------------------------
//
TInt CSVPEmergencySession::StartDtmfTone( const TChar aTone )
    {
    SVPDEBUG1("CSVPEmergencySession::StartDtmfTone() In")
    
    TInt dtmfErr( KErrNone );
    if ( iSVPUtility.GetDTMFMode() )
        {
        const RPointerArray<CMceMediaStream>& streams = 
            iEmergencySession->Streams();
        TInt count = streams.Count();
        while ( count )
            {
            count--;
            CMceMediaStream& mediaStream = *streams[ count ];
            if ( SVPAudioUtility::DtmfActionCapableStream( mediaStream ) )
                {
                TRAP( dtmfErr, mediaStream.Source()->StartDtmfToneL( aTone ) )
                }
            else
                {
                dtmfErr = KErrNotSupported;
                }
            
            if ( KErrNone != dtmfErr )
                {
                SVPDEBUG2("CSVPEmergencySession::StartDtmfToneL dtmfErr: %d",
                    dtmfErr)
                return dtmfErr;
                }
            }
        }
    else
        {
        iDtmfTone = aTone;
        DtmfObserver().HandleDTMFEvent( MCCPDTMFObserver::ECCPDtmfManualStart, 
                                        KErrNone, 
                                        aTone );
        }
    SVPDEBUG1("CSVPEmergencySession::StartDtmfTone() Out")
    return dtmfErr;
    }

// ---------------------------------------------------------------------------
// Stops DTMF tone
// ---------------------------------------------------------------------------
//
TInt CSVPEmergencySession::StopDtmfTone()
    {
    SVPDEBUG1("CSVPEmergencySession::StopDtmfTone() In")
    
    TInt dtmfErr( KErrNone );
    if ( iSVPUtility.GetDTMFMode() )
        {
        const RPointerArray<CMceMediaStream>& streams = 
            iEmergencySession->Streams();
        TInt count = streams.Count();
        while( count )
            {
            count--;
            CMceMediaStream& mediaStream = *streams[ count ];
            if ( SVPAudioUtility::DtmfActionCapableStream( mediaStream ) )
                {
                TRAP( dtmfErr, mediaStream.Source()->StopDtmfToneL() )
                }
            // NOP with inband.
            
            if ( KErrNone != dtmfErr )
                {
                SVPDEBUG2("CSVPEmergencySession::StopDtmfTone dtmfErr: %d",
                    dtmfErr)
                
                return dtmfErr;
                }
            }
        }
    else
        {
        DtmfObserver().HandleDTMFEvent( MCCPDTMFObserver::ECCPDtmfManualStop, 
                                        KErrNone, 
                                        iDtmfTone );
        }
    SVPDEBUG1("CSVPEmergencySession::StopDtmfTone() Out")
    return dtmfErr;
    }

// ---------------------------------------------------------------------------
// Sends DTMF tone string
// ---------------------------------------------------------------------------
//
TInt CSVPEmergencySession::SendDtmfToneString( const TDesC& aString )
    {
    SVPDEBUG1("CSVPEmergencySession::SendDtmfToneString() In")
    
    TInt error( KErrNone );

    TChar dtmfPause('p');
    // MCE calls if outband DTMF.
    // Exception is character 'p' which is handled always locally
    if ( !iSVPUtility.GetDTMFMode() ||
        ( aString.Length() == 1 &&
          dtmfPause == aString[0] ) )   
        {
        delete iDtmfString;
        iDtmfString = NULL;
        TRAP( error, iDtmfString = HBufC::NewL( aString.Length() ) );
        if ( KErrNone != error )
            {
            return error;
            }
                       
        *iDtmfString = aString;
        iDtmfLex.Assign( *iDtmfString );
        
        SVPDEBUG1("CSVPEmergencySession::SendDtmfToneString, inband")
        if ( !iDTMFEventGenerator )
            {
            TRAP( error,
            iDTMFEventGenerator = CSVPDTMFEventGenerator::NewL( *this ) );
            }
        
        if ( KErrNone != error )
            {
            return error;    
            }
        
        // Dtmf pause interval is 2.5s
        TBool pauseChar = ( aString.Length() == 1 && 
                            dtmfPause == aString[0] ); 
        // start events
        iDTMFEventGenerator->StartDtmfEvents( aString.Length(), pauseChar );
        }
    else
        {
        SVPDEBUG1("CSVPEmergencySession::SendDtmfToneString, outband")
        
        const RPointerArray<CMceMediaStream>& streams = 
            iEmergencySession->Streams();
        TInt count = streams.Count();
        while( count && KErrNone == error )
            {
            count--;
            CMceMediaStream& mediaStream = *streams[ count ];
            if ( SVPAudioUtility::DtmfActionCapableStream( mediaStream ) )
                {
                TRAP( error, mediaStream.Source()->SendDtmfToneSequenceL( 
                    aString ) )
                }
            else
                {
                error = KErrNotSupported;
                }
            }
        }

    SVPDEBUG2("CSVPEmergencySession::SendDtmfToneString, error: %d", error)
    return error;
    }

// ---------------------------------------------------------------------------
// Cancels DTMF tone string sending
// ---------------------------------------------------------------------------
//
TInt CSVPEmergencySession::CancelDtmfStringSending()
    {
    SVPDEBUG1("CSVPEmergencySession::CancelDtmfStringSending() In")
    
    TInt error( KErrNone );
    if ( !iSVPUtility.GetDTMFMode() ) 
        {
        error = KErrNotFound;
        if ( iDTMFEventGenerator )
            {
            iDTMFEventGenerator->StopEvents();
            error = KErrNone;
            }
        }
    else 
        {
        SVPDEBUG1("CSVPEmergencySession::CancelDtmfStringSending, outband")
        error = KErrNotSupported;
        }

    SVPDEBUG2("CSVPEmergencySession::CancelDtmfStringSending, error: %d", 
        error)
    return error;
    }

// ---------------------------------------------------------------------------
// CSVPEmergencySession::Dial
// ---------------------------------------------------------------------------
//
TInt CSVPEmergencySession::Dial( const TDesC& /*aRecipient*/ )
    {
    SVPDEBUG1("CSVPEmergencySession::Dial()")

    if ( iIsDummy )
        {
        SVPDEBUG1("CSVPEmergencySession::Dial, dummy session")
        ErrorOccurred( ECCPErrorGeneral );
        return KErrNone;
        }

    iIsDialed = ETrue;
    ProceedDial();

    iEmergencyObserver->CallStateChanged( 
        MCCPCallObserver::ECCPStateDialling, NULL );

    return KErrNone;
    }

// ---------------------------------------------------------------------------
// CSVPEmergencySession::Cancel
// ---------------------------------------------------------------------------
//
TInt CSVPEmergencySession::Cancel()
    {
    SVPDEBUG1("CSVPEmergencySession::Cancel()")
    
    TInt error( KErrNone );    
    if ( iEmergencySession )
        {
        TRAP( error, ( ( CMceOutSession* )iEmergencySession )->CancelL() )
        if ( error )
            {
            SVPDEBUG2("CSVPEmergencySession::Cancel, error: %d", error)
            iEmergencyObserver->CallStateChanged( 
                MCCPCallObserver::ECCPStateIdle, NULL );
            }
        }
    else
        {
        iEmergencyObserver->CallStateChanged( 
            MCCPCallObserver::ECCPStateIdle, NULL );
        }
    
    return error;
    }

// ---------------------------------------------------------------------------
// CSVPEmergencySession::HangUp
// ---------------------------------------------------------------------------
//
TInt CSVPEmergencySession::HangUp()
    {
    SVPDEBUG1("CSVPEmergencySession::HangUp()")

    if ( NULL == iEmergencySession )
        {
        iEmergencyObserver->CallStateChanged( 
            MCCPCallObserver::ECCPStateIdle, NULL );
        return KErrNone;
        }
    
    CMceSession::TState mceState = iEmergencySession->State();
    SVPDEBUG2("CSVPEmergencySession::HangUp, MCE state: %d", mceState)
    
    TInt err( KErrNone );

    if ( CMceSession::EEstablished == mceState || 
         CMceSession::EOffering == mceState )
        {
        if ( CMceSession::EEstablished == mceState )
            {
            TRAP( err, iEmergencySession->TerminateL() )
            }
        else // CMceSession::EOffering
            {
            err = Cancel();
            }
        
        if ( !err )
            {
            iEmergencyObserver->CallStateChanged( 
                MCCPCallObserver::ECCPStateDisconnecting, NULL );
            TRAP_IGNORE( StartTimerL( 
                KSVPMoHangupTerminatingTime, KSVPHangUpTimerExpired ) )
            }   
        }    
    else // Wrong MCE state
        {
        SVPDEBUG2("CSVPEmergencySession::HangUp, wrong state: %d ", mceState )
        StopTimers();
        iEmergencyObserver->CallStateChanged( 
            MCCPCallObserver::ECCPStateIdle, NULL );
        }
    
    return err;
    }

// ---------------------------------------------------------------------------
// CSVPEmergencySession::Answer
// ---------------------------------------------------------------------------
//
TInt CSVPEmergencySession::Answer()
    {
    SVPDEBUG1("CSVPEmergencySession::Answer()")
    return KErrNotSupported;
    }

// ---------------------------------------------------------------------------
// CSVPEmergencySession::TimedOut
// ---------------------------------------------------------------------------
// 
void CSVPEmergencySession::TimedOut( TInt aTimerId )
    {
    SVPDEBUG1("CSVPEmergencySession::TimedOut()")
    
     // Find the timer and delete it.
    for ( TInt t = 0; t < iTimers.Count(); )
        {
        if ( iTimers[t] ->Id() == aTimerId )
            {
            delete iTimers[t];
            iTimers.Remove( t );
            }
        else
            {
            t++;
            }
        }

    switch ( aTimerId )
        {
        case KSVPHangUpTimerExpired:
            SVPDEBUG1("CSVPEmergencySession::TimedOut, hangup")
            iEmergencyObserver->CallStateChanged( 
                MCCPCallObserver::ECCPStateIdle, NULL );
            break;

        case KSVPTerminationTimerExpired:
            SVPDEBUG1("CSVPEmergencySession::TimedOut, termination")
            iSessionState = MCCPCallObserver::ECCPStateIdle;
            iEmergencyObserver->CallStateChanged( State(), NULL );
            break;

        case KSVPInviteTimerExpired:
            SVPDEBUG1("CSVPEmergencySession::TimedOut, invite")
            // Connection made but no answer, no point trying other profiles
            ErrorOccurred( ECCPEmergencyFailed );
            Cancel();
            iEmergencyObserver->CallStateChanged( 
                MCCPCallObserver::ECCPStateDisconnecting, NULL );
            iEmergencyObserver->CallStateChanged( 
                MCCPCallObserver::ECCPStateIdle, NULL );
            break;
        
        case KSVPEmergencyExpired:
            SVPDEBUG1("CSVPEmergencySession::TimedOut, emergency")
            ErrorOccurred( ECCPErrorTimedOut );
            break;
        
        case KSVPRemoteEndDiedExpired:
            SVPDEBUG1("CSVPEmergencySession::TimedOut, remote end died")
            iEmergencyObserver->CallStateChanged( 
                MCCPCallObserver::ECCPStateIdle, NULL );
            break;
        
        default:
            SVPDEBUG1("CSVPEmergencySession::TimedOut, no timer found")
            break;
        }    
    }

// ---------------------------------------------------------------------------
// From class MSIPObserver
// CSVPEmergencySession::IncomingRequest
// ---------------------------------------------------------------------------
// 
void CSVPEmergencySession::IncomingRequest( 
    TUint32 /*aIapId*/, CSIPServerTransaction* /*aTransaction*/ )
    {
    }

// ---------------------------------------------------------------------------
// From class MSIPObserver
// CSVPEmergencySession::TimedOut
// ---------------------------------------------------------------------------
//     
void CSVPEmergencySession::TimedOut( 
    CSIPServerTransaction& /*aSIPServerTransaction*/ )
    {
    }

// ---------------------------------------------------------------------------
// From class MSIPProfileRegistryObserver
// CSVPEmergencySession::ProfileRegistryErrorOccurred
// ---------------------------------------------------------------------------
//  
void CSVPEmergencySession::ProfileRegistryErrorOccurred( 
    TUint32 /*aSIPProfileId*/, TInt /*aError*/ )
    {
    }

// ---------------------------------------------------------------------------
// From class MSIPProfileRegistryObserver
// CSVPEmergencySession::ProfileRegistryEventOccurred
// ---------------------------------------------------------------------------
//  
void CSVPEmergencySession::ProfileRegistryEventOccurred( 
    TUint32 /*aProfileId*/, TEvent /*aEvent*/ )
    {
    }

// ---------------------------------------------------------------------------
// From class MSVPPositioningProviderObserver.
// Handles successful positioning requests
// ---------------------------------------------------------------------------
//
void CSVPEmergencySession::PositioningRequestComplete( 
    const TDesC8& aPosition )
    {
    SVPDEBUG2("CSVPEmergencySession::PositioningRequestComplete() - \
     length: %d", aPosition.Length())
    
    iIsLIRequestReady = ETrue;
    
    delete iPositionInformation;
    iPositionInformation = NULL;
    TRAPD( err, iPositionInformation = HBufC8::NewL( aPosition.Length() ) )
    if ( !err )
        {
        ( iPositionInformation->Des() ).Copy( aPosition );
        }

    iPositioningProvider->CloseModule();
    ProceedDial();
    }

// ---------------------------------------------------------------------------
// From class MSVPPositioningProviderObserver.
// Handles failed positioning requests
// ---------------------------------------------------------------------------
//
#ifdef _DEBUG
void CSVPEmergencySession::PositioningErrorOccurred( TInt aError )
#else
void CSVPEmergencySession::PositioningErrorOccurred( TInt /*aError*/ )
#endif // _DEBUG
    {
    SVPDEBUG2("CSVPEmergencySession::PositioningErrorOccurred( %d )", aError)
    
    iIsLIRequestReady = ETrue;
    iPositioningProvider->CloseModule();
    ProceedDial();
    }

// ---------------------------------------------------------------------------
// From class MSVPEmergencyConnectionObserver.
// SNAP connection is established
// ---------------------------------------------------------------------------
//
void CSVPEmergencySession::SnapConnected()
    {
    SVPDEBUG1("CSVPEmergencySession::SnapConnected() In")
    
    if ( NULL == iEmergencyConnection )
        {
        SVPDEBUG1("CSVPEmergencySession::SnapConnected, no connection object")
        ErrorOccurred( ECCPErrorGeneral );
        return;
        }
    
    TInt err = iEmergencyConnection->IapId( iIapId );
    SVPDEBUG2("CSVPEmergencySession::ConnectionReady, IAP ID: %d", iIapId)
    if ( err )
        {
        SVPDEBUG2("CSVPEmergencySession::SnapConnected, error: %d", err)
        ErrorOccurred( ECCPErrorGeneral );
        return;
        }

    TRAP( err, CreateUnregistedSessionL() )
    if ( err )
        {
        SVPDEBUG2("CSVPEmergencySession::SnapConnected, error: %d", err)
        ErrorOccurred( ECCPErrorGeneral );
        return;
        }

    // Request for position information
    RequestPosition( iIapId );    
    
    ProceedDial();
        
    SVPDEBUG1("CSVPEmergencySession::SnapConnected() Out")
    }

// ---------------------------------------------------------------------------
// From class MSVPEmergencyConnectionObserver.
// Connection is established
// ---------------------------------------------------------------------------
//    
void CSVPEmergencySession::Connected()
    {
    SVPDEBUG1("CSVPEmergencySession::Connected()")
    
    TRAPD( error, RequestSipProxyAddressL() )
    if ( error )
        {
        SVPDEBUG2("CSVPEmergencySession::Connected, error: %d", error)
        ErrorOccurred( ECCPErrorGeneral );
        }
    }

// ---------------------------------------------------------------------------
// From class MSVPEmergencyConnectionObserver.
// SIP proxy address ready
// ---------------------------------------------------------------------------
//    
void CSVPEmergencySession::SipProxyAddressReady( const TDesC16& aAddress )
    {
    SVPDEBUG1("CSVPEmergencySession::SipProxyAddressReady()")
    
    TRAPD( error, ContinueConstructWithIapIdL( aAddress ) )
    if ( error )
        {
        SVPDEBUG2("CSVPEmergencySession::SipProxyAddressReady, error: %d", 
            error)
        ErrorOccurred( ECCPErrorGeneral );
        }
    }

// ---------------------------------------------------------------------------
// From class MSVPEmergencyConnectionObserver.
// Connection error has occurred
// ---------------------------------------------------------------------------
//
#ifdef _DEBUG
void CSVPEmergencySession::ConnectionError( TInt aError )
#else
void CSVPEmergencySession::ConnectionError( TInt /*aError*/ )
#endif // _DEBUG
    {
    SVPDEBUG2("CSVPEmergencySession::ConnectionError, error: %d", aError)
    
    ErrorOccurred( ECCPErrorGeneral );
    }

// ---------------------------------------------------------------------------
// From class MSVPHoldObserver.
// Local hold
// ---------------------------------------------------------------------------
//
void CSVPEmergencySession::SessionLocallyHeld()
    {
    SVPDEBUG1("CSVPEmergencySession::SessionLocallyHeld()")
    iEmergencyObserver->CallStateChanged( MCCPCallObserver::ECCPStateHold, 
                                          NULL );
    }

// ---------------------------------------------------------------------------
// From class MSVPHoldObserver.
// Local resume
// ---------------------------------------------------------------------------
//
void CSVPEmergencySession::SessionLocallyResumed()
    {
    SVPDEBUG1("CSVPEmergencySession::SessionLocallyResumed()")
    iEmergencyObserver->CallStateChanged( 
        MCCPCallObserver::ECCPStateConnected, NULL );
    }

// ---------------------------------------------------------------------------
// From class MSVPHoldObserver.
// Remote hold
// ---------------------------------------------------------------------------
//
void CSVPEmergencySession::SessionRemoteHeld()
    {
    SVPDEBUG1("CSVPEmergencySession::SessionRemoteHeld()")
    iEmergencyObserver->CallEventOccurred( MCCPCallObserver::ECCPRemoteHold, 
                                           NULL );
    }

// ---------------------------------------------------------------------------
// From class MSVPHoldObserver.
// Remote resume
// ---------------------------------------------------------------------------
//
void CSVPEmergencySession::SessionRemoteResumed()
    {
    SVPDEBUG1("CSVPEmergencySession::SessionRemoteResumed()")
    iEmergencyObserver->CallEventOccurred( 
        MCCPCallObserver::ECCPRemoteResume, NULL );
    }

// ---------------------------------------------------------------------------
// From class MSVPHoldObserver.
// Hold request failed
// ---------------------------------------------------------------------------
//
void CSVPEmergencySession::HoldRequestFailed()
    {
    SVPDEBUG1("CSVPEmergencySession::HoldRequestFailed()")
    iEmergencyObserver->ErrorOccurred( ECCPLocalHoldFail, NULL );
    }

// ---------------------------------------------------------------------------
// From class MSVPHoldObserver.
// Resume request failed
// ---------------------------------------------------------------------------
//
void CSVPEmergencySession::ResumeRequestFailed()
    {
    SVPDEBUG1("CSVPEmergencySession::ResumeRequestFailed()")
    iEmergencyObserver->ErrorOccurred( ECCPLocalResumeFail, NULL );
    }

// ---------------------------------------------------------------------------
// Inband DTMF event occurred
// ---------------------------------------------------------------------------
//   
void CSVPEmergencySession::InbandDtmfEventOccurred( TSVPDtmfEvent aEvent )
    {
    SVPDEBUG2("CSVPEmergencySession::InbandDtmfEventOccurred(), event:%d", 
        aEvent)
    
    switch ( aEvent )
        {
        case ESvpDtmfSendStarted:
            iDtmfObserver->HandleDTMFEvent( 
                MCCPDTMFObserver::ECCPDtmfSequenceStart, 
                KErrNone, 
                iDtmfLex.Peek() );
            break;
            
        case ESvpDtmfSendStopped:
            iDtmfObserver->HandleDTMFEvent( 
                MCCPDTMFObserver::ECCPDtmfSequenceStop, 
                KErrNone, 
                iDtmfLex.Get() );
            break;
            
        case ESvpDtmfSendCompleted:
            {
            iDtmfObserver->HandleDTMFEvent( 
                MCCPDTMFObserver::ECCPDtmfStringSendingCompleted, 
                KErrNone, 
                iDtmfLex.Peek() );
            
            // String can be deleted as whole string has been sent 
            delete iDtmfString;
            iDtmfString = NULL;
            
            break;
            }
            
        default:
            break;
        }
    
    SVPDEBUG1("CSVPEmergencySession::InbandDtmfEventOccurred() Out");
    }

// ---------------------------------------------------------------------------
// Deletes failed MCE session and creates a new one without LI. Used when 
// 415 Unsupported Media Type received.
// ---------------------------------------------------------------------------
//
void CSVPEmergencySession::CreateNonLISessionL()
    {
    SVPDEBUG1("CSVPEmergencySession::CreateNonLISessionL() IN")

    // Save failed emergency session
    iFailedEmergencySession = iEmergencySession;
    iEmergencySession = NULL;

    // Delete LI
    delete iPositionInformation;
    iPositionInformation = NULL;
    iIsLIRequestReady = ETrue;
    
    if ( KErrNotFound == iVoipProfileId )
        {
        // No VoIP profile, trying IAP emergency call
        SVPDEBUG1("CSVPEmergencySession::CreateNonLISessionL, IAP EC")
        CreateUnregistedSessionL();
        return;
        }
    
    // Initialize SIP registry
    CSIP* sip = CSIP::NewLC( KSVPUid, *this ); // CS:1
    CSIPProfileRegistry* sipProfileRegistry = CSIPProfileRegistry::NewLC( 
        *sip, *this ); // CS:2

    // Get SIP profile, only one SIP profile per VoIP profile
    CSIPProfile* sipProfile = sipProfileRegistry->ProfileL( iSipProfileId );
    CleanupStack::PushL( sipProfile ); // CS:3

    // Create MCE out session
    TBool registered( EFalse );
    sipProfile->GetParameter( KSIPProfileRegistered, registered );
    if ( registered )
        {
        SVPDEBUG1("CSVPEmergencySession::CreateNonLISessionL, registered")
        iEmergencySession = CMceOutSession::NewL( 
            iMceManager, *sipProfile, *iRecipientUri );
        ConstructAudioStreamsL();
        }
    else
        {
        CreateUnregistedSessionL();        
        }
    
    CleanupStack::PopAndDestroy( 3, sip ); 
    // CS:0 sip, sipProfileRegistry, sipProfile

    SVPDEBUG1("CSVPEmergencySession::CreateNonLISessionL() OUT")
    }

// ---------------------------------------------------------------------------
// Creates unregistered MCE session
// ---------------------------------------------------------------------------
//
void CSVPEmergencySession::CreateUnregistedSessionL()
    {
    SVPDEBUG1("CSVPEmergencySession::CreateUnregistedSessionL()")
    
    iEmergencySession = CMceOutSession::NewL( 
        iMceManager, iIapId, *iUserAor, *iRecipientUri );

    ConstructAudioStreamsL();
    }

// ---------------------------------------------------------------------------
// Handles emergency session state change
// ---------------------------------------------------------------------------
//
void CSVPEmergencySession::SessionStateChangedL( TInt aMceStatusCode )
    {
    SVPDEBUG3("CSVPEmergencySession::SessionStateChangedL,\
     status: %d,state: %d ", aMceStatusCode, iEmergencySession->State() )
         
    // Match TCCPSessionError
    TInt ccpStatusCode = aMceStatusCode;     
    TCCPError ccpError = iSVPUtility.GetCCPError( ccpStatusCode, iTone );
    
    // Call voip event logger with original status
    if ( ECCPErrorNone != ccpError && KErrNotFound != iVoipProfileId )
        {
        iSVPUtility.LogVoipEventL( 
            aMceStatusCode, iSipProfileId, KNullDesC, KNullDesC );
        }        
   
    // Status code returns KErrNone if TCCPSessionError is not found
    if ( KErrNone != ccpStatusCode )
        {
        SVPDEBUG2("CSVPEmergencySession::SessionStateChanged:\
         error: %d", aMceStatusCode )

        if ( ECCPErrorRejected == ccpError || 
             ECCPErrorBusy == ccpError || 
             ECCPErrorTimedOut == ccpError )
            {     
            SVPDEBUG1("CSVPEmergencySession::SessionStateChanged\
             iSessionState -> Disconnecting")
            iSessionState = MCCPCallObserver::ECCPStateDisconnecting;
            }
        else if ( KSVPUnsupportedMediaTypeVal == aMceStatusCode && 
                  CMceSession::ETerminated == iEmergencySession->State() && 
                  iPositionInformation )
            {
            // MT cannot handle LI: create a new session without LI
            CreateNonLISessionL();
            ProceedDial();
            return;
            }

        ErrorOccurred( ccpError );
        }
    
    // Handle provisional responses 1XX
    if ( KSVPRingingVal == aMceStatusCode || 
         KSVPForwardedVal == aMceStatusCode || 
         KSVPQueuedVal == aMceStatusCode || 
         KSVPSessionProgressVal == aMceStatusCode )
        {        
        // Response received, stop emergency timer
        StopTimer( KSVPEmergencyExpired );

        if ( KSVPRingingVal == aMceStatusCode )
            {
            SVPDEBUG1(
            "CSVPEmergencySession::SessionStateChanged, 180 Ringing received")
            iEmergencyObserver->CallStateChanged( 
                MCCPCallObserver::ECCPStateConnecting, NULL );
            }
        }

    switch( iEmergencySession->State() )
        {
        case CMceSession::EEstablished:
            {
            StopTimers();
            
            // Save state because it may change while checking priorities
            MCCPCallObserver::TCCPCallState ccpState = State();
            
            if ( SVPAudioUtility::MmfPriorityUpdateNeededL( 
                     iEmergencySession->Streams() ) )
                {
                CheckMmfPrioritiesForDtmfL( iEmergencySession->Streams() );
                }
            
            UpdateKeepAliveL();
            
            SVPAudioUtility::EnableSpeakerSinksL( 
                iEmergencySession->Streams() );
            
            iEmergencyObserver->CallStateChanged( ccpState, NULL );
            break;
            }
        case CMceSession::EAnswering:
        case CMceSession::EReserving:
        case CMceSession::EIncoming:
        case CMceSession::EOffering:
            {
            SVPDEBUG1("CSVPEmergencySession:SessionStateChanged, no action")
            break;
            }
        case CMceSession::ECancelling:
        case CMceSession::EIdle:
        case CMceSession::ETerminating:
        case CMceSession::EProceeding:
            {
            SVPDEBUG1("CSVPEmergencySession:SessionStateChanged:\
             Callback state change")
            iEmergencyObserver->CallStateChanged( State(), NULL );
            break;
            }
        case CMceSession::ETerminated:
            {
            SVPDEBUG1("CSVPEmergencySession::SessionStateChanged, terminated")
            iSessionState = MCCPCallObserver::ECCPStateDisconnecting;
            StartTimerL( KSVPTerminatingTime, KSVPTerminationTimerExpired );
            iEmergencyObserver->CallStateChanged( State(), NULL );
            break;
            }
        default:
            {
            SVPDEBUG1("CSVPEmergencySession:SessionStateChanged: default")
            break;
            }
        }
        
    SVPDEBUG1("CSVPEmergencySession::SessionStateChanged Out")
    }

// ---------------------------------------------------------------------------
// Determines if dialing can be proceeded
// ---------------------------------------------------------------------------
//
void CSVPEmergencySession::ProceedDial()
    {
    SVPDEBUG1("CSVPEmergencySession::ProceedDial()")
    
    if ( iIsDialed && 
         iIsLIRequestReady && 
         iEmergencySession &&
         iEmergencySession->ConnectionActive() )
        {
        TRAPD( err, DialL() );
        if ( err )
            {
            SVPDEBUG2("CSVPEmergencySession::ProceedDial(), error: %d", err)
            ErrorOccurred( ECCPErrorGeneral );
            }
        }
    }

// ---------------------------------------------------------------------------
// CSVPEmergencySession::DialL
// ---------------------------------------------------------------------------
//
void CSVPEmergencySession::DialL()
    {
    SVPDEBUG1("CSVPEmergencySession::DialL()")
    
    // Add priority header
    CDesC8ArrayFlat* headers = new ( ELeave ) CDesC8ArrayFlat( 1 );
    CleanupStack::PushL( headers ); // CS:1
    headers->AppendL( KSVPEmergencyPriorityEmergency() );
    
    // Add location related headers
    if ( iPositionInformation && iUserAor )
        {
        // Create content headers
        CDesC8ArrayFlat* contentHeaders = new ( ELeave ) CDesC8ArrayFlat( 1 );
        CleanupStack::PushL( contentHeaders ); // CS:2

        // Content-ID: alice at atlanta.example.com
        HBufC8* contentIdValue = ParseContentIdL( *iUserAor );
        CleanupStack::PushL( contentIdValue ); // CS:3

        HBufC8* contentId = HBufC8::NewLC( 
            KSVPEmergencyContentIdName().Length() + 
            contentIdValue->Length() ); // CS:4
        ( contentId->Des() ).Copy( KSVPEmergencyContentIdName() );
        ( contentId->Des() ).Append( *contentIdValue );

        contentHeaders->AppendL( *contentId );
        CleanupStack::PopAndDestroy( contentId ); // CS:3

        // Geolocation: <cid:alice at atlanta.example.com>;
        // inserted-by=alice at atlanta.example.com;recipient=endpoint
        HBufC8* cidValue = ParseCidL( *contentIdValue );
        CleanupStack::PushL( cidValue ); // CS:4
        
        HBufC8* geolocation = HBufC8::NewL( 
            KSVPEmergencyGeolocation().Length() + 
            cidValue->Length() + 
            KSVPEmergencyTagInsertedBy().Length() + 
            contentIdValue->Length() + 
            KSVPEmergencyTagRecipientEndpoint().Length() );
        ( geolocation->Des() ).Copy( KSVPEmergencyGeolocation() );
        ( geolocation->Des() ).Append( *cidValue );
        ( geolocation->Des() ).Append( KSVPEmergencyTagInsertedBy() );
        ( geolocation->Des() ).Append( *contentIdValue );
        ( geolocation->Des() ).Append( KSVPEmergencyTagRecipientEndpoint() );
        
        // cidValue, contentIdValue CS:2
        CleanupStack::PopAndDestroy( 2, contentIdValue );
        CleanupStack::PushL( geolocation ); // CS:3
        headers->AppendL( *geolocation );
        CleanupStack::PopAndDestroy( geolocation ); // CS:2

        // Accept: application/pidf+xml
        headers->AppendL( KSVPEmergencyAcceptApplicationSdp() );

        // Content-Type: application/pidf+xml
        HBufC8* contentType = HBufC8::NewLC( 
            KSVPEmergencyApplicationPidfXml().Length() ); // CS:3
        ( contentType->Des() ).Copy( KSVPEmergencyApplicationPidfXml() );

        // Establish call
        ( ( CMceOutSession* )iEmergencySession )->EstablishL( 
            iSessionExpires, 
            headers, 
            contentType, 
            iPositionInformation->AllocL(), 
            contentHeaders );

        // contentType, contentHeaders, Ownership transferred CS:1
        CleanupStack::Pop( 2, contentHeaders );
        }
    else
        {
        ( ( CMceOutSession* )iEmergencySession )->EstablishL( 
            iSessionExpires, headers );
        }
    CleanupStack::Pop( headers ); // Ownership transferred, CS:0
    
    // Start INVITE timer in case remote end does not respond
    StartTimerL( KSVPInviteTimer, KSVPInviteTimerExpired );
    }

// ---------------------------------------------------------------------------
// CSVPEmergencySession::ConstructAudioStreamsL
// ---------------------------------------------------------------------------
//  
void CSVPEmergencySession::ConstructAudioStreamsL()
    {
    SVPDEBUG1( "CSVPEmergencySession::ConstructAudioStreamsL In" )

    // OUT STREAM
    CMceAudioStream* audioOutStream = CMceAudioStream::NewLC(); // CS:1
    // Set microphone as audio out source, only one source at a time    
    CMceMicSource* mic = CMceMicSource::NewLC(); // CS:2
    audioOutStream->SetSourceL( mic );
    CleanupStack::Pop( mic ); // CS:1
    CMceRtpSink* rtpSink = CMceRtpSink::NewLC(); // CS:2
	audioOutStream->AddSinkL( rtpSink );
	CleanupStack::Pop( rtpSink ); // CS:1
  
    // IN STREAM
    CMceAudioStream* audioInStream = CMceAudioStream::NewLC(); // CS:2
	CMceRtpSource* rtpSource = CMceRtpSource::NewLC( 
	    KSvpJitterBufferLength, 
	    KSvpJitterBufferThreshold, 
	    KSvpStandbyTimerInMillisecs ); // CS:3
	audioInStream->SetSourceL( rtpSource );
	CleanupStack::Pop( rtpSource ); // CS:2
	// Set speaker as audio in sink	
	CMceSpeakerSink* speakerSink = CMceSpeakerSink::NewLC(); // CS:3
	audioInStream->AddSinkL( speakerSink );
	CleanupStack::Pop( speakerSink ); // CS:2

	// Bind "audio out" stream to "audio in" stream
	audioOutStream->BindL( audioInStream );
	CleanupStack::Pop( audioInStream ); // CS: 1
	
    iEmergencySession->AddStreamL( audioOutStream );
    CleanupStack::Pop( audioOutStream ); // CS: 0
    
    // Modify QoS preconditions off
    iEmergencySession->SetModifierL( 
        KMcePreconditions, KMcePreconditionsNotUsed );
        
    // Modify Old way hold on
    iEmergencySession->SetModifierL( 
        KMceMediaDirection, KMceMediaDirectionWithAddress );

    SVPDEBUG2("CSVPEmergencySession::ConstructAudioStreamsL, in codecs: %d", 
        audioInStream->Codecs().Count())
    SVPDEBUG2("CSVPEmergencySession::ConstructAudioStreamsL, out codecs: %d", 
        audioOutStream->Codecs().Count())

    // Set keep-alive value
    SetKeepAlive();
    
    // Add codecs to audiostream
    iSVPUtility.SetAudioCodecsForEmergencyL( 
        *audioInStream, iKeepAlive, iVoipProfileId );
    
    audioOutStream->SetLocalMediaPortL( audioInStream->LocalMediaPort() );
    
    iSVPUtility.UpdateJitterBufferSizeL( *rtpSource );
    
    // Set MMF priorities and preferences to codecs
    iSVPUtility.SetDtmfMode( SVPAudioUtility::SetPriorityCodecValuesL( 
        *audioInStream, *audioOutStream ) );
                                         
    SVPDEBUG1( "CSVPEmergencySession::ConstructAudioStreamsL Out" )
    }

// ---------------------------------------------------------------------------
// Sets keep-alive value
// ---------------------------------------------------------------------------
//  
void CSVPEmergencySession::SetKeepAlive()
    {
    SVPDEBUG1("CSVPEmergencySession::SetKeepAlive()")
    
    // Get keep-alive value, do not leave: return default value instead
    TBool found( EFalse );
    TRAPD( errKeepAlive, 
        found = iSVPUtility.GetKeepAliveByIapIdL( iIapId, iKeepAlive ) )
    if ( errKeepAlive || !found )
        {
        TRAP( errKeepAlive, found = iSVPUtility.GetKeepAliveByAORL( 
            *iUserAor, iKeepAlive ) )
        if ( errKeepAlive || !found )
            {
            iKeepAlive = KSVPDefaultUDPRefreshInterval;
            }
        }
    
    SVPDEBUG2("CSVPEmergencySession::KeepAlive, value: %d", iKeepAlive)
    }

// ---------------------------------------------------------------------------
// Updates keepalive parameters for MCE session
// ---------------------------------------------------------------------------
//
void CSVPEmergencySession::UpdateKeepAliveL()
    {
    SVPDEBUG1("CSVPEmergencySession::UpdateKeepAliveL()")
    
    const RPointerArray<CMceMediaStream>& streamArray = 
        iEmergencySession->Streams();
    TInt streamCount( streamArray.Count() );
    TBool cnInAnswer( EFalse );
    
    for ( TInt i = 0; i < streamCount; i++ )
        {
        CMceAudioStream* stream = 
            static_cast<CMceAudioStream*>( streamArray[i] );
        if ( iSVPUtility.IsComfortNoise( *stream ) )
            {
            cnInAnswer = ETrue;
            iSVPUtility.SetCNKeepAliveL( *stream, iKeepAlive );
            }
        }
    
    if ( !cnInAnswer )
        {
        while( streamCount-- )
            {
            CMceAudioStream* stream = 
                static_cast<CMceAudioStream*>( streamArray[streamCount] );
            iSVPUtility.SetKeepAliveL( *stream, iKeepAlive );
            }
        }
    
    iEmergencySession->UpdateL();
    }

// ---------------------------------------------------------------------------
// Check audio priorities in audio streams
// ---------------------------------------------------------------------------
//
void CSVPEmergencySession::CheckMmfPrioritiesForDtmfL(
    const RPointerArray<CMceMediaStream>& aAudioStreams ) const
    {
    SVPDEBUG1( "CSVPEmergencySession::CheckMmfPrioritiesForDtmfL In" )
    
    RPointerArray<CMceMediaSource> micsToEnable;
    CleanupClosePushL( micsToEnable );
    const TInt streamCount( aAudioStreams.Count() );
    
    // First disable the mic before doing any priority updating.
    for ( TInt s = 0; s < streamCount; s++ )
        {
        CMceMediaSource* mic = aAudioStreams[s]->Source();
        
        if ( mic && KMceMicSource == mic->Type() && mic->IsEnabled() )
            {
            mic->DisableL();
            micsToEnable.AppendL( mic );
            }
        mic = NULL;
        
        if ( aAudioStreams[s]->BoundStream() )
            {
            mic = aAudioStreams[s]->BoundStreamL().Source();
            if ( mic && KMceMicSource == mic->Type() && mic->IsEnabled() )
                {
                mic->DisableL();
                micsToEnable.AppendL( mic );
                }
            }
        mic = NULL;
        }
    
    // Set the correct priority and preference values.
    for ( TInt k = 0; k < streamCount; k++ )
        {
        if ( KMceAudio == aAudioStreams[k]->Type() && 
            aAudioStreams[k]->BoundStream() )
            {
            CMceAudioStream* stream = 
                static_cast<CMceAudioStream*>( aAudioStreams[k] );
            
            TBool dtmfMode = EFalse;
            if ( SVPAudioUtility::IsDownlinkStream( *stream ) )
                {
                dtmfMode = SVPAudioUtility::SetPriorityCodecValuesL( 
                    *stream,
                    static_cast<CMceAudioStream&>( stream->BoundStreamL() ) );
                }
            else
                {
                dtmfMode = SVPAudioUtility::SetPriorityCodecValuesL(
                    static_cast<CMceAudioStream&>( stream->BoundStreamL() ),
                    *stream );
                }
            
            iSVPUtility.SetDtmfMode( dtmfMode );
            }
        }
        
    // Priorities are now correct, so update the session.
    iEmergencySession->UpdateL();
    
    // Now enable mics after we have correct priorities.
    const TInt mics = micsToEnable.Count();
    for ( TInt t = 0; t < mics; t++ )
        {
        micsToEnable[t]->EnableL();
        }
    
    // Mics not owned
    CleanupStack::PopAndDestroy( &micsToEnable );
    
    SVPDEBUG1( "CSVPEmergencySession::CheckMmfPrioritiesForDtmfL Out" )
    }

// ---------------------------------------------------------------------------
// CSVPEmergencySession::StartTimerL
// ---------------------------------------------------------------------------
//
void CSVPEmergencySession::StartTimerL( TInt aMilliSeconds, TInt aTimerId )
    {
    CSVPTimer* timer = CSVPTimer::NewL( *this, aTimerId );
    timer->SetTime( aMilliSeconds );
    iTimers.Append( timer );
    }

// ---------------------------------------------------------------------------
// Stop timer
// ---------------------------------------------------------------------------
//
void CSVPEmergencySession::StopTimer( TInt aTimerId )
    {
    SVPDEBUG2("CSVPEmergencySession::StopTimer, ID: %d", aTimerId)

    for ( TInt i = 0; i < iTimers.Count(); )
        {
        if ( aTimerId == iTimers[i]->Id() )
            {
            iTimers[i]->Stop();
            delete iTimers[i];
            iTimers.Remove( i );
            }
        else
            {
            i++;
            }
        }
    }

// ---------------------------------------------------------------------------
// CSVPEmergencySession::StopTimers
// ---------------------------------------------------------------------------
//
void CSVPEmergencySession::StopTimers()
    {
    SVPDEBUG1("CSVPEmergencySession::StopTimers")
    
    while ( iTimers.Count() )
        {
        iTimers[0]->Stop();
        delete iTimers[0];
        iTimers.Remove( 0 );   
        }
    }

// ---------------------------------------------------------------------------
// Notify client about an error
// ---------------------------------------------------------------------------
//
void CSVPEmergencySession::ErrorOccurred( TCCPError aError )
    {
    SVPDEBUG2("CSVPEmergencySession::ErrorOccurred: %d", (TInt)aError)
    
    if ( iIsLastProfile )
        {
        iEmergencyObserver->ErrorOccurred( ECCPEmergencyFailed, NULL );
        }
    else
        {
        iEmergencyObserver->ErrorOccurred( aError, NULL );
        }
    }

// ---------------------------------------------------------------------------
// Traps leaves of RequestPositionL
// ---------------------------------------------------------------------------
//
void CSVPEmergencySession::RequestPosition( TUint32 aIapId )
    {
    SVPDEBUG1( "CSVPEmergencySession::RequestPosition" )
    iIsLIRequestReady = EFalse;
    TRAP_IGNORE( RequestPositionL( aIapId ) );
    }

// ---------------------------------------------------------------------------
// Initializes position provider and requests for position information
// ---------------------------------------------------------------------------
//
void CSVPEmergencySession::RequestPositionL( TUint32 aIapId )
    {
    iPositioningProvider = CSVPPositioningProvider::NewL( 
        KSVPEmergencyPositioningPriority, *this );
    if ( iPositioningProvider )
        {
        iPositioningProvider->OpenModuleL( 
            KSVPEmergencyDhcpDefaultPsyModuleId );
        iPositioningProvider->MakePositioningRequestL( 
            aIapId, 
            KSVPEmergencyApplicationName, 
            KSVPEmergencyPositioningTimeout );
        }
    }

// ---------------------------------------------------------------------------
// Parses content ID from URI: removes "sip(s):" prefix, if one exists
// ---------------------------------------------------------------------------
//
HBufC8* CSVPEmergencySession::ParseContentIdL( const TDesC8& aUri )
    {
    HBufC8* contentId = HBufC8::NewLC( aUri.Length() ); // CS:1
    ( contentId->Des() ).Copy( aUri );
    if ( 0 == contentId->Find( KSVPSipPrefix ) )
        {
        contentId->Des().Delete( 0, KSVPSipPrefixLength );
        }
    else if ( 0 == contentId->Find( KSVPSipsPrefix ) )
        {
        contentId->Des().Delete( 0, KSVPSipsPrefixLength );
        }
    CleanupStack::Pop( contentId ); // CS:0
    contentId = contentId->ReAllocL( contentId->Length() );
    return contentId;
    }

// ---------------------------------------------------------------------------
// Parses cid: adds "cid:" prefix and brackets
// ---------------------------------------------------------------------------
//
HBufC8* CSVPEmergencySession::ParseCidL( const TDesC8& aContentId )
    {
    HBufC8* cid = HBufC8::NewL( 
        KSVPLeftBracketMark().Length() + 
        KSVPCidPrefix().Length() + 
        aContentId.Length() + 
        KSVPRightBracketMark().Length() );

    TPtr8 cidPtr = cid->Des();
    cidPtr.Copy( KSVPLeftBracketMark() );
    cidPtr.Append( KSVPCidPrefix() );
    cidPtr.Append( aContentId );
    cidPtr.Append( KSVPRightBracketMark() );
    
    return cid;
    }