diff -r 000000000000 -r 1bce908db942 multimediacommscontroller/mmccrtpsourcesink/src/mccrtpdatasource.cpp --- /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 +#include + +#include "rtpapi.h" +#include "mccrtpdatasource.h" +#include "mccinternalevents.h" +#include "formatstatemachine.h" +#include "mccrtpdefs.h" +#include "mmccinterfacedef.h" +#include "mcctimermanager.h" + +#include +#include + +// MACROS +#define MCC_RTPSOURCE_ENDPOINT_ID reinterpret_cast( static_cast( 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( 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( 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( 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( + &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& 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& 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 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 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 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