--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/multimediacommscontroller/mmccsubcontroller/src/mccrtpkeepalive.cpp Tue Feb 02 01:04:58 2010 +0200
@@ -0,0 +1,584 @@
+/*
+* Copyright (c) 2007-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: RTP Keepalive mechanism
+*
+*/
+
+
+
+
+// INCLUDE FILES
+#include <e32math.h>
+#include "mccrtpkeepalive.h"
+#include "mccdef.h"
+#include "mccinternaldef.h"
+#include "mccsubcontrollerlogs.h"
+#include "mccinternalevents.h"
+#include "mccrtpinterface.h"
+#include "mccrtpmediaclock.h"
+
+
+// EXTERNAL DATA STRUCTURES
+
+// EXTERNAL FUNCTION PROTOTYPES
+
+// CONSTANTS
+
+// MACROS
+
+// LOCAL CONSTANTS AND MACROS
+
+// MODULE DATA STRUCTURES
+
+// LOCAL FUNCTION PROTOTYPES
+
+// FORWARD DECLARATIONS
+
+
+// ============================= LOCAL FUNCTIONS =============================
+
+
+// ============================ MEMBER FUNCTIONS =============================
+
+
+// ---------------------------------------------------------------------------
+// CMccRtpKeepalive::NewL
+// Two-phased constructor.
+// ---------------------------------------------------------------------------
+//
+CMccRtpKeepalive* CMccRtpKeepalive::NewL(
+ MAsyncEventHandler& aEventHandler,
+ CRtpAPI& aRtpAPI,
+ TRtpId aRtpSessionId,
+ TUint8 aKeepalivePayloadType,
+ TUint8 aKeepaliveInterval,
+ const TDesC8& aKeepaliveData,
+ TBool aRemoteAddressSet )
+ {
+ CMccRtpKeepalive* self =
+ new( ELeave ) CMccRtpKeepalive( aEventHandler, aRtpAPI,
+ aRtpSessionId, aRemoteAddressSet );
+ CleanupStack::PushL( self );
+ self->ConstructL( aKeepalivePayloadType, aKeepaliveInterval,
+ aKeepaliveData );
+ CleanupStack::Pop( self );
+ return self;
+ }
+
+// ---------------------------------------------------------------------------
+// CMccRtpKeepalive::~CMccRtpKeepalive
+// Destructor
+// ---------------------------------------------------------------------------
+//
+CMccRtpKeepalive::~CMccRtpKeepalive()
+ {
+ __SUBCONTROLLER( "CMccRtpKeepalive::~CMccRtpKeepalive()" )
+
+ Cancel();
+
+ if ( KNullId != iRtpStreamId && !iRtpSinkExists )
+ {
+ iRtpAPI.CloseStream( iRtpStreamId );
+ }
+
+ iTimer.Close();
+
+ delete iKeepaliveData;
+
+ iUsers.Reset();
+ }
+
+// ---------------------------------------------------------------------------
+// CMccRtpKeepalive::StartKeepaliveL
+// ---------------------------------------------------------------------------
+//
+void CMccRtpKeepalive::StartKeepaliveL( MMccRtpInterface& aUser,
+ CMccRtpMediaClock& aRtpMediaClock )
+ {
+ __SUBCONTROLLER( "CMccRtpKeepalive::StartKeepaliveL()" )
+
+ iRtpMediaClock = &aRtpMediaClock;
+
+ if ( KErrNotFound == iUsers.Find( &aUser ) )
+ {
+ iUsers.AppendL( &aUser );
+ }
+
+ User::LeaveIfError( ToggleKeepaliveSending( ResolveActivity() ) );
+
+ __SUBCONTROLLER( "CMccRtpKeepalive::StartKeepaliveL(), exit" )
+ }
+
+// ---------------------------------------------------------------------------
+// CMccRtpKeepalive::StopKeepalive
+// ---------------------------------------------------------------------------
+//
+TInt CMccRtpKeepalive::StopKeepalive( MMccRtpInterface& aUser,
+ TInt& aRefCount )
+ {
+ __SUBCONTROLLER( "CMccRtpKeepalive::StopKeepalive()" )
+
+ TInt err( KErrNotFound );
+ TInt index = iUsers.Find( &aUser );
+ if ( KErrNotFound != index)
+ {
+ iUsers.Remove( index );
+
+ err = ToggleKeepaliveSending( ResolveActivity() );
+ if ( err )
+ {
+ SendErrorToClient( err );
+ }
+ }
+
+ __SUBCONTROLLER_INT1( "CMccRtpKeepalive::StopKeepalive(), exit with err:", err )
+
+ aRefCount = iUsers.Count();
+
+ return err;
+ }
+
+// ---------------------------------------------------------------------------
+// CMccRtpKeepalive::ResetKeepaliveTimer
+// ---------------------------------------------------------------------------
+//
+void CMccRtpKeepalive::ResetKeepaliveTimer( )
+ {
+ __SUBCONTROLLER_INT1( "CMccRtpKeepalive::ResetKeepaliveTimer() active:",
+ IsActive() )
+
+ Cancel();
+ StartSending();
+ }
+
+// ---------------------------------------------------------------------------
+// CMccRtpKeepalive::StreamId
+// ---------------------------------------------------------------------------
+//
+TRtpId CMccRtpKeepalive::StreamId() const
+ {
+ return iRtpStreamId;
+ }
+
+// -----------------------------------------------------------------------------
+// CMccRtpKeepalive::PayloadType
+// -----------------------------------------------------------------------------
+//
+TUint8 CMccRtpKeepalive::PayloadType() const
+ {
+ return iRtpHeaderInfo.iPayloadType;
+ }
+
+// ---------------------------------------------------------------------------
+// CMccRtpKeepalive::RemoteAddressSet
+// ---------------------------------------------------------------------------
+//
+TInt CMccRtpKeepalive::RemoteAddressSet()
+ {
+ __SUBCONTROLLER( "CMccRtpKeepalive::RemoteAddressSet()" )
+
+ TInt err( KErrNone );
+ iRemoteAddressSet = ETrue;
+ if ( iCurrentState == ESendingPending )
+ {
+ err = StartSending();
+ }
+
+ __SUBCONTROLLER_INT1( "CMccRtpKeepalive::RemoteAddressSet(), exit with err:",
+ err )
+ return err;
+ }
+
+// ---------------------------------------------------------------------------
+// CMccRtpKeepalive::IsForSink
+// ---------------------------------------------------------------------------
+//
+TBool CMccRtpKeepalive::IsForSink()
+ {
+ TBool sinkFound = EFalse;
+ TInt count = iUsers.Count();
+ for ( TInt i = 0; i < count && !sinkFound; i++ )
+ {
+ sinkFound = iUsers[i]->IsSink();
+ }
+ return sinkFound;
+ }
+
+// ---------------------------------------------------------------------------
+// CMccRtpKeepalive::UpdateParamsL
+// ---------------------------------------------------------------------------
+//
+void CMccRtpKeepalive::UpdateParamsL( TUint8 aKeepalivePT,
+ TUint8 aKeepaliveInterval, const TDesC8& aKeepaliveData )
+ {
+ __SUBCONTROLLER_INT1(
+ "CMccRtpKeepalive::UpdateParamsL(), PT:", aKeepalivePT )
+ __SUBCONTROLLER_INT1(
+ "CMccRtpKeepalive::UpdateParamsL(), INT:", aKeepaliveInterval )
+
+ __ASSERT_ALWAYS( aKeepalivePT < KMccPayloadTypeMax,
+ User::Leave( KErrArgument ) );
+
+ iRtpHeaderInfo.iPayloadType = aKeepalivePT;
+
+ HBufC8* tmp = aKeepaliveData.AllocL();
+ delete iKeepaliveData;
+ iKeepaliveData = tmp;
+
+ const TUint KMccSecsToMicroSecs = 1000000;
+ iKeepaliveInterval = aKeepaliveInterval * KMccSecsToMicroSecs;
+ }
+
+// ---------------------------------------------------------------------------
+// CMccRtpKeepalive::RunL
+// ---------------------------------------------------------------------------
+//
+void CMccRtpKeepalive::RunL()
+ {
+ TInt status = iStatus.Int();
+
+ __SUBCONTROLLER_INT1( "CMccRtpKeepalive::RunL(), status:", status )
+
+ User::LeaveIfError( status );
+
+ switch ( iCurrentState )
+ {
+ case EWaitingTimer:
+ {
+ // Timer completed, send again
+ User::LeaveIfError( Send() );
+ break;
+ }
+ case ESending:
+ {
+ // Send completed, start timer again
+ iSequenceNum++;
+ User::LeaveIfError( StartSending() );
+ break;
+ }
+ default:
+ {
+ User::Leave( KErrArgument );
+ break;
+ }
+ }
+ }
+
+// ---------------------------------------------------------------------------
+// CMccRtpKeepalive::DoCancel
+// ---------------------------------------------------------------------------
+//
+void CMccRtpKeepalive::DoCancel()
+ {
+ if ( EWaitingTimer == iCurrentState )
+ {
+ __SUBCONTROLLER( "Keepalive: Cancel Timer !!!" )
+ iTimer.Cancel();
+ }
+ else if ( ESending == iCurrentState )
+ {
+ __SUBCONTROLLER( "Keepalive: Cancel Sending !!!" )
+ iRtpAPI.CancelSend( iRtpSessionId );
+ }
+
+ iCurrentState = EIdle;
+ }
+
+// ---------------------------------------------------------------------------
+// CMccRtpKeepalive::RunError
+// ---------------------------------------------------------------------------
+//
+TInt CMccRtpKeepalive::RunError( TInt aError )
+ {
+ __SUBCONTROLLER_INT1( "CMccRtpKeepalive::RunError(), err:", aError )
+ __SUBCONTROLLER_INT1( "CMccRtpKeepalive::RunError(), at state:", iCurrentState )
+
+ SendErrorToClient( aError );
+
+ if ( aError != KErrNoMemory )
+ {
+ return KErrNone;
+ }
+ return aError;
+ }
+
+// ---------------------------------------------------------------------------
+// CMccRtpKeepalive::ResolveActivity
+// ---------------------------------------------------------------------------
+//
+TBool CMccRtpKeepalive::ResolveActivity()
+ {
+ __SUBCONTROLLER( "CMccRtpKeepalive::ResolveActivity()" )
+
+ // Keepalive is always active if there's only rtpsource.
+ iRtpSinkExists = EFalse;
+ TBool rtpSourceExists( EFalse );
+ for ( TInt i = 0; i < iUsers.Count(); i++ )
+ {
+ if ( iUsers[ i ]->IsSink() )
+ {
+ iRtpSinkExists = ETrue;
+ iRtpSinkIndex = i;
+ }
+ else
+ {
+ rtpSourceExists = ETrue;
+ }
+ }
+
+ TBool keepAliveActive = ( iRtpSinkExists ) ||
+ ( !iRtpSinkExists && rtpSourceExists );
+
+ __SUBCONTROLLER_INT1( "CMccRtpKeepalive::ResolveActivity(), active:",
+ keepAliveActive )
+
+ return keepAliveActive;
+ }
+
+// ---------------------------------------------------------------------------
+// CMccRtpKeepalive::ToggleKeepaliveSending
+// ---------------------------------------------------------------------------
+//
+TInt CMccRtpKeepalive::ToggleKeepaliveSending( TBool aIsActive )
+ {
+ __SUBCONTROLLER_INT1( "CMccRtpKeepalive::ToggleKeepaliveSending(), active",
+ aIsActive )
+
+ TInt err( KErrNone );
+ if ( aIsActive )
+ {
+ if ( iRtpStreamId == KNullId )
+ {
+ __SUBCONTROLLER( "CMccRtpKeepalive::ToggleKeepaliveSending(), create rtp transmit stream" )
+
+ TTranStreamParams transParams;
+ transParams.iPayloadType = iRtpHeaderInfo.iPayloadType;
+
+ if ( !iRtpSinkExists )
+ {
+ TRAP( err, iRtpStreamId =
+ iRtpAPI.CreateTransmitStreamL( iRtpSessionId,
+ transParams,
+ iSSRC ) );
+ }
+ else
+ {
+ // get rtp sink id
+ iRtpStreamId = iUsers[iRtpSinkIndex]->RtpStreamId();
+ }
+
+ if ( iRtpStreamId == KNullId )
+ {
+ err = KErrCouldNotConnect;
+ }
+ }
+
+ if ( !err && iCurrentState == EIdle )
+ {
+ err = StartSending();
+ }
+ }
+ else
+ {
+ Cancel();
+ }
+
+ __SUBCONTROLLER_INT1( "CMccRtpKeepalive::ToggleKeepaliveSending(), exit with err:",
+ err )
+
+ return err;
+ }
+
+// ---------------------------------------------------------------------------
+// CMccRtpKeepalive::StartSending
+// ---------------------------------------------------------------------------
+//
+TInt CMccRtpKeepalive::StartSending()
+ {
+ __SUBCONTROLLER( "CMccRtpKeepalive::StartSending()" )
+
+ TInt err( KErrNone );
+
+ if ( !IsActive() && ( 0 < iKeepaliveInterval ) )
+ {
+ if ( iRemoteAddressSet )
+ {
+ __SUBCONTROLLER( "CMccRtpKeepalive::StartSending(), issue send timer" )
+
+ if ( iPreAudioPacketSent || !iRtpSinkExists )
+ {
+ iTimer.After( iStatus, iKeepaliveInterval );
+ SetActive();
+ iCurrentState = EWaitingTimer;
+ }
+ else
+ {
+ // Send firewall punching packet before possibly later
+ // starting audio.
+ Send();
+ iPreAudioPacketSent = ETrue;
+ }
+ }
+ else
+ {
+ iCurrentState = ESendingPending;
+ }
+ }
+
+ return err;
+ }
+
+// ---------------------------------------------------------------------------
+// CMccRtpKeepalive::Send
+// ---------------------------------------------------------------------------
+//
+TInt CMccRtpKeepalive::Send()
+ {
+ TInt err( KErrInUse );
+ if ( !IsActive() )
+ {
+ // not called if rtpsink exists
+ if ( !iRtpSinkExists )
+ {
+ __SUBCONTROLLER( "CMccRtpKeepalive::StartSending() - No RtpSink Exists" )
+ iCurrentTime.UniversalTime();
+ TTimeIntervalMicroSeconds interval =
+ iCurrentTime.MicroSecondsFrom( iInitialTime );
+ iRtpHeaderInfo.iTimestamp = interval.Int64();
+
+ err = iRtpAPI.SendRtpPacket( iRtpStreamId,
+ iSequenceNum,
+ iRtpHeaderInfo,
+ *iKeepaliveData,
+ iStatus );
+ }
+ else
+ {
+ __SUBCONTROLLER_INT1( "CMccRtpKeepalive::Send() PT:", iRtpHeaderInfo.iPayloadType )
+ __SUBCONTROLLER_INT1( "CMccRtpKeepalive::Send() Data:", iKeepaliveData->Length() )
+ iRtpMediaClock->GetLatestConsumedTS( iRtpHeaderInfo.iTimestamp );
+ err = iRtpAPI.SendRtpPacket( iRtpStreamId,
+ iRtpHeaderInfo,
+ *iKeepaliveData,
+ iStatus );
+ }
+ if ( !err )
+ {
+ __SUBCONTROLLER( "CMccRtpKeepalive::StartSending - Sending" )
+ SetActive();
+ iCurrentState = ESending;
+ }
+ }
+ return err;
+ }
+
+// ---------------------------------------------------------------------------
+// CMccRtpKeepalive::Random
+// ---------------------------------------------------------------------------
+//
+TUint16 CMccRtpKeepalive::Random() const
+ {
+ const TInt KRandMax = 0x7fff;
+ TTime tmp_time;
+ tmp_time.HomeTime();
+ TInt64 seed = tmp_time.Int64();
+ TInt32 rand = Math::Rand( seed );
+ return static_cast<TUint16>( Abs( rand ) % KRandMax );
+ }
+
+// ---------------------------------------------------------------------------
+// CMccRtpKeepalive::SendErrorToClient
+// ---------------------------------------------------------------------------
+//
+void CMccRtpKeepalive::SendErrorToClient( TInt aError )
+ {
+ __SUBCONTROLLER( "CMccRtpKeepalive::SendErrorToClient()" )
+
+ TMccEvent event;
+ event.iErrorCode = aError;
+ event.iEventCategory = KMccEventCategoryRtp;
+ event.iEventType = KMccStreamError;
+
+ // Use whatever internal uid
+ TMccInternalEvent internalEvent( KMccRtpSourceUid,
+ EMccInternalEventNone,
+ event );
+
+ iEventHandler.SendEventToClient( internalEvent );
+
+ __SUBCONTROLLER( "CMccRtpKeepalive::SendErrorToClient(), exit" )
+ }
+
+// ---------------------------------------------------------------------------
+// CMccRtpKeepalive::CMccRtpKeepalive
+// C++ default constructor can NOT contain any code, that
+// might leave.
+// ---------------------------------------------------------------------------
+//
+CMccRtpKeepalive::CMccRtpKeepalive(
+ MAsyncEventHandler& aEventHandler,
+ CRtpAPI& aRtpAPI,
+ TRtpId aRtpSessionId,
+ TBool aRemoteAddressSet ) :
+ CActive( EPriorityStandard ),
+ iEventHandler( aEventHandler ),
+ iRtpAPI( aRtpAPI ),
+ iRtpSessionId( aRtpSessionId ),
+ iRtpStreamId( KNullId ),
+ iRemoteAddressSet( aRemoteAddressSet )
+ {
+ CActiveScheduler::Add( this );
+ }
+
+// ---------------------------------------------------------------------------
+// CMccRtpKeepalive::ConstructL
+// Symbian 2nd phase constructor can leave.
+// ---------------------------------------------------------------------------
+//
+void CMccRtpKeepalive::ConstructL(
+ TUint8 aKeepalivePayloadType,
+ TUint8 aKeepaliveInterval,
+ const TDesC8& aKeepaliveData )
+ {
+ __SUBCONTROLLER( "CMccRtpKeepalive::ConstructL()" )
+
+ User::LeaveIfError( iTimer.CreateLocal() );
+
+ __ASSERT_ALWAYS( aKeepalivePayloadType < KMccPayloadTypeMax,
+ User::Leave( KErrArgument ) );
+
+ iRtpHeaderInfo.iMarker = 0;
+
+ UpdateParamsL( aKeepalivePayloadType, aKeepaliveInterval,
+ aKeepaliveData );
+
+ iSequenceNum = Random();
+
+ iInitialTime.UniversalTime();
+
+ __SUBCONTROLLER_INT1( "CMccRtpKeepalive::ConstructL(), keepalive pt:",
+ aKeepalivePayloadType )
+ __SUBCONTROLLER_INT1( "CMccRtpKeepalive::ConstructL(), keepalive interval (microsecs):",
+ iKeepaliveInterval )
+ __SUBCONTROLLER_INT1( "CMccRtpKeepalive::ConstructL(), keepalive data len:",
+ iKeepaliveData->Length() )
+ __SUBCONTROLLER( "CMccRtpKeepalive::ConstructL(), exit" )
+ }
+
+
+
+
+// ========================== OTHER EXPORTED FUNCTIONS =======================
+
+// End of File