sipvoipprovider/src/svpemergencysession.cpp
changeset 0 a4daefaec16c
child 6 fc8c25e5a2e8
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sipvoipprovider/src/svpemergencysession.cpp	Mon Jan 18 20:12:36 2010 +0200
@@ -0,0 +1,1870 @@
+/*
+* 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 ) )
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// 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;
+    }