multimediacommscontroller/mmccrtpsourcesink/src/mccrtpsender.cpp
changeset 0 1bce908db942
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/multimediacommscontroller/mmccrtpsourcesink/src/mccrtpsender.cpp	Tue Feb 02 01:04:58 2010 +0200
@@ -0,0 +1,608 @@
+/*
+* Copyright (c) 2002-2004 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 Datasink
+*
+*/
+
+
+
+
+// INCLUDE FILES
+#include "mccrtpsender.h"
+#include "mccrtpdefs.h"
+#include "mcctimermanager.h"
+
+// CONSTANTS
+const TInt KMccMaxSendQueueSize = 30;
+const TUint32 KMccRtpSendTimeoutLongMillisecs = 600;
+
+
+// -----------------------------------------------------------------------------
+// CMccRtpSender::NewL
+// -----------------------------------------------------------------------------
+//                     
+CMccRtpSender* CMccRtpSender::NewL( 
+    MMccRtpSenderObserver& aObserver, 
+    CRtpAPI& aRtpApi, 
+    TRtpId aSessionId,
+    TBool aDoMarkerBasedCleanup )
+    {
+    TRACE_RTP_SINK_PRINT( "CMccRtpSender::NewL, entry" )
+    
+    CMccRtpSender* self = 
+        new ( ELeave ) CMccRtpSender( 
+            aObserver, aRtpApi, aSessionId, aDoMarkerBasedCleanup );
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    CleanupStack::Pop( self );
+    
+    TRACE_RTP_SINK_PRINT( "CMccRtpSender::NewL, exit" )
+    
+    return self;
+    }
+
+// -----------------------------------------------------------------------------
+// CMccRtpSender::~CMccRtpSender
+// -----------------------------------------------------------------------------
+//    
+CMccRtpSender::~CMccRtpSender()
+    {
+    TRACE_RTP_SINK_PRINT( "CMccRtpSender::~CMccRtpSender, entry" )
+    
+    Cancel();
+    delete iTimeoutTimer;
+    
+    iSendQueue.ResetAndDestroy();
+    
+    TRACE_RTP_SINK_PRINT( "CMccRtpSender::~CMccRtpSender, exit" )
+    }
+
+// -----------------------------------------------------------------------------
+// CMccRtpSender::SendRtpPacketL
+// -----------------------------------------------------------------------------
+//    
+void CMccRtpSender::SendRtpPacketL( 
+    TRtpId aRtpStreamId, 
+    const TRtpSendHeader& aRtpHeader, 
+    const TDesC8& aData )
+    {
+    TInt count( iSendQueue.Count() );
+    
+    if ( CheckDiscarding( aRtpHeader ) )
+        {
+        TRACE_RTP_SINK_PRINT2( "CMccRtpSender::SendRtpPacketL [%d], packet dropped 1", 
+                               reinterpret_cast<TUint32>( this ) )
+        return;
+        }
+    
+    if ( count >= KMccMaxSendQueueSize )
+        {
+        // Full, frame must be dropped. Check also if there's already in queue
+        // rtp packets which contain parts of the same frame. In that case,
+        // those can be also dropped as the frame is useless if something is
+        // missing from it.
+        DoQueueCleanup( count - 1, aRtpHeader );
+        
+        TRACE_RTP_SINK_PRINT2( "CMccRtpSender::SendRtpPacketL [%d], packet dropped 2",
+                               reinterpret_cast<TUint32>( this ) )
+        return;
+        }
+    
+    TRACE_RTP_SINK_PRINT3( "CMccRtpSender::SendRtpPacketL [%d], items in queue:%d", 
+                           reinterpret_cast<TUint32>( this ), count )
+        
+    CMccRtpSendItem* sendItem = 
+        CMccRtpSendItem::NewLC( aRtpStreamId, aRtpHeader, aData );
+    iSendQueue.AppendL( sendItem );
+    CleanupStack::Pop( sendItem );
+ 
+    if ( !IsActive() )
+        {
+        SendPacketL();
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CMccRtpSender::SendDataL
+// -----------------------------------------------------------------------------
+//
+void CMccRtpSender::SendDataL( TRtpId aSessionId, TBool aUseRtpSocket, 
+    const TDesC8& aData )
+    {
+    if ( KMccMaxSendQueueSize <= iSendQueue.Count() )
+        {
+        TRACE_RTP_SINK_PRINT2( 
+            "CMccRtpSender::SendDataL [%d], queue full, leaving",
+            reinterpret_cast<TUint32>( this ) )
+        User::Leave( KErrOverflow );
+        }
+    else
+        {
+        TRACE_RTP_SINK_PRINT3( 
+            "CMccRtpSender::SendDataL [%d], items in queue: %d",  
+            reinterpret_cast<TUint32>( this ), iSendQueue.Count() )
+        
+        CMccRtpSendItem* sendItem = 
+            CMccRtpSendItem::NewLC( aSessionId, aUseRtpSocket, aData );
+        iSendQueue.AppendL( sendItem );
+        CleanupStack::Pop( sendItem );
+        
+        if ( !IsActive() )
+            {
+            SendPacketL();
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CMccRtpSender::Clear
+// -----------------------------------------------------------------------------
+//
+void CMccRtpSender::Clear()
+    {
+    TRACE_RTP_SINK_PRINT( "CMccRtpSender::Clear, entry" )
+    
+    Cancel();
+    iSendQueue.ResetAndDestroy();
+    
+    iDiscarding = EFalse;
+    
+    TRACE_RTP_SINK_PRINT( "CMccRtpSender::Clear, exit" )
+    }
+
+// -----------------------------------------------------------------------------
+// CMccRtpSender::RunL
+// -----------------------------------------------------------------------------
+//
+void CMccRtpSender::RunL()
+    {
+    TInt status = iStatus.Int();
+    
+    TRACE_RTP_SINK_PRINT3( "CMccRtpSender::RunL [%d], status:%d", 
+                           reinterpret_cast<TUint32>( this ), status )
+    
+    RemovePacket();
+    
+    if ( !ErrorReport( status ) )
+        {
+        SendPacketL();
+        } 
+    
+    TRACE_RTP_SINK_PRINT( "CMccRtpSender::RunL, exit" )
+    }
+
+// -----------------------------------------------------------------------------
+// CMccRtpSender::DoCancel
+// -----------------------------------------------------------------------------
+//    
+void CMccRtpSender::DoCancel()
+    {
+    TRACE_RTP_SINK_PRINT( "CMccRtpSender::DoCancel, entry" )
+    
+    iRtpApi.CancelSend( iSessionId );
+    iTimeoutTimer->Stop( iTimerId );
+    
+    TRACE_RTP_SINK_PRINT( "CMccRtpSender::DoCancel, exit" )
+    }
+
+// -----------------------------------------------------------------------------
+// CMccRtpSender::RunError
+// -----------------------------------------------------------------------------
+//
+TInt CMccRtpSender::RunError( TInt aError )
+    {
+    TRACE_RTP_SINK_PRINT2( "CMccRtpSender::RunError, err:%d", aError )
+    
+    ErrorReport( aError );
+        
+    if ( aError != KErrNoMemory )
+        {
+        aError = KErrNone;
+        }
+        
+    return aError;
+    }
+
+// -----------------------------------------------------------------------------
+// CMccRtpSender::InactivityTimeout
+// -----------------------------------------------------------------------------
+//    
+void CMccRtpSender::TimerExpiredL( 
+    TMccTimerId /*aTimerId*/, TAny* /*aTimerParam*/ )
+    {
+    TRACE_RTP_SINK_PRINT( "CMccRtpSender::TimerExpiredL, entry" )
+    
+    if ( iTimeoutTimeMilliseconds > KMccRtpSendTimeoutLongMillisecs )
+        {
+        // Timeout value is so long that if sending of one rtp packet really
+        // took so long, receiver will have big problems and it's better
+        // to drop all frames queued in order to avoid delay increase 
+        // at receiver side.
+        Clear();
+        }
+    else
+        {
+        // Sending timeout, cancel send and discard that packet
+        Cancel();
+        
+        // Do also cleanup of related packets as those are useless as this 
+        // packet is removed because of timeout
+        RemovePacket( ETrue ); 
+        
+        // Send next packet anyway
+        TRAPD( err, SendPacketL() )
+        if ( err )
+            {
+            ErrorReport( err );
+            }
+        }
+    
+    TRACE_RTP_SINK_PRINT( "CMccRtpSender::TimerExpiredL, exit" )
+    }
+
+// -----------------------------------------------------------------------------
+// CMccRtpSender::ConstructL
+// -----------------------------------------------------------------------------
+//
+void CMccRtpSender::ConstructL()
+    {
+    iTimeoutTimer = CMccTimerManager::NewL();
+    }
+
+// -----------------------------------------------------------------------------
+// CMccRtpSender::CMccRtpSender
+// -----------------------------------------------------------------------------
+//    
+CMccRtpSender::CMccRtpSender( 
+    MMccRtpSenderObserver& aObserver, 
+    CRtpAPI& aRtpApi, 
+    TRtpId aSessionId,
+    TBool aDoMarkerBasedCleanup ) :
+    CActive( EPriorityStandard ),
+    iObserver( aObserver ),
+    iRtpApi( aRtpApi ),
+    iSessionId( aSessionId ),
+    iDoMarkerBasedCleanup( aDoMarkerBasedCleanup ),
+    iTimeoutTimeMilliseconds( KMccRtpSendTimeoutLongMillisecs )
+    {
+    CActiveScheduler::Add( this );
+    
+    TRACE_RTP_SINK_PRINT2( "CMccRtpSender::CMccRtpSender, marker based cleanup:%d", 
+                           iDoMarkerBasedCleanup )
+    }
+
+// -----------------------------------------------------------------------------
+// CMccRtpSender::SendPacketL
+// -----------------------------------------------------------------------------
+//
+void CMccRtpSender::SendPacketL()
+    {
+    if ( iSendQueue.Count() > 0 )
+        {
+        CMccRtpSendItem* item = iSendQueue[ 0 ];
+        if ( KNullId == item->SessionId( ) )
+            {
+            User::LeaveIfError( 
+                iRtpApi.SendRtpPacket( 
+                    item->RtpStreamId(), 
+                    item->RtpHeader(), 
+                    item->DataPtr(), 
+                    iStatus ) );            
+            }
+        else
+            {
+            iRtpApi.SendDataL( item->SessionId(), item->UseRtpSocket(), 
+                item->DataPtr(), iStatus );
+            }
+        
+        SetActive();
+        
+        iTimeoutTimer->Stop( iTimerId );
+        iTimerId = iTimeoutTimer->StartL( this, iTimeoutTimeMilliseconds );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CMccRtpSender::RemovePacket
+// -----------------------------------------------------------------------------
+//    
+void CMccRtpSender::RemovePacket( TBool aDoQueueCleanup )
+    {
+    if ( iSendQueue.Count() > 0 )
+        {
+        TBool removed( EFalse );
+        
+        if ( aDoQueueCleanup )
+            {
+            removed = DoQueueCleanup( 0, iSendQueue[ 0 ]->RtpHeader() );
+            }
+        else
+            {
+#ifdef TRACE_RTP_SINK
+            TRACE_RTP_SINK_PRINT2( "CMccRtpSender::RemovePacket, sent packet size: %d",
+                                   iSendQueue[ 0 ]->DataPtr().Length() )
+#endif 
+            }
+        
+        if ( !removed )
+            {
+            delete iSendQueue[ 0 ];
+            iSendQueue.Remove( 0 );
+            }
+            
+        iTimeoutTimer->Stop( iTimerId );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CMccRtpSender::ErrorReport
+// -----------------------------------------------------------------------------
+//
+TBool CMccRtpSender::ErrorReport( TInt aError )
+    {    
+    TBool errorReported( EFalse );
+    
+    if ( aError != KErrNone && aError != KErrCancel && aError != KErrTooBig )
+        {
+        iObserver.SendErrorOccured( aError );
+        errorReported = ETrue;
+        } 
+        
+    return errorReported;
+    }
+
+// -----------------------------------------------------------------------------
+// CMccRtpSender::CheckDiscarding
+// -----------------------------------------------------------------------------
+//
+TBool CMccRtpSender::CheckDiscarding( const TRtpSendHeader& aRtpHeader )
+    {
+    TBool discard( EFalse );
+    if ( iDiscarding )
+        {                
+        if ( aRtpHeader.iMarker )
+            {
+            TRACE_RTP_SINK_PRINT( "CMccRtpSender::CheckDiscarding, stop discarding" )
+            iDiscarding = EFalse;
+            }
+        discard = ETrue;
+        }
+    return discard;
+    }
+    
+// -----------------------------------------------------------------------------
+// CMccRtpSender::DoQueueCleanup
+// -----------------------------------------------------------------------------
+//
+TBool CMccRtpSender::DoQueueCleanup( TInt aItemIndex, 
+        const TRtpSendHeader& aRtpHeader )
+    {
+    TRACE_RTP_SINK_PRINT( "CMccRtpSender::DoQueueCleanup, entry" )
+    
+    TInt queueCount = iSendQueue.Count();
+    TInt itemIndex = aItemIndex;
+    TBool itemRemoved = EFalse;
+    TBool markerEnabled( aRtpHeader.iMarker );
+    
+    if ( !iDoMarkerBasedCleanup || itemIndex >= queueCount )
+        {
+        TRACE_RTP_SINK_PRINT( "CMccRtpSender::DoQueueCleanup (disabled), exit" )
+        return itemRemoved;
+        }
+    
+    // Check if this item is zero marker packet or if there's items with zero
+    // marker before this one in the queue. All of those can be removed as they
+    // belong to the same frame.
+    //
+    TBool removingCompleted( EFalse );
+    for ( TInt i = itemIndex; i >= 0 && !removingCompleted; i-- )
+        {
+        if ( !iSendQueue[ i ]->RtpHeader().iMarker )
+            {
+            TRACE_RTP_SINK_PRINT( "CMccRtpSender::DoQueueCleanup, clean earlier packet" )
+            
+            delete iSendQueue[ i ];
+            iSendQueue.Remove( i );
+            itemIndex--;
+            
+            itemRemoved = ( itemRemoved || ( i == aItemIndex ) );
+            
+            if ( i == 0 )
+                {
+                // Deleted first item which is always the one which is sent currently,
+                // must cancel sending
+                TRACE_RTP_SINK_PRINT( "CMccRtpSender::DoQueueCleanup, deleted active item" )
+                Cancel();
+                }
+            }
+        else
+            {
+            removingCompleted = ETrue;
+            }
+        }
+    
+    if ( !markerEnabled )
+        {
+        // If zero marker frame was removed, all upcoming frames until
+        // next marker frame can be removed (also that marker frame can be removed)
+        //
+        removingCompleted = EFalse;
+        
+        TInt beginIndex( itemIndex + 1 );
+        for ( TInt j = beginIndex; j < iSendQueue.Count() && !removingCompleted; j++ )
+            {
+            TRACE_RTP_SINK_PRINT( "CMccRtpSender::DoQueueCleanup, clean next packet" )
+            
+            TUint8 marker = iSendQueue[ j ]->RtpHeader().iMarker;
+              
+            delete iSendQueue[ j ];
+            iSendQueue.Remove( j );
+                
+            if ( marker )
+                {
+                removingCompleted = ETrue;
+                }
+            
+            // Start again from beginning as packet was removed from queue    
+            j = beginIndex - 1;
+            }
+            
+        if ( !removingCompleted )
+            {
+            // Following packets of the same frame can be discarded when
+            // those are tried to be sent.
+            iDiscarding = ETrue;
+            }
+        else
+            {
+            iDiscarding = EFalse;
+            }
+        }
+
+    
+    TRACE_RTP_SINK_PRINT2( "CMccRtpSender::DoQueueCleanup, exit with discarding:%d",
+                           iDiscarding )
+    return itemRemoved;
+    }
+    
+// ========================== HELPER CLASS  ====================================
+
+// -----------------------------------------------------------------------------
+// CMccRtpSendItem::NewLC
+// -----------------------------------------------------------------------------
+//
+CMccRtpSendItem* CMccRtpSendItem::NewLC( 
+    TRtpId aRtpStreamId, 
+    const TRtpSendHeader& aRtpHeader, 
+    const TDesC8& aData )
+    {
+    CMccRtpSendItem* self = 
+        new ( ELeave ) CMccRtpSendItem( aRtpStreamId, aRtpHeader );
+    CleanupStack::PushL( self );
+    self->ConstructL( aData );
+    return self;
+    }
+
+// -----------------------------------------------------------------------------
+// CMccRtpSendItem::NewLC
+// -----------------------------------------------------------------------------
+//
+CMccRtpSendItem* CMccRtpSendItem::NewLC( TRtpId aSessionId, 
+    TBool aUseRtpSocket, const TDesC8& aData )
+    {
+    CMccRtpSendItem* self = 
+        new ( ELeave ) CMccRtpSendItem( aSessionId, aUseRtpSocket );
+    CleanupStack::PushL( self );
+    self->ConstructL( aData );
+    return self;
+    }
+
+// -----------------------------------------------------------------------------
+// CMccRtpSendItem::~CMccRtpSendItem
+// -----------------------------------------------------------------------------
+//
+CMccRtpSendItem::~CMccRtpSendItem()
+    {
+    delete iData;
+    }
+
+// -----------------------------------------------------------------------------
+// CMccRtpSendItem::DataPtr
+// -----------------------------------------------------------------------------
+//    
+const TDesC8& CMccRtpSendItem::DataPtr() const
+    {
+    return iDataPtr;
+    }
+
+// -----------------------------------------------------------------------------
+// CMccRtpSendItem::RtpStreamId
+// -----------------------------------------------------------------------------
+// 
+TRtpId CMccRtpSendItem::RtpStreamId() const
+    {
+    return iRtpStreamId;
+    }
+
+// -----------------------------------------------------------------------------
+// CMccRtpSendItem::RtpHeader
+// -----------------------------------------------------------------------------
+//   
+const TRtpSendHeader& CMccRtpSendItem::RtpHeader() const
+    {
+    return iRtpHeader;
+    }
+
+// -----------------------------------------------------------------------------
+// CMccRtpSendItem::SessionId
+// -----------------------------------------------------------------------------
+// 
+TRtpId CMccRtpSendItem::SessionId() const
+    {
+    return iSessionId;
+    }
+
+
+// -----------------------------------------------------------------------------
+// CMccRtpSendItem::UseRtpSocket
+// -----------------------------------------------------------------------------
+// 
+TBool CMccRtpSendItem::UseRtpSocket() const
+    {
+    return iUseRtpSocket;
+    }
+
+
+// -----------------------------------------------------------------------------
+// CMccRtpSendItem::ConstructL
+// -----------------------------------------------------------------------------
+//    
+void CMccRtpSendItem::ConstructL( const TDesC8& aData )
+    {
+    iData = aData.AllocL();
+    iDataPtr.Set( *iData );
+    }
+
+// -----------------------------------------------------------------------------
+// CMccRtpSendItem::CMccRtpSendItem
+// -----------------------------------------------------------------------------
+//    
+CMccRtpSendItem::CMccRtpSendItem( 
+    TRtpId aRtpStreamId, 
+    const TRtpSendHeader& aRtpHeader ) :
+    iRtpStreamId( aRtpStreamId ),
+    iRtpHeader( aRtpHeader ),
+    iDataPtr( NULL, 0 ),
+    iSessionId( KNullId )
+    {
+    }
+
+
+// -----------------------------------------------------------------------------
+// CMccRtpSendItem::CMccRtpSendItem
+// -----------------------------------------------------------------------------
+//    
+CMccRtpSendItem::CMccRtpSendItem( 
+    TRtpId aSessionId, 
+    TBool aUseRtpSocket ) 
+    :
+    iRtpStreamId( KNullId ),
+    iDataPtr( NULL, 0 ),
+    iSessionId( aSessionId ),
+    iUseRtpSocket( aUseRtpSocket )
+    {
+    }
+
+//  End of File  
+