multimediacommscontroller/mmccrtpsourcesink/src/mccrtpdatasink.cpp
changeset 0 1bce908db942
child 32 f2ed1fc4c163
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/multimediacommscontroller/mmccrtpsourcesink/src/mccrtpdatasink.cpp	Tue Feb 02 01:04:58 2010 +0200
@@ -0,0 +1,852 @@
+/*
+* 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 <mmf/common/mmfcontroller.h> 
+
+#include "rtpheader.h"
+#include <srtpcryptocontext.h>
+#include <srtpstreamout.h>
+
+#include "mccrtpdatasink.h"
+#include "mmccevents.h"
+#include "mccinternaldef.h"
+#include "mccrtpdefs.h"
+#include "mmccinterfacedef.h"
+#include "mccrtpmediaclock.h"
+
+// MACROS
+
+// EXTERNAL DATA STRUCTURES
+
+// EXTERNAL FUNCTION PROTOTYPES  
+
+// CONSTANTS
+
+// MACROS
+#define MCC_RTPSINK_ENDPOINT_ID MCC_ENDPOINT_ID( static_cast<MDataSink*>( this ) )
+
+// LOCAL CONSTANTS AND MACROS
+
+// MODULE DATA STRUCTURES
+
+// LOCAL FUNCTION PROTOTYPES
+
+// FORWARD DECLARATIONS
+
+// ============================= LOCAL FUNCTIONS ===============================
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CMccRtpDataSink::CMccRtpDataSink
+// C++ default constructor can NOT contain any code, that
+// might leave.
+// -----------------------------------------------------------------------------
+//
+CMccRtpDataSink::CMccRtpDataSink() :
+    CMccDataSink( KMccRtpSinkUid ),
+    MMccRtpInterface(), iRtpStreamId( KNullId )
+    {
+    }
+
+// -----------------------------------------------------------------------------
+// CMccRtpDataSink::NewSinkL
+// Static constructor.
+// -----------------------------------------------------------------------------
+//
+MDataSink* CMccRtpDataSink::NewSinkL( TUid /*aImplementationUid*/, 
+                                      const TDesC8& /*aInitData*/ )
+    {
+    TRACE_RTP_SINK_PRINT( "CMccRtpDataSink::NewSinkL()" )
+       
+    CMccRtpDataSink* self = new ( ELeave ) CMccRtpDataSink();
+    return static_cast<MDataSink*>( self ); 
+    }
+
+// -----------------------------------------------------------------------------
+// CMccRtpDataSink::ConstructSinkL
+// class MDataSink inherited 2nd phase construction
+// -----------------------------------------------------------------------------
+//
+void CMccRtpDataSink::ConstructSinkL( const TDesC8& aInitData )
+    {
+    TRACE_RTP_SINK_PRINT( "CMccRtpDataSink::ConstructSinkL" )
+    
+    SetStateL( ERtpStateConstructed );
+    
+    TInt res = aInitData.Compare( KNullDesC8 );
+    if ( 0 != res )
+        {
+        TRACE_RTP_SOURCE_PRINT( "CMccRtpDataSink::ConstructSinkL KErrArgument" )
+    
+        User::Leave( KErrArgument );
+        }
+        
+    #ifdef FTD_ENABLED
+    TInt err = iStreamStatsQueue.OpenGlobal( KMccStreamStats, EOwnerProcess );
+    if ( KErrNone != err )
+        {
+        User::Leave( err );
+        }
+    #endif
+    }
+
+// -----------------------------------------------------------------------------
+// CMccRtpDataSink::~CMccRtpDataSink
+// Destructor
+// -----------------------------------------------------------------------------
+//
+CMccRtpDataSink::~CMccRtpDataSink()
+    {
+    TRACE_RTP_SINK_PRINT2( "CMccRtpDataSink::~CMccRtpDataSink 0x%x", this )
+    
+    // We don't own this
+    iEventHandler = NULL;
+        
+    CloseStreams();
+        
+    iDataSource = NULL;
+    iBufferToBeEmptied = NULL;
+    
+    iUsers.Close();
+        
+    delete iSender;
+    
+    #ifdef FTD_ENABLED
+    iStreamStatsQueue.Close();
+    #endif
+    }
+
+
+// -----------------------------------------------------------------------------
+// CMccRtpDataSink::SetCurrentUser
+// -----------------------------------------------------------------------------
+//
+void CMccRtpDataSink::SetCurrentUser( MAsyncEventHandler* aEventHandler )
+    {
+    iEventHandler = aEventHandler;
+    }
+
+
+// -----------------------------------------------------------------------------
+// CMccRtpDataSink::Mute
+// -----------------------------------------------------------------------------
+//
+void CMccRtpDataSink::Mute( TBool aMuteOn, TUint8 aExceptionPt )
+    {
+    TRACE_RTP_SINK_PRINT3( "CMccRtpDataSink::Mute, ENABLED: %d, PT: %u", 
+        aMuteOn, aExceptionPt )
+    
+    iMuteOn = aMuteOn;
+    iExceptionPt = aExceptionPt;
+    }
+
+// -----------------------------------------------------------------------------
+// CMccRtpDataSink::SinkThreadLogon
+//
+// Method to 'logon' the data sink to the same thread that sink will be consuming
+// data in. Thread specific initialisation is done here.
+// -----------------------------------------------------------------------------
+//
+TInt CMccRtpDataSink::SinkThreadLogon( MAsyncEventHandler& aEventHandler ) 
+    {
+    TRACE_RTP_SINK_PRINT ( "CMccRtpDataSink::SinkThreadLogon" )
+    
+    if ( FindRtpUserEntryForCurrent( aEventHandler ) )
+        {
+        TRACE_RTP_SINK_PRINT2( "CMccRtpDataSink::SinkThreadLogon, ERR: %d", KErrAlreadyExists )
+        return KErrAlreadyExists;
+        }
+
+    TMccRtpUser user( &aEventHandler );
+    TInt err = iUsers.Append( user );
+    
+    TRACE_RTP_SINK_PRINT2( "CMccRtpDataSink::SinkThreadLogon, exit with err: %d", err )
+    
+    return err;
+    }
+
+// -----------------------------------------------------------------------------
+// CMccRtpDataSink::SinkThreadLogoff
+//
+// Method to 'logoff' the data sink from the same thread that sink consumes 
+// data in. Thread specific releasing of resources is done here.
+// -----------------------------------------------------------------------------
+//
+void CMccRtpDataSink::SinkThreadLogoff() 
+    {
+    TRACE_RTP_SINK_PRINT( "CMccRtpDataSink::SinkThreadLogoff" )
+    
+    RemoveCurrentRtpUser();
+    
+    SetCurrentUser( NULL );
+    
+    if ( 0 == iUsers.Count() )
+        {
+        // SinkThreadLogoff may be called while not stopped, so don't
+        // bother checking any states here. SinkThreadLogoff means that the
+        // thread is going down, so we must cleanup here...
+    
+        StopKeepalive();
+    	CloseStreams();
+        iRtpAPI = NULL;
+        iRtpStreamId = KNullId;
+        iUsers.Close();
+        
+    	delete iSender;
+	    iSender = NULL;
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CMccRtpDataSink::SetSinkDataTypeCode
+// Sets the datatype code ( codec )
+// ----------------------------------------------------------------------------- 
+//
+TInt CMccRtpDataSink::SetSinkDataTypeCode( TFourCC aCodec, TMediaId aMedia )
+    {
+    if ( KUidMediaTypeAudio == aMedia.iMediaType || 
+         KUidMediaTypeVideo == aMedia.iMediaType )
+        {
+        TRACE_RTP_SINK_PRINT2( "CMccRtpDataSink::SetSinkDataTypeCode, mediatype:%d", 
+                               aMedia.iMediaType.iUid )
+        iMedia = aMedia;
+        iCodecInfo.iFourCC = aCodec;
+        return KErrNone;
+        }
+    else
+        {
+        return KErrNotSupported;
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CMccRtpDataSink::SinkDataTypeCode
+// Returns the datatype code ( codec )
+// -----------------------------------------------------------------------------
+//
+TFourCC CMccRtpDataSink::SinkDataTypeCode( TMediaId aMediaId )
+    {
+    if ( KUidMediaTypeAudio == aMediaId.iMediaType ||
+         KUidMediaTypeVideo == aMediaId.iMediaType )
+        {
+        return iCodecInfo.iFourCC;
+        }
+    else
+        {
+        // Initializes to KMMFFourCCCodeNULL so the caller cannot see
+        // if this sink really has some media type currently registered
+        return TFourCC();
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CMccRtpDataSink::EmptyBufferL
+// NOT SUPPORTED. MDataSink pure virtual function must be implemented.
+// -----------------------------------------------------------------------------
+//
+void CMccRtpDataSink::EmptyBufferL( CMMFBuffer* /*aBuffer*/, 
+                                    MDataSource* /*aSupplier*/, 
+                                    TMediaId /*aMediaId*/ )
+    {
+    User::Leave( KErrNotSupported );
+    }
+
+// -----------------------------------------------------------------------------
+// CMccRtpDataSink::EmptyBufferL
+// Overload to class MDataSink pure virtual function implementation.
+// Take RTP packet in the buffer and send it.
+// -----------------------------------------------------------------------------
+//
+void CMccRtpDataSink::EmptyBufferL( CMMFBuffer* aBuffer,
+                                    MDataSource* aSupplier,
+                                    TMediaId /*aMediaId*/,
+                                    TRtpSendHeader& aHeaderInfo )
+    {
+    __ASSERT_ALWAYS( KNullId != iRtpStreamId, User::Leave( KErrNotReady ) );
+    this->CheckBufferSupportL( aBuffer );
+    User::LeaveIfNull( aSupplier );
+    
+    if ( SendingAllowed( aHeaderInfo ) )
+        {
+        __ASSERT_ALWAYS( iSender, User::Leave( KErrNotReady ) );
+
+        TRACE_RTP_SINK_PRINT3( 
+            "CMccRtpDataSink::EmptyBufferL, timestamp: %d, datalen: %d", 
+            aHeaderInfo.iTimestamp, aBuffer->BufferSize() )
+                               
+        iBufferToBeEmptied = static_cast<CMMFDataBuffer*>( aBuffer );
+
+        iSender->SendRtpPacketL( iRtpStreamId,
+                                 aHeaderInfo, 
+                                 iBufferToBeEmptied->Data() ); 
+        ResetKeepaliveTimer();
+        }
+    else
+        {
+        TRACE_RTP_SINK_PRINT( "CMccRtpDataSink::EmptyBufferL, PACKET DROPPED" )
+        }
+    
+    // Buffer is emptied, notify the caller so it can reuse the buffer.
+    // We risk a dead lock if we don't do this if the supplier relies on this
+    // callback.
+    aSupplier->BufferEmptiedL( aBuffer ); 
+        
+    #ifdef FTD_ENABLED
+    TMccStreamStats stats;
+    stats.iPacketsSent = ++iPacketsSent;
+    stats.SetFieldUpdatedFlag( EPacketsSent );
+    iStreamStatsQueue.Send( stats );
+    #endif
+    }
+
+// -----------------------------------------------------------------------------
+// CMccRtpDataSink::BufferFilledL
+// NOT SUPPORTED. MDataSink pure virtual function must be implemented.
+// -----------------------------------------------------------------------------
+//
+void CMccRtpDataSink::BufferFilledL( CMMFBuffer* /*aBuffer*/ )
+    {
+    // DataSource calls synchronously CMccRtpDataSink->EmptyBuffer(),
+    // so DataSource->FillBuffer, CMccRtpDataSink->BufferFilledL chain is not used at the moment
+    User::Leave( KErrNotSupported );
+    }
+
+// -----------------------------------------------------------------------------
+// CMccRtpDataSink::CanCreateSinkBuffer
+// NOT SUPPORTED. MDataSink pure virtual function must be implemented.
+// -----------------------------------------------------------------------------
+//
+TBool CMccRtpDataSink::CanCreateSinkBuffer()
+    {
+    return EFalse;
+    }
+
+// -----------------------------------------------------------------------------
+// CMccRtpDataSink::CreateSinkBufferL
+// NOT SUPPORTED. MDataSink pure virtual function must be implemented.
+// -----------------------------------------------------------------------------
+//
+CMMFBuffer* CMccRtpDataSink::CreateSinkBufferL( TMediaId /*aMediaId*/,
+                                                TBool& /*aReference*/ )
+    {
+    User::Leave( KErrNotSupported ); 
+    return NULL;
+    }
+
+// -----------------------------------------------------------------------------
+// CMccRtpDataSink::SinkPrimeL
+// Prime the sink. 
+// -----------------------------------------------------------------------------
+//
+void CMccRtpDataSink::SinkPrimeL()
+    { 
+    TRACE_RTP_SINK_PRINT( "CMccRtpDataSink::SinkPrimeL" )
+    
+    SetStateL( ERtpStatePrimed );
+    
+    // Start sending keep alive packets. Secure session has to wait until
+    // secure stream is created 
+    if ( !iSecSession )
+        {
+        StartKeepaliveL( *iRtpMediaClock ); 
+        }
+        
+    SendStreamEventToClient( KMccStreamPrepared );
+    }
+
+// -----------------------------------------------------------------------------
+// CMccRtpDataSink::SinkPlayL
+// Start the playout operation.
+// -----------------------------------------------------------------------------
+//
+void CMccRtpDataSink::SinkPlayL()
+    {
+    TRACE_RTP_SINK_PRINT( "CMccRtpDataSink::SinkPlayL IN" )
+    if ( iSecureKeyExpired )
+    	{
+    	TRACE_RTP_SINK_PRINT( "Leave becuase the secure key expired" )
+    	User::Leave( KErrGeneral );
+    	}
+    TMccRtpUser* user = FindRtpUserEntryForCurrent( *iEventHandler );
+    __ASSERT_ALWAYS( user, User::Leave( KErrNotReady ) );
+    
+    SetStateL( ERtpStatePlaying );
+    
+    if ( user->iStartedOnce )
+        {
+        SendStreamEventToClient( KMccStreamResumed ); 
+        }
+    else
+        {
+        SendStreamEventToClient( KMccStreamStarted ); 
+        user->iStartedOnce = ETrue;
+        }
+
+    TRACE_RTP_SINK_PRINT( "CMccRtpDataSink::SinkPlayL OUT" )
+    }
+
+// -----------------------------------------------------------------------------
+// CMccRtpDataSink::SinkPauseL
+// Pauses the playout operation.
+// -----------------------------------------------------------------------------
+//
+void CMccRtpDataSink::SinkPauseL()
+    {
+    TRACE_RTP_SINK_PRINT( "CMccRtpDataSink::SinkPauseL" )
+    
+    SetStateL( ERtpStatePaused );
+    
+    
+    iSender->Clear();
+    
+    SendStreamEventToClient( KMccStreamPaused ); 
+    }
+
+// -----------------------------------------------------------------------------
+// CMccRtpDataSink::SinkStopL
+// Stop the playout operation. 
+// -----------------------------------------------------------------------------
+//
+void CMccRtpDataSink::SinkStopL()
+    {
+    TRACE_RTP_SINK_PRINT( "CMccRtpDataSink::SinkStopL" )
+    
+    SetStateL( ERtpStateStopped );
+    
+    StopKeepalive();
+    
+    iSender->Clear();
+    
+    SendStreamEventToClient( KMccStreamStopped ); 
+    }
+
+// -----------------------------------------------------------------------------
+// CMccRtpDataSink::SendMediaSignallingL()
+// Sends media level signalling
+// -----------------------------------------------------------------------------
+//
+void CMccRtpDataSink::SendMediaSignallingL( const TMccEvent& aEvent )
+    {
+    TRACE_RTP_SINK_PRINT( "CMccRtpDataSink::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 KRtcpSdesPacket:
+            {
+            TPckgBuf<TRtpSdesParams> package;
+            package.Copy( rtcpEvent.iRtcpPacketData );
+            iRtpAPI->SetLocalSdes( package() );
+            break;
+            }   
+        case KRtcpByePacket:
+            {
+			__ASSERT_ALWAYS( KNullId != iRtpStreamId, User::Leave( KErrNotReady ) );
+            User::LeaveIfError( 
+                iRtpAPI->SendRtcpByePacket( iRtpStreamId, 
+                    rtcpEvent.iRtcpPacketData ) );
+            break;
+            }
+        case KRtcpAppPacket:
+            {
+			__ASSERT_ALWAYS( KNullId != iRtpStreamId, User::Leave( KErrNotReady ) );
+			
+            TPckgBuf<TRtcpApp> package;
+            package.Copy( rtcpEvent.iRtcpPacketData );
+			
+            User::LeaveIfError( 
+                iRtpAPI->SendRtcpAppPacket( iRtpStreamId, package() ) );
+            
+            break;
+            }
+        case KRtcpSrPacket:
+            {
+            TRACE_RTP_SINK_PRINT( "CMccRtpDataSink::SendMediaSignallingL, SR" )
+            	
+            __ASSERT_ALWAYS( KNullId != iRtpStreamId, User::Leave( KErrNotReady ) ); 
+            User::LeaveIfError( iRtpAPI->SendRtcpSrPacket( iRtpStreamId ) );
+            break;
+            }
+        case KRtcpAnyPacket:
+            {
+            TRACE_RTP_SINK_PRINT( "CMccRtpDataSink::SendMediaSignallingL, FC" )
+            TRACE_RTP_SINK_PRINT2( "CMccRtpDataSink::SendMediaSignallingL, sessionid:%d", 
+                                   iSessionID )
+            TRACE_RTP_SINK_PRINT2( "CMccRtpDataSink::SendMediaSignallingL, datalen: %d", 
+                                   rtcpEvent.iRtcpPacketData.Length() )
+            
+            __ASSERT_ALWAYS( iSender, User::Leave( KErrNotReady ) );
+            TBool useRTPSocket( EFalse );
+            iSender->SendDataL( iSessionID,
+                                useRTPSocket,
+                                rtcpEvent.iRtcpPacketData );
+            break;
+            }
+        default:
+            {
+            TRACE_RTP_SINK_PRINT( "CMccRtpDataSink::SendMediaSignallingL, default" )
+            User::Leave( KErrArgument );
+            break;
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CMccRtpDataSink::DoCreateStreamL
+// Creates a transmit stream.
+// -----------------------------------------------------------------------------
+//
+void CMccRtpDataSink::DoCreateStreamL()
+    {
+    TRACE_RTP_SINK_PRINT( "CMccRtpDataSink::DoCreateStreamL IN" )
+    __ASSERT_ALWAYS( KNullId == iRtpStreamId, User::Leave( KErrAlreadyExists ) );
+    __ASSERT_ALWAYS( NULL != iRtpAPI, User::Leave( KErrNotReady ) );
+    
+    if ( !iSender )
+        {
+        // Can do marker based cleanup only with video stream
+        TBool doMarkerBasedCleanup( iMedia.iMediaType == KUidMediaTypeVideo );
+        iSender = CMccRtpSender::NewL( 
+                        *this, *iRtpAPI, iSessionID, doMarkerBasedCleanup );
+        }
+    
+    TTranStreamParams transParams;
+    transParams.iPayloadType = iCodecInfo.iPayloadType;
+    iRtpStreamId =
+    	iRtpAPI->CreateTransmitStreamL( iSessionID, transParams, iSSRC ); 
+    
+    if ( KNullId == iRtpStreamId )
+        {
+        TRACE_RTP_SINK_PRINT( "CMccRtpDataSink::DoCreateStreamL KErrCouldNotConnect 1" )
+        
+        User::Leave( KErrCouldNotConnect );
+        }
+        
+    TRACE_RTP_SINK_PRINT( "CMccRtpDataSink::DoCreateStreamL SetSamplingRate 1" ) 
+        
+    User::LeaveIfError( iRtpAPI->SetSamplingRate( 
+        iCodecInfo.iPayloadType, KDefSampleRate ) );
+
+    if ( KMccPayloadTypeMax != iCodecInfo.iRedundantPayload )
+        {
+        User::LeaveIfError( iRtpAPI->SetSamplingRate( 
+            iCodecInfo.iRedundantPayload, KDefSampleRate ) );
+        }
+   
+    DoCreateSrtpStreamL();
+            
+  	TRACE_RTP_SINK_PRINT( "CMccRtpDataSink::DoCreateStreamL OUT" )
+    }
+
+// -----------------------------------------------------------------------------
+// CMccRtpDataSink::SendErrorOccured
+// Asynchronous sending error occured
+// -----------------------------------------------------------------------------
+//    
+void CMccRtpDataSink::SendErrorOccured( TInt aError )
+    {
+    TRACE_RTP_SINK_PRINT2( "CMccRtpDataSink::SendErrorOccured, err: %d", aError )
+    
+    SendInternalRtpEventToAllClients( iUsers,
+                                      KMccRtpSinkUid, 
+                                      EMccInternalRtpSinkError, 
+                                      KMccStreamError,
+                                      MCC_RTPSINK_ENDPOINT_ID,
+                                      aError );
+    
+    TRACE_RTP_SINK_PRINT( "CMccRtpDataSink::SendErrorOccured, exit" )
+    }
+
+// -----------------------------------------------------------------------------
+// CMccRtpDataSink::DoCreateSrtpStreamL
+// -----------------------------------------------------------------------------
+//
+void CMccRtpDataSink::DoCreateSrtpStreamL()
+	{
+	TRACE_RTP_SINK_PRINT( "CMccRtpDataSink::DoCreateSrtpStreamL IN" )
+    if ( !iSrtpStream && iContext && iSecSession && KNullId != iRtpStreamId )
+        {
+        TRACE_RTP_SINK_PRINT( "CMccRtpDataSink::DoCreateSrtpStreamL, creating" )
+        iSrtpStream = CSRTPStreamOut::NewL( 
+            *iSecSession, static_cast<TUint>( iSSRC ), iContext, *this );
+        
+        // Now it's possible to send keepalive
+        StartKeepaliveL( *iRtpMediaClock );
+        }
+    TRACE_RTP_SINK_PRINT( "CMccRtpDataSink::DoCreateSrtpStreamL OUT" )
+	}
+	
+// ---------------------------------------------------------------------------
+// CMccRtpDataSink::SinkCustomCommand()
+// 
+// ---------------------------------------------------------------------------
+//
+void CMccRtpDataSink::SinkCustomCommand( TMMFMessage& aMessage )
+    {
+    TRACE_RTP_SINK_PRINT2( "CMccRtpDataSink::SinkCustomCommand - FUNCTION: %d",
+            aMessage.Function() )
+
+    TInt result( KErrNone );
+    aMessage.Complete( result );
+    }
+
+// ---------------------------------------------------------------------------
+// CMccRtpDataSink::SendRTCPData()
+// Sends Non-RTCP data
+// ---------------------------------------------------------------------------
+//    
+void CMccRtpDataSink::SendRTCPDataL( const TDesC8& aData )
+    {
+    if ( iRtpAPI && iSender )
+        {
+        TBool useRTPSocket( EFalse );
+        iSender->SendDataL( iSessionID, useRTPSocket, aData );
+        }
+    else
+        {
+        User::Leave( KErrNotReady );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CMccRtpDataSink::HandleBySsrc
+// -----------------------------------------------------------------------------
+//   
+TBool CMccRtpDataSink::HandleBySsrc( const TRtpSSRC& aSsrc )
+    {
+    return ( iSSRC == aSsrc );
+    }
+    
+// -----------------------------------------------------------------------------
+// CMccRtpDataSink::RtpStreamId
+// -----------------------------------------------------------------------------
+//    
+TRtpId CMccRtpDataSink::RtpStreamId()
+    {
+    return iRtpStreamId;
+    }
+    
+// -----------------------------------------------------------------------------
+// CMccRtpDataSink::IsSink
+// -----------------------------------------------------------------------------
+//
+TBool CMccRtpDataSink::IsSink() const
+    {
+    return ETrue;
+    }
+
+// -----------------------------------------------------------------------------
+// CMccRtpDataSink::IsSending
+// -----------------------------------------------------------------------------
+//        
+TBool CMccRtpDataSink::IsSending() const
+    {
+    return ( ERtpStatePlaying == State() );
+    }
+
+// -----------------------------------------------------------------------------
+// CMccRtpDataSink::SendStreamEventToClient()
+// -----------------------------------------------------------------------------
+//	
+void CMccRtpDataSink::SendStreamEventToClient( 
+    TMccEventType aEventType,
+    TInt aError )
+    {
+    TRACE_RTP_SOURCE_PRINT( "CMccRtpDataSink::SendStreamEventToClient" )
+    
+    if ( iEventHandler )
+	    {
+	    TMccEvent event( 0, 
+	                     0, 
+	                     0, 
+	                     MCC_ENDPOINT_ID( static_cast<MDataSink*>( this ) ), 
+	                     KMccEventCategoryStream, 
+	                     aEventType, 
+	                     aError, 
+	                     KNullDesC8 );
+
+		TMccInternalEvent internalEvent( KMccRtpSinkUid, 
+		                                 EMccInternalEventNone,
+		                                 event );
+		                         
+		iEventHandler->SendEventToClient( internalEvent );
+	    }
+	else
+		{
+		TRACE_RTP_SOURCE_PRINT( "CMccRtpDataSink::SendStreamEventToClient, \
+		iEventHandler=NULL" )
+		}
+    }
+ 
+// ---------------------------------------------------------------------------
+// CMccRtpDataSink::FindRtpUserEntryForCurrent
+// ---------------------------------------------------------------------------
+//
+TMccRtpUser* CMccRtpDataSink::FindRtpUserEntryForCurrent( 
+    MAsyncEventHandler& aEventHandler )
+    {
+    TMccRtpUser entry( &aEventHandler );
+    TIdentityRelation<TMccRtpUser> comparison( RtpUserMatch );
+    TInt index = iUsers.Find( entry, comparison );
+    if ( index != KErrNotFound )
+        {
+        return &iUsers[ index ];
+        }
+    return NULL;
+    }
+
+// ---------------------------------------------------------------------------
+// CMccRtpDataSink::RemoveCurrentRtpUser
+// ---------------------------------------------------------------------------
+//
+void CMccRtpDataSink::RemoveCurrentRtpUser()
+    {
+    TMccRtpUser entry( iEventHandler );
+    TIdentityRelation<TMccRtpUser> comparison( RtpUserMatch );
+    TInt index = iUsers.Find( entry, comparison );
+    if ( index != KErrNotFound )
+        {
+        iUsers.Remove( index );
+        }
+    }
+        
+// ---------------------------------------------------------------------------
+// CMccRtpDataSink::RtpUserMatch
+// ---------------------------------------------------------------------------
+//   
+TBool CMccRtpDataSink::RtpUserMatch( 
+    const TMccRtpUser& aUser1, 
+    const TMccRtpUser& aUser2 )
+    {
+    // First argument is always the search term
+    
+    TBool match( EFalse );
+    if ( aUser1.iEventHandler )
+        {
+        match = ( aUser1.iEventHandler == aUser2.iEventHandler );
+        }
+    return match;
+    }
+
+// ---------------------------------------------------------------------------
+// CMccRtpDataSink::SendingAllowed
+// ---------------------------------------------------------------------------
+//   
+TBool CMccRtpDataSink::SendingAllowed( 
+        const TRtpSendHeader& aHeaderInfo ) const
+    {
+    // If secure session, srtp stream has to exist
+    TRACE_RTP_SINK_PRINT2( "CMccRtpDataSink::Sending allowed iSecureKeyExpired = ",
+        iSecureKeyExpired )
+    
+    TBool isPayloadMuted 
+        = iMuteOn ? aHeaderInfo.iPayloadType != iExceptionPt : EFalse;
+    
+    return ( ERtpStatePlaying == State() && 
+             ( !iSecSession || iSrtpStream ) &&
+    		 !iSecureKeyExpired && 
+    		 !isPayloadMuted );
+    }
+
+// ---------------------------------------------------------------------------
+// CMccRtpDataSink::SetMediaClock
+// ---------------------------------------------------------------------------
+//    
+void CMccRtpDataSink::SetMediaClock( CMccRtpMediaClock& aRtpMediaClock )
+    {
+    TRACE_RTP_SINK_PRINT( "CMccRtpDataSink::SetMediaClock" )
+    
+    if ( !iRtpMediaClock )
+        {
+        iRtpMediaClock = &aRtpMediaClock;
+        }
+    else
+        {
+        TRACE_RTP_SINK_PRINT( "CMccRtpDataSink::SetMediaClock - Allready set!" )
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// 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 CMccRtpDataSink::SRTPMasterKeyStaleEvent( const CSRTPStream& aStream )
+    {
+    TRACE_RTP_INTERFACE_PRINT( "CMccRtpDataSink::SRTPMasterKeyStaleEvent" )
+    
+    if ( iSrtpStream == &aStream )
+        {
+        iSecureKeyExpired = ETrue;
+        SendSecureRtpEventToClient( iEventHandler,
+                                    KMccRtpSinkUid,
+                                    EMccInternalEventNone,
+                                    KMccMasterKeyStaled,
+                                    MCC_RTPSINK_ENDPOINT_ID );   
+        }
+    else
+        {
+        TRACE_RTP_INTERFACE_PRINT( "CMccRtpDataSink::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 CMccRtpDataSink::SRTPMasterKeyStaleEvent(const CSRTPSession& aSession )
+    {
+    TRACE_RTP_INTERFACE_PRINT( "CMccRtpStream::SRTPMasterKeyStaleEvent" )
+    
+    if ( iSecSession == &aSession )
+        {
+        iSecureKeyExpired = ETrue;
+        SendSecureRtpEventToClient( iEventHandler,
+                                    KMccRtpSinkUid,
+                                    EMccInternalEventNone,
+                                    KMccMasterKeyStaled,
+                                    MCC_RTPSINK_ENDPOINT_ID );    
+        }
+    else
+        {
+         TRACE_RTP_INTERFACE_PRINT( "MccRtpStream::SRTPMasterKeyStaleEvent - Wrong session" )
+        }
+    } 
+    
+// ========================== OTHER EXPORTED FUNCTIONS =========================
+
+//  End of File  
+