multimediacommscontroller/mmccsubcontroller/src/mccrtpkeepalive.cpp
changeset 0 1bce908db942
child 18 817c922b90eb
--- /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