multimediacommscontroller/mmccmultiplexer/src/mccmultiplexer.cpp
changeset 0 1bce908db942
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/multimediacommscontroller/mmccmultiplexer/src/mccmultiplexer.cpp	Tue Feb 02 01:04:58 2010 +0200
@@ -0,0 +1,958 @@
+/*
+* 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/mmfdatabuffer.h>
+#include "mccmultiplexer.h"
+#include "mccsinkitem.h"
+#include "mccinternaldef.h"
+#include "mccinternalevents.h"
+#include "mccmultiplexerlogs.h"
+#include "mccinternalevents.h"
+#include "mccrtpdatasource.h"
+
+// MACROS
+
+// LOCAL FUNCTION PROTOTYPES
+
+// LOCAL CONSTANTS
+const TUint KMultiplexerDefBufSize( 160 );
+
+// ============================= LOCAL FUNCTIONS ===============================
+        
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CMccMultiplexer::NewL
+// -----------------------------------------------------------------------------
+//
+EXPORT_C CMccMultiplexer* CMccMultiplexer::NewL( MDataSource* aSource )
+    {
+	CMccMultiplexer* self = new ( ELeave ) CMccMultiplexer;
+	CleanupStack::PushL( self );
+    self->ConstructL( aSource );
+    CleanupStack::Pop( self );
+    return self;
+    }
+
+// -----------------------------------------------------------------------------
+// CMccMultiplexer::~CMccMultiplexer
+// -----------------------------------------------------------------------------
+//
+EXPORT_C CMccMultiplexer::~CMccMultiplexer()
+    {
+    __MULTIPLEXER( "CMccMultiplexer::~CMccMultiplexer" )
+    
+    iSinkItems.ResetAndDestroy();
+    delete iDataBuf;
+    
+    __MULTIPLEXER( "CMccMultiplexer::~CMccMultiplexer, exit" )
+    }
+  
+// -----------------------------------------------------------------------------
+// CMccMultiplexer::SourceThreadLogon
+// -----------------------------------------------------------------------------
+//
+EXPORT_C TInt CMccMultiplexer::MultiplexerSourceThreadLogon( 
+    MAsyncEventHandler& aEventHandler, 
+    MDataSink& aSink, 
+    TBool aSinkIsDecoder, 
+    TUid aMediaType,
+    TBool aPassAllBuffersSink )
+    {
+    __MULTIPLEXER_INT1( "CMccMultiplexer::MultiplexerSourceThreadLogon, endpoint:",
+                        MCC_ENDPOINT_ID( &aSink ) )
+    
+    TInt err( KErrNone );
+    
+    TRAP( err, 
+          AddSinkL( &aSink, aSinkIsDecoder, aMediaType, aPassAllBuffersSink ) );
+    
+    // Gather events from source and propagate them to all sink owners
+    
+    if ( !err && !iSourceLogonDone )
+        {
+        __MULTIPLEXER( "CMccMultiplexer::MultiplexerSourceThreadLogon, source logon" )
+        
+        err = iSource->SourceThreadLogon( *this );
+        iSourceLogonDone = ETrue;
+        }
+        
+    if ( !err )
+        {
+        err = FindSinkItemIndex( &aSink );
+        if ( err != KErrNotFound )
+            {
+            err = iSinkItems[ err ]->SourceThreadLogon( aEventHandler );
+            }
+        if ( MCC_INTERNAL_ENDPOINT( iSource->DataSourceType().iUid ) )
+            {
+            static_cast<CMccDataSource*>( iSource )->AddUser( &aEventHandler );
+            }
+        }
+        
+    __MULTIPLEXER( "CMccMultiplexer::SourceThreadLogon, exit" )
+    
+    return err;
+    }
+
+// -----------------------------------------------------------------------------
+// CMccMultiplexer::SourceThreadLogoff
+// -----------------------------------------------------------------------------
+//       
+EXPORT_C TInt CMccMultiplexer::MultiplexerSourceThreadLogoff( MDataSink* aSink )
+    {
+    __MULTIPLEXER_INT1( "CMccMultiplexer::MultiplexerSourceThreadLogoff, endpoint:",
+                        MCC_ENDPOINT_ID( aSink ) )
+    
+    if ( aSink )
+        {
+        TInt index = FindSinkItemIndex( aSink );
+        if ( index != KErrNotFound )
+            {
+            CMccSinkItem* item = iSinkItems[ index ];
+            if ( KMccRtpSourceUid == iSource->DataSourceType() )
+                {
+                const RArray<TUint>& payloads = item->RegisteredPayloadTypes();
+                static_cast<CMccRtpDataSource*>( iSource )
+                    ->UnRegisterPayloadTypes( payloads );
+                }
+            
+            // Clear current user
+            if ( item == iCurrentUser )
+                {
+                iCurrentUser = NULL;
+                }
+                
+            TBool passedAllRequests = PassAllRequestsToSource( *item );
+                
+            iSinkItems.Remove( index );
+
+            UpdateSinkModes();
+            
+            // Update primary buffer or logoff source
+            HandleCleanup( item, passedAllRequests );
+
+            return KErrNone;
+            }
+        return KErrNotFound;
+        }
+    return KErrArgument;
+    }
+
+// -----------------------------------------------------------------------------
+// CMccMultiplexer::SetCurrentUserL
+// -----------------------------------------------------------------------------
+//    
+EXPORT_C void CMccMultiplexer::SetCurrentUserL( MDataSink& aSink )
+    {
+    __MULTIPLEXER_INT1( "CMccMultiplexer::SetCurrentUserL, endpoint:", 
+                        MCC_ENDPOINT_ID( &aSink ) )
+    
+    iCurrentUser = FindSinkItemL( &aSink );
+    
+    __MULTIPLEXER( "CMccMultiplexer::SetCurrentUserL, exit" )
+    }
+    
+// -----------------------------------------------------------------------------
+// CMccMultiplexer::RegClientForPayloadsL
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CMccMultiplexer::RegClientForPayloadsL( MDataSink& aConsumer, 
+        const RArray<TUint>& aPayloadTypes )
+    {
+    __MULTIPLEXER( "CMccMultiplexer::RegClientForPayloadsL" )
+    __ASSERT_ALWAYS( iSource, User::Leave( KErrNotReady ) );
+    __ASSERT_ALWAYS( KMccRtpSourceUid == iSource->DataSourceType(),
+        User::Leave( KErrNotSupported ) );
+    
+    FindSinkItemL( &aConsumer )->RegisterPayloadTypesL( aPayloadTypes );
+    static_cast<CMccRtpDataSource*>( iSource )
+        ->RegisterPayloadTypesL( aPayloadTypes );
+    }
+    
+// -----------------------------------------------------------------------------
+// CMccMultiplexer::Streams
+// -----------------------------------------------------------------------------
+//
+TUint CMccMultiplexer::Streams( TUid /*aMediaType*/ ) const
+    {
+    return 1;
+    }
+
+// -----------------------------------------------------------------------------
+// CMccMultiplexer::FrameTimeInterval
+// -----------------------------------------------------------------------------
+//
+TTimeIntervalMicroSeconds CMccMultiplexer::FrameTimeInterval( 
+    TMediaId /*aMediaId*/ ) const
+    {
+    return TTimeIntervalMicroSeconds( TInt64( 0 ) );
+    }  
+
+// -----------------------------------------------------------------------------
+// CMccMultiplexer::DataSourceType
+// -----------------------------------------------------------------------------
+//
+TUid CMccMultiplexer::DataSourceType() const
+    {
+    return KMccMultiplexerUid;
+    }
+
+// -----------------------------------------------------------------------------
+// CMccMultiplexer::FillBufferL
+// -----------------------------------------------------------------------------
+//
+void CMccMultiplexer::FillBufferL( 
+    CMMFBuffer* aBuffer, 
+    MDataSink* aConsumer, 
+    TMediaId aMediaId )
+    {
+    __MULTIPLEXER_INT1( "CMccMultiplexer::FillBufferL, endpoint:",
+                        MCC_ENDPOINT_ID( aConsumer ) )
+    __MULTIPLEXER_INT1( "CMccMultiplexer::FillBufferL, mediaId uid:",
+                        aMediaId.iMediaType.iUid )
+    
+    __ASSERT_ALWAYS( aBuffer, User::Leave( KErrArgument ) );
+    __ASSERT_ALWAYS( aBuffer->Type() == KUidMmfDataBuffer, 
+                     User::Leave( KErrArgument ) ); 
+    __ASSERT_ALWAYS( aConsumer, User::Leave( KErrArgument ) );
+    
+    // Store request
+    CMccSinkItem* item = FindSinkItemL( aConsumer );
+    item->FillBufferRequestL( aBuffer );
+                                                        
+    // If not in pass all mode, only one sink at the time can control
+    // the source
+    if ( iState == EPlaying && 
+       ( item->PassAllRequestsToSource() || CanCommandSource( aConsumer ) ) )
+        {
+        __MULTIPLEXER( "CMccMultiplexer::FillBufferL, command source" )
+        
+        if ( KMccRtpSourceUid == iSource->DataSourceType() )
+            {
+            // Multiplexer buffer needed for payload type multiplexing
+            __ASSERT_ALWAYS( 
+                static_cast<CMMFDataBuffer*>( aBuffer )
+                ->Data().MaxSize() <= iDataBuf->Data().MaxSize(),
+                User::Leave( KErrTooBig ) );
+            
+            __MULTIPLEXER( "CMccMultiplexer::FillBufferL, using own buffer" )
+            iDataBuf->SetStatus( EBeingFilled );
+            iDataBuf->SetLastBuffer( EFalse );
+            iSource->FillBufferL( iDataBuf, this, aMediaId );
+            }
+        else
+            {
+            iSource->FillBufferL( aBuffer, this, aMediaId );
+            }
+        }
+        
+    __MULTIPLEXER( "CMccMultiplexer::FillBufferL, exit" )
+    }  
+        
+// -----------------------------------------------------------------------------
+// CMccMultiplexer::SourceDataTypeCode
+// -----------------------------------------------------------------------------
+//
+TFourCC CMccMultiplexer::SourceDataTypeCode( 
+	TMediaId aMediaId )
+    {
+    return iSource->SourceDataTypeCode( aMediaId );
+    }
+
+// -----------------------------------------------------------------------------
+// CMccMultiplexer::SetSourceDataTypeCode
+// -----------------------------------------------------------------------------
+//
+TInt CMccMultiplexer::SetSourceDataTypeCode( 
+    TFourCC aSourceFourCC, 
+    TMediaId aMediaId )
+    {
+    return iSource->SetSourceDataTypeCode( aSourceFourCC, aMediaId );
+    }
+
+// -----------------------------------------------------------------------------
+// CMccMultiplexer::SourceThreadLogon
+// -----------------------------------------------------------------------------
+//
+TInt CMccMultiplexer::SourceThreadLogon( 
+    MAsyncEventHandler& /*aEventHandler*/ )
+    {
+    return KErrNotSupported;
+    }
+    
+// -----------------------------------------------------------------------------
+// CMccMultiplexer::NegotiateSourceL
+// -----------------------------------------------------------------------------
+//
+void CMccMultiplexer::NegotiateSourceL( MDataSink& aDataSink )
+    {
+    __MULTIPLEXER( "CMccMultiplexer::NegotiateSourceL" )
+    
+    if ( !iSourceNegotiationDone )
+        {
+        if ( KUidMmfAudioInput == iSource->DataSourceType() )
+            {
+            // Audio input need settings from real sink.
+            // This is just quick workaround, better way would be to route
+            // those requests through multiplexer to the sink
+            
+            __MULTIPLEXER( "CMccMultiplexer::NegotiateSourceL, negotiate (use sink)" )
+            
+            iSource->NegotiateSourceL( aDataSink );
+            }
+        else
+            {
+            __MULTIPLEXER( "CMccMultiplexer::NegotiateSourceL, negotiate (normal)" )
+            
+            iSource->NegotiateSourceL( *this );
+            }
+            
+        iSourceNegotiationDone = ETrue;
+        }
+    __MULTIPLEXER( "CMccMultiplexer::NegotiateSourceL, exit" )
+    }
+
+// -----------------------------------------------------------------------------
+// CMccMultiplexer::SourceThreadLogoff
+// -----------------------------------------------------------------------------
+//
+void CMccMultiplexer::SourceThreadLogoff()
+    {
+    // NOP
+    }
+    
+// -----------------------------------------------------------------------------
+// CMccMultiplexer::SourcePrimeL
+// -----------------------------------------------------------------------------
+//
+void CMccMultiplexer::SourcePrimeL()
+    {
+    __MULTIPLEXER( "CMccMultiplexer::SourcePrimeL" )
+    
+    if ( SetMultiplexerState( EPrepared ) )
+        {
+        iSource->SourcePrimeL();
+        }
+        
+    __MULTIPLEXER( "CMccMultiplexer::SourcePrimeL, exit" )
+    }
+
+// -----------------------------------------------------------------------------
+// CMccMultiplexer::SourcePlayL
+// -----------------------------------------------------------------------------
+//
+void CMccMultiplexer::SourcePlayL()
+    {
+    __MULTIPLEXER( "CMccMultiplexer::SourcePlayL" )
+    
+    if ( SetMultiplexerState( EPlaying ) )
+        {
+        iSource->SourcePlayL();
+        }
+        
+    __MULTIPLEXER( "CMccMultiplexer::SourcePlayL, exit" )
+    }
+
+// -----------------------------------------------------------------------------
+// CMccMultiplexer::SourcePauseL
+// -----------------------------------------------------------------------------
+//
+void CMccMultiplexer::SourcePauseL()
+    {
+    __MULTIPLEXER( "CMccMultiplexer::SourcePauseL" )
+    
+    if ( SetMultiplexerState( EResourcePaused ) )
+        {
+        iSource->SourcePauseL();
+        }
+        
+    __MULTIPLEXER( "CMccMultiplexer::SourcePauseL, exit" )
+    }
+
+// -----------------------------------------------------------------------------
+// CMccMultiplexer::SourceStopL
+// -----------------------------------------------------------------------------
+//
+void CMccMultiplexer::SourceStopL()
+    {
+    __MULTIPLEXER( "CMccMultiplexer::SourceStopL" )
+    
+    if ( SetMultiplexerState( EResourceStopped ) )
+        {
+        iSource->SourceStopL();
+        }
+        
+    __MULTIPLEXER( "CMccMultiplexer::SourceStopL, exit" )
+    }
+
+// -----------------------------------------------------------------------------
+// CMccMultiplexer::DataBufferFilledL
+// -----------------------------------------------------------------------------
+//
+void CMccMultiplexer::DataBufferFilledL( 
+    CMMFBuffer* aBuffer, 
+    const TRtpRecvHeader& aRtpHeader )
+    {
+    __MULTIPLEXER( "CMccMultiplexer::DataBufferFilledL" )
+    __ASSERT_ALWAYS( NULL != aBuffer, User::Leave( KErrArgument ) );
+    
+    DoBufferFilledL( aBuffer, &aRtpHeader );
+    }
+
+// -----------------------------------------------------------------------------
+// CMccMultiplexer::ConfigurePayloadFormatL
+// -----------------------------------------------------------------------------
+//
+void CMccMultiplexer::ConfigurePayloadFormatL( const TDesC8& /*aConfigParams*/ )
+    {
+    }
+
+// -----------------------------------------------------------------------------
+// CMccMultiplexer::BufferFilledL
+// -----------------------------------------------------------------------------
+//
+void CMccMultiplexer::BufferFilledL( CMMFBuffer* aBuffer )
+	{
+    __MULTIPLEXER( "CMccMultiplexer::BufferFilledL" )
+    __ASSERT_ALWAYS( NULL != aBuffer, User::Leave( KErrArgument ) );
+    
+    DoBufferFilledL( aBuffer, 0 );
+	}
+	
+// -----------------------------------------------------------------------------
+// CMccMultiplexer::Duration
+// -----------------------------------------------------------------------------
+//
+TTimeIntervalMicroSeconds CMccMultiplexer::Duration( 
+	TMediaId /*aMediaType*/ ) const
+    {
+    return TTimeIntervalMicroSeconds( TInt64( 0 ) );
+    }
+
+// -----------------------------------------------------------------------------
+// CMccMultiplexer::CanCreateSourceBuffer
+// -----------------------------------------------------------------------------
+//    
+TBool CMccMultiplexer::CanCreateSourceBuffer()
+    {
+    return ETrue;
+    }
+
+// -----------------------------------------------------------------------------
+// CMccMultiplexer::CreateSourceBufferL
+// Created buffer is not intended for sink use.
+// -----------------------------------------------------------------------------
+//
+CMMFBuffer* CMccMultiplexer::CreateSourceBufferL( 
+    TMediaId /*aMediaId*/, 
+    TBool& aReference )
+    {
+    __MULTIPLEXER( "CMccMultiplexer::CreateSourceBufferL" )
+    __ASSERT_ALWAYS( iSuggestedBufSize, User::Leave( KErrNotReady ) );
+    
+    aReference = EFalse;
+    
+    if ( iDataBuf->Data().MaxSize() < iSuggestedBufSize )
+        {
+        static_cast<CMMFDescriptorBuffer*>( iDataBuf )
+            ->ReAllocBufferL( iSuggestedBufSize );
+        }
+    
+    CMMFDataBuffer* buf = CMMFDataBuffer::NewL( iSuggestedBufSize );
+    iSuggestedBufSize = 0;
+    return buf;
+    }
+
+// -----------------------------------------------------------------------------
+// CMccMultiplexer::SuggestSourceBufferSize
+// -----------------------------------------------------------------------------
+//
+void CMccMultiplexer::SuggestSourceBufferSize( TUint aSuggestedBufferSize )
+    {
+    __MULTIPLEXER_INT1( "CMccMultiplexer::SuggestSourceBufferSize, SIZE: ",
+         aSuggestedBufferSize )
+    
+    iSuggestedBufSize = aSuggestedBufferSize;
+    }
+
+// -----------------------------------------------------------------------------
+// CMccMultiplexer::SendEventToClient
+// -----------------------------------------------------------------------------
+//
+TInt CMccMultiplexer::SendEventToClient( const TMMFEvent& aEvent )
+    {
+    __MULTIPLEXER( "CMccMultiplexer::SendEventToClient" )
+    
+    // Stream control event has to be stored at this level since control
+    // request can go back to source synchronously causing stream state change
+    // event, which then overwrites the control event.
+    //
+    if ( IS_MCC_EVENT( aEvent ) )
+	    {
+	    TMccEvent* mccEventPtr = 
+	        reinterpret_cast<const TMccInternalEvent&>( aEvent ).iMccEvent;
+	        
+	    if ( mccEventPtr && 
+	         MCC_STREAM_STATE_CHANGE_EVENT( mccEventPtr ) &&
+	         mccEventPtr->iEventNumData != KMccAutomaticEvent )
+            {
+            if ( iCurrentUser )
+                {
+                return iCurrentUser->SendEventToClient( aEvent );
+                }
+            else
+                {
+                __MULTIPLEXER( "CMccMultiplexer::SendEventToClient, KErrNotReady" )
+                return KErrNotReady;
+                }
+            }
+        
+	    if ( mccEventPtr && 
+	         mccEventPtr->iEventCategory == KMccEventCategoryStreamControl )
+	        {
+	        iStreamControlEvent = *mccEventPtr;
+	        TMccInternalEvent internalEvent( KMccMultiplexerUid, EMccInternalEventNone,
+    		                                 iStreamControlEvent );
+            
+            SendEventToAllClients( internalEvent );
+            
+            return KErrNone;
+	        }
+	    }
+	
+	SendEventToAllClients( aEvent );        
+
+    return KErrNone;
+    }
+    
+// -----------------------------------------------------------------------------
+// CMccMultiplexer::CMccMultiplexer
+// -----------------------------------------------------------------------------
+//
+CMccMultiplexer::CMccMultiplexer()
+    {
+    }
+
+// -----------------------------------------------------------------------------
+// CMccMultiplexer::ConstructL
+// -----------------------------------------------------------------------------
+//
+void CMccMultiplexer::ConstructL( MDataSource* aSource )
+    {
+    __ASSERT_ALWAYS( aSource, User::Leave( KErrArgument ) );
+    
+    iSource = aSource;
+    iDataBuf = CMMFDataBuffer::NewL( KMultiplexerDefBufSize );
+    }
+
+// -----------------------------------------------------------------------------
+// CMccMultiplexer::FindSinkItemL
+// -----------------------------------------------------------------------------
+//
+CMccSinkItem* CMccMultiplexer::FindSinkItemL( MDataSink* aSink )
+    {
+    TInt index = FindSinkItemIndex( aSink );
+    __ASSERT_ALWAYS( index != KErrNotFound, User::Leave( KErrNotFound ) );
+    
+    return iSinkItems[ index ];
+    }
+    
+// -----------------------------------------------------------------------------
+// CMccMultiplexer::FindSinkItemIndex
+// -----------------------------------------------------------------------------
+//
+TInt CMccMultiplexer::FindSinkItemIndex( MDataSink* aSink )
+    {
+    for ( TInt i = 0; i < iSinkItems.Count(); i++ )
+        {
+        if ( iSinkItems[ i ]->Match( aSink ) )
+            {
+            return i;
+            }
+        }
+    return KErrNotFound;
+    }
+
+// -----------------------------------------------------------------------------
+// CMccMultiplexer::CanCommandSource
+// Primary sink has always preferred access to source, other sinks can use
+// source only if primary is not using it
+// -----------------------------------------------------------------------------
+// 
+TBool CMccMultiplexer::CanCommandSource( MDataSink* aSink )
+    {
+    TBool canCommandSource( EFalse );
+    if ( IsPrimarySink( aSink ) )
+        {
+        canCommandSource = ETrue;
+        }
+    else if ( iSinkItems.Count() > 0 && 
+              !IsActiveState( iSinkItems[ 0 ]->MultiplexerState() ) )
+        {
+        canCommandSource = ETrue;
+        }
+    else
+        {
+        // NOP
+        }
+    return canCommandSource;
+    }
+    
+// -----------------------------------------------------------------------------
+// CMccMultiplexer::IsPrimarySink
+// -----------------------------------------------------------------------------
+//    
+TBool CMccMultiplexer::IsPrimarySink( MDataSink* aSink )
+    {
+    // Primary sink is always the first one
+    return ( iSinkItems.Count() > 0 && iSinkItems[ 0 ]->Match( aSink ) );
+    }
+    
+// -----------------------------------------------------------------------------
+// CMccMultiplexer::DoBufferFilledL
+// -----------------------------------------------------------------------------
+//
+void CMccMultiplexer::DoBufferFilledL( 
+    CMMFBuffer* aBuffer, 
+    const TRtpRecvHeader* aRtpHeader )
+    {
+    TUid mediaType = KNullUid;
+    iDataBuf->SetStatus( EFull );
+    
+    if ( iResolveFilledBufferMediaType )
+        {
+        for ( TInt i = 0; i < iSinkItems.Count() && mediaType == KNullUid; i++ )
+            {
+            mediaType = iSinkItems[ i ]->ResolveMediaType( aBuffer );
+            }
+        }
+        
+    for ( TInt i = 0; i < iSinkItems.Count(); i++ )
+        {
+        // First item is always the primary sink, but multiplexer can be
+        // also set into mode where all fillbuffer requests are passed to the
+        // source (i.e. all sinks are kind of primary ones). In such case,
+        // incoming buffer must match the one which was given when fillbuffer
+        // request was issued (i.e. source cannot return different buffer).
+        TBool isPrimary( !i );
+        
+        iSinkItems[ i ]->BufferFilledL( aBuffer, 
+                                        aRtpHeader, 
+                                        isPrimary,
+                                        mediaType );
+        }
+    }   
+
+// -----------------------------------------------------------------------------
+// CMccMultiplexer::AddSinkL
+// -----------------------------------------------------------------------------
+//  
+void CMccMultiplexer::AddSinkL( 
+    MDataSink* aSink, 
+    TBool aSinkIsDecoder,
+    TUid aMediaType,
+    TBool aPassAllBuffersSink )
+    {
+    __ASSERT_ALWAYS( FindSinkItemIndex( aSink ) == KErrNotFound, 
+                     User::Leave( KErrAlreadyExists ) );
+    
+    CMccSinkItem* item = CMccSinkItem::NewLC( aSink, 
+                                              aSinkIsDecoder, 
+                                              aMediaType, 
+                                              aPassAllBuffersSink );
+    iSinkItems.AppendL( item );
+    CleanupStack::Pop( item );
+    
+    // Update sinks
+    UpdateSinkModes();
+    }
+
+// -----------------------------------------------------------------------------
+// CMccMultiplexer::SetMultiplexerState
+// -----------------------------------------------------------------------------
+//    
+TBool CMccMultiplexer::SetMultiplexerState( TMccMultiplexerState aState )
+    {
+    __MULTIPLEXER_INT1( "CMccMultiplexer::SetMultiplexerState, state:", aState )
+    
+    // If state of the multiplexed source is already what is tried to be set,
+    // multiplexer generates the corresponding completion event
+    TBool controlSource( iState != aState );
+    
+    TMccEventType eventType = KMccEventNone;
+    
+    switch ( aState )
+        {
+        case EPrepared:
+            {
+            eventType = KMccStreamPrepared;
+            
+            if ( iState == EPlaying || iState == EResourcePaused )
+                {
+                controlSource = EFalse;
+                }
+            else
+                {
+                iState = aState;
+                }
+            break;
+            }
+        case EPlaying:
+            {
+            eventType = KMccStreamStarted;
+            iState = aState;
+            break;
+            }
+        case EResourcePaused:
+            {
+            eventType = KMccStreamPaused;
+            iState = aState;
+            break;
+            }
+        case EResourceStopped:
+            {
+            eventType = KMccStreamStopped;
+            iState = aState;
+            break;
+            }
+        default:
+            {
+            break;
+            }
+        }
+    
+    if ( iCurrentUser )
+        {
+        iCurrentUser->SetMultiplexerState( iState );
+        }
+        
+    if ( eventType != KMccEventNone && !controlSource )
+        {
+        SendStreamEventToClient( eventType );
+        }
+        
+    return controlSource;
+    }
+    
+// -----------------------------------------------------------------------------
+// CMccMultiplexer::SendStreamEventToClient
+// -----------------------------------------------------------------------------
+//     
+void CMccMultiplexer::SendStreamEventToClient( TMccEventType& aEventType )
+    {
+    __MULTIPLEXER( "CMccMultiplexer::SendStreamEventToClient" )
+    
+   	TMccEvent event( 0, 
+                     0, 
+                     0, 
+                     MCC_ENDPOINT_ID( iSource ), 
+                     KMccEventCategoryStream, 
+                     aEventType, 
+                     KErrNone, 
+                     KNullDesC8 );
+   
+    TMccInternalEvent internalEvent( KMccMultiplexerUid, 
+                                     EMccInternalEventNone,
+                                     event );
+                                     
+    if ( iCurrentUser )
+        {
+        __MULTIPLEXER( "CMccMultiplexer::SendStreamEventToClient, sending to current user" )
+        
+        iCurrentUser->SendEventToClient( internalEvent );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CMccMultiplexer::UpdateSinkModes
+// -----------------------------------------------------------------------------
+//
+void CMccMultiplexer::UpdateSinkModes()
+    {
+    __MULTIPLEXER( "CMccMultiplexer::UpdateSinkModes" )
+    
+    // Check if mediatype has to be resolved for each filled buffer
+    iResolveFilledBufferMediaType = EFalse;
+    
+    for ( TInt i = 0; i < iSinkItems.Count(); i++ )
+        {
+        TBool passAllRequestsToSource = PassAllRequestsToSource( *iSinkItems[ i ] );
+        iSinkItems[ i ]->SetSourceMode( passAllRequestsToSource );
+        
+        iResolveFilledBufferMediaType |= passAllRequestsToSource;
+        }
+    
+    __MULTIPLEXER_INT1( "CMccMultiplexer::UpdateSinkModes, resolve buffers mode:", 
+                        iResolveFilledBufferMediaType  )     
+    __MULTIPLEXER( "CMccMultiplexer::UpdateSinkModes, exit" )
+    }
+    
+// -----------------------------------------------------------------------------
+// CMccMultiplexer::PassAllRequestsToSource
+// -----------------------------------------------------------------------------
+//   
+TBool CMccMultiplexer::PassAllRequestsToSource( CMccSinkItem& aItem ) const
+    {
+    // If source is filesource, it can support two primary sinks; one for audio
+    // and one for video.
+    //
+
+    if ( iSource->DataSourceType() == KMccFileSourceUid )
+        {
+        TUid mediaType = aItem.MediaType();
+        for ( TInt i = 0; i < iSinkItems.Count(); i++ )
+            {
+            // If sinkitem has highest preference from group of sinkitems of same
+            // media type, all its requests can be passed to the source
+            if ( mediaType == iSinkItems[ i ]->MediaType() )
+                {
+                return ( iSinkItems[ i ] == &aItem );
+                }
+            }
+        }
+    else if ( iSource->DataSourceType() == KMccRtpSourceUid )
+        {
+        // Payload type multiplexing is used with network resource. Multiple
+        // clients are allowed to request fillbuffer from RTP-source.
+        return ETrue;
+        }
+    else
+        {
+        // Make PC-LINT happy
+        }
+    
+    return EFalse;
+    }
+
+// -----------------------------------------------------------------------------
+// CMccMultiplexer::IsSupportedMediaType
+// -----------------------------------------------------------------------------
+//    
+TBool CMccMultiplexer::IsSupportedMediaType( TUid aMediaType ) const
+    {
+    return ( aMediaType == KUidMediaTypeVideo || 
+             aMediaType == KUidMediaTypeAudio );
+    }
+
+// -----------------------------------------------------------------------------
+// CMccMultiplexer::SendEventToAllClients
+// -----------------------------------------------------------------------------
+// 
+void CMccMultiplexer::SendEventToAllClients( const TMMFEvent& aEvent )
+    {
+    for ( TInt i = 0; i < iSinkItems.Count(); i++ )
+        {
+        iSinkItems[ i ]->SendEventToClient( aEvent );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CMccMultiplexer::HandleCleanup
+// -----------------------------------------------------------------------------
+//
+void CMccMultiplexer::HandleCleanup( 
+    CMccSinkItem* aSinkItem, 
+    TBool aPassedAllRequests )
+    {
+    TRAP_IGNORE( HandleCleanupL( aSinkItem, aPassedAllRequests ) )
+    delete aSinkItem;
+    }
+    
+// -----------------------------------------------------------------------------
+// CMccMultiplexer::HandleCleanupL
+// -----------------------------------------------------------------------------
+//
+void CMccMultiplexer::HandleCleanupL( 
+    CMccSinkItem* aSinkItem,
+    TBool aPassedAllRequests )
+    {
+    __MULTIPLEXER( "CMccMultiplexer::HandleCleanupL" )
+    
+     if ( iSinkItems.Count() == 0 )
+        {
+        // If no more sinks, source can be logged off
+        iSource->SourceThreadLogoff();
+        iSourceLogonDone = EFalse;
+        }
+     else
+        {      
+        // Update source's sinkbuffer (may be also NULL) and user info
+        
+        if ( aSinkItem )
+            {
+            if ( aPassedAllRequests )
+                {
+                __MULTIPLEXER( "CMccMultiplexer::HandleCleanupL, clear old" )
+                iSource->FillBufferL( NULL, this, TMediaId( aSinkItem->MediaType() ) );
+                }
+            
+            if ( MCC_INTERNAL_ENDPOINT( iSource->DataSourceType().iUid ) )
+                {
+                static_cast<CMccDataSource*>( 
+                    iSource )->RemoveUser( aSinkItem->EventHandler() );
+                }
+            }
+            
+        CMMFBuffer* newPrimaryBuf = iSinkItems[ 0 ]->RequestedBuffer();
+        
+        if ( newPrimaryBuf && KMccRtpSourceUid == iSource->DataSourceType() )
+            {
+            // When payload type multiplexing, multiplexer's own buffer is used
+            newPrimaryBuf = iDataBuf;
+            }
+        
+        __MULTIPLEXER( "CMccMultiplexer::HandleCleanupL, set new" )    
+        iSource->FillBufferL( newPrimaryBuf, 
+                              this, 
+                              TMediaId( iSinkItems[ 0 ]->MediaType() ) );
+        }
+    
+    __MULTIPLEXER( "CMccMultiplexer::HandleCleanupL, exit" )
+    }
+    
+// -----------------------------------------------------------------------------
+// CMccMultiplexer::IsActiveState
+// -----------------------------------------------------------------------------
+//
+TBool CMccMultiplexer::IsActiveState( TMccMultiplexerState aState ) const
+    {
+    return ( aState == EPlaying );
+    }
+    
+// ========================== OTHER EXPORTED FUNCTIONS =========================
+
+// -----------------------------------------------------------------------------
+// E32Dll.
+// DLL Entry point
+// Returns: KErrNone
+// -----------------------------------------------------------------------------
+//
+#ifndef EKA2
+EXPORT_C TInt E32Dll( TDllReason )
+    {
+    return KErrNone;
+    }
+#endif
+
+
+//  End of File 
+