diff -r 000000000000 -r 1bce908db942 multimediacommscontroller/mmccrtpsourcesink/src/mccrtpsender.cpp --- /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( 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( this ) ) + return; + } + + TRACE_RTP_SINK_PRINT3( "CMccRtpSender::SendRtpPacketL [%d], items in queue:%d", + reinterpret_cast( 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( this ) ) + User::Leave( KErrOverflow ); + } + else + { + TRACE_RTP_SINK_PRINT3( + "CMccRtpSender::SendDataL [%d], items in queue: %d", + reinterpret_cast( 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( 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 +