--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/multimediacommscontroller/mmccrtpsourcesink/src/mccrtpdatasource.cpp Tue Feb 02 01:04:58 2010 +0200
@@ -0,0 +1,1284 @@
+/*
+* 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 Datasource
+*
+*/
+
+
+
+
+// INCLUDE FILES
+#include <in_sock.h>
+#include <mmf/common/mmfcontroller.h>
+
+#include "rtpapi.h"
+#include "mccrtpdatasource.h"
+#include "mccinternalevents.h"
+#include "formatstatemachine.h"
+#include "mccrtpdefs.h"
+#include "mmccinterfacedef.h"
+#include "mcctimermanager.h"
+
+#include <srtpcryptocontext.h>
+#include <srtpstreamin.h>
+
+// MACROS
+#define MCC_RTPSOURCE_ENDPOINT_ID reinterpret_cast<TUint32>( static_cast<MDataSource*>( this ) )
+
+
+// ============================= LOCAL FUNCTIONS ===============================
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CMccRtpDataSource::CMccRtpDataSource
+// C++ default constructor can NOT contain any code, that
+// might leave.
+// -----------------------------------------------------------------------------
+//
+CMccRtpDataSource::CMccRtpDataSource() :
+ CMccDataSource( KMccRtpSourceUid ),
+ MMccRtpInterface(),
+ iStandByTimerValue( KRtpStandByTimer ),
+ iRtpStreamId( KNullId ),
+ iInactivityTimerId( KMaxTUint32 )
+ {
+ iCurRecvPayloadType = KMccPTNotDefined;
+ }
+
+// -----------------------------------------------------------------------------
+// CMccRtpDataSource::ConstructSourceL
+// Symbian 2nd phase constructor can leave.
+// -----------------------------------------------------------------------------
+//
+void CMccRtpDataSource::ConstructSourceL( const TDesC8& aInitData )
+ {
+ TRACE_RTP_SOURCE_PRINT( "CMccRtpDataSource::ConstructSourceL" )
+
+ SetStateL( ERtpStateConstructed );
+
+ TMccRtpSourceSetting rtpSettings;
+ rtpSettings.iStandByTimerValue = 200;
+ TMccRtpSourceSettingBuf rtpSettingsBuf( rtpSettings );
+
+ if ( aInitData.Length() > 0)
+ {
+ TMccRtpSourceSettingBuf settingsBuf;
+ settingsBuf.Copy( aInitData );
+ iStandByTimerValue = settingsBuf().iStandByTimerValue;
+ }
+
+ iTimer = CMccTimerManager::NewL();
+
+ TRACE_RTP_SOURCE_PRINT2( "CMccRtpDataSource::ConstructSourceL iStandByTimerValue %d",
+ iStandByTimerValue )
+ }
+
+// -----------------------------------------------------------------------------
+// CMccRtpDataSource::NewSourceL
+// Static constructor.
+// -----------------------------------------------------------------------------
+//
+MDataSource* CMccRtpDataSource::NewSourceL( TUid /*aImplementationUid*/,
+ const TDesC8& /*aInitData*/ )
+ {
+ TRACE_RTP_SOURCE_PRINT( "CMccRtpDataSource::NewSourceL" )
+
+ CMccRtpDataSource* self = new ( ELeave ) CMccRtpDataSource();
+ return static_cast<MDataSource*>( self );
+ }
+
+
+// -----------------------------------------------------------------------------
+// CMccRtpDataSource::~CMccRtpDataSource()
+// Destructor.
+// -----------------------------------------------------------------------------
+//
+CMccRtpDataSource::~CMccRtpDataSource()
+ {
+ TRACE_RTP_SOURCE_PRINT2( "CMccRtpDataSource::~CMccRtpDataSource 0x%x", this )
+
+ iBufferToFill = NULL;
+ iEventHandler = NULL;
+ iFillBufferRequester = NULL;
+
+ CloseStreams();
+ iUsers.Close();
+
+ delete iTimer;
+ delete iJitCalc;
+
+ TRACE_RTP_SOURCE_PRINT( "CMccRtpDataSource::~CMccRtpDataSource OUT" )
+ }
+
+// -----------------------------------------------------------------------------
+// CMccRtpDataSource::FillBufferL
+// FillBufferL works synchronously.
+// -----------------------------------------------------------------------------
+//
+void CMccRtpDataSource::FillBufferL( CMMFBuffer* aBuffer,
+ MDataSink* aConsumer,
+ TMediaId /*aMediaId*/ )
+ {
+ TRACE_RTP_SOURCE_PRINT ( "CMccRtpDataSource::FillBufferL" )
+
+ // Sink might want to indicate pause/stop by passing NULL buffer
+ if ( aBuffer )
+ {
+ __ASSERT_ALWAYS ( aConsumer, User::Leave( KErrArgument ) );
+ __ASSERT_ALWAYS ( KUidMmfDataBuffer == aBuffer->Type( ),
+ User::Leave( KErrNotSupported ) );
+ }
+
+ iBufferToFill = static_cast<CMMFDataBuffer*>( aBuffer );
+ }
+
+// -----------------------------------------------------------------------------
+// CMccRtpDataSource::CanCreateSourceBuffer
+// NOT SUPPORTED. MDataSource pure virtual function must to be implemented.
+// -----------------------------------------------------------------------------
+//
+TBool CMccRtpDataSource::CanCreateSourceBuffer()
+ {
+ return EFalse;
+ }
+
+// -----------------------------------------------------------------------------
+// CMccRtpDataSource::CreateSourceBufferL
+// NOT SUPPORTED. MDataSource pure virtual function must to be implemented.
+// -----------------------------------------------------------------------------
+//
+CMMFBuffer* CMccRtpDataSource::CreateSourceBufferL( TMediaId /*aMediaId*/,
+ TBool& /*aReference*/ )
+ {
+ TRACE_RTP_SOURCE_PRINT ( "CMccRtpDataSource::CreateSourceBufferL KErrNotSupported" )
+
+ User::Leave( KErrNotSupported );
+ return NULL;
+ }
+
+// -----------------------------------------------------------------------------
+// CMccRtpDataSource::RtpPacketReceived
+// RTP stack callback function for received RTP packet.
+// -----------------------------------------------------------------------------
+//
+void CMccRtpDataSource::RtpPacketReceived( TRtpId aStreamId,
+ const TRtpRecvHeader& aHeaderInfo,
+ const TDesC8& aPayloadData )
+ {
+ TRACE_RTP_SOURCE_PRINT2( "CMccRtpDataSource::RtpPacketReceived iSecureKeyExpired: %d",
+ iSecureKeyExpired )
+ TRACE_RTP_SOURCE_PRINT2( "CMccRtpDataSource::RtpPacketReceived iPayloadType: %u",
+ aHeaderInfo.iPayloadType )
+
+ // Filter out also bogus payload types here. NB; should something be done
+ // for the trapped errorcode and bogus RTP packets. Though they should not
+ // reach this point.
+ if ( !iSecureKeyExpired &&
+ aHeaderInfo.iPayloadType < KPayloadTypeUndefined )
+ {
+ TRAP_IGNORE( RtpPacketReceivedL( aStreamId, aHeaderInfo, aPayloadData ) )
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CMccRtpDataSource::RtpPacketReceivedL
+// RTP stack callback function for received RTP packet.
+// -----------------------------------------------------------------------------
+//
+void CMccRtpDataSource::RtpPacketReceivedL( TRtpId aStreamId,
+ const TRtpRecvHeader& aHeaderInfo,
+ const TDesC8& aPayloadData )
+ {
+ TRACE_RTP_SOURCE_PRINT2( "CMccRtpDataSource::RtpPacketReceivedL DATALEN: %d",
+ aPayloadData.Length() )
+ TRACE_RTP_SOURCE_PRINT2( "CMccRtpDataSource::RtpPacketReceivedL ASTREAM: %d",
+ aStreamId )
+ TRACE_RTP_SOURCE_PRINT2( "CMccRtpDataSource::RtpPacketReceivedL ISTREAM: %d",
+ iRtpStreamId )
+ TRACE_RTP_SOURCE_PRINT2( "CMccRtpDataSource::RtpPacketReceivedL SEQ_NUM: %d",
+ aHeaderInfo.iSeqNum )
+ TRACE_RTP_SOURCE_PRINT2( "CMccRtpDataSource::RtpPacketReceivedL T_STAMP: %d",
+ aHeaderInfo.iTimestamp )
+ TRACE_RTP_SOURCE_PRINT2( "CMccRtpDataSource::RtpPacketReceivedL MARKER: %d",
+ aHeaderInfo.iMarker )
+ TRACE_RTP_SOURCE_PRINT2( "CMccRtpDataSource::RtpPacketReceivedL STATE: %d",
+ State() )
+
+ if ( ERtpStatePlaying == State() )
+ {
+ __ASSERT_ALWAYS( iBufferToFill, User::Leave( KErrNotReady ) );
+ __ASSERT_ALWAYS( iFillBufferRequester, User::Leave( KErrNotReady ) );
+
+ TMccRtpUser* currentUser = ValidatePacketL( aStreamId, aHeaderInfo, aPayloadData );
+ TBool isCN = EFalse;
+
+ // Change the main receive PT only if it is not CN.
+ if ( KCnPayloadType != aHeaderInfo.iPayloadType &&
+ KCnPayloadTypeReserved != aHeaderInfo.iPayloadType )
+ {
+ iCurRecvPayloadType = aHeaderInfo.iPayloadType;
+ }
+ else
+ {
+ isCN = ETrue;
+ }
+
+ if ( InactivityTimerActive() )
+ {
+ TRACE_RTP_SOURCE_PRINT( "CMccRtpDataSource::resetting inactivity timer" )
+
+ StartInactivityTimerL( iTimeoutTime );
+ }
+
+ // Note that ValidataPacketL may return a NULL ptr, thus guard against
+ // it.
+ if ( currentUser )
+ {
+ StartRtpStandByTimerL( currentUser );
+ DoStandByDecision( currentUser );
+ }
+
+ // Do jitter calculations
+ if ( iJitCalc->IsObserving() )
+ {
+ iJitCalc->RtpPacketReceived( aHeaderInfo.iTimestamp,
+ aHeaderInfo.iMarker );
+ }
+
+ // First packet after SourcePlayL, notify event handler by sending
+ // the event.
+ if ( !iDlStreamStarted )
+ {
+ iDlStreamStarted = ETrue;
+ SendInternalRtpEventToClient( iEventHandler,
+ KMccRtpSourceUid,
+ KMccInternalRtpSrcMmfEvent,
+ KMccActivityEvent,
+ MCC_RTPSOURCE_ENDPOINT_ID );
+ }
+
+ // CN is not currently sent forward to decoding and playback. It
+ // causes problems with jitterbuffering and results into a degraded
+ // audio quality.
+ if ( !isCN )
+ {
+ TRAPD( err, PlayoutRtpPacketL( aHeaderInfo, aPayloadData ) )
+
+ // Notify the event handler about error cases so appropriate
+ // actions can be taken.
+ if ( KErrNone != err )
+ {
+ SendInternalRtpEventToClient( iEventHandler,
+ KMccRtpSourceUid,
+ KMccInternalRtpSrcMmfEvent,
+ KMccStreamError,
+ MCC_RTPSOURCE_ENDPOINT_ID,
+ err );
+ }
+ }
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CMccRtpDataSource::SetSourceDataTypeCode
+// Sets the sources datatype code ( Codec )
+// -----------------------------------------------------------------------------
+//
+TInt CMccRtpDataSource::SetSourceDataTypeCode( TFourCC aCodec, TMediaId /*aMedia*/ )
+ {
+ iCodecInfo.iFourCC = aCodec;
+ return KErrNone;
+ }
+
+// -----------------------------------------------------------------------------
+// CMccRtpDataSource::SourceDataTypeCode()
+// Sets the datatype code ( codec )
+// -----------------------------------------------------------------------------
+//
+TFourCC CMccRtpDataSource::SourceDataTypeCode( TMediaId /*aMediaId*/ )
+ {
+ return iCodecInfo.iFourCC;
+ }
+
+// -----------------------------------------------------------------------------
+// CMccRtpDataSource::BufferEmptiedL
+// CMccRtpDataSource supports only passive mode of operation.
+// Thus, Datapath->EmptyBufferL isn't called.
+// -----------------------------------------------------------------------------
+//
+void CMccRtpDataSource::BufferEmptiedL( CMMFBuffer* /*aBuffer*/ )
+ {
+ TRACE_RTP_SOURCE_PRINT( "CMccRtpDataSource::BufferEmptiedL KErrNotSupported" )
+
+ User::Leave( KErrNotSupported );
+ }
+
+// -----------------------------------------------------------------------------
+// CMccRtpDataSource::SourceThreadLogon
+//
+// Method to 'logon' the data source to the same thread that source will be
+// consuming data in. Thread specific initialisation is done here.
+// -----------------------------------------------------------------------------
+//
+TInt CMccRtpDataSource::SourceThreadLogon( MAsyncEventHandler& aEventHandler )
+ {
+ TRACE_RTP_SOURCE_PRINT( "CMccRtpDataSource::SourceThreadLogon" )
+
+ TInt err( KErrNone );
+
+ iEventHandler = &aEventHandler;
+ if ( NULL == iJitCalc )
+ {
+ TRACE_RTP_SOURCE_PRINT( "CMccRtpDataSource::SourceThreadLogon,\
+ create jitter calculator" )
+ TRAP( err, iJitCalc = CMccJitterCalculator::NewL( *this ) );
+ }
+
+ return err;
+ }
+
+// -----------------------------------------------------------------------------
+// CMccRtpDataSource::SourceThreadLogoff
+//
+// Method to 'logoff' the data source from the same thread that source consumes
+// data in. Thread specific releasing of resources is done here.
+// -----------------------------------------------------------------------------
+//
+void CMccRtpDataSource::SourceThreadLogoff()
+ {
+ TRACE_RTP_SOURCE_PRINT( "CMccRtpDataSource::SourceThreadLogoff" )
+ StopKeepalive();
+
+ iEventHandler = NULL;
+
+ // Close the streams (if any)
+ if ( KNullId != iRtpStreamId )
+ {
+ iRtpAPI->UnregisterRtpObserver( iSessionID );
+ }
+
+ CloseStreams();
+ iRtpAPI = NULL;
+ iRtpStreamId = KNullId;
+
+ iBufferToFill = NULL;
+
+ delete iTimer;
+ iTimer = NULL;
+
+ delete iJitCalc;
+ iJitCalc = NULL;
+ }
+
+// ---------------------------------------------------------------------------
+// CMccRtpDataSource::SourcePrimeL
+// Source must be primed before playing.
+// -----------------------------------------------------------------------------
+//
+void CMccRtpDataSource::SourcePrimeL()
+ {
+ TRACE_RTP_SOURCE_PRINT( "CMccRtpDataSource::SourcePrimeL" )
+
+ SetStateL( ERtpStatePrimed );
+
+ SendStreamEventToClient( KMccStreamPrepared );
+ }
+
+// -----------------------------------------------------------------------------
+// CMccRtpDataSource::SourcePlayL
+// Start receiving RTP packets.
+// -----------------------------------------------------------------------------
+//
+void CMccRtpDataSource::SourcePlayL()
+ {
+ TRACE_RTP_SOURCE_PRINT( "CMccRtpDataSource::SourcePlayL" )
+ if ( iSecureKeyExpired )
+ {
+ TRACE_RTP_SINK_PRINT( "Leave becuase the secure key expired" )
+ User::Leave( KErrGeneral );
+ }
+ //Leave when is the secure evnet key expired and try to restart
+ iPacketsReceived = 0;
+ iDlStreamStarted = EFalse;
+
+ TSourceSinkState oldState = State();
+
+ __ASSERT_ALWAYS( iJitCalc, User::Leave( KErrNotFound ) );
+ iJitCalc->ResetCounters();
+
+ ResetStandBy();
+
+ SetStateL( ERtpStatePlaying );
+
+ // Enable keepalive while receiving (depending on codec settings)
+ // Keepalive is not supported in recvonly secure sessions
+ if ( !iSecSession )
+ {
+ StartKeepaliveL( *iRtpMediaClock );
+ }
+
+ if ( oldState == ERtpStatePaused )
+ {
+ SendStreamEventToClient( KMccStreamResumed );
+ }
+ else
+ {
+ SendStreamEventToClient( KMccStreamStarted );
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CMccRtpDataSource::SourcePauseL
+// Pause RTP packet receiving.
+// -----------------------------------------------------------------------------
+//
+void CMccRtpDataSource::SourcePauseL()
+ {
+ TRACE_RTP_SOURCE_PRINT( "CMccRtpDataSource::SourcePauseL" )
+
+ iPacketsReceived = 0;
+ __ASSERT_ALWAYS( iJitCalc, User::Leave( KErrNotFound ) );
+ iJitCalc->ResetCounters();
+
+ SetStateL( ERtpStatePaused );
+
+ TRACE_RTP_SOURCE_PRINT( "CMccRtpDataSource::SourcePauseL\
+ stop standby timers" )
+
+ StopRtpStandByTimers();
+
+ SendStreamEventToClient( KMccStreamPaused );
+ }
+
+// -----------------------------------------------------------------------------
+// CMccRtpDataSource::SourceStopL
+// Stop RTP packet receiving.
+// -----------------------------------------------------------------------------
+//
+void CMccRtpDataSource::SourceStopL()
+ {
+ TRACE_RTP_SOURCE_PRINT( "CMccRtpDataSource::SourceStopL" )
+
+ iDlStreamStarted = EFalse;
+ SetStateL( ERtpStateStopped );
+
+ StopKeepalive();
+
+ TRACE_RTP_SOURCE_PRINT( "CMccRtpDataSource::SourceStopL,\
+ Stop standby timers" )
+
+ StopRtpStandByTimers();
+
+ SendStreamEventToClient( KMccStreamStopped );
+ }
+
+// -----------------------------------------------------------------------------
+// CMccRtpDataSource::PlayoutRtpPacketL
+// Pass filled buffer to the data sink of RTP data source.
+// -----------------------------------------------------------------------------
+//
+void CMccRtpDataSource::PlayoutRtpPacketL( const TRtpRecvHeader& aHeaderInfo,
+ const TDesC8& aPayloadData )
+ {
+ TRACE_RTP_SOURCE_PRINT( "CMccRtpDataSource::PlayoutRtpPacketL" )
+ __ASSERT_ALWAYS( iBufferToFill, User::Leave( KErrNotReady ) );
+ __ASSERT_ALWAYS( iFillBufferRequester, User::Leave( KErrNotReady ) );
+
+ iBufferToFill->Data().Copy( aPayloadData );
+
+ CPayloadFormatRead* sink = static_cast<CPayloadFormatRead*>( iFillBufferRequester );
+ User::LeaveIfNull( sink );
+ sink->DataBufferFilledL( iBufferToFill, aHeaderInfo );
+ }
+
+
+// -----------------------------------------------------------------------------
+// CMccRtpDataSource::DoCreateStreamL
+// Creates a receive stream.
+// -----------------------------------------------------------------------------
+//
+void CMccRtpDataSource::DoCreateStreamL()
+ {
+ TRACE_RTP_SOURCE_PRINT( "CMccRtpDataSource::DoCreateStreamL IN !!!!" )
+ __ASSERT_ALWAYS( KNullId == iRtpStreamId, User::Leave( KErrAlreadyExists ) );
+ __ASSERT_ALWAYS( NULL != iRtpAPI, User::Leave( KErrNotReady ) );
+
+ TRcvStreamParams rcvParams;
+ rcvParams.iPayloadType = iCodecInfo.iPayloadType;
+
+ TRACE_RTP_SOURCE_PRINT2( "CMccRtpDataSource::DoCreateStreamL CONFIGURED_PT: %u",
+ iCodecInfo.iPayloadType )
+
+ iRtpStreamId = iRtpAPI->CreateReceiveStreamL( iSessionID, rcvParams );
+ if ( KNullId == iRtpStreamId )
+ {
+ TRACE_RTP_SOURCE_PRINT( "CMccRtpDataSource::DoCreateStreamL KErrCouldNotConnect 1" )
+
+ User::Leave( KErrCouldNotConnect );
+ }
+
+ TRACE_RTP_SOURCE_PRINT( "CMccRtpDataSource::DoCreateStreamL SetSamplingRate 1" )
+
+ User::LeaveIfError(
+ iRtpAPI->SetSamplingRate( iCodecInfo.iPayloadType, KDefSampleRate ) );
+
+ if ( KMccPayloadTypeMax != iCodecInfo.iRedundantPayload )
+ {
+ User::LeaveIfError( iRtpAPI->SetSamplingRate(
+ iCodecInfo.iRedundantPayload, KDefSampleRate ) );
+ }
+
+ User::LeaveIfError( iRtpAPI->RegisterRtpObserver( iSessionID, *this ) );
+
+ DoCreateSrtpStreamL();
+
+ TRACE_RTP_SINK_PRINT( "CMccRtpDataSource::DoCreateStreamL OUT" )
+ }
+
+// -----------------------------------------------------------------------------
+// CMccRtpDataSource::DoCreateSrtpStreamL
+// -----------------------------------------------------------------------------
+//
+void CMccRtpDataSource::DoCreateSrtpStreamL()
+ {
+ TRACE_RTP_SINK_PRINT( "CMccRtpDataSource::DoCreateStreamL IN" )
+ if ( !iSrtpStream && iContext && iSecSession && KNullId != iRtpStreamId )
+ {
+ TRACE_RTP_SINK_PRINT( "CMccRtpDataSource::DoCreateStreamL, creating" )
+ iSrtpStream = CSRTPStreamIn::NewL( *iSecSession, iContext, *this );
+ }
+ TRACE_RTP_SINK_PRINT( "CMccRtpDataSource::DoCreateStreamL OUT" )
+ }
+
+// -----------------------------------------------------------------------------
+// CMccRtpDataSource::NegotiateSourceL
+// Derived from MDataSource
+// -----------------------------------------------------------------------------
+//
+void CMccRtpDataSource::NegotiateSourceL( MDataSink& aDataSink )
+ {
+ iFillBufferRequester = &aDataSink;
+ }
+
+// -----------------------------------------------------------------------------
+// CMccRtpDataSource::SendMediaSignallingL
+// Derived from CRtpInterface
+// -----------------------------------------------------------------------------
+//
+void CMccRtpDataSource::SendMediaSignallingL( const TMccEvent& aEvent )
+ {
+ TRACE_RTP_SOURCE_PRINT( "CMccRtpDataSource::SendMediaSignallingL" )
+
+ __ASSERT_ALWAYS( aEvent.iEventCategory == KMccEventCategoryRtcp &&
+ aEvent.iEventType == KMccRtcpControl &&
+ iEnableRtcp,
+ User::Leave( KErrNotSupported ) );
+
+ __ASSERT_ALWAYS( iRtpAPI, User::Leave( KErrNotReady ) );
+
+ const TMccRtcpEventData& rtcpEvent =
+ (*reinterpret_cast<const TMccRtcpEventDataPackage*>(
+ &aEvent.iEventData ))();
+
+ switch ( rtcpEvent.iRtcpPacketType )
+ {
+ case KRtcpRrPacket:
+ {
+ TRACE_RTP_SOURCE_PRINT( "CMccRtpDataSource::SendMediaSignallingL, RR" )
+
+ __ASSERT_ALWAYS( KNullId != iRtpStreamId, User::Leave( KErrNotReady ) );
+ User::LeaveIfError( iRtpAPI->SendRtcpRrPacket( iRtpStreamId ) );
+ break;
+ }
+ default:
+ {
+ User::Leave( KErrArgument );
+ break;
+ }
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CMccRtpDataSource::StartInactivityTimer
+// Starts inactivity timer for a stream
+// -----------------------------------------------------------------------------
+//
+void CMccRtpDataSource::StartInactivityTimerL( TUint32 aTimeoutTime )
+ {
+ TRACE_RTP_SOURCE_PRINT ( "CMccRtpDataSource::StartInactivityTimerL" )
+
+ if( aTimeoutTime == 0 )
+ {
+ User::Leave( KErrArgument );
+ }
+
+ iTimeoutTime = aTimeoutTime;
+
+ StopInactivityTimerL();
+
+ iInactivityTimerId = iTimer->StartL( this, aTimeoutTime );
+
+ TRACE_RTP_SOURCE_PRINT2 ( "CMccRtpDataSource::StartInactivityTimerL, timer id: %d",
+ iInactivityTimerId )
+
+ TRACE_RTP_SOURCE_PRINT ( "CMccRtpDataSource::StartInactivityTimerL, Exit" )
+ }
+
+// -----------------------------------------------------------------------------
+// CMccRtpDataSource::StopInactivityTimer
+// Stops inactivity timer for a stream
+// -----------------------------------------------------------------------------
+//
+void CMccRtpDataSource::StopInactivityTimerL()
+ {
+ TRACE_RTP_SOURCE_PRINT( "CMccRtpDataSource::StopInactivityTimerL" )
+
+ // It does not matter whether timer is active or not
+ iTimer->Stop( iInactivityTimerId );
+ }
+
+
+// -----------------------------------------------------------------------------
+// CMccRtpDataSource::StandBy
+// -----------------------------------------------------------------------------
+//
+TInt CMccRtpDataSource::StandBy(
+ TMccStandbyActionType aActionType,
+ TUint aPayloadType )
+ {
+ TRACE_RTP_SOURCE_PRINT2( "CMccRtpDataSource::StandBy, action type:%d", aActionType )
+
+ TRAPD( err, StandByL( aActionType, aPayloadType ) );
+ if ( err != KErrNone )
+ {
+ TRACE_RTP_SOURCE_PRINT2( "CMccRtpDataSource::StandByL, error=%d", err )
+ }
+
+ TRACE_RTP_SOURCE_PRINT( "CMccRtpDataSource::StandBy, Exit" )
+ return err;
+ }
+
+// -----------------------------------------------------------------------------
+// CMccRtpDataSource::RtpStreamId
+// -----------------------------------------------------------------------------
+//
+TRtpId CMccRtpDataSource::RtpStreamId()
+ {
+ return iRtpStreamId;
+ }
+
+// -----------------------------------------------------------------------------
+// CMccRtpDataSource::RegisterPayloadTypesL
+// -----------------------------------------------------------------------------
+//
+void CMccRtpDataSource::RegisterPayloadTypesL( const RArray<TUint>& aPayloadTypes )
+ {
+ TRACE_RTP_SOURCE_PRINT( "CMccRtpDataSource::RegisterPayloadTypesL" )
+
+#ifdef _DEBUG
+
+ for( TInt k = 0; k < aPayloadTypes.Count(); k++ )
+ {
+ TRACE_RTP_SOURCE_PRINT2( "CMccRtpDataSource::RegisterPayloadTypesL PT: %u",
+ aPayloadTypes[k] )
+ }
+
+#endif
+
+
+ TInt ind = aPayloadTypes.Count();
+ while ( ind-- )
+ {
+ if ( !FindUserEntryByPayloadType( aPayloadTypes[ind] ) )
+ {
+ TMccRtpUser entry( iEventHandler );
+ entry.iPayloadType = aPayloadTypes[ind];
+ iUsers.AppendL( entry );
+ }
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CMccRtpDataSource::UnRegisterPayloadTypes
+// Unregisters payload types to accept.
+// -----------------------------------------------------------------------------
+//
+void CMccRtpDataSource::UnRegisterPayloadTypes( const RArray<TUint>& aPayloadTypes )
+ {
+#ifdef _DEBUG
+
+ for( TInt k = 0; k < aPayloadTypes.Count(); k++ )
+ {
+ TRACE_RTP_SOURCE_PRINT2( "CMccRtpDataSource::UnRegisterPayloadTypes PT: %u",
+ aPayloadTypes[k] )
+ }
+
+#endif
+
+ TInt ind = aPayloadTypes.Count();
+ while ( ind-- )
+ {
+ TMccRtpUser* userEntry = FindUserEntryByPayloadType( aPayloadTypes[ind] );
+ TInt index = FindUserEntryIndex( userEntry );
+ if ( index != KErrNotFound )
+ {
+ iUsers.Remove( index );
+ }
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CMccRtpDataSource::ValidatePacketL
+// Validates the received RTP packet and it's header
+// -----------------------------------------------------------------------------
+//
+TMccRtpUser* CMccRtpDataSource::ValidatePacketL( const TRtpId aStreamId,
+ const TRtpRecvHeader& aHeader, const TDesC8& aData )
+ {
+ TRACE_RTP_SOURCE_PRINT( "CMccRtpDataSource::ValidatePacketL" )
+
+ __ASSERT_ALWAYS( iBufferToFill, User::Leave( KErrNotReady ) );
+ __ASSERT_ALWAYS( iBufferToFill->Data().MaxSize() >= aData.Size(),
+ User::Leave( KErrOverflow ) );
+
+ TMccRtpUser* userEntry = FindUserEntryByPayloadType( aHeader.iPayloadType );
+ TBool isCN = EFalse;
+
+ if ( KCnPayloadType == aHeader.iPayloadType ||
+ KCnPayloadTypeReserved == aHeader.iPayloadType )
+ {
+ isCN = ETrue;
+ }
+
+ if ( !userEntry )
+ {
+ if ( iCurRecvPayloadType != aHeader.iPayloadType && !isCN )
+ {
+ TRACE_RTP_SOURCE_PRINT( "CMccRtpDataSource::ValidatePacketL Unknown media" )
+
+ iCurRecvPayloadType = aHeader.iPayloadType;
+
+ // Support for unsymmetric speech codecs, payload type is reported as
+ // an error code in this case.
+ SendStreamEventToClient( KMccUnknownMediaReceived,
+ aHeader.iPayloadType );
+ }
+
+ if ( !isCN )
+ {
+ TRACE_RTP_SOURCE_PRINT( "CMccRtpDataSource::ValidatePacketL PT NOK" )
+
+ User::Leave( KErrNotSupported );
+ }
+
+ // Try to find user on current PT so the inactivity could be reset.
+ userEntry = FindUserEntryByPayloadType( iCurRecvPayloadType );
+ }
+ else if ( userEntry &&
+ KMaxTUint == userEntry->iTimerId &&
+ isCN )
+ {
+ // This is because timers are used against the main payloadtype in CN
+ // cases.
+ userEntry = FindUserEntryByPayloadType( iCurRecvPayloadType );
+ }
+
+ if ( iRtpAPI && ( iRtpStreamId != aStreamId ) )
+ {
+ // Adapt to SSRC change
+ iRtpAPI->CloseStream( iRtpStreamId );
+ iRtpStreamId = aStreamId;
+ }
+
+ TRACE_RTP_SOURCE_PRINT2( "CMccRtpDataSource::ValidatePacketL userEntry: 0x%x",
+ userEntry )
+
+ return userEntry;
+ }
+
+// -----------------------------------------------------------------------------
+// CMccRtpDataSource::SendStreamEventToClient()
+// -----------------------------------------------------------------------------
+//
+void CMccRtpDataSource::SendStreamEventToClient(
+ TMccEventType aEventType,
+ TInt aError,
+ TUint32 aTargetPayloadType )
+ {
+ TRACE_RTP_SOURCE_PRINT( "CMccRtpDataSource::SendStreamEventToClient" )
+
+ if ( iEventHandler )
+ {
+ ClearMccEvent();
+
+ iMccEvent.iEndpointId = MCC_RTPSOURCE_ENDPOINT_ID;
+ iMccEvent.iEventCategory = KMccEventCategoryStream;
+ iMccEvent.iEventType = aEventType;
+ iMccEvent.iErrorCode = aError;
+
+ if ( aTargetPayloadType != KMccPTNotDefined )
+ {
+ iMccEvent.iEventNumData = KMccPayloadSpecificEvent;
+ iMccEvent.iReserved = aTargetPayloadType;
+ }
+
+ TMccInternalEvent internalEvent( KMccRtpSourceUid,
+ EMccInternalEventNone,
+ iMccEvent );
+
+ iEventHandler->SendEventToClient( internalEvent );
+ }
+ else
+ {
+ TRACE_RTP_SOURCE_PRINT( "CMccRtpDataSource::SendStreamEventToClient, \
+ iEventHandler=NULL" )
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CMccRtpDataSource::SendJitterEvent()
+// -----------------------------------------------------------------------------
+//
+void CMccRtpDataSource::SendJitterEvent( TMccRtpEventData aEvent, TInt aError )
+ {
+ TRACE_RTP_SOURCE_PRINT( "CMccRtpDataSource::SendJitterEvent" )
+
+ SendInternalRtpEventToClient( iEventHandler,
+ KMccRtpSourceUid,
+ EMccInternalJitterEventStatusReport,
+ KMccMediaQualityStatus,
+ MCC_RTPSOURCE_ENDPOINT_ID,
+ aError,
+ aEvent.iJitterEstimate,
+ aEvent.iPacketsReceived,
+ aEvent.iPrevTransTime,
+ aEvent.iTriggeredJitterLevel );
+ }
+
+// -----------------------------------------------------------------------------
+// CMccRtpDataSource::SourceCustomCommand()
+//
+// -----------------------------------------------------------------------------
+//
+void CMccRtpDataSource::SourceCustomCommand( TMMFMessage& aMessage )
+ {
+ TRAPD( err, SourceCustomCommandL( aMessage ) );
+
+ #ifdef TRACE_RTP_SOURCE
+ RDebug::Print( _L("CMcpRtpDataSource::SourceCustomCommand ERR: %d"), err );
+ #endif
+
+ aMessage.Complete( err );
+ }
+
+// -----------------------------------------------------------------------------
+// CMccRtpDataSource::SourceCustomCommandL()
+// Worker function for TRAP'ping possible leaves that custom commands may have
+// -----------------------------------------------------------------------------
+//
+void CMccRtpDataSource::SourceCustomCommandL( TMMFMessage& aMessage )
+ {
+ #ifdef TRACE_RTP_SOURCE
+ RDebug::Print( _L("CMcpRtpDataSource::SourceCustomCommandL FUNC: %d"), aMessage.Function() );
+ #endif
+
+ switch( aMessage.Function() )
+ {
+ case EStartMediaQualityObserving:
+ // Send message data to jitter calculator, SetMediaConfigsL will
+ // leave with KErrAlreadyExists if there is already a pending
+ // client request, which will propagate to SourceCustomCommand()
+ iJitCalc->SetMediaConfigsL( aMessage );
+ User::LeaveIfError( iJitCalc->StartObserving() );
+ break;
+
+ case ECancelMediaQualityObserving:
+ if ( iJitCalc->IsObserving() )
+ {
+ iJitCalc->CancelObserving();
+ }
+ else
+ {
+ User::Leave( KErrNotReady );
+ }
+ break;
+
+ default:
+ // Not supported CustomCommand => Leave
+ User::Leave( KErrNotSupported );
+ break;
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CMccRtpDataSource::InactivityTimerActive
+// -----------------------------------------------------------------------------
+//
+TBool CMccRtpDataSource::InactivityTimerActive() const
+ {
+ return ( iInactivityTimerId != KMaxTUint32 &&
+ iTimer &&
+ iTimer->IsRunning( iInactivityTimerId ) );
+ }
+
+// -----------------------------------------------------------------------------
+// CMccRtpDataSource::StandbyEnabled
+// -----------------------------------------------------------------------------
+//
+TBool CMccRtpDataSource::StandbyEnabled( TMccRtpUser* aUser ) const
+ {
+ return ( iCodecInfo.iType == KUidMediaTypeAudio &&
+ iStandByTimerValue > 0 &&
+ aUser &&
+ aUser->iStandbyState != ETurnedOff );
+ }
+
+// -----------------------------------------------------------------------------
+// CMccRtpDataSource::StandByL
+// -----------------------------------------------------------------------------
+//
+void CMccRtpDataSource::StandByL(
+ TMccStandbyActionType aActionType,
+ TUint aPayloadType )
+ {
+ TMccRtpUser* userEntry = FindUserEntryByPayloadType( aPayloadType );
+ __ASSERT_ALWAYS( userEntry, User::Leave( KErrNotFound ) );
+
+ switch ( aActionType )
+ {
+ case EForceStandby:
+ {
+ if ( ERtpStatePlaying == State() )
+ {
+ TRACE_RTP_SOURCE_PRINT( "CMccRtpDataSource::StandByL, force" )
+ iTimer->Stop( userEntry->iTimerId );
+ HandleStandByL( userEntry );
+ }
+ break;
+ }
+ case EActivateStandby:
+ {
+ TRACE_RTP_SOURCE_PRINT2( "CMccRtpDataSource::StandByL, activate, \
+standby state before: %d", userEntry->iStandbyState )
+
+ if ( userEntry->iStandbyState == EActivating )
+ {
+ // If currently activating, activation was not possible,
+ // stop timer and wait that mechanism is activated again
+ iTimer->Stop( userEntry->iTimerId );
+ }
+ else if ( userEntry->iStandbyState == EActive )
+ {
+ // If was active, re-activation can
+ // be tried when data for this user is received.
+ iTimer->Stop( userEntry->iTimerId );
+ userEntry->iStandbyState = EInactive;
+ }
+ else
+ {
+ // NOP
+ }
+
+ TRACE_RTP_SOURCE_PRINT2( "CMccRtpDataSource::StandByL, activate, \
+standby state after: %d", userEntry->iStandbyState )
+
+ break;
+ }
+ case EDeactivateStandby:
+ {
+ TRACE_RTP_SOURCE_PRINT( "CMccRtpDataSource::StandByL, deactivate" )
+ iTimer->Stop( userEntry->iTimerId );
+ userEntry->iStandbyState = ETurnedOff;
+ break;
+ }
+ default:
+ {
+ User::Leave( KErrArgument );
+ break;
+ }
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CMccRtpDataSource::StartRtpStandByTimerL
+// Starts rtp standby timer
+// -----------------------------------------------------------------------------
+//
+void CMccRtpDataSource::StartRtpStandByTimerL( TMccRtpUser* aUser )
+ {
+ TRACE_RTP_SOURCE_PRINT2( "CMccRtpDataSource::StartRtpStandByTimer iStartedOnce: %d",
+ aUser->iStartedOnce )
+ TRACE_RTP_SOURCE_PRINT2( "CMccRtpDataSource::StartRtpStandByTimer iPayloadType: %d",
+ aUser->iPayloadType )
+ TRACE_RTP_SOURCE_PRINT2( "CMccRtpDataSource::StartRtpStandByTimer iTimerId: %d",
+ aUser->iTimerId )
+ TRACE_RTP_SOURCE_PRINT2( "CMccRtpDataSource::StartRtpStandByTimer iStandbyState: %d",
+ aUser->iStandbyState )
+
+ if ( StandbyEnabled( aUser ) )
+ {
+ // It does not matter whether timer is active or not
+ iTimer->Stop( aUser->iTimerId );
+ aUser->iTimerId = iTimer->StartL( this, iStandByTimerValue );
+
+ TRACE_RTP_SOURCE_PRINT ( "CMCCRtpDataSource::StartRtpStandByTimer standby enabled" )
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CMccRtpDataSource::StopRtpStandByTimers
+// Stop rtp standby timers
+// -----------------------------------------------------------------------------
+//
+void CMccRtpDataSource::StopRtpStandByTimers()
+ {
+ TRACE_RTP_SOURCE_PRINT ( "CMccRtpDataSource::StopRtpStandByTimer" )
+
+ // Stop all rtp standby timers
+ for ( TInt i = 0; i < iUsers.Count(); i++ )
+ {
+ iTimer->Stop( iUsers[ i ].iTimerId );
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CMccRtpDataSource::ResetStandBy
+// -----------------------------------------------------------------------------
+//
+void CMccRtpDataSource::ResetStandBy()
+ {
+ TRACE_RTP_SOURCE_PRINT ( "CMccRtpDataSource::ResetStandBy" )
+
+ // Stop all rtp standby timers
+ for ( TInt i = 0; i < iUsers.Count(); i++ )
+ {
+ iUsers[ i ].iStandbyState = EInactive;
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CMccRtpDataSource::HandleStandByL
+// -----------------------------------------------------------------------------
+//
+void CMccRtpDataSource::HandleStandByL( TMccRtpUser* aUser )
+ {
+ __ASSERT_ALWAYS( StandbyEnabled( aUser ), User::Leave( KErrNotSupported ) );
+
+ TRACE_RTP_SOURCE_PRINT2( "CMccRtpDataSource::HandleStandByL, deactivate, \
+standby state before: %d", aUser->iStandbyState )
+
+ aUser->iStandbyState = EDeactivating;
+
+ SendStreamEventToClient( KMccStandbyInactivityEvent,
+ KErrNone,
+ aUser->iPayloadType );
+
+ aUser->iStandbyState = EInactive;
+
+ TRACE_RTP_SOURCE_PRINT2( "CMccRtpDataSource::HandleStandByL, deactivate, \
+standby state after: %d", aUser->iStandbyState )
+ }
+
+// ---------------------------------------------------------------------------
+// CMccRtpDataSource::DoStandByDecision
+// If standby activation has been done for some other payload type than
+// currently received payload type, stream for old payload type is paused
+// and stream for the new payload type is started/resumed.
+// ---------------------------------------------------------------------------
+//
+void CMccRtpDataSource::DoStandByDecision( TMccRtpUser* aUser )
+ {
+
+
+ if ( StandbyEnabled( aUser ) &&
+ ( aUser->iStandbyState == EInactive || aUser->iStandbyState == EDeactivating ) )
+ {
+ TRACE_RTP_SOURCE_PRINT2( "CMccRtpDataSource::DoStandByDecision, \
+standby state before: %d", aUser->iStandbyState )
+
+ aUser->iStandbyState = EActivating;
+
+ SendStreamEventToClient( KMccStandbyActivityEvent,
+ KErrNone,
+ iCurRecvPayloadType );
+
+ if ( aUser->iStandbyState == EActivating )
+ {
+ aUser->iStandbyState = EActive;
+ }
+
+ TRACE_RTP_SOURCE_PRINT2( "CMccRtpDataSource::DoStandByDecision, \
+standby state after: %d", aUser->iStandbyState )
+ }
+ }
+
+// ---------------------------------------------------------------------------
+// CMccRtpDataSource::FindUserEntryByPayloadType
+// ---------------------------------------------------------------------------
+//
+TMccRtpUser* CMccRtpDataSource::FindUserEntryByPayloadType( TUint aPayloadType )
+ {
+ TMccRtpUser entry( iEventHandler );
+ entry.iPayloadType = aPayloadType;
+ TIdentityRelation<TMccRtpUser> comparison( RtpUserMatch );
+ const TInt index = iUsers.Find( entry, comparison );
+ if ( index != KErrNotFound )
+ {
+ return &iUsers[ index ];
+ }
+
+ return NULL;
+ }
+
+// ---------------------------------------------------------------------------
+// CMccRtpDataSource::FindRtpUserEntryByTimerId
+// ---------------------------------------------------------------------------
+//
+TMccRtpUser* CMccRtpDataSource::FindUserEntryByTimerId( TMccTimerId aTimerId )
+ {
+ TMccRtpUser entry( iEventHandler );
+ entry.iTimerId = aTimerId;
+ TIdentityRelation<TMccRtpUser> comparison( RtpUserMatch );
+ TInt index = iUsers.Find( entry, comparison );
+ if ( index != KErrNotFound )
+ {
+ return &iUsers[ index ];
+ }
+ return NULL;
+ }
+
+// ---------------------------------------------------------------------------
+// CMccRtpDataSource::FindUserEntryIndex
+// ---------------------------------------------------------------------------
+//
+TInt CMccRtpDataSource::FindUserEntryIndex( TMccRtpUser* aUser )
+ {
+ TInt index( KErrNotFound );
+ if ( aUser )
+ {
+ TIdentityRelation<TMccRtpUser> comparison( RtpUserMatch );
+ index = iUsers.Find( *aUser, comparison );
+ }
+ return index;
+ }
+
+// ---------------------------------------------------------------------------
+// CMccRtpDataSource::RtpUserMatch
+// ---------------------------------------------------------------------------
+//
+TBool CMccRtpDataSource::RtpUserMatch(
+ const TMccRtpUser& aUser1,
+ const TMccRtpUser& aUser2 )
+ {
+ // First argument is always the search term
+
+ TBool match( EFalse );
+ if ( aUser1.iPayloadType != KMccPTNotDefined )
+ {
+ match = ( aUser1.iPayloadType == aUser2.iPayloadType );
+ }
+ else if ( aUser1.iTimerId != KMaxTUint32 )
+ {
+ match = ( aUser1.iTimerId == aUser2.iTimerId );
+ }
+ else
+ {
+ match = ( &aUser1 == &aUser2 );
+ }
+ return match;
+ }
+
+// ---------------------------------------------------------------------------
+// FROM SRTP API
+// This function is called by SRTP Stream initiated with
+// MSRTPReKeyingObserver when a master key is stale and needs
+// to be refreshed.
+// ---------------------------------------------------------------------------
+//
+void CMccRtpDataSource::SRTPMasterKeyStaleEvent( const CSRTPStream& aStream )
+ {
+ TRACE_RTP_INTERFACE_PRINT( "CMccRtpDataSource::SRTPMasterKeyStaleEvent" )
+
+ if ( iSrtpStream == &aStream )
+ {
+ iSecureKeyExpired = ETrue;
+ SendSecureRtpEventToClient( iEventHandler,
+ KMccRtpSourceUid,
+ EMccInternalEventNone,
+ KMccMasterKeyStaled,
+ MCC_RTPSOURCE_ENDPOINT_ID );
+ }
+ else
+ {
+ TRACE_RTP_INTERFACE_PRINT( "CMccRtpDataSource::SRTPMasterKeyStaleEvent - Wrong stream" )
+ }
+ }
+
+// ---------------------------------------------------------------------------
+// FROM SRTP API
+// This function is called by SRTP Stream initiated with
+// CSRTPSession when a master key is stale and
+// needs to be refreshed.
+// ---------------------------------------------------------------------------
+//
+void CMccRtpDataSource::SRTPMasterKeyStaleEvent(const CSRTPSession& aSession )
+ {
+ TRACE_RTP_INTERFACE_PRINT( "CMccRtpStream::SRTPMasterKeyStaleEvent" )
+
+ if ( iSecSession == &aSession )
+ {
+ iSecureKeyExpired = ETrue;
+ SendSecureRtpEventToClient( iEventHandler,
+ KMccRtpSourceUid,
+ EMccInternalEventNone,
+ KMccMasterKeyStaled,
+ MCC_RTPSOURCE_ENDPOINT_ID );
+
+ }
+ else
+ {
+ TRACE_RTP_INTERFACE_PRINT( "MccRtpStream::SRTPMasterKeyStaleEvent - Wrong session" )
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CMccRtpDataSource::TimerExpiredL
+// From MMccExpirationHandler
+// -----------------------------------------------------------------------------
+//
+void CMccRtpDataSource::TimerExpiredL( TMccTimerId aTimerId, TAny* /*aTimerParam*/ )
+ {
+ TRACE_RTP_SOURCE_PRINT2( "CMccRtpStream::TimerExpiredL, timer id: %d", aTimerId )
+ if ( aTimerId == iInactivityTimerId )
+ {
+ TRACE_RTP_SOURCE_PRINT ( "CMccRtpDataSource::TimerExpiredL, inactivity timer expired" )
+
+ SendInternalRtpEventToClient( iEventHandler,
+ KMccRtpSourceUid,
+ KMccInternalRtpSrcMmfEvent,
+ KMccInactivityEvent,
+ MCC_RTPSOURCE_ENDPOINT_ID );
+ }
+ else
+ {
+ // Standby timeout
+ TMccRtpUser* userEntry = FindUserEntryByTimerId( aTimerId );
+ HandleStandByL( userEntry );
+ }
+ }
+
+// ========================== OTHER EXPORTED FUNCTIONS =========================
+
+// End of File