multimediacommscontroller/mmccfilesourcesink/src/mccfilesink.cpp
changeset 0 1bce908db942
child 17 a5ac35ca6d81
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/multimediacommscontroller/mmccfilesourcesink/src/mccfilesink.cpp	Tue Feb 02 01:04:58 2010 +0200
@@ -0,0 +1,1104 @@
+/*
+* 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 <mmcccodecinformationfactory.h>
+#include <mmcccodecinformation.h>
+#include "mccfilesink.h"
+#include "mmccinterfacedef.h"
+#include "mmcccodecinformation.h"
+#include "mccfilesinklogs.h"
+#include "mccinternalevents.h"
+#include "mccinternaldef.h"
+#include "mccresources.h"
+
+// CONSTANTS
+
+const TInt KMccMaxNumTimestamps = 5;
+
+const TInt KMccTimestampDifferenceMultiplier = 10;
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CMccFileSink::NewSinkL
+// -----------------------------------------------------------------------------
+//
+MDataSink* CMccFileSink::NewSinkL( TUid /*aImplementationUid*/, 
+                                   const TDesC8& /*aInitData*/ )
+    {
+    __FILESINK_CONTROLL( "CMccFileSink::NewSinkL" )
+    CMccFileSink* self = new ( ELeave ) CMccFileSink();
+    return static_cast<MDataSink*>( self );
+    }
+
+// -----------------------------------------------------------------------------
+// CMccFileSink::ConstructSinkL
+// -----------------------------------------------------------------------------
+//
+void CMccFileSink::ConstructSinkL( const TDesC8& aInitData )
+    {
+    __FILESINK_CONTROLL( "CMccFileSink::ConstructSinkL" )
+
+	iFileComposer = CCamC3GPDataSink::NewL( this );
+    iFileComposer->SetSizeLimit( iMaxFileSize );
+    
+    TPckgBuf<TFileName> initData;
+    initData.Copy( aInitData );
+    iFileName = initData();
+    
+    }
+    
+// -----------------------------------------------------------------------------
+// CMccFileSink::CMccFileSink
+// -----------------------------------------------------------------------------
+//
+CMccFileSink::CMccFileSink() : 
+    CMccDataSink( KMccFileSinkUid )
+    {
+    iVideoCodec.iFourCC = TFourCC( KMccFourCCIdH263 );
+    // FJKI-7J58CB no use case for audio in file, hence removing the audio track capability 
+    //             per request from customer
+    // iAudioFourCC = TFourCC( KMccFourCCIdAMRNB );
+    iAudioFourCC = TFourCC( KMMFFourCCCodeNULL );
+    iFileName = KNullDesC;
+    iMaxFileSize = 0; 
+    iT1 = 0;
+    iT2 = 0;
+    iPausedDuration = 0;
+    iPreviousTimestamp = 0;
+    iAddToTimestamp = 0;
+    iSizeLimitReached = EFalse;
+    iNotifySizeLimitReached = EFalse;
+    SetActiveUserIndex( 0 );
+    }
+        
+// -----------------------------------------------------------------------------
+// CMccFileSink::~CMccFileSink
+// -----------------------------------------------------------------------------
+//
+CMccFileSink::~CMccFileSink()
+    {
+    __FILESINK_CONTROLL( "CMccFileSink::~CMccFileSink" )
+    // Cleanup and other ending operations...
+    if ( iCurrentState == ERecording || iCurrentState == EPaused )
+        {
+        TRAP_IGNORE( CMccFileSink::SinkStopL() );
+        }	
+	delete iFileComposer;
+	iTimestamps.Close();
+	
+	iUsers.ResetAndDestroy();
+    }
+
+// -----------------------------------------------------------------------------
+// CMccFileSink::SetCurrentUser
+// -----------------------------------------------------------------------------
+//
+void CMccFileSink::SetCurrentUser( MAsyncEventHandler* aEventHandler )
+    {
+    iAsyncEventHandler = aEventHandler;
+    }
+
+// -----------------------------------------------------------------------------
+// CMccFileSink::SinkPrimeL
+// -----------------------------------------------------------------------------
+//
+void CMccFileSink::SinkPrimeL()
+	{
+	__FILESINK_CONTROLL( "CMccFileSink::SinkPrimeL" )
+
+    DoSinkPrimeL();	
+	}
+	
+// -----------------------------------------------------------------------------
+// CMccFileSink::SinkPlayL()
+// -----------------------------------------------------------------------------
+//
+void CMccFileSink::SinkPlayL()
+    {
+    __FILESINK_CONTROLL( "CMccFileSink::SinkPlayL" )  
+    
+    DoSinkPlayL();
+    }
+
+// -----------------------------------------------------------------------------
+// CMccFileSink::SinkPauseL()
+// 
+// Pauses streaming by cancelling timers
+// -----------------------------------------------------------------------------
+//
+void CMccFileSink::SinkPauseL()
+    {
+    __FILESINK_CONTROLL( "CMccFileSink::SinkPauseL" )
+
+    DoSinkPauseL();
+	}
+
+// -----------------------------------------------------------------------------
+// CMccFileSink::SinkStopL()
+// 
+// Stops streaming
+// -----------------------------------------------------------------------------
+//
+void CMccFileSink::SinkStopL()
+    {
+    __FILESINK_CONTROLL( "CMccFileSink::SinkStopL" )
+    
+    DoSinkStopL();		
+    }
+
+// -----------------------------------------------------------------------------
+// CMccFileSink::SinkDataTypeCode
+// -----------------------------------------------------------------------------
+//
+TFourCC CMccFileSink::SinkDataTypeCode( TMediaId aMediaId )
+	{
+    __FILESINK_CONTROLL( "CMccFileSink::SinkDataTypeCode" )
+
+    if ( KUidMediaTypeVideo == aMediaId.iMediaType )
+        {
+        return iVideoCodec.iFourCC;
+        }
+    else if ( KUidMediaTypeAudio == aMediaId.iMediaType  )
+        {
+        return iAudioFourCC;
+        }
+    else
+        {
+        return TFourCC( KMMFFourCCCodeNULL );
+        }
+	}
+	
+// -----------------------------------------------------------------------------
+// CMccFileSink::SetSinkDataTypeCode
+// -----------------------------------------------------------------------------
+//
+TInt CMccFileSink::SetSinkDataTypeCode( TFourCC aCodec, 
+                            TMediaId aMediaId )
+	{
+    __FILESINK_CONTROLL( "CMccFileSink::SetSinkDataTypeCode" )
+
+    TInt retVal = KErrNone;
+    if ( KUidMediaTypeVideo == aMediaId.iMediaType &&
+    	aCodec == iVideoCodec.iFourCC )
+        {
+        retVal = KErrNone;
+        }
+    else if ( KUidMediaTypeAudio == aMediaId.iMediaType &&
+    	aCodec == iAudioFourCC )
+        {
+        retVal = KErrNone;
+        }
+    else
+        {
+        retVal = KErrNotSupported;
+        }
+
+	return retVal;
+	}	
+
+// -----------------------------------------------------------------------------
+// CMccFileSink::BufferEmptiedL
+// -----------------------------------------------------------------------------
+//
+void CMccFileSink::BufferEmptiedL( CMMFBuffer* /*aBuffer*/ )
+	{
+    __FILESINK_MEDIA( "CMccFileSink::BufferEmptiedL" )
+    User::Leave( KErrNotSupported );
+	}
+	
+// -----------------------------------------------------------------------------
+// CMccFileSink::CanCreateSinkBuffer
+// -----------------------------------------------------------------------------
+//
+TBool CMccFileSink::CanCreateSinkBuffer()
+	{
+    __FILESINK_CONTROLL( "CMccFileSink::CanCreateSinkBuffer, EFalse" )
+	return EFalse;
+	}	
+
+// -----------------------------------------------------------------------------
+// CMccFileSink::CreateSinkBufferL
+// -----------------------------------------------------------------------------
+//
+CMMFBuffer* CMccFileSink::CreateSinkBufferL( 
+	TMediaId /*aMediaId*/, 
+    TBool& /*aReference*/ )
+	{
+	__FILESINK_CONTROLL( "CMccFileSink::CreateSinkBufferL, return NULL" )
+    CMMFBuffer* buffer = NULL;
+	User::Leave( KErrNotSupported );	
+	return buffer;	
+	}
+	
+// -----------------------------------------------------------------------------
+// CMccFileSink::SinkThreadLogon
+// -----------------------------------------------------------------------------
+//
+TInt CMccFileSink::SinkThreadLogon( MAsyncEventHandler& aEventHandler )
+	{
+    __FILESINK_CONTROLL( "CMccFileSink::SinkThreadLogon" )
+
+    TInt err( KErrNone );
+    TMccFileSinkUser* userEntry = 
+        MccUserArray<TMccFileSinkUser>::FindUserEntryForCurrent( iUsers, &aEventHandler );
+    if ( !userEntry )
+        {
+        TRAP( err, AddUserL( &aEventHandler ) );
+        }
+    
+    __FILESINK_CONTROLL_INT1( 
+        "CMccFileSink::SinkThreadLogon, exit with err:", err )
+        
+    return err;
+	}
+	
+// -----------------------------------------------------------------------------
+// CMccFileSink::SinkThreadLogoff
+// -----------------------------------------------------------------------------
+//
+void CMccFileSink::SinkThreadLogoff()
+	{
+	__FILESINK_CONTROLL( "CMccFileSink::SinkThreadLogoff" )
+
+    // If multiple different codecs are using the filesink and active user
+    // is removed, reset active user information so that new active user
+    // can be seleceted once someone else tries to use the sink
+    if ( IsActiveUser( iAsyncEventHandler ) )
+        {
+        SetActiveUserIndex( KErrNotFound );
+        }
+         
+    MccUserArray<TMccFileSinkUser>::RemoveCurrentUser( iUsers, iAsyncEventHandler );
+    
+    if ( iUsers.Count() > 0 )
+        {
+        SetCurrentUser( iUsers[ 0 ]->iEventHandler );
+        }
+    else
+        {
+        SetCurrentUser( NULL );
+        }
+	}
+
+// -----------------------------------------------------------------------------
+// CMccFileSink::EmptyBufferL
+// -----------------------------------------------------------------------------
+//
+void CMccFileSink::EmptyBufferL( CMMFBuffer* aBuffer,
+                  MDataSource* aProvider,
+                  TMediaId aMediaId )
+	{
+	__FILESINK_MEDIA( "CMccFileSink::EmptyBufferL" )
+	
+	__ASSERT_ALWAYS( aBuffer && aProvider, User::Leave( KErrArgument ) );
+	
+	
+    if ( iCurrentState != ERecording )
+        {
+        __FILESINK_MEDIA( "CMccFileSink::EmptyBufferL, IGNORED" )
+        
+        // Do not let the datapath to halt
+        aProvider->BufferEmptiedL( aBuffer );
+        return;
+        }
+
+    if ( iNotifySizeLimitReached )
+        {
+        __FILESINK_MEDIA( 
+            "CMccFileSink::EmptyBufferL, IGNORED (notify size limit reached)" )
+        MfcoSizeLimitReachedL();
+        
+        // Do not let the datapath to halt
+        aProvider->BufferEmptiedL( aBuffer );
+        return;
+        }
+        
+	CMMFDataBuffer* buffer = static_cast<CMMFDataBuffer*>(aBuffer);
+	CCMRMediaBuffer* outBuffer = NULL; 
+	                  
+	TTimeIntervalMicroSeconds timeToPlay = TimeToPlayL( buffer->TimeToPlay() );
+    	    	
+   	__FILESINK_MEDIA_INT1( "CMccFileSink::EmptyBufferL, timeToPlay = ", 
+	                       timeToPlay.Int64() )
+	
+	TBool dropBuffer( EFalse );                      
+	if ( aMediaId.iMediaType == KUidMediaTypeAudio )
+		{
+    	__FILESINK_MEDIA( "CMccFileSink::EmptyBufferL, audio" )
+    	    
+    	outBuffer = new ( ELeave ) CCMRMediaBuffer(
+        	buffer->Data(), CCMRMediaBuffer::EAudioAMRNB, buffer->BufferSize(),
+            ETrue,  timeToPlay ); 
+        CleanupStack::PushL( outBuffer );  
+		}
+	else if ( aMediaId.iMediaType == KUidMediaTypeVideo )
+		{
+    	__FILESINK_MEDIA( "CMccFileSink::EmptyBufferL, video" )    
+        
+        TFourCC providerDataType = UpdateActiveUserL( aMediaId, *aProvider );
+        
+        CCMRMediaBuffer::TBufferType bufType = 
+            ResolveBufferType( *buffer, providerDataType );	
+        
+        dropBuffer = CheckWritingPermission( *buffer, bufType );
+        
+    	outBuffer = new ( ELeave ) CCMRMediaBuffer(
+        	buffer->Data(), bufType, buffer->BufferSize(),
+            ETrue,  timeToPlay );    
+            
+        CleanupStack::PushL( outBuffer );   
+		}
+	else
+		{
+    	__FILESINK_MEDIA( "CMccFileSink::EmptyBufferL, unknown media" ) 
+		User::Leave( KErrNotSupported );	
+		}
+    
+    if ( !dropBuffer )
+        {
+    	iFileComposer->WriteBufferL( outBuffer );
+        }
+        
+	CleanupStack::PopAndDestroy( outBuffer );
+	outBuffer= NULL;
+	aProvider->BufferEmptiedL( aBuffer );
+	}	
+
+// -----------------------------------------------------------------------------
+// CMccFileSink::BufferFilledL
+// -----------------------------------------------------------------------------
+//
+void CMccFileSink::BufferFilledL( CMMFBuffer* /*aBuffer*/ )
+	{
+	__FILESINK_MEDIA( "CMccFileSink::BufferFilledL" )
+	}	                  
+
+// -----------------------------------------------------------------------------
+// CMccFileSink::MfcoDiskFullL
+// -----------------------------------------------------------------------------
+//
+void CMccFileSink::MfcoDiskFullL()
+	{
+	__FILESINK_MEDIA( "CMccFileSink::MfcoDiskFullL" )
+	
+	// After size limit has been reached, there is no way to really continue
+	// recording to the same file, writebuffer returns without error but
+	// has no effect. Pause the sink anyway but fail if resume is tried.
+	// Creating new filewriter would be only way to recover from this but
+	// that would overwrite old recording.
+	iSizeLimitReached = ETrue;
+	
+	SendStreamEventToClient( KMccResourceNotAvailable, KErrNoMemory, ETrue );
+	
+    TRAP_IGNORE( AutomaticPauseL() );
+    
+    iNotifySizeLimitReached = EFalse;
+	}	                  
+
+// -----------------------------------------------------------------------------
+// CMccFileSink::MfcoSizeLimitReachedL
+// -----------------------------------------------------------------------------
+//
+void CMccFileSink::MfcoSizeLimitReachedL()
+	{
+	__FILESINK_MEDIA( "CMccFileSink::MfcoSizeLimitReachedL" )
+	
+	iSizeLimitReached = ETrue;
+	
+	SendStreamEventToClient( KMccResourceNotAvailable, KErrNone, ETrue );
+
+    TRAP_IGNORE( AutomaticPauseL() );
+    
+    iNotifySizeLimitReached = EFalse;
+	}	                  
+
+// -----------------------------------------------------------------------------
+// CMccFileSink::SetVideoCodecL
+// -----------------------------------------------------------------------------
+//
+void CMccFileSink::SetVideoCodecL( const TMccCodecInfo& aVideoCodec )
+    {
+   	__FILESINK_CONTROLL_STR8( 
+	    "CMccFileSink::SetVideoCodecL, sdpname:", aVideoCodec.iSdpName )
+    
+    TMccFileSinkUser* user = 
+        MccUserArray<TMccFileSinkUser>::FindUserEntryForCurrent( iUsers, iAsyncEventHandler );
+    if ( user )
+        {
+        user->iCodecInfo = aVideoCodec;
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CMccFileSink::SetAudioCodecL
+// -----------------------------------------------------------------------------
+//
+void CMccFileSink::SetAudioCodecL( const TMccCodecInfo& /*aAudioCodec*/ )
+    {
+    __FILESINK_MEDIA( "CMccFileSink::SetAudioCodecL" )
+    }
+    
+// -----------------------------------------------------------------------------
+// CMccFileSink::RecordTimeAvailableL
+// -----------------------------------------------------------------------------
+//
+void CMccFileSink::RecordTimeAvailableL( TTimeIntervalMicroSeconds& aTime )
+	{ 
+	__FILESINK_CONTROLL( "CMccFileSink::RecordTimeAvailableL" )
+	aTime = iFileComposer->GetRemainingTimeL();
+	}
+
+// -----------------------------------------------------------------------------
+// CMccFileSink::SetFileNameL
+// -----------------------------------------------------------------------------
+//
+void CMccFileSink::SetFileNameL( const TFileName aFileName )
+	{
+	__FILESINK_CONTROLL( "CMccFileSink::SetFileNameL" )
+	iFileName = aFileName;
+	}
+	
+// -----------------------------------------------------------------------------
+// CMccFileSink::SendStreamEventToClient
+// -----------------------------------------------------------------------------
+//	
+void CMccFileSink::SendStreamEventToClient( 
+    TMccEventType aEventType, 
+    TInt aError,
+    TBool aToAllClients )
+	{
+	__FILESINK_CONTROLL_INT2( 
+	    "CMccFileSink::SendStreamEventToClient, type", aEventType, 
+	    " to all:", aToAllClients )
+	
+    TMccEvent event( 0, 
+                     0, 
+                     0, 
+                     MCC_ENDPOINT_ID( static_cast<MDataSink*>( this ) ), 
+                     KMccEventCategoryStream, 
+                     aEventType, 
+                     aError, 
+                     KNullDesC8 );
+
+    if ( aToAllClients )
+        {
+        for ( TInt i = 0; i < iUsers.Count(); i++ )
+            {
+            FinalizeSendEvent( iUsers[ i ]->iEventHandler, event );
+            }
+        }
+    else
+        {
+        FinalizeSendEvent( iAsyncEventHandler, event );
+        }
+	}
+	
+// -----------------------------------------------------------------------------
+// CMccFileSink::TimeToPlayL
+// -----------------------------------------------------------------------------
+//	   	
+TTimeIntervalMicroSeconds CMccFileSink::TimeToPlayL( 
+    TTimeIntervalMicroSeconds aCurrentTimestamp )
+    { 
+    CalculateAverageTimestampDifferenceL( aCurrentTimestamp );
+
+    TTimeIntervalMicroSeconds timeToPlay( 0 );
+    
+    if ( aCurrentTimestamp >= iPausedDuration )
+        {
+        __FILESINK_CONTROLL("CMccFileSink::TimeToPlay aCurrentTimestamp \
+>= iPausedDuration" )
+
+        timeToPlay = aCurrentTimestamp.Int64() - iPausedDuration.Int64();    
+        }
+    else
+        {
+        __FILESINK_CONTROLL("CMccFileSink::TimeToPlay aCurrentTimestamp \
+< iPausedDuration" )
+        timeToPlay = aCurrentTimestamp; 
+        }
+   
+    timeToPlay = ( timeToPlay.Int64() + iAddToTimestamp );
+    
+    __FILESINK_CONTROLL_INT1("CMccFileSink::TimeToPlay, \
+timeToPlay=", timeToPlay.Int64() )  
+
+    iPreviousTimestamp = aCurrentTimestamp;
+  
+    return timeToPlay;
+    }
+
+// -----------------------------------------------------------------------------
+// CMccFileSink::CalculateAverageTimestampDifferenceL
+// -----------------------------------------------------------------------------
+//  
+void CMccFileSink::CalculateAverageTimestampDifferenceL( 
+    const TTimeIntervalMicroSeconds& aCurrentTimestamp )
+    {
+    TInt64 averageTimeStampDifference = 0;
+    if ( iTimestamps.Count() == KMccMaxNumTimestamps )
+       {
+       
+       for ( TInt i = iTimestamps.Count() - 1; i > 0; i-- )
+               {
+               averageTimeStampDifference += ( iTimestamps[ i ] - iTimestamps[ i - 1 ] );
+               }
+               
+       averageTimeStampDifference = averageTimeStampDifference / ( KMccMaxNumTimestamps - 1 );
+       }
+    
+    if ( aCurrentTimestamp > iPreviousTimestamp )
+       {
+       if ( iTimestamps.Count() >= KMccMaxNumTimestamps )
+           {
+           iTimestamps.Remove( 0 );
+           }
+       iTimestamps.AppendL( aCurrentTimestamp.Int64() );
+       }
+    else
+       {
+       TInt64 currDifference = iPreviousTimestamp.Int64() - aCurrentTimestamp.Int64();
+       if ( averageTimeStampDifference != 0 && 
+            currDifference > ( averageTimeStampDifference * KMccTimestampDifferenceMultiplier ) )
+           {
+           iAddToTimestamp += ( currDifference + averageTimeStampDifference );
+           iTimestamps.Reset();
+           
+           __FILESINK_CONTROLL_INT1("CMccFileSink::TimeToPlay, iAddToTimestamp=", iAddToTimestamp )  
+           }
+       }
+    }
+
+// -----------------------------------------------------------------------------
+// CMccFileSink::ResetTimers
+// -----------------------------------------------------------------------------
+//	  
+void CMccFileSink::ResetTimers()
+    {
+    iT1 = 0;
+    iT2 = 0; 
+    iPausedDuration = 0;  
+    iPreviousTimestamp = 0;
+    iAddToTimestamp = 0;
+    iTimestamps.Reset();
+    }
+
+// -----------------------------------------------------------------------------
+// CMccFileSink::SetPausedDuration
+// -----------------------------------------------------------------------------
+//	
+void CMccFileSink::SetPausedDuration( TTime aT1, TTime aT2 )
+    {
+    __FILESINK_CONTROLL( "CMccFileSink::SetPausedDuration" )
+    __FILESINK_CONTROLL_INT2( 
+        "CMccFileSink::SetPausedDuration, aT1=", aT1.Int64(),
+        "aT2=", aT2.Int64() )
+
+    if ( aT1 != 0 && aT1 < aT2 )
+        {
+        __FILESINK_CONTROLL_INT1("CMccFileSink::SetPausedDuration, \
+before iPausedDuration=", iPausedDuration.Int64() ) 
+
+        iPausedDuration = ( iPausedDuration.Int64() + 
+                            aT2.MicroSecondsFrom( aT1 ).Int64() );
+                            
+        __FILESINK_CONTROLL_INT1("CMccFileSink::SetPausedDuration, \
+after iPausedDuration=", iPausedDuration.Int64() ) 
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CMccFileSink::AutomaticPauseL
+// -----------------------------------------------------------------------------
+//
+void CMccFileSink::AutomaticPauseL()
+    {
+    __FILESINK_CONTROLL( "CMccFileSink::AutomaticPauseL" )
+    
+    for ( TInt i = 0; i < iUsers.Count(); i++ )
+        {
+        TMccEvent* controlEvent = new ( ELeave ) TMccEvent;
+        CleanupStack::PushL( controlEvent );
+        
+        controlEvent->iEndpointId = MCC_ENDPOINT_ID( static_cast<MDataSink*>( this ) );
+    	controlEvent->iEventCategory = KMccEventCategoryStreamControl;
+    	controlEvent->iEventType = KMccStreamPaused;
+    	controlEvent->iEventNumData = KMccAutomaticEvent;
+
+        User::LeaveIfError( 
+            FinalizeSendEvent( iUsers[ i ]->iEventHandler, *controlEvent ) );
+        
+        CleanupStack::PopAndDestroy( controlEvent );
+        }
+    
+    __FILESINK_CONTROLL( "CMccFileSink::AutomaticPauseL, exit" )
+    }  
+	
+// -----------------------------------------------------------------------------
+// CMccFileSink::FinalizeSendEvent
+// -----------------------------------------------------------------------------
+//	
+TInt CMccFileSink::FinalizeSendEvent( 
+    MAsyncEventHandler* aEventHandler, 
+    TMccEvent& aEvent )
+	{
+	TInt err( KErrNone );
+	if ( aEventHandler )
+	    {
+	    TMccInternalEvent internalEvent( KMccFileSinkUid, 
+		                                 EMccInternalEventNone,
+		                                 aEvent );
+		                         
+		err = aEventHandler->SendEventToClient( internalEvent );
+	    }
+	else
+		{
+		__FILESINK_CONTROLL( "CMccFileSink::FinalizeSend, aEventHandler=NULL" )
+		err = KErrNotReady;
+		}
+    return err;
+	}
+
+// ---------------------------------------------------------------------------
+// CMccFileSink::GetCodecTypeStringLC
+// ---------------------------------------------------------------------------
+//
+HBufC8* CMccFileSink::GetCodecTypeStringLC( const TMccCodecInfo& aCodecInfo )    
+    {
+    __FILESINK_CONTROLL( "CMccFileSink::GetCodecTypeStringLC" )
+    
+    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 );
+    
+    _LIT8( KMccCodecTypeFormat, "video/%S; %S" );
+    HBufC8* codecType = HBufC8::NewL( 
+        KMccCodecTypeFormat().Length() + fmtp->Length() + KMaxSdpNameLength );
+        
+    // Disabling PC-lint warnings 1025 and 64, which seems to be false warnings
+    /*lint -e1025 -e64*/  
+    codecType->Des().AppendFormat( KMccCodecTypeFormat(), &aCodecInfo.iSdpName, &*fmtp ); 
+    CleanupStack::PopAndDestroy( fmtp );
+    CleanupStack::PushL( codecType );
+     
+    __FILESINK_CONTROLL_STR8( "type string:", *codecType )
+    
+    return codecType;
+    }
+
+// ---------------------------------------------------------------------------
+// CMccFileSink::ResolveBufferType
+// Dec spec info cannot be given multiple times for file writer so ignore
+// all later dec spec info buffers. H264 bytestream buffers needs to be
+// ignored until dec spec info buffer has been written.
+// ---------------------------------------------------------------------------
+//
+CCMRMediaBuffer::TBufferType CMccFileSink::ResolveBufferType( 
+    CMMFDataBuffer& aBuffer,
+    TFourCC aDataType )
+    { 
+    CCMRMediaBuffer::TBufferType type = CCMRMediaBuffer::EVideoH263;
+    if ( aDataType == KMccFourCCIdAVC )
+        {
+        if ( TMccCodecInfo::IsAvcPpsOrSpsData( aBuffer.Data() ) )
+            {
+            __FILESINK_CONTROLL( "pps or sps" )
+            type = CCMRMediaBuffer::EVideoH264BytestreamDecSpecInfo;
+            }
+        else
+            {
+            type = CCMRMediaBuffer::EVideoH264Bytestream;
+            }
+        }
+    
+    __FILESINK_CONTROLL_INT1( "CMccFileSink::ResolveBufferType, type:", type )
+    
+    return type;
+    }
+
+// ---------------------------------------------------------------------------
+// CMccFileSink::CheckWritingPermissionL
+// 1) H264 dec spec info can be written only once to the file.
+// 2) Normal frames should not be written until IFrame has been written to file
+// as it will cause bad quality for the clip. 
+// 3) H264 bytestream cannot be written before dec spec info has been written.
+// ---------------------------------------------------------------------------
+//
+TBool CMccFileSink::CheckWritingPermission( 
+    CMMFDataBuffer& aBuffer,
+    const CCMRMediaBuffer::TBufferType& aBufferType )
+    { 
+    TBool ignoreBuffer( EFalse );
+
+    if ( aBufferType == CCMRMediaBuffer::EVideoH264BytestreamDecSpecInfo )
+        {
+        if ( !iDecSpecInfoProvided )
+            {
+            iDecSpecInfoProvided = ETrue;
+            ignoreBuffer = EFalse;
+            }
+        else
+            {
+            __FILESINK_CONTROLL( "Ignore as dec spec info already provided!" )
+            ignoreBuffer = ETrue;
+            }
+        }
+    else if ( iMccResources && !iKeyFrameProvided )
+        {
+        TBool keyFrame = iMccResources->IsKeyFrame( 
+                MCC_ENDPOINT_ID( static_cast<MDataSink*>( this ) ), aBuffer );
+        if ( keyFrame )
+            {
+            __FILESINK_CONTROLL_INT1( "Key frame match for timestamp:", 
+                                      aBuffer.TimeToPlay().Int64() )
+            iKeyFrameProvided = ETrue;
+            }
+        else
+            {
+            __FILESINK_CONTROLL( "Ignore as key frame not yet provided!" )
+            ignoreBuffer = ETrue;
+            }
+        }
+    else if ( aBufferType == CCMRMediaBuffer::EVideoH264Bytestream )
+        {
+        if ( !iDecSpecInfoProvided )
+            {
+            __FILESINK_CONTROLL( "Ignore as dec spec info not yet provided!" )
+            ignoreBuffer = ETrue;
+            }
+        }
+    else
+        {
+        // NOP
+        }
+    
+    __FILESINK_CONTROLL_INT1( "CMccFileSink::CheckWritingPermission, ignore:", 
+                              ignoreBuffer )
+    
+    return ignoreBuffer;
+    }
+
+// ---------------------------------------------------------------------------
+// CMccFileSink::SetStateL
+// ---------------------------------------------------------------------------
+//
+TBool CMccFileSink::SetStateL( TFileSinkState aState )
+    {
+    TBool controlSink( iCurrentState != aState );
+    TBool transitionOk( iCurrentState == aState );
+    switch ( aState )
+        {
+        case EReady:
+            { 
+            transitionOk = ETrue;
+            iCurrentState = aState;
+            break;
+            }
+        case EPaused:
+            {
+            if ( iCurrentState == ERecording )
+                {
+                transitionOk = ETrue;
+                iCurrentState = aState;
+                }
+            break;
+            }
+        case ERecording:
+            {
+            if ( iCurrentState == EReady || iCurrentState == EPaused )
+                {
+                transitionOk = ETrue;
+                iCurrentState = aState;
+                }
+            break;
+            }
+        case EStopped:
+            {
+            // State is not changed to stopped if there's several users
+            transitionOk = ETrue;
+            const TInt KMccFileSinkMultipleUsers = 2;
+            if ( iUsers.Count() < KMccFileSinkMultipleUsers )
+                {
+                iCurrentState = aState;
+                }
+            break;
+            }
+        default:
+            {
+            break;       
+            }
+        }
+
+    __ASSERT_ALWAYS( transitionOk, User::Leave( KErrNotReady ) );
+    
+    return controlSink;    
+    }
+
+// -----------------------------------------------------------------------------
+// CMccFileSink::DoSinkPrimeL
+// -----------------------------------------------------------------------------
+//
+void CMccFileSink::DoSinkPrimeL( TBool aSendEvent )
+	{
+	__FILESINK_CONTROLL( "CMccFileSink::DoSinkPrimeL" )
+
+    // If disk is full at beginning, ignore error at this stage and send disk
+    // full event when first buffer is tried to be written to file.
+    //
+    if ( SetStateL( EReady ) )
+        {
+        HBufC8* codecType = GetCodecTypeStringLC( ActiveUserL().iCodecInfo );
+    	TRAPD( err, iFileComposer->OpenFileL( iFileName, 
+    	                                      iAudioFourCC, 
+    	                                      *codecType ) );  
+
+        CleanupStack::PopAndDestroy( codecType );
+    	if ( err == KErrDiskFull )
+    	    {
+    	    __FILESINK_CONTROLL( "CMccFileSink::SinkPrimeL, disk full" )
+    	    iNotifySizeLimitReached = ETrue;
+    	    err = KErrNone;
+    	    }
+    	User::LeaveIfError( err );
+    	
+    	iDecSpecInfoProvided = EFalse;
+        }
+
+    if ( aSendEvent )
+        {
+    	SendStreamEventToClient( KMccStreamPrepared );	
+        }
+	}
+
+// -----------------------------------------------------------------------------
+// CMccFileSink::DoSinkPlayL
+// -----------------------------------------------------------------------------
+//
+void CMccFileSink::DoSinkPlayL( TBool aSendEvent )
+    { 
+    __ASSERT_ALWAYS( !iSizeLimitReached, User::Leave( KErrDiskFull ) );
+    
+    TMccEventType eventType = 
+        iCurrentState == EPaused ? KMccStreamResumed : KMccStreamStarted;
+    TFileSinkState oldState = iCurrentState;
+    
+    if ( SetStateL( ERecording ) )
+        {    
+        // First frame written to file should be keyframe
+        iKeyFrameProvided = EFalse;
+        
+    	if ( oldState == EPaused )
+            {
+            iT2.HomeTime();
+            __FILESINK_CONTROLL_INT1( "CMccFileSink::SinkPlayL, iT2=", iT2.Int64() )
+            SetPausedDuration( iT1, iT2 );
+            }
+        }
+	
+	if ( aSendEvent )
+	    {
+        SendStreamEventToClient( eventType );
+	    }
+    }
+
+// -----------------------------------------------------------------------------
+// CMccFileSink::DoSinkPauseL
+// -----------------------------------------------------------------------------
+//
+void CMccFileSink::DoSinkPauseL( TBool aSendEvent )
+    { 
+    TFileSinkState oldState = iCurrentState;
+    
+    if ( SetStateL( EPaused ) )
+        {  
+        if ( oldState == ERecording )
+            {
+            iT1.HomeTime();  
+            __FILESINK_CONTROLL_INT1( "CMccFileSink::SinkPauseL, iT1=", iT1.Int64() )
+            }   
+        }
+    
+	if ( aSendEvent )
+	    {
+	    SendStreamEventToClient( KMccStreamPaused );
+	    }
+    }
+    
+// -----------------------------------------------------------------------------
+// CMccFileSink::DoSinkStopL
+// -----------------------------------------------------------------------------
+//
+void CMccFileSink::DoSinkStopL( TBool aSendEvent )
+    {
+    __FILESINK_CONTROLL( "CMccFileSink::DoSinkStopL" )
+    
+     if ( SetStateL( EStopped ) )
+        {  
+    	iFileComposer->SinkStopL();
+        
+        ResetTimers();
+        }
+
+    if ( aSendEvent )
+        {
+	    SendStreamEventToClient( KMccStreamStopped );	
+        }
+    }	
+
+// -----------------------------------------------------------------------------
+// CMccFileSink::DoCodecChangeL
+// -----------------------------------------------------------------------------
+//
+void CMccFileSink::DoCodecChangeL()
+    {
+    __FILESINK_CONTROLL( "CMccFileSink::DoCodecChangeL" )
+    
+    TFileSinkState oldState = iCurrentState;
+    
+    DoSinkStopL( EFalse );
+    DoSinkPrimeL( EFalse );
+    
+    if ( oldState == ERecording || oldState == EPaused )
+        {
+        DoSinkPlayL( EFalse );
+        if ( oldState == EPaused )
+            {
+            DoSinkPauseL( EFalse );
+            }
+        }
+    
+    __FILESINK_CONTROLL( "CMccFileSink::DoCodecChangeL, exit" )
+    }
+
+// -----------------------------------------------------------------------------
+// CMccFileSink::AddUserL()
+// -----------------------------------------------------------------------------
+// 
+void CMccFileSink::AddUserL( MAsyncEventHandler* aEventHandler )
+    {
+    TMccFileSinkUser* user = new ( ELeave ) TMccFileSinkUser( aEventHandler );
+    CleanupStack::PushL( user );
+    iUsers.AppendL( user );
+    CleanupStack::Pop( user );
+    }
+
+// -----------------------------------------------------------------------------
+// CMccFileSink::ActiveUserL()
+// -----------------------------------------------------------------------------
+//
+TMccFileSinkUser& CMccFileSink::ActiveUserL()
+    {
+    __ASSERT_ALWAYS( iUsers.Count() > 0, User::Leave( KErrNotReady ) );
+    TInt index( 0 );
+    if ( iActiveUserIndex != KErrNotFound && iActiveUserIndex < iUsers.Count() )
+        {
+        index = iActiveUserIndex;
+        }
+    return *iUsers[ index ];
+    }
+
+// -----------------------------------------------------------------------------
+// CMccFileSink::IsActiveUser()
+// -----------------------------------------------------------------------------
+//
+TBool CMccFileSink::IsActiveUser( MAsyncEventHandler* aUser )
+    {
+    TInt index = 
+        MccUserArray<TMccFileSinkUser>::FindUserEntryIndexForCurrent( iUsers, aUser );
+    return ( index != KErrNotFound && index == iActiveUserIndex );
+    }
+
+// -----------------------------------------------------------------------------
+// CMccFileSink::UpdateActiveUserL()
+// -----------------------------------------------------------------------------
+//
+TFourCC CMccFileSink::UpdateActiveUserL( TMediaId aMediaId, MDataSource& aDataProvider )
+    {
+    TBool doCodecChange( EFalse );
+    
+    TFourCC providerDataType = aDataProvider.SourceDataTypeCode( aMediaId );
+    
+    if ( iActiveUserIndex == KErrNotFound )
+        {
+        SetActiveUserIndex( 0 );
+        doCodecChange = ETrue;
+        
+        __FILESINK_CONTROLL_INT1( 
+            "CMccFileSink::UpdateActiveUserL, new active user index:", iActiveUserIndex )
+        }
+    else
+        {
+        if ( ActiveUserL().iCodecInfo.iFourCC != providerDataType )
+            {    
+            __FILESINK_CONTROLL_INT1( 
+                "CMccFileSink::UpdateActiveUserL, provider fourcc:", 
+                providerDataType.FourCC() )
+            
+            __FILESINK_CONTROLL_INT1( 
+                "CMccFileSink::UpdateActiveUserL, active user fourcc:", 
+                ActiveUserL().iCodecInfo.iFourCC.FourCC() )
+            
+            for ( TInt i = 0; i < iUsers.Count() && !doCodecChange; i++ )
+                {
+                if ( iUsers[ i ]->iCodecInfo.iFourCC == providerDataType )
+                    {
+                    SetActiveUserIndex( i );
+                    doCodecChange = ETrue;
+                    }
+                }
+            }
+        }
+        
+    if ( doCodecChange )
+        {
+        SetCurrentUser( ActiveUserL().iEventHandler );
+        DoCodecChangeL();
+        }
+        
+    return providerDataType;
+    }
+
+// -----------------------------------------------------------------------------
+// CMccFileSink::SetActiveUserIndex()
+// -----------------------------------------------------------------------------
+//
+void CMccFileSink::SetActiveUserIndex( TInt aIndex )
+    {
+    __FILESINK_CONTROLL_INT1( "CMccFileSink::SetActiveUserIndex, index:", aIndex )
+            
+    iActiveUserIndex = aIndex;
+    }
+    
+#ifndef EKA2
+EXPORT_C TInt E32Dll( TDllReason )
+    {
+    return KErrNone;
+    }
+#endif
+