--- /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;
+ }