diff -r 000000000000 -r 1bce908db942 multimediacommscontroller/mmccsubcontroller/src/mccrtpkeepalive.cpp --- /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 +#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( 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