multimediacommscontroller/mmccmultiplexer/src/mccsinkitem.cpp
changeset 0 1bce908db942
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/multimediacommscontroller/mmccmultiplexer/src/mccsinkitem.cpp	Tue Feb 02 01:04:58 2010 +0200
@@ -0,0 +1,622 @@
+/*
+* Copyright (c) 2006 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:   
+*
+*/
+
+
+
+
+// INCLUDE FILES
+#include <mmf/server/mmfdatasink.h>
+#include <mmf/server/mmfbuffer.h>
+#include "rtpheader.h"
+#include "mccsinkitem.h"
+#include "formatstatemachine.h"
+#include "mccmultiplexerlogs.h"
+#include "mccinternaldef.h"
+#include "mccinternalevents.h"
+#include "mccuids.hrh"
+
+// MACROS
+
+#define MCC_PAYLOAD_READ( a ) static_cast<CPayloadFormatRead*>( a )
+
+// LOCAL FUNCTION PROTOTYPES
+
+// LOCAL CONSTANTS
+
+const TInt KMccBadDataCount = 20;
+
+const TInt KMccMaxStoredBuffers = 10;
+
+// ============================= LOCAL FUNCTIONS ===============================
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CMccSinkItem::NewLC
+// -----------------------------------------------------------------------------
+//
+CMccSinkItem* CMccSinkItem::NewLC( 
+    MDataSink* aSink, 
+    TBool aSinkIsDecoder,
+    TUid aMediaType,
+    TBool aPassAllBuffersSink )
+    {
+    CMccSinkItem* self = 
+        new ( ELeave ) CMccSinkItem( aMediaType, aPassAllBuffersSink );
+    CleanupStack::PushL( self );
+    self->ConstructL( aSink, aSinkIsDecoder );
+    return self;
+    }
+
+// -----------------------------------------------------------------------------
+// CMccSinkItem::~CMccSinkItem
+// -----------------------------------------------------------------------------
+//    
+CMccSinkItem::~CMccSinkItem()
+    {
+    iStoredBuffers.ResetAndDestroy();
+    iPayloadsToAccept.Close();
+    }
+
+// -----------------------------------------------------------------------------
+// CMccSinkItem::BufferFilledL
+// -----------------------------------------------------------------------------
+//    
+void CMccSinkItem::BufferFilledL( 
+    CMMFBuffer* aBuffer, 
+    const TRtpRecvHeader* aHeaderInfo,
+    TBool aPrimary,
+    TUid aMediaType )
+    {
+    __MULTIPLEXER_INT1( "CMccSinkItem::BufferFilledL, sinkitem:", 
+                        reinterpret_cast<TUint32>( this ) )
+
+    CMMFBuffer* completedBuffer = NULL;
+    
+    CMMFDataBuffer* dataBuffer = static_cast<CMMFDataBuffer*>( aBuffer );
+    
+    if ( aMediaType != KNullUid && MediaType() != aMediaType )
+        {
+        __MULTIPLEXER( "CMccSinkItem::BufferFilledL, wrong media type" )
+        return;
+        }
+    
+    if ( HandleBadDataL( dataBuffer ) )
+        {
+        __MULTIPLEXER( "CMccSinkItem::BufferFilledL, stopping buffer forwarding" )
+        return;
+        }
+    
+    if ( aHeaderInfo
+        && ( KErrNotFound != iPayloadsToAccept.Find( aHeaderInfo->iPayloadType ) ) )
+        {
+        __MULTIPLEXER( "CMccSinkItem::BufferFilledL, payload type demultiplexing" )
+        
+        if ( iRequestedBuffer )
+            {
+            __MULTIPLEXER( "CMccSinkItem::BufferFilledL, fillbuffer request exists" )
+            
+            CopyBufferL( iRequestedBuffer, aBuffer );
+            completedBuffer = iRequestedBuffer;
+            iRequestedBuffer = NULL;
+            }
+        }
+    else if ( iPassAllBuffersSink )
+        {
+        __MULTIPLEXER( "CMccSinkItem::BufferFilledL, in passall buffers mode" )
+        
+        // Do not zero the request, sink will eat all buffers
+        // once it has requested for one
+        if ( iRequestedBuffer )
+            {
+            completedBuffer = aBuffer;
+            }
+        }
+    else if ( iPassAllRequestsSource )
+        {
+        __MULTIPLEXER( "CMccSinkItem::BufferFilledL, in passall requests mode" )
+        
+        // If in passall mode, buffer received from source must match with the
+        // one the sink gave when requesting the buffer fill
+        if ( iRequestedBuffer &&
+             iRequestedBuffer == aBuffer )
+            {
+            __MULTIPLEXER( "CMccSinkItem::BufferFilledL, existing fillbuffer request" )
+            
+            completedBuffer = aBuffer;
+            iRequestedBuffer = NULL;
+            }
+        }
+    else if ( iRequestedBuffer && aPrimary )
+        {
+        __MULTIPLEXER( "CMccSinkItem::BufferFilledL, existing fillbuffer request for primary" )
+        
+        completedBuffer = aBuffer;
+        iRequestedBuffer = NULL;
+        }
+    else
+        {
+        if ( iRequestedBuffer )
+            {
+            __MULTIPLEXER( "CMccSinkItem::BufferFilledL, existing fillbuffer request" )
+            
+            // If secondary sink has already requested buffer fill, the request
+            // can be completed immediately
+            CopyBufferL( iRequestedBuffer, aBuffer );
+            completedBuffer = iRequestedBuffer;
+            iRequestedBuffer = NULL;
+            }
+        else
+            {
+            // Otherwise the buffer has to be "stored"
+            StoreBufferL( aBuffer );
+            }
+        }
+    
+    if ( completedBuffer )
+        {    
+        if ( iDecoder && aHeaderInfo )
+            {
+            iDecoder->DataBufferFilledL( completedBuffer, *aHeaderInfo );
+            }
+        else
+            {
+            Sink()->BufferFilledL( completedBuffer );
+            }
+        }
+        
+    __MULTIPLEXER( "CMccSinkItem::BufferFilledL, exit" )
+    }
+
+// -----------------------------------------------------------------------------
+// CMccSinkItem::FillBufferRequestL
+// -----------------------------------------------------------------------------
+//    
+void CMccSinkItem::FillBufferRequestL( CMMFBuffer* aBuffer )
+    {
+    __MULTIPLEXER_INT1( "CMccSinkItem::FillBufferRequestL, sinkitem:", 
+                        reinterpret_cast<TUint32>( this ) )
+    
+    CMMFBuffer* storedBuffer = GetStoredBuffer();
+    if ( storedBuffer )
+        {
+        __MULTIPLEXER( "CMccSinkItem::FillBufferRequestL, stored buffer exists" )
+        
+        CleanupStack::PushL( storedBuffer );
+        CopyBufferL( aBuffer, storedBuffer );
+        CleanupStack::PopAndDestroy( storedBuffer );
+        
+        Sink()->BufferFilledL( aBuffer );
+        }
+    else
+        {
+        __MULTIPLEXER( "CMccSinkItem::FillBufferRequestL, store fillbuffer request" )
+        
+        iRequestedBuffer = aBuffer;
+        }
+        
+    __MULTIPLEXER( "CMccSinkItem::FillBufferRequestL, exit" )
+    }
+
+// -----------------------------------------------------------------------------
+// CMccSinkItem::Match
+// -----------------------------------------------------------------------------
+//                            
+TBool CMccSinkItem::Match( MDataSink* aSink )
+    {
+    return ( Sink() == aSink );
+    }
+
+// -----------------------------------------------------------------------------
+// CMccSinkItem::SourceThreadLogon
+// -----------------------------------------------------------------------------
+//
+TInt CMccSinkItem::SourceThreadLogon( MAsyncEventHandler& aEventHandler )
+    {
+    iEventHandler = &aEventHandler;
+    return KErrNone;
+    }
+    
+// -----------------------------------------------------------------------------
+// CMccSinkItem::SendEventToClient
+// -----------------------------------------------------------------------------
+//    
+TInt CMccSinkItem::SendEventToClient( const TMMFEvent& aEvent )
+    {
+    __MULTIPLEXER( "CMccSinkItem::SendEventToClient" )
+    
+    // Filter duplicate stream state change events. Errors are always reported.
+    // Check also whether the event is targeted for specific payload type.
+    //
+    
+    TInt ret( KErrNotReady );
+    TBool sendEvent( ETrue );
+
+  	if ( IS_MCC_EVENT( aEvent ) )
+	    {
+	    TMccEvent* mccEventPtr = 
+	        reinterpret_cast<const TMccInternalEvent&>( aEvent ).iMccEvent;  
+	        
+	    if ( mccEventPtr && MCC_STREAM_STATE_CHANGE_EVENT( mccEventPtr ) &&
+	         !mccEventPtr->iErrorCode )
+	        {
+	        sendEvent = HandleStreamStateChangeEvent( *mccEventPtr );
+	        ret = KErrNone;
+	        }
+	    else if ( mccEventPtr && 
+	              mccEventPtr->iEventNumData == KMccPayloadSpecificEvent &&
+	              mccEventPtr->iReserved != KMccPTNotDefined )
+	        {
+	        __MULTIPLEXER_INT1( "CMccSinkItem::SendEventToClient, event for payload type:",
+	                            mccEventPtr->iReserved )
+	                            
+	        sendEvent = 
+	            ( iPayloadsToAccept.Find( mccEventPtr->iReserved ) != KErrNotFound );
+	        }
+	    else
+	        {
+	        // NOP
+	        }
+	    }
+    
+    if ( iEventHandler && sendEvent )
+        {
+        ret = iEventHandler->SendEventToClient( aEvent );
+        }
+    else
+        {
+        __MULTIPLEXER( "CMccSinkItem::SendEventToClient, dropping event" )
+        }
+    return ret;
+    }
+
+// -----------------------------------------------------------------------------
+// CMccSinkItem::MediaType
+// -----------------------------------------------------------------------------
+//     
+TUid CMccSinkItem::MediaType() const
+    {
+    return iMediaType;
+    }
+    
+// -----------------------------------------------------------------------------
+// CMccSinkItem::RegisterPayloadTypesL
+// -----------------------------------------------------------------------------
+//     
+void CMccSinkItem::RegisterPayloadTypesL( const RArray<TUint>& aPayloadTypes )
+    {
+    __MULTIPLEXER( "CMccSinkItem::RegisterPayloadTypesL" )
+    
+    TInt ind = aPayloadTypes.Count();
+    while ( ind-- )
+        {
+        if ( KErrNotFound == iPayloadsToAccept.Find( aPayloadTypes[ind]) )
+            {
+            iPayloadsToAccept.AppendL( aPayloadTypes[ind] );
+            }
+        else
+            {
+            User::Leave( KErrAlreadyExists );
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CMccSinkItem::RegisteredPayloadTypes
+// -----------------------------------------------------------------------------
+//
+const RArray<TUint>& CMccSinkItem::RegisteredPayloadTypes() const
+    {
+    return iPayloadsToAccept;
+    }
+
+// -----------------------------------------------------------------------------
+// CMccSinkItem::RequestedBuffer
+// -----------------------------------------------------------------------------
+//
+CMMFBuffer* CMccSinkItem::RequestedBuffer()
+    {
+    return iRequestedBuffer;
+    }
+
+// -----------------------------------------------------------------------------
+// CMccSinkItem::EventHandler
+// -----------------------------------------------------------------------------
+//
+MAsyncEventHandler* CMccSinkItem::EventHandler()
+    {
+    return iEventHandler;
+    }
+
+// -----------------------------------------------------------------------------
+// CMccSinkItem::SetMultiplexerState
+// -----------------------------------------------------------------------------
+//
+void CMccSinkItem::SetMultiplexerState( CMccMultiplexer::TMccMultiplexerState aState )
+    {
+    __MULTIPLEXER_INT2( "CMccSinkItem::SetMultiplexerState, sinkitem:", 
+                        reinterpret_cast<TUint32>( this ),
+                        " state:", aState )
+    iState = aState;
+    }
+
+// -----------------------------------------------------------------------------
+// CMccSinkItem::MultiplexerState
+// -----------------------------------------------------------------------------
+//
+CMccMultiplexer::TMccMultiplexerState CMccSinkItem::MultiplexerState() const
+    {
+    return iState;
+    }
+    
+// -----------------------------------------------------------------------------
+// CMccSinkItem::SetSourceMode
+// -----------------------------------------------------------------------------
+//    
+void CMccSinkItem::SetSourceMode( TBool aPassAllRequestsSource )
+    {
+    __MULTIPLEXER_INT1( "CMccSinkItem::SetSourceMode, sinkitem:", 
+                        reinterpret_cast<TUint32>( this ) )
+    __MULTIPLEXER_INT1( "CMccSinkItem::SetSourceMode, mediatype:", 
+                        iMediaType.iUid )
+    __MULTIPLEXER_INT1( "CMccSinkItem::SetSourceMode, mode:", 
+                        aPassAllRequestsSource )
+    
+    iPassAllRequestsSource = aPassAllRequestsSource;
+    }
+
+// -----------------------------------------------------------------------------
+// CMccSinkItem::PassAllRequestsToSource
+// -----------------------------------------------------------------------------
+//     
+TBool CMccSinkItem::PassAllRequestsToSource() const
+    {
+    return iPassAllRequestsSource;
+    }
+
+// -----------------------------------------------------------------------------
+// CMccSinkItem::CMccSinkItem
+// -----------------------------------------------------------------------------
+//     
+TUid CMccSinkItem::ResolveMediaType( CMMFBuffer* aBuffer ) const
+    {
+    if ( aBuffer && iPassAllRequestsSource && iRequestedBuffer == aBuffer )
+        {
+        return MediaType();
+        }
+    return KNullUid;
+    }
+    
+// -----------------------------------------------------------------------------
+// CMccSinkItem::CMccSinkItem
+// -----------------------------------------------------------------------------
+//   
+CMccSinkItem::CMccSinkItem( TUid aMediaType, TBool aPassAllBuffersSink ) :
+    iMediaType( aMediaType ),
+    iPassAllBuffersSink( aPassAllBuffersSink ),
+    iReportedEvent( KMccEventNone ), iBadDataCount( 0 )
+    {
+    }
+
+// -----------------------------------------------------------------------------
+// CMccSinkItem::Sink
+// -----------------------------------------------------------------------------
+//       
+void CMccSinkItem::ConstructL( MDataSink* aSink, TBool aSinkIsDecoder )
+    {
+    __MULTIPLEXER( "CMccSinkItem::ConstructL" )
+    
+    __ASSERT_ALWAYS( aSink, User::Leave( KErrArgument ) );
+    
+    if ( aSinkIsDecoder )
+        {
+        __MULTIPLEXER( "CMccSinkItem::ConstructL, sink is decoder" )
+        
+        CMMFFormatDecode* decoder = static_cast<CMMFFormatDecode*>( aSink ); 
+        
+        iDecoder = MCC_PAYLOAD_READ( decoder );
+        }
+    else
+        {
+        iSink = aSink;
+        }
+        
+    __MULTIPLEXER( "CMccSinkItem::ConstructL, exit" )
+    }
+
+// -----------------------------------------------------------------------------
+// CMccSinkItem::Sink
+// -----------------------------------------------------------------------------
+//    
+MDataSink* CMccSinkItem::Sink()
+    {
+    if ( iDecoder )
+        {
+        return iDecoder;
+        }
+    
+    return iSink;
+    }
+    
+// ---------------------------------------------------------------------------
+// CMccSinkItem::CopyBufferL
+// ---------------------------------------------------------------------------
+//  
+void CMccSinkItem::CopyBufferL( 
+    CMMFBuffer* aDesBuffer,
+    CMMFBuffer* aOrigBuffer )
+	{
+	__ASSERT_ALWAYS( aDesBuffer && aOrigBuffer, User::Leave( KErrArgument ) );
+	
+	// Copy buffer setting
+    aDesBuffer->SetFrameNumber( aOrigBuffer->FrameNumber() );
+    aDesBuffer->SetLastBuffer( aOrigBuffer->LastBuffer() );
+    aDesBuffer->SetPosition( aOrigBuffer->Position() );
+     // Note: setting the status to available clears the buffer data
+    aDesBuffer->SetStatus( aOrigBuffer->Status() );
+    aDesBuffer->SetTimeToPlay( aOrigBuffer->TimeToPlay() );
+    	
+	// Copy buffer data
+	CMMFDataBuffer* desBuffer = static_cast<CMMFDataBuffer*>( aDesBuffer );
+	CMMFDataBuffer* origBuffer = static_cast<CMMFDataBuffer*>( aOrigBuffer );
+	
+	__ASSERT_ALWAYS( desBuffer->Data().MaxLength() >= (TInt) origBuffer->BufferSize(), 
+	                 User::Leave( KErrOverflow ) );
+	
+    desBuffer->Data().Copy( origBuffer->Data() );
+	}
+
+// ---------------------------------------------------------------------------
+// CMccSinkItem::IsInternalDecoder
+// ---------------------------------------------------------------------------
+//  
+TBool CMccSinkItem::IsInternalDecoder( TUid aDecoderUid ) const
+    {
+    TUint32 decoderUid = aDecoderUid.iUid;
+    return ( decoderUid == KImplUidAmrPayloadFormatDecode ||
+             decoderUid == KImplUidAnyPayloadFormatDecode ||
+             decoderUid == KImplUidDTMFPayloadFormatDecode ||
+             decoderUid == KImplUidRedPayloadFormatDecode );
+    
+    }
+
+// ---------------------------------------------------------------------------
+// CMccSinkItem::StoreBufferL
+// ---------------------------------------------------------------------------
+//     
+void CMccSinkItem::StoreBufferL( CMMFBuffer* aBuffer )
+    {
+    __MULTIPLEXER( "CMccSinkItem::StoreBufferL" )
+    
+    // If secondary sink has not yet requested buffer fill, the buffer
+    // will be stored
+    if ( iStoredBuffers.Count() >= KMccMaxStoredBuffers )
+        {
+        __MULTIPLEXER( "CMccSinkItem::BufferFilledL, dropping oldest stored buffer!" )
+        delete iStoredBuffers[ 0 ];
+        iStoredBuffers.Remove( 0 );
+        }
+    
+    CMMFDataBuffer* storedBuffer = CMMFDataBuffer::NewL( aBuffer->BufferSize() );
+    
+    CleanupStack::PushL( storedBuffer );
+    CopyBufferL( storedBuffer, aBuffer ); 
+    iStoredBuffers.AppendL( storedBuffer );
+    CleanupStack::Pop( storedBuffer );
+    
+    __MULTIPLEXER( "CMccSinkItem::StoreBufferL, exit" )
+    }
+
+// ---------------------------------------------------------------------------
+// CMccSinkItem::GetStoredBuffer
+// ---------------------------------------------------------------------------
+//   
+CMMFBuffer* CMccSinkItem::GetStoredBuffer()
+    {
+    CMMFBuffer* buffer = NULL;
+    
+    if ( iStoredBuffers.Count() > 0 )
+        {
+        buffer = iStoredBuffers[ 0 ];
+        iStoredBuffers.Remove( 0 );
+        }
+        
+    return buffer;
+    }
+
+// ---------------------------------------------------------------------------
+// CMccSinkItem::HandleBadData
+// ---------------------------------------------------------------------------
+// 
+TBool CMccSinkItem::HandleBadDataL( CMMFDataBuffer* aBuffer )
+    { 
+    TBool stopBufferForwarding( EFalse ); 
+    if ( aBuffer == NULL || !aBuffer->BufferSize() )
+        {
+        __MULTIPLEXER( "CMccSinkItem::HandleBadDataL, bad data received" )
+        iBadDataCount++;
+        if ( iBadDataCount >= KMccBadDataCount && iEventHandler )
+            {
+            __MULTIPLEXER( "CMccSinkItem::HandleBadDataL, pausing stream" )
+            iBadDataCount = 0;
+            
+    	    TMccEvent* event = new ( ELeave ) TMccEvent;
+	        CleanupStack::PushL( event );
+    	    event->iEndpointId = 0;
+    	    event->iEventCategory = KMccEventCategoryStreamControl;
+    	    event->iEventType = KMccStreamPaused;
+    	    event->iErrorCode = KErrNone;
+
+    		TMccInternalEvent internalEvent( KMccMultiplexerUid, EMccInternalEventNone,
+    		                                 *event );
+		                         
+		    User::LeaveIfError( iEventHandler->SendEventToClient( internalEvent ) );
+		    
+		    CleanupStack::PopAndDestroy( event );
+            __MULTIPLEXER( "CMccSinkItem::HandleBadDataL, pausing event sent" )
+            
+            stopBufferForwarding = ETrue;
+            }
+        }
+    else    
+        {
+        iBadDataCount = 0;
+        }
+        
+    return stopBufferForwarding;
+    }
+
+// ---------------------------------------------------------------------------
+// CMccSinkItem::HandleStreamStateChangeEvent
+// ---------------------------------------------------------------------------
+//
+TBool CMccSinkItem::HandleStreamStateChangeEvent( TMccEvent& aEvent )
+    {
+    TBool sendEvent( ETrue );
+    
+    // Modify started event to resumed event if previously paused
+    if ( aEvent.iEventType == KMccStreamStarted && 
+         iReportedEvent == KMccStreamPaused )
+        {
+        __MULTIPLEXER( "CMccSinkItem::SendEventToClient, modify event type" )
+        aEvent.iEventType = KMccStreamResumed;
+        }
+    
+    // Automatic started/resumed event is not forwarded if this user hasn't yet
+    // started the source
+    if ( aEvent.iEventNumData == KMccAutomaticEvent &&
+       ( aEvent.iEventType == KMccStreamStarted ||
+         aEvent.iEventType == KMccStreamResumed ) )
+        {
+        sendEvent = ( iState >= CMccMultiplexer::EPlaying );
+        
+        __MULTIPLEXER_INT1( 
+        "CMccSinkItem::SendEventToClient, automatic event send:", sendEvent )
+        }
+    
+    if ( sendEvent )
+        {
+        sendEvent = ( aEvent.iEventType != iReportedEvent );
+        
+        iReportedEvent = aEvent.iEventType;
+        }
+    
+    return sendEvent;
+    }
+    
+//  End of File 
+