multimediacommscontroller/mmccmultiplexer/src/mccmultiplexer.cpp
author William Roberts <williamr@symbian.org>
Thu, 22 Jul 2010 16:37:27 +0100
branchGCC_SURGE
changeset 36 e07c9cb4153d
parent 0 1bce908db942
permissions -rw-r--r--
Catchup to latest Symbian^4

/*
* 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