/*
* 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/devvideo/devvideobase.h>
#include <mmcccodecinformationfactory.h>
#include <mmcccodecinformation.h>
#include "mccvideosourceimpl.h"
#include "mccinternalcodecs.h"
#include "mmcccodecinformation.h"
#include "mmcccodech263.h"
#include "mmcccodecavc.h"
#include "mccvideosourcewrapper.h"
#include "mccvideosourcesinklogs.h"
#include "mccinternalevents.h"
#include "mmccinterfacedef.h"
#include "mccrateadaptationdef.h"
#include "mccdef.h"
#include "mccinternaldef.h"
#include "mccvideosourcekeyretriever.h"
#include "mccresources.h"
    
_LIT8(KVideoCodecFourCC, "video/%S; %S");

const TInt KMccMaxVideoQueueSize = 10;
const TUint KMccBitrateTooLowLimit = 20000;

// ============================ MEMBER FUNCTIONS ===============================

// -----------------------------------------------------------------------------
// CMccVideoSourceImpl::NewL
// -----------------------------------------------------------------------------
//
CMccVideoSourceImpl* CMccVideoSourceImpl::NewL( 
    TUint32 aEndpointId, MMccResources* aMccResources, TBool aConfigKeyRetrieval )
    {
    CMccVideoSourceImpl* self = new ( ELeave ) CMccVideoSourceImpl( 
            aEndpointId, aMccResources, aConfigKeyRetrieval );
    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop( self );
    return self;
    }

// -----------------------------------------------------------------------------
// CMccVideoSourceImpl::ConstructL
// -----------------------------------------------------------------------------
//
void CMccVideoSourceImpl::ConstructL()
    {
	iMediaRecorder = CMccVideoSourceWrapper::NewL(*this, *this);
    iVideoCodec.iFourCC = TFourCC();
    iAudioFourCC = TFourCC();
    iFrameRate = KMccDefaultVideoFrameRate;
    }
    
// -----------------------------------------------------------------------------
// CMccVideoSourceImpl::CMccVideoSourceImpl
// -----------------------------------------------------------------------------
//
CMccVideoSourceImpl::CMccVideoSourceImpl( 
    TUint32 aEndpointId, MMccResources* aMccResources, TBool aConfigKeyRetrieval ) : 
    iAudioEnabled( EFalse ),
    iEndpointId( aEndpointId ),
    iMccResources( aMccResources ),
    iConfigKeyRetrieval( aConfigKeyRetrieval )
	{
    }
        
// -----------------------------------------------------------------------------
// CMccVideoSourceImpl::~CMccVideoSourceImpl 
// -----------------------------------------------------------------------------
//
CMccVideoSourceImpl::~CMccVideoSourceImpl()
    {
    __V_SOURCESINK_CONTROLL( "CMccVideoSourceImpl::~CMccVideoSourceImpl" )
    
    StopCameraMonitoring();
        
    if ( iMediaRecorder )
        {
        TRAP_IGNORE( iMediaRecorder->StopL() )
        }

	delete iVideoCodecFourCC;
	delete iMediaRecorder;
	iAsyncEventHandler = NULL;
	
	iVideoQueue.ResetAndDestroy();
	
	delete iConfigKey;	
	delete iConfigKeyData;
	
	__V_SOURCESINK_CONTROLL( "CMccVideoSourceImpl::~CMccVideoSourceImpl, exit" )
    }

// -----------------------------------------------------------------------------
// CMccVideoSourceImpl::SetResources
// -----------------------------------------------------------------------------
//
void CMccVideoSourceImpl::SetResources( MMccResources* aResources )
	{
	__V_SOURCESINK_CONTROLL( "CMccVideoSourceImpl::SetResources" )		

	iMccResources = aResources;
	}
	
// -----------------------------------------------------------------------------
// CMccVideoSourceImpl::SetCameraHandler
// -----------------------------------------------------------------------------
//
void CMccVideoSourceImpl::SetCameraHandler( MMccCameraHandler& aCameraHandler )
	{
	__V_SOURCESINK_CONTROLL( "CMccVideoSourceImpl::SetCameraHandler" )		

	iCameraHandler = &aCameraHandler;
	}

// -----------------------------------------------------------------------------
// CMccVideoSourceImpl::SourcePrimeL
// -----------------------------------------------------------------------------
//
void CMccVideoSourceImpl::SourcePrimeL( TBool aMultipleCodecs )
	{
    __V_SOURCESINK_CONTROLL( "CMccVideoSourceImpl::SourcePrimeL" )
    __ASSERT_ALWAYS( iMediaRecorder, User::Leave( KErrNotReady ) );
    __ASSERT_ALWAYS( iCameraHandler, User::Leave( KErrNotReady ) );

    iMultipleCodecs = aMultipleCodecs;
    
    if ( !iCameraHandler->IsCameraReady() )
        {
        __V_SOURCESINK_CONTROLL( "CMccVideoSourceImpl::SourcePrimeL, camera not ready" )
        
        HandleCameraReservationL();
        }
    else if ( iMediaRecorder->State() == CCMRMediaRecorder::EStateNone )
        {       
        if ( !FullPrepareAllowed() )
            {
            __V_SOURCESINK_CONTROLL( "CMccVideoSourceImpl::SourcePrimeL, prepare partially" )
            
            // Cannot prepare recorder yet fully, fake preparing and do it
            // later automatically once recording is started
            SendStreamEventToClient( KMccStreamPrepared, KErrNone, KMccAutomaticEvent );
            }
        else
            {
            __V_SOURCESINK_CONTROLL( "CMccVideoSourceImpl::SourcePrimeL, prepare fully" )
            
            TUid encoderUid( KNullUid );
            DoCodecSpecificConfigurationL( encoderUid );
            
            __ASSERT_ALWAYS( iVideoCodecFourCC, User::Leave( KErrNotReady ) );
            	
            __V_SOURCESINK_CONTROLL( "CMccVideoSourceImpl::SourcePrimeL, opening source" )		
        	iMediaRecorder->OpenL( iAudioSource, iCameraHandler->Handle(), 
        		*iVideoCodecFourCC, iAudioFourCC, encoderUid ) ;
            }
        }
    else
        {
        __V_SOURCESINK_CONTROLL( "CMccVideoSourceImpl::SourcePrimeL, not priming" )
        }

    __V_SOURCESINK_CONTROLL( "CMccVideoSourceImpl::SourcePrimeL, exit" )
	}

// -----------------------------------------------------------------------------
// CMccVideoSourceImpl::SourcePlayL()
// -----------------------------------------------------------------------------
//
void CMccVideoSourceImpl::SourcePlayL()
    {
    __V_SOURCESINK_CONTROLL( "CMccVideoSourceImpl::SourcePlayL" )
    
    TMccEventType event = KMccEventNone;
    TUint32 eventNumData = 0;
    iMultipleCodecs = EFalse;
    
    if ( iMediaRecorder->State() == CCMRMediaRecorder::EStateNone )
        {
        __V_SOURCESINK_CONTROLL( "CMccVideoSourceImpl::SourcePlayL, \
not prepared, prepare in autoplay mode" )
        SetAutoPlayMode( ETrue );
        SourcePrimeL();
        }
    else if ( iMediaRecorder->State() == CCMRMediaRecorder::EStateReadyToRecord )
        {        
	    iMediaRecorder->PlayL();
	    if ( AutoPlayMode() )
	        {
	        event = KMccStreamResumed;
	        eventNumData = KMccAutomaticEvent;
	        SetAutoPlayMode( EFalse );
	        }
	    else
	        {
	        event = KMccStreamStarted;
	        }
        }
    else
        {
        __V_SOURCESINK_CONTROLL( "CMccVideoSourceImpl::SourcePlayL, \
already playing or stopping" )
        }
        
    if ( event != KMccEventNone && !AutoPlayMode() )
        {
        SendStreamEventToClient( event, KErrNone, eventNumData );
        }
    
    __V_SOURCESINK_CONTROLL( "CMccVideoSourceImpl::SourcePlayL, exit" )
    }

// -----------------------------------------------------------------------------
// CMccVideoSourceImpl::SourcePauseL()
// -----------------------------------------------------------------------------
//
void CMccVideoSourceImpl::SourcePauseL()
    {
    __V_SOURCESINK_CONTROLL( "CMccVideoSourceImpl::SourcePauseL")
    
    iVideoConsumer = NULL;
	iVideoConsumerBuffer = NULL;
	SetAutoPlayMode( EFalse );
	
	StopCameraMonitoring();
	    
    // Always stop the recorder, this will free camera resources
    iMediaRecorder->StopL();
    
    iVideoQueue.ResetAndDestroy();
    
    SendStreamEventToClient( KMccStreamPaused );
    	
    __V_SOURCESINK_CONTROLL( "CMccVideoSourceImpl::SourcePauseL, exit")
	}

// -----------------------------------------------------------------------------
// CMccVideoSourceImpl::SourceStopL()
// -----------------------------------------------------------------------------
//
void CMccVideoSourceImpl::SourceStopL()
    {
    __V_SOURCESINK_CONTROLL( "CMccVideoSourceImpl::SourceStopL" )
    __V_SOURCESINK_MEDIA_INT1("CMccVideoSourceImpl::SourceStopL, thread", \
        RThread().Id().operator TUint());
	iVideoConsumer = NULL;
	iVideoConsumerBuffer = NULL;
	iMultipleCodecs = EFalse;
	iMediaRecorder->StopL();

    iVideoQueue.ResetAndDestroy();
    
    SendStreamEventToClient( KMccStreamStopped );
    
    __V_SOURCESINK_CONTROLL( "CMccVideoSourceImpl::SourceStopL, exit" )
    }

// -----------------------------------------------------------------------------
// CMccVideoSourceImpl::SourceDataTypeCode()
// -----------------------------------------------------------------------------
//
TFourCC CMccVideoSourceImpl::SourceDataTypeCode( TMediaId aMediaId )
	{
    __V_SOURCESINK_CONTROLL( "CMccVideoSourceImpl::SourceDataTypeCode" )

    if ( KUidMediaTypeVideo == aMediaId.iMediaType )
        {
        return iVideoCodec.iFourCC;
        }
    else if ( KUidMediaTypeAudio == aMediaId.iMediaType  )
        {
        return iAudioFourCC;
        }
    else
        {
        return TFourCC( KMMFFourCCCodeNULL );
        }
	}
	
// -----------------------------------------------------------------------------
// CMccVideoSourceImpl::SetSourceDataTypeCode()
// -----------------------------------------------------------------------------
//
TInt CMccVideoSourceImpl::SetSourceDataTypeCode( 
    TFourCC aCodec, 
    TMediaId aMediaId )
	{
    __V_SOURCESINK_CONTROLL( "CMccVideoSourceImpl::SetSourceDataTypeCode" )

    if ( KUidMediaTypeVideo == aMediaId.iMediaType &&
    	aCodec == iVideoCodec.iFourCC )
        {
        return KErrNone;
        }
    else if ( KUidMediaTypeAudio == aMediaId.iMediaType &&
    	aCodec == iAudioFourCC )
        {
        return KErrNone;
        }
    else
        {
        return KErrNotSupported;
        }
	}	

// -----------------------------------------------------------------------------
// CMccVideoSourceImpl::BufferEmptiedL()
// -----------------------------------------------------------------------------
//
void CMccVideoSourceImpl::BufferEmptiedL( CMMFBuffer* /*aBuffer*/ )
	{
    __V_SOURCESINK_MEDIA( "CMccVideoSourceImpl::BufferEmptiedL" )
    __ASSERT_ALWAYS( EFalse, User::Leave( KErrNotSupported ) );
	}
	
// -----------------------------------------------------------------------------
// CMccVideoSourceImpl::CanCreateSourceBuffer()
// -----------------------------------------------------------------------------
//
TBool CMccVideoSourceImpl::CanCreateSourceBuffer()
	{
    __V_SOURCESINK_CONTROLL( "CMccVideoSourceImpl::CanCreateSourceBuffer, ETrue" )
	return EFalse;
	}	

// -----------------------------------------------------------------------------
// CMccVideoSourceImpl::CreateSourceBufferL()
// -----------------------------------------------------------------------------
//
CMMFBuffer* CMccVideoSourceImpl::CreateSourceBufferL( 
    TMediaId /*aMediaId*/, 
    TBool& /*aReference*/ )
	{
	__V_SOURCESINK_CONTROLL( "CMccVideoSourceImpl::CreateSourceBufferL" )
    CMMFBuffer* buffer = NULL;
    __ASSERT_ALWAYS( EFalse, User::Leave( KErrNotSupported ) );

	return buffer;	
	}
	
// -----------------------------------------------------------------------------
// CMccVideoSourceImpl::SourceThreadLogon()
// -----------------------------------------------------------------------------
//
TInt CMccVideoSourceImpl::SourceThreadLogon( MAsyncEventHandler& aEventHandler )
	{
    __V_SOURCESINK_CONTROLL( "CMccVideoSourceImpl::SourceThreadLogon" )	
	iAsyncEventHandler = static_cast<MAsyncEventHandler*>( &aEventHandler );
	return KErrNone;
	}
	
// -----------------------------------------------------------------------------
// CMccVideoSourceImpl::SourceThreadLogoff()
// -----------------------------------------------------------------------------
//
void CMccVideoSourceImpl::SourceThreadLogoff()
	{
    __V_SOURCESINK_CONTROLL( "CMccVideoSourceImpl::SourceThreadLogoff" )
    iAsyncEventHandler = NULL;
    
    iVideoQueue.ResetAndDestroy();
	}
	
// -----------------------------------------------------------------------------
// CMccVideoSourceImpl::FillBufferL()
// -----------------------------------------------------------------------------
//
void CMccVideoSourceImpl::FillBufferL( 
    CMMFBuffer* aBuffer,
    MDataSink* aConsumer,
    TMediaId aMediaId )
	{
	__V_SOURCESINK_MEDIA( "CMccVideoSourceImpl::FillBufferL" )
    
    // Sink might want to indicate pause/stop by passing NULL buffer
    if ( aBuffer )
        {
        __ASSERT_ALWAYS ( aConsumer, User::Leave( KErrArgument ) );
        }

    if ( aMediaId.iMediaType == KUidMediaTypeVideo )
		{
    	__V_SOURCESINK_MEDIA( "CMccVideoSourceImpl::FillBufferL, video" )
	    iVideoConsumer = aConsumer;
		iVideoConsumerBuffer = aBuffer;	
			
	    WriteFirstBufferL();
		}
	else
		{
    	__V_SOURCESINK_MEDIA_INT1( "CMccVideoSourceImpl::FillBufferL, \
unknown media, type=", aMediaId.iMediaType.iUid ) 
		User::Leave( KErrNotSupported );	
		}
	}	
                  
// -----------------------------------------------------------------------------
// CMccVideoSourceImpl::NegotiateSourceL()
// -----------------------------------------------------------------------------
//
void CMccVideoSourceImpl::NegotiateSourceL( MDataSink& /*aDataSink*/ )
	{
    __V_SOURCESINK_CONTROLL( "CMccVideoSourceImpl::NegotiateSourceL" )
	}
	
// -----------------------------------------------------------------------------
// CMccVideoSourceImpl::WriteBufferL()
// -----------------------------------------------------------------------------
//
void CMccVideoSourceImpl::WriteBufferL( CCMRMediaBuffer* aBuffer )
	{
	__V_SOURCESINK_MEDIA( "CMccVideoSourceImpl::WriteBufferL" )
    
    __ASSERT_ALWAYS( aBuffer, User::Leave( KErrArgument ) );

    if ( QueueBufferL( *aBuffer ) )
        {
        WriteFirstBufferL();
        }
        
    __V_SOURCESINK_MEDIA( "CMccVideoSourceImpl::WriteBufferL, exit" )
	}
    
// -----------------------------------------------------------------------------
// CMccVideoSourceImpl::SetVideoFrameSize()
// -----------------------------------------------------------------------------
//
TInt CMccVideoSourceImpl::SetVideoFrameSize( TSize aSize )
	{
    __V_SOURCESINK_CONTROLL_INT2( 
        "CMccVideoSourceImpl::SetVideoFrameSize (from mediarecorder), width", 
        aSize.iWidth,
        " heigth", 
        aSize.iHeight )
        
    iVideoCodec.iVideoHeight = aSize.iHeight;
    iVideoCodec.iVideoWidth = aSize.iWidth;
    				
    return KErrNone;				
	}

// -----------------------------------------------------------------------------
// CMccVideoSourceImpl::SetAverageVideoBitRate()
// -----------------------------------------------------------------------------
//
TInt CMccVideoSourceImpl::SetAverageVideoBitRate( TInt aBitRate )
	{
    __V_SOURCESINK_CONTROLL_INT1( 
        "CMccVideoSourceImpl::SetAverageVideoBitRate (from mediarecorder)", 
        aBitRate )				
    iVideoCodec.iAverageBitrate = (TUint)aBitRate;
    return KErrNone;				
	}

// -----------------------------------------------------------------------------
// CMccVideoSourceImpl::SetMaxVideoBitRate()
// -----------------------------------------------------------------------------
//
TInt CMccVideoSourceImpl::SetMaxVideoBitRate( TInt aBitRate )
	{
    __V_SOURCESINK_CONTROLL_INT1( 
        "CMccVideoSourceImpl::SetMaxVideoBitRate (from mediarecorder)", 
        aBitRate )
                                  				
    // Do not reset max bitrate as mediarecorder will call back with the same
    // value which was given in SetVideoBitrate phase (i.e. value is meaningless)
    aBitRate = aBitRate; 
    return KErrNone;				
	}

// -----------------------------------------------------------------------------
// CMccVideoSourceImpl::SetAverageAudioBitRate()
// -----------------------------------------------------------------------------
//
TInt CMccVideoSourceImpl::SetAverageAudioBitRate( TInt aBitRate )
	{
    __V_SOURCESINK_CONTROLL_INT1( 
        "CMccVideoSourceImpl::SetAverageAudioBitRate (from mediarecorder)", 
        aBitRate )
    iAverageAudioBitRate = aBitRate;
    return KErrNone;				
	}
		
// -----------------------------------------------------------------------------
// CMccVideoSourceImpl::MmroPrepareComplete()
// -----------------------------------------------------------------------------
//
void CMccVideoSourceImpl::MmroPrepareComplete( TInt aError )    
	{
    __V_SOURCESINK_CONTROLL_INT1( "CMccVideoSourceImpl::MmroPrepareComplete=", aError )
	
	if ( !aError )
    	{	
    	aError = SetVideoBitrate( iVideoCodec.iBitrate );  
        if ( !aError )
            {
            TRAP( aError, iMediaRecorder->SetVideoFrameRateL( iVideoCodec.iFramerate ) );
            
            if ( !aError )
                {
                TRateControlOptions options;
                TRAP( aError, iMediaRecorder->GetVideoRateControlOptionsL( options ) );
                if ( !aError )
                    {
                    __V_SOURCESINK_CONTROLL_INT1( 
                        "Ratecontrol options:: control:", options.iControl )
                    __V_SOURCESINK_CONTROLL_INT1( 
                        "Ratecontrol options:: bitrate:", options.iBitrate )
                    __V_SOURCESINK_CONTROLL_INT1( 
                        "Ratecontrol options:: quality:", options.iPictureQuality )
                    __V_SOURCESINK_CONTROLL_REAL( 
                        "Ratecontrol options:: rate:", options.iPictureRate )
                    __V_SOURCESINK_CONTROLL_REAL( 
                        "Ratecontrol options:: qtt:", options.iQualityTemporalTradeoff )
                    __V_SOURCESINK_CONTROLL_REAL( 
                        "Ratecontrol options:: lqt:", options.iLatencyQualityTradeoff )
        
                    // Enable constant bitrate (CBR i.e. more strict bitrate control)
                    options.iLatencyQualityTradeoff = KMccLatencyQyalityTradeoff; 
                    
					__V_SOURCESINK_CONTROLL( "CMccVideoSourceImpl::MmroPrepareComplete, set CBR" )
                    TRAP( aError, iMediaRecorder->SetVideoRateControlOptionsL( options ) );
                    }
                }
            }
    	}
    	
    	
	if ( AutoPlayMode() && !aError )
	    {
	    __V_SOURCESINK_CONTROLL( "CMccVideoSourceImpl::MmroPrepareComplete, autoplay" )
	    
	    TRAPD( err, SourcePlayL() );
	    if ( err )
	        {
            SendStreamEventToClient( KMccStreamPrepared, err, KMccAutomaticEvent );
	        }
	    }
	else
	    { 
        SendStreamEventToClient( KMccStreamPrepared, aError, KMccAutomaticEvent );
	    }
	}

// -----------------------------------------------------------------------------
// CMccVideoSourceImpl::MmroStateChange()
// -----------------------------------------------------------------------------
//
void CMccVideoSourceImpl::MmroStateChange( TInt aState, TInt aError )
	{
    __V_SOURCESINK_CONTROLL_INT2( "CMccVideoSourceImpl::MmroStateChange, \
aState=", aState, "aError=", aError )

	if ( aError )
		{
		SendStreamEventToClient( KMccStreamError, aError );
		}
	else
		{
		switch ( aState )
			{
		    case CCMRMediaRecorder::EStateNone:
		        {	
		        __V_SOURCESINK_CONTROLL_INT1( "CMccVideoSourceImpl::MmroStateChange, \
aState=EStateNone, aError=", aError )
		        }
		        break;
		    case CCMRMediaRecorder::EStateOpen:
		        {
		        __V_SOURCESINK_CONTROLL_INT1( "CMccVideoSourceImpl::MmroStateChange, \
aState=EStateOpen, aError=", aError )	
		        }
		        break;
		    case CCMRMediaRecorder::EStatePreparing:
		        {
		        __V_SOURCESINK_CONTROLL_INT1( "CMccVideoSourceImpl::MmroStateChange, \
aState=EStatePreparing, aError=", aError )			        	
		        }
		        break;
		    case CCMRMediaRecorder::EStateRecording:
		        {
		        __V_SOURCESINK_CONTROLL_INT1( "CMccVideoSourceImpl::MmroStateChange, \
aState=EStateRecording, aError=", aError )		        	
		        }
		        break;
		    case CCMRMediaRecorder::EStatePausing:
		        {
		        __V_SOURCESINK_CONTROLL_INT1( "CMccVideoSourceImpl::MmroStateChange, \
aState=EStatePausing, aError=", aError )			        	
		        }
		        break;
			case CCMRMediaRecorder::EStateStopping:
			    {
		        __V_SOURCESINK_CONTROLL_INT1( "CMccVideoSourceImpl::MmroStateChange, \
aState=EStateStopping, aError=", aError )			        	
		        }
		        break;
		    case CCMRMediaRecorder::EStateReadyToRecord:
		    	{
		        __V_SOURCESINK_CONTROLL_INT1( "CMccVideoSourceImpl::MmroStateChange, \
aState=EStateReadyToRecord, aError=", aError )	
		       	}
		        break;
		    case CCMRMediaRecorder::EStatePaused:
		        {
		        __V_SOURCESINK_CONTROLL_INT1( "CMccVideoSourceImpl::MmroStateChange, \
aState=EStatePaused, aError=", aError )	
		        }
		        break;
		    default:
		        break;
			}	
		}
	}

// -----------------------------------------------------------------------------
// CMccVideoSourceImpl::MmroTemporaryError()
// -----------------------------------------------------------------------------
//
void CMccVideoSourceImpl::MmroTemporaryError( TInt aError )    
	{
    __V_SOURCESINK_CONTROLL_INT1( "CMccVideoSourceImpl::MmroTemporaryError=", 
                                  aError )   
    
    SendStreamEventToClient( KMccStreamError, aError );                         
	}

// -----------------------------------------------------------------------------
// CMccVideoSourceImpl::MmroFatalError()
// -----------------------------------------------------------------------------
//
void CMccVideoSourceImpl::MmroFatalError( TInt aError )
	{
    __V_SOURCESINK_CONTROLL_INT1( "CMccVideoSourceImpl::MmroFatalError=", aError )
    
    SendStreamEventToClient( KMccStreamError, aError );
	}

// -----------------------------------------------------------------------------
// CMccVideoSourceImpl::CameraReady()
// -----------------------------------------------------------------------------
//	
void CMccVideoSourceImpl::CameraReady( TInt aError )
    {
    __V_SOURCESINK_CONTROLL_INT1( "CMccVideoSourceImpl::CameraReady", aError )
    
    if ( !aError )
        {
        TRAP( aError, SourcePrimeL( iMultipleCodecs ) );
        }
    
    if ( aError )
        {
        SendStreamEventToClient( KMccStreamError, aError );
        }
    }

// -----------------------------------------------------------------------------
// CMccVideoSourceImpl::SetVideoCodecL()
// -----------------------------------------------------------------------------
//
void CMccVideoSourceImpl::SetVideoCodecL( const TMccCodecInfo& aVideoCodec )
	{
    __V_SOURCESINK_CONTROLL( "CMccVideoSourceImpl::SetVideoCodecL " )
    
    iVideoCodec = aVideoCodec;	

    if ( iVideoCodec.iConfigKey.Length() > 0 && !iConfigKey )
        {
        __V_SOURCESINK_CONTROLL( "Setting config key" )
        iConfigKey = iVideoCodec.iConfigKey.AllocL();
        }

    __V_SOURCESINK_CONTROLL_INT1( "CMccVideoSourceImpl::SetVideoCodecL, iVideoHeight ", 
        iVideoCodec.iVideoHeight )
    __V_SOURCESINK_CONTROLL_INT1( "CMccVideoSourceImpl::SetVideoCodecL, iVideoWidth ", 
        iVideoCodec.iVideoWidth )
    __V_SOURCESINK_CONTROLL_INT1( "CMccVideoSourceImpl::SetVideoCodecL, iVideoFourCC ", 
        iVideoCodec.iFourCC.FourCC() )
    __V_SOURCESINK_CONTROLL_INT1( "CMccVideoSourceImpl::SetVideoCodecL, iVideoBitRate ",
        iVideoCodec.iBitrate )
    __V_SOURCESINK_CONTROLL_INT1( "CMccVideoSourceImpl::SetVideoCodecL, iAverageVideoBitRate ", 
        iVideoCodec.iAverageBitrate )
    __V_SOURCESINK_CONTROLL_INT1( "CMccVideoSourceImpl::SetVideoCodecL, iMaxVideoBitRate ", 
        iVideoCodec.iMaxBitrate )
    __V_SOURCESINK_CONTROLL_INT1( "CMccVideoSourceImpl::SetVideoCodecL, iVideoCodecMode ", 
        iVideoCodec.iCodecMode )
    __V_SOURCESINK_CONTROLL_REAL( "CMccVideoSourceImpl::SetVideoCodecL, iFrameRate ", 
        iVideoCodec.iFramerate )
	}
	
// -----------------------------------------------------------------------------
// CMccVideoSourceImpl::GetVideoCodecL()
// -----------------------------------------------------------------------------
//
void CMccVideoSourceImpl::GetVideoCodecL( TMccCodecInfo& aVideoCodec )
	{
    __V_SOURCESINK_CONTROLL( "CMccVideoSourceImpl::GetVideoCodecL " )
    
    aVideoCodec = iVideoCodec;
	}

// -----------------------------------------------------------------------------
// CMccVideoSourceImpl::GetSupportedVideoCodecsL()
// -----------------------------------------------------------------------------
//
void CMccVideoSourceImpl::GetSupportedVideoCodecsL( RArray<TFourCC>& /*aVideoTypes*/ )
	{
	__V_SOURCESINK_CONTROLL( "CMccVideoSourceImpl::GetSupportedVideoCodecsL " )
	}

// -----------------------------------------------------------------------------
// CMccVideoSourceImpl::SetAudioCodecL()
// -----------------------------------------------------------------------------
//
void CMccVideoSourceImpl::SetAudioCodecL( const TMccCodecInfo& aAudioCodec )
	{
	__V_SOURCESINK_CONTROLL( "CMccVideoSourceImpl::SetAudioCodecL" )
	iAudioFourCC = aAudioCodec.iFourCC;
    iAverageAudioBitRate = aAudioCodec.iAverageBitrate;
	}

// -----------------------------------------------------------------------------
// CMccVideoSourceImpl::GetAudioCodecL()
// -----------------------------------------------------------------------------
//
void CMccVideoSourceImpl::GetAudioCodecL( TMccCodecInfo& aAudioCodec )
	{
	__V_SOURCESINK_CONTROLL( "CMccVideoSourceImpl::GetAudioCodecL" )

	aAudioCodec.iFourCC = iAudioFourCC;
    aAudioCodec.iAverageBitrate = iAverageAudioBitRate;
	}

// -----------------------------------------------------------------------------
// CMccVideoSourceImpl::GetSupportedAudioCodecsL()
// -----------------------------------------------------------------------------
//
void CMccVideoSourceImpl::GetSupportedAudioCodecsL( RArray<TFourCC>& /*aAudioTypes*/ )
	{
	__V_SOURCESINK_CONTROLL( "CMccVideoSourceImpl::GetSupportedAudioCodecsL" )
	}

// -----------------------------------------------------------------------------
// CMccVideoSourceImpl::SetAudioEnabledL()
// -----------------------------------------------------------------------------
//
void CMccVideoSourceImpl::SetAudioEnabledL( TBool aEnabled )
	{
	__V_SOURCESINK_CONTROLL( "CMccVideoSourceImpl::SetAudioEnabledL" )
	iAudioEnabled = aEnabled;
	}

// -----------------------------------------------------------------------------
// CMccVideoSourceImpl::AudioEnabledL()
// -----------------------------------------------------------------------------
//
TBool CMccVideoSourceImpl::AudioEnabledL() const
	{
	__V_SOURCESINK_CONTROLL( "CMccVideoSourceImpl::AudioEnabledL" )
	return iAudioEnabled;
	}

// -----------------------------------------------------------------------------
// CMccVideoSourceImpl::SetGainL()
// -----------------------------------------------------------------------------
//
void CMccVideoSourceImpl::SetGainL( TInt aGain )
	{
	__V_SOURCESINK_CONTROLL( "CMccVideoSourceImpl::SetGainL" )
	iAudioGain = aGain;
	}

// -----------------------------------------------------------------------------
// CMccVideoSourceImpl::GainL()
// -----------------------------------------------------------------------------
//
TInt CMccVideoSourceImpl::GainL() const
	{
	__V_SOURCESINK_CONTROLL( "CMccVideoSourceImpl::GainL" )

	return iAudioGain;
	}

// -----------------------------------------------------------------------------
// CMccVideoSourceImpl::MaxGainL()
// -----------------------------------------------------------------------------
//
TInt CMccVideoSourceImpl::MaxGainL() const
	{
	__V_SOURCESINK_CONTROLL( "CMccVideoSourceImpl::MaxGainL" )
	return iAudioGain;	
	}

// -----------------------------------------------------------------------------
// CMccVideoSourceImpl::RateAdaptationRequest
// -----------------------------------------------------------------------------
//     
TInt CMccVideoSourceImpl::RateAdaptationRequest( 
    const TMccEvent& aInputData, 
    TMccEvent& aOutputData )
    {
    __V_SOURCESINK_CONTROLL( "CMccVideoSourceImpl::RateAdaptationRequest, entry" )

    TRAPD( err, RateAdaptationRequestL( aInputData, aOutputData ) );
    
    __V_SOURCESINK_CONTROLL_INT1( 
        "CMccVideoSourceImpl::RateAdaptationRequest, exit with err:", err )
    
    return err;
    }

// -----------------------------------------------------------------------------
// CMccVideoSourceImpl::IsStopped()
// -----------------------------------------------------------------------------
//   
TBool CMccVideoSourceImpl::IsStopped() const
    {
    return ( iMediaRecorder->State() == CCMRMediaRecorder::EStateNone );
    }

// -----------------------------------------------------------------------------
// CMccVideoSourceImpl::GetConfigKeyL()
// -----------------------------------------------------------------------------
//
void CMccVideoSourceImpl::GetConfigKeyL( 
    const TMccCodecInfo& aVideoCodec, 
    TDes8& aConfigKey,
    TBool aAllowAsyncRetrieval )
    {
    __V_SOURCESINK_CONTROLL( "CMccVideoSourceImpl::GetConfigKeyL" )
    
    if ( iConfigKey )
        {
        __ASSERT_ALWAYS( iConfigKey->Length() <= aConfigKey.MaxLength(), 
                         User::Leave( KErrArgument ) );
        aConfigKey.Copy( *iConfigKey );
        }
    else
        {
        __ASSERT_ALWAYS( iCameraHandler != NULL, User::Leave( KErrNotReady ) );
        __ASSERT_ALWAYS( aAllowAsyncRetrieval, User::Leave( KErrNotReady ) );
        
        CMccVideoSourceConfigKeyRetriever* retriever = 
            CMccVideoSourceConfigKeyRetriever::NewLC( *iCameraHandler );
        retriever->RetrieveL( aVideoCodec, aConfigKey );
        CleanupStack::PopAndDestroy( retriever );
        
        iConfigKey = aConfigKey.AllocL();  
        }
        
    __V_SOURCESINK_CONTROLL( "CMccVideoSourceImpl::GetConfigKeyL, entry" )
    }

// -----------------------------------------------------------------------------
// CMccVideoSourceImpl::HasConfigKey()
// -----------------------------------------------------------------------------
//
TBool CMccVideoSourceImpl::HasConfigKey() const
    {
    return ( iConfigKey != NULL );
    }
    
// -----------------------------------------------------------------------------
// CMccVideoSourceImpl::SendStreamEventToClient()
// -----------------------------------------------------------------------------
//	
void CMccVideoSourceImpl::SendStreamEventToClient( 
    TMccEventType aEventType,
    TInt aError,
    TUint32 aEventNumData )
    {
    __V_SOURCESINK_CONTROLL( "CMccVideoSourceImpl::SendStreamEventToClient" )
    
    if ( iAsyncEventHandler )
	    {
	    aEventType = aError ? KMccStreamError : aEventType;
	    
	    TMccEvent event( 0, 
	                     0, 
	                     0, 
	                     iEndpointId, 
	                     KMccEventCategoryStream, 
	                     aEventType, 
	                     aError, 
	                     KNullDesC8 );
	                     
	    event.iEventNumData = aEventNumData;

		TMccInternalEvent internalEvent( KMccVideoSourceUid, 
		                                 EMccInternalEventNone,
		                                 event );
		                         
		iAsyncEventHandler->SendEventToClient( internalEvent );
	    }
	else
		{
		__V_SOURCESINK_CONTROLL( "CMccVideoSourceImpl::SendStreamEventToClient, \
		iAsyncEventHandler=NULL" )
		}
    }

// -----------------------------------------------------------------------------
// CMccVideoSourceImpl::SetAutoPlayMode()
// -----------------------------------------------------------------------------
//
void CMccVideoSourceImpl::SetAutoPlayMode( TBool aIsInAutoPlayMode )
    {
    iAutoPlayMode = aIsInAutoPlayMode;
    }

// -----------------------------------------------------------------------------
// CMccVideoSourceImpl::AutoPlayMode()
// -----------------------------------------------------------------------------
//       
TBool CMccVideoSourceImpl::AutoPlayMode() const
    {
    return iAutoPlayMode;
    }


// -----------------------------------------------------------------------------
// CMccVideoSourceImpl::CopyBufferData()
// -----------------------------------------------------------------------------
//
TBool CMccVideoSourceImpl::CopyBufferData( 
    CMMFBuffer& aDstBuffer, 
    CCMRMediaBuffer& aSrcBuffer )
    {
    CMMFDataBuffer& dstBuf = 
  	    static_cast<CMMFDataBuffer&>( aDstBuffer ); 		
       
    __V_SOURCESINK_MEDIA_INT2( "CMccVideoSourceImpl::CopyBufferData, \
src buf length =", aSrcBuffer.Data().Length(), " type =", aSrcBuffer.Type() )
        
  	__V_SOURCESINK_MEDIA_INT1( "CMccVideoSourceImpl::CopyBufferData, \
dst buf size =", dstBuf.BufferSize() )

    if ( aSrcBuffer.Type() == CCMRMediaBuffer::EVideoH264NALDecSpecInfo ||
         aSrcBuffer.Type() == CCMRMediaBuffer::EVideoH264BytestreamDecSpecInfo )
        {
        __V_SOURCESINK_CONTROLL_STR8( "Decoder spec info:", aSrcBuffer.Data() ) 
        TRAP_IGNORE( SetConfigKeyL( aSrcBuffer.Data() ) )
        }
        
    TBool copied( EFalse );
    if ( dstBuf.Data().MaxLength() >= aSrcBuffer.Data().Length() )
        {
        dstBuf.Data().Copy( aSrcBuffer.Data() );
        dstBuf.SetTimeToPlay( aSrcBuffer.TimeStamp().Int64() );
        dstBuf.SetLastBuffer( EFalse );
        copied = ETrue;
        }
        
    return copied;
    }

// -----------------------------------------------------------------------------
// CMccVideoSourceImpl::CopyBufferData()
// -----------------------------------------------------------------------------
//
TBool CMccVideoSourceImpl::CopyBufferData( 
    CMMFBuffer& aDstBuffer, 
    CMMFDataBuffer& aSrcBuffer )
    {
    CMMFDataBuffer& dstBuf = 
  	    static_cast<CMMFDataBuffer&>( aDstBuffer ); 		
       
    __V_SOURCESINK_MEDIA_INT1( "CMccVideoSourceImpl::CopyBufferData, \
src buf size =", aSrcBuffer.BufferSize() )
        
  	__V_SOURCESINK_MEDIA_INT1( "CMccVideoSourceImpl::CopyBufferData, \
dst buf size =", dstBuf.BufferSize() )

    TBool copied( EFalse );
    if ( dstBuf.Data().MaxLength() >= aSrcBuffer.Data().Length() )
        {
        dstBuf.Data().Copy( aSrcBuffer.Data() );
        dstBuf.SetTimeToPlay( aSrcBuffer.TimeToPlay() );
        dstBuf.SetLastBuffer( EFalse );
        copied = ETrue;
        }
    return copied;
    }
        
// -----------------------------------------------------------------------------
// CMccVideoSourceImpl::QueueBufferL()
// -----------------------------------------------------------------------------
//
TBool CMccVideoSourceImpl::QueueBufferL( CCMRMediaBuffer& aBuffer )
    {
    TBool queued( EFalse );
                               
    if ( iVideoQueue.Count() < KMccMaxVideoQueueSize )
        {
        CMMFDataBuffer* dataBuf = CMMFDataBuffer::NewL( aBuffer.Data().Length() );
        CleanupStack::PushL( dataBuf );
        if ( CopyBufferData( *dataBuf, aBuffer ) )
            {
            // Random access point buffers (IFrames) have special handling
            if ( aBuffer.RandomAccessPoint() )
                {
                AddIFrameToQueueL( dataBuf );
                CleanupStack::Pop( dataBuf );
                }
            else
                {
                iVideoQueue.AppendL( dataBuf );
                CleanupStack::Pop( dataBuf );
                }
            queued = ETrue;
            }
        else
            {
            CleanupStack::PopAndDestroy( dataBuf );
            }
        }
    return queued;
    }

// -----------------------------------------------------------------------------
// CMccVideoSourceImpl::FetchQueuedBuffer()
// -----------------------------------------------------------------------------
//
CMMFDataBuffer* CMccVideoSourceImpl::FetchQueuedBuffer()
    {
    CMMFDataBuffer* queuedBuf = NULL;
    if ( iVideoQueue.Count() > 0 )
        {
        queuedBuf = iVideoQueue[ 0 ];
        iVideoQueue.Remove( 0 );
        }
    return queuedBuf;
    }

// -----------------------------------------------------------------------------
// CMccVideoSourceImpl::DoBufferFilledL()
// -----------------------------------------------------------------------------
//
void CMccVideoSourceImpl::DoBufferFilledL()
    {
    CMMFBuffer* tempBuf = iVideoConsumerBuffer;
    MDataSink* tempSink = iVideoConsumer;
    iVideoConsumer = NULL;
    iVideoConsumerBuffer = NULL;
    
    if ( tempSink )
        {
        tempSink->BufferFilledL( tempBuf );
        }
    }
    
// -----------------------------------------------------------------------------
// CMccVideoSourceImpl::SetVideoBitrate()
// -----------------------------------------------------------------------------
//
TInt CMccVideoSourceImpl::SetVideoBitrate( TUint& aVideoBitrate )
    {
    // Respect maximum negotiation bitrate and do not allow too low values
    //

    __V_SOURCESINK_CONTROLL( "CMccVideoSourceImpl::SetVideoBitrate" )
    
    TUint videoBitrate( aVideoBitrate );
    
    if ( videoBitrate > iMaxNegBitRate )
        {
        __V_SOURCESINK_CONTROLL( 
            "CMccVideoSourceImpl:: bitrate higher than negotiated" )
        videoBitrate = iMaxNegBitRate;
        }
        
    if ( videoBitrate > iVideoCodec.iMaxBitrate )
        {
        __V_SOURCESINK_CONTROLL( 
            "CMccVideoSourceImpl:: bitrate higher than maximum set" )
        videoBitrate = iVideoCodec.iMaxBitrate;
        }
    
    if ( videoBitrate < KMccBitrateTooLowLimit )
        {
        __V_SOURCESINK_CONTROLL( "CMccVideoSourceImpl:: bitrate too low" )   
        videoBitrate = KMccBitrateTooLowLimit;
        }
            
    TRAPD( err, iMediaRecorder->SetVideoBitrateL( videoBitrate ) );  
    if ( err == KErrNone )
        {
        aVideoBitrate = videoBitrate;
        }
    
    __V_SOURCESINK_CONTROLL_INT1( 
        "CMccVideoSourceImpl::SetVideoBitrate, exit with err", err )
        
    return err;
    }
    
// -----------------------------------------------------------------------------
// CMccVideoSourceImpl::RateAdaptationRequestL
// -----------------------------------------------------------------------------
//     
void CMccVideoSourceImpl::RateAdaptationRequestL( 
    const TMccEvent& aInputData, 
    TMccEvent& aOutputData )
    {
    __V_SOURCESINK_CONTROLL( "CMccVideoSourceImpl::RateAdaptationRequestL" )
    
    TMccRateAdaptationEventDataPackage inputdatapkg;
	inputdatapkg.Copy(aInputData.iEventData);
	TMccRateAdaptationEventData inputdata = inputdatapkg();
    TMccRateAdaptationEventData outputdata = TMccRateAdaptationEventData();

#ifdef RATECONTROL

    if ( iMediaRecorder && 
       ( iMediaRecorder->State() == CCMRMediaRecorder::EStateRecording ||
         iMediaRecorder->State() == CCMRMediaRecorder::EStatePaused ) )
    	{
    	__V_SOURCESINK_CONTROLL( 
    	"CMccVideoSourceImpl::RateAdaptationRequest EStateRecording or EStatePaused" )

    	TUint bitrate = 0;
		
		bitrate = iMediaRecorder->GetVideoBitrateL();
		
		__V_SOURCESINK_CONTROLL( 
		"CMccVideoSourceImpl::RateAdaptationRequest GetVideoBitRateL done" )

		outputdata.iBitrateOriginal = bitrate;
		
		__V_SOURCESINK_CONTROLL_INT1(
		"CMccVideoSourceImpl::RateAdaptationRequest originalBitrate=", bitrate)	
		TUint mbitrate = TUint( inputdata.iRateAdaptationAdvice * TReal( bitrate ) );
		__V_SOURCESINK_CONTROLL_INT1(
		"CMccVideoSourceImpl::RateAdaptationRequest modifiedBitrate=", mbitrate)	
			
        TInt bitrateErr = SetVideoBitrate( mbitrate );
        if ( bitrateErr == KErrNone )
            {
            __V_SOURCESINK_CONTROLL( 
            "CMccVideoSourceImpl::RateAdaptationRequest SetVideoBitRate ok" )
            iVideoCodec.iBitrate = mbitrate; // This will be used after pause/resume
            outputdata.iBitrateModified = mbitrate;
            }
        else
            {
            __V_SOURCESINK_CONTROLL( 
            "CMccVideoSourceImpl::RateAdaptationRequest SetVideoBitRate nok" )
            outputdata.iBitrateModified = bitrate;
            }		

#ifdef FRAMERATECONTROL 

        TReal frameRate = KMccDefaultVideoFrameRate;
		
		if ( mbitrate > KIPULFrameRate10Limit )
			{
			__V_SOURCESINK_CONTROLL_INT1(
			"CMccVideoSourceImpl::RateAdaptationRequest frameRate=", (TInt) frameRate)	

			frameRate = iFrameRate;
			}
		else if (mbitrate < KIPULFrameRate5Limit )
			{
			__V_SOURCESINK_CONTROLL_INT1(
			"CMccVideoSourceImpl::RateAdaptationRequest frameRate=", (TInt) frameRate)	

			frameRate = Min( 5.0, (TUint) iFrameRate );
			}
		else 
			{
			__V_SOURCESINK_CONTROLL_INT1(
			"CMccVideoSourceImpl::RateAdaptationRequest frameRate=", (TInt) frameRate)	

			frameRate = Min( 10.0, (TUint) iFrameRate );
			}
		
		iMediaRecorder->SetVideoFrameRateL( frameRate );
		
		__V_SOURCESINK_CONTROLL( 
		"CMccVideoSourceImpl::RateAdaptationRequest SetVideoFrameRateL done" )
	
#endif //FRAMERATECONTROL 
	
		TMccRateAdaptationEventDataPackage temp( outputdata );
		aOutputData.iEventData.Copy( temp );
		
		__V_SOURCESINK_CONTROLL( "CMccVideoSourceImpl::RateAdaptationRequest end" )
		return;		
    	}
	
#endif //RATECONTROL
    	
    User::Leave( KErrNotSupported );
    }

// ---------------------------------------------------------------------------
// CMccVideoSourceImpl::DoCodecSpecificConfigurationL
// ---------------------------------------------------------------------------
//
void CMccVideoSourceImpl::DoCodecSpecificConfigurationL( TUid& aEncoderUid )
    {
    __V_SOURCESINK_CONTROLL( "CMccVideoSourceImpl::DoCodecSpecificConfigurationL" )
    
    TBuf8<KMaxSdpNameLength> sdpName = iVideoCodec.iSdpName;
    
    if ( iVideoCodec.iSdpName.FindF( KH263SdpName ) != KErrNotFound )
        {
        __V_SOURCESINK_CONTROLL( "H263" )
        const TUint maxBitRateOne = 64000;
        const TUint maxBitRateTwo = 128000;
        
        if ( iVideoCodec.iMaxBitrate <= maxBitRateOne )
    	    {
            __V_SOURCESINK_CONTROLL( "level set 10" )			
    	    iMaxNegBitRate = maxBitRateOne;
    	    }
    	else if ( iVideoCodec.iMaxBitrate > maxBitRateOne && 
    		 iVideoCodec.iMaxBitrate <= maxBitRateTwo )  
    		{
            __V_SOURCESINK_CONTROLL( "level set 45" )			
    		iMaxNegBitRate = maxBitRateTwo;
    		}
        else
            {
            __V_SOURCESINK_CONTROLL( "max bitrate too high, set level 45" )	
    		iMaxNegBitRate = maxBitRateTwo;
    		iVideoCodec.iMaxBitrate = maxBitRateTwo;
            }

        if ( iVideoCodec.iCodecMode == KH263FormatModeOld )
            {
            __V_SOURCESINK_CONTROLL( "mode set 1998" )		
            }
        
        // Always use H263-2000 mime type as mediarecorder doesn't support 1998 mode    
        sdpName = KH2632000SdpName;
        }
    else if ( iVideoCodec.iSdpName.CompareF( KAVCSdpName ) == 0 )
        {
        __V_SOURCESINK_CONTROLL( "AVC" )
        
        iMaxNegBitRate = iVideoCodec.iMaxBitrate;
        __V_SOURCESINK_CONTROLL_INT1( "CMccVideoSourceImpl::DoCodecSpecificConfigurationL, EncodingDecodingDeviceUid:", 
    		                              iVideoCodec.iEncodingDecodingDevice.iUid )
        aEncoderUid = iVideoCodec.iEncodingDecodingDevice;
        }
    else
        {
        // NOP
        }
    	
    HBufC8* fmtp = GetFmtpLC( iVideoCodec );
    
    delete iVideoCodecFourCC;
    iVideoCodecFourCC = NULL;
    iVideoCodecFourCC = 
        HBufC8::NewL( KVideoCodecFourCC().Length() + KMaxSdpNameLength + fmtp->Length() );
        
    iVideoCodecFourCC->Des().Format( KVideoCodecFourCC, &sdpName, &*fmtp );
    
    CleanupStack::PopAndDestroy( fmtp );
             	
    __V_SOURCESINK_CONTROLL( "CMccVideoSourceImpl::DoCodecSpecificConfigurationL, exit" );	
    }
    
// ---------------------------------------------------------------------------
// CMccVideoSourceImpl::GetFmtpLC
// ---------------------------------------------------------------------------
//
HBufC8* CMccVideoSourceImpl::GetFmtpLC( const TMccCodecInfo& aCodecInfo )    
    {
    __V_SOURCESINK_CONTROLL( "CMccVideoSourceImpl::GetFmtpLC" )
    
    CMccCodecInformationFactory* factory = CMccCodecInformationFactory::NewL();
    CleanupStack::PushL( factory );
    CMccCodecInformation* codec = 
        factory->CreateCodecInformationL( aCodecInfo.iSdpName );
    CleanupStack::PushL( codec );
    codec->SetValues( aCodecInfo );
    HBufC8* fmtp = codec->GetFmtpL().AllocL();
    CleanupStack::PopAndDestroy( codec );
    CleanupStack::PopAndDestroy( factory );
    CleanupStack::PushL( fmtp );
    
    __V_SOURCESINK_CONTROLL_STR8( "fmtp:", *fmtp )
    
    if ( aCodecInfo.iSdpName.CompareF( KAVCSdpName ) == 0 )
        {
        __V_SOURCESINK_CONTROLL( "avc handling" )
        
        TPtr8 ptrFmtp( fmtp->Des() );
        // Strip useless information off from SDP 
        // (mediarecorder does not accept packetization mode etc.)
        TInt index = ptrFmtp.Find( KTxtProfileLevelId );
        if ( index >= 0 )
            {
            _LIT8( KSemicolon, ";" );
            TInt semicolonIndex = ptrFmtp.Mid( index ).Find( KSemicolon );
            
            if ( semicolonIndex > 0 )
                {
                HBufC8* strippedFmtp = ptrFmtp.Mid( index, semicolonIndex ).AllocL();
                CleanupStack::PopAndDestroy( fmtp );
                fmtp = strippedFmtp;
                CleanupStack::PushL( fmtp );
                __V_SOURCESINK_CONTROLL_STR8( "stripped fmtp:", *fmtp )
                }
            }
        }
    
    return fmtp;
    }

// ---------------------------------------------------------------------------
// CMccVideoSourceImpl::SetConfigKeyL
// Base 64 encoded version of key is more for session negotiation and does
// not need to be updated if it already existis. Raw data config key is
// used inside stream and it will represent current configuration information
// as it will be received from mediarecorded. Therefore keep updating it.
// ---------------------------------------------------------------------------
//            
void CMccVideoSourceImpl::SetConfigKeyL( const TDesC8& aData )
    {
    __V_SOURCESINK_CONTROLL( "CMccVideoSourceImpl::SetConfigKeyL" )
    
    if ( iConfigKey == NULL )
        {
        TInt bufferProgressIndex( 0 );
        TInt part1StartIndex = 
            TMccCodecInfo::FindAvcNaluStart( bufferProgressIndex, aData );
        __ASSERT_ALWAYS( part1StartIndex != KErrNotFound, User::Leave( KErrNotFound ) );

        TInt part1EndIndex = TMccCodecInfo::FindAvcNaluEnd( bufferProgressIndex, aData );
        __ASSERT_ALWAYS( part1EndIndex != KErrNotFound, User::Leave( KErrNotFound ) );
                         
        TInt part2StartIndex = TMccCodecInfo::FindAvcNaluStart( bufferProgressIndex, aData );
        __ASSERT_ALWAYS( part2StartIndex != KErrNotFound, User::Leave( KErrNotFound ) );

        TInt part2EndIndex = TMccCodecInfo::FindAvcNaluEnd( bufferProgressIndex, aData );
        __ASSERT_ALWAYS( part2EndIndex != KErrNotFound, User::Leave( KErrNotFound ) );
        
        TInt part1Len = part1EndIndex - part1StartIndex;
        HBufC8* confKeyPart1 =
            MccConversionUtility::Base64EncodeLC( aData.Mid( part1StartIndex, part1Len ) );
        
        TInt part2Len = part2EndIndex - part2StartIndex;
        HBufC8* confKeyPart2 =
            MccConversionUtility::Base64EncodeLC( aData.Mid( part2StartIndex, part2Len ) );
            
        _LIT8( KMccVideoSourceNaluSeparator, "," );
        
        iConfigKey = HBufC8::NewL( 
            confKeyPart1->Length() + 
            confKeyPart2->Length() + 
            KMccVideoSourceNaluSeparator().Length() );
        TPtr8 ptrConfigKey( iConfigKey->Des() );    
		ptrConfigKey.Append( *confKeyPart1 );
		ptrConfigKey.Append( KMccVideoSourceNaluSeparator() );
		ptrConfigKey.Append( *confKeyPart2 );

        CleanupStack::PopAndDestroy( confKeyPart2 );
        CleanupStack::PopAndDestroy( confKeyPart1 );
        
        __V_SOURCESINK_CONTROLL_STR8( "base64 encoded:", *iConfigKey ) 
        }
    
    delete iConfigKeyData;
    iConfigKeyData = NULL;
    iConfigKeyData = aData.AllocL();
        
    __V_SOURCESINK_CONTROLL( "CMccVideoSourceImpl::SetConfigKeyL, exit" )
    }

// ---------------------------------------------------------------------------
// CMccVideoSourceImpl::FullPrepareAllowed
// ---------------------------------------------------------------------------
//
TBool CMccVideoSourceImpl::FullPrepareAllowed()
    {
    TBool allowed( !iMultipleCodecs );
    if ( iVideoCodec.iSdpName.CompareF( KAVCSdpName ) == 0 )
        {
        // Config key needs to exists before full prepare is allowed for AVC
        allowed &= ( iConfigKey != NULL || iConfigKeyRetrieval );
        }
        
    return allowed;
    }

// ---------------------------------------------------------------------------
// CMccVideoSourceImpl::WriteFirstBufferL
// ---------------------------------------------------------------------------
//
void CMccVideoSourceImpl::WriteFirstBufferL()
    {
    if ( iVideoConsumerBuffer )
        {
        __V_SOURCESINK_CONTROLL( "CMccVideoSourceImpl::WriteFirstBufferL" )
        
    	CMMFDataBuffer* queuedBuf = FetchQueuedBuffer();
    	CleanupStack::PushL( queuedBuf );
    	if ( queuedBuf && CopyBufferData( *iVideoConsumerBuffer, *queuedBuf ) )
    	    {
    	    DoBufferFilledL();
    	    }
    	CleanupStack::PopAndDestroy( queuedBuf );
    	
    	__V_SOURCESINK_CONTROLL( "CMccVideoSourceImpl::WriteFirstBufferL, exit" )
        }
    }

// ---------------------------------------------------------------------------
// CMccVideoSourceImpl::AddIFrameToQueueL
// In case of AVC is used, config data is sent before each iframe.
// Config data is not sent before first iframe or if queue doesn't have
// room for config data.
// ---------------------------------------------------------------------------
//
void CMccVideoSourceImpl::AddIFrameToQueueL( CMMFDataBuffer* aBuffer )
    {
    __V_SOURCESINK_CONTROLL( "CMccVideoSourceImpl::AddIFrameToQueueL" )
    
    __ASSERT_ALWAYS( aBuffer, User::Leave( KErrArgument ) );
    
    if ( iConfigKeyData && 
       ( iVideoCodec.iSdpName.CompareF( KAVCSdpName ) == 0 ) &&
       ( iVideoQueue.Count() < ( KMccMaxVideoQueueSize - 1 ) ) &&
         iFirstIFrameQueued )
        {
        __V_SOURCESINK_CONTROLL( 
            "CMccVideoSourceImpl::AddIFrameToQueueL, adding config data" )
            
        CMMFDataBuffer* configDataBuf = 
            CMMFDataBuffer::NewL( iConfigKeyData->Length() );
        CleanupStack::PushL( configDataBuf );
        configDataBuf->Data().Copy( *iConfigKeyData );
        configDataBuf->SetTimeToPlay( aBuffer->TimeToPlay() );
        configDataBuf->SetLastBuffer( EFalse );
        iVideoQueue.AppendL( configDataBuf );
        CleanupStack::Pop( configDataBuf );
        }
    
    if ( iMccResources )
        {
        __V_SOURCESINK_CONTROLL( 
                "CMccVideoSourceImpl::AddIFrameToQueueL, store iframe info" )
        iMccResources->StoreKeyFrameInfoL( iEndpointId, *aBuffer );
        
        __V_SOURCESINK_CONTROLL( 
                "CMccVideoSourceImpl::AddIFrameToQueueL, info stored" )
        }
    
    iVideoQueue.AppendL( aBuffer );
    
    iFirstIFrameQueued = ETrue;
    
    __V_SOURCESINK_CONTROLL( "CMccVideoSourceImpl::AddIFrameToQueueL, exit" )
    }

// ---------------------------------------------------------------------------
// CMccVideoSourceImpl::HandleCameraReservationL
// Camera is needed only for real once autoplay is enabled or config key
// is retrieved. If retrieving config key, we need to force camera creation.
// ---------------------------------------------------------------------------
//
void CMccVideoSourceImpl::HandleCameraReservationL()
    {
    if ( AutoPlayMode() || iConfigKeyRetrieval )
        {
        TBool forceImmediateCameraCreation( iConfigKeyRetrieval );
        
        __V_SOURCESINK_CONTROLL_INT1( 
                "CMccVideoSourceImpl::HandleCameraReservationL, force", 
                forceImmediateCameraCreation )
        
        User::LeaveIfError( iCameraHandler->MonitorCameraReservation( 
                *this, forceImmediateCameraCreation ) );
        }
    else
        {
        __V_SOURCESINK_CONTROLL( "CMccVideoSourceImpl::HandleCameraReservationL, nop" )
        
        SendStreamEventToClient( KMccStreamPrepared, KErrNone, KMccAutomaticEvent );
        }
    __V_SOURCESINK_CONTROLL( "CMccVideoSourceImpl::HandleCameraReservationL, exit" )
    }

// ---------------------------------------------------------------------------
// CMccVideoSourceImpl::StopCameraMonitoring
// ---------------------------------------------------------------------------
//
void CMccVideoSourceImpl::StopCameraMonitoring()
    {
    if ( iCameraHandler )
        {
        // Unregister, ignore error as we might not be even monitoring
        // Can release resource as if it was created just for temporary purpose
        TBool forceImmediateCameraRelease( iConfigKeyRetrieval );
        iCameraHandler->StopCameraMonitoring( 
                *this, forceImmediateCameraRelease );
        }
    }

#ifndef EKA2
// DLL interface code
EXPORT_C TInt E32Dll( TDllReason )
    {
    return KErrNone;
    }
#endif
