multimediacommscontroller/mmccfilesourcesink/src/mccfilesink.cpp
changeset 0 1bce908db942
child 17 a5ac35ca6d81
equal deleted inserted replaced
-1:000000000000 0:1bce908db942
       
     1 /*
       
     2 * Copyright (c) 2006 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:    
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 
       
    20         
       
    21 // INCLUDE FILES
       
    22 #include <mmcccodecinformationfactory.h>
       
    23 #include <mmcccodecinformation.h>
       
    24 #include "mccfilesink.h"
       
    25 #include "mmccinterfacedef.h"
       
    26 #include "mmcccodecinformation.h"
       
    27 #include "mccfilesinklogs.h"
       
    28 #include "mccinternalevents.h"
       
    29 #include "mccinternaldef.h"
       
    30 #include "mccresources.h"
       
    31 
       
    32 // CONSTANTS
       
    33 
       
    34 const TInt KMccMaxNumTimestamps = 5;
       
    35 
       
    36 const TInt KMccTimestampDifferenceMultiplier = 10;
       
    37 
       
    38 // ============================ MEMBER FUNCTIONS ===============================
       
    39 
       
    40 // -----------------------------------------------------------------------------
       
    41 // CMccFileSink::NewSinkL
       
    42 // -----------------------------------------------------------------------------
       
    43 //
       
    44 MDataSink* CMccFileSink::NewSinkL( TUid /*aImplementationUid*/, 
       
    45                                    const TDesC8& /*aInitData*/ )
       
    46     {
       
    47     __FILESINK_CONTROLL( "CMccFileSink::NewSinkL" )
       
    48     CMccFileSink* self = new ( ELeave ) CMccFileSink();
       
    49     return static_cast<MDataSink*>( self );
       
    50     }
       
    51 
       
    52 // -----------------------------------------------------------------------------
       
    53 // CMccFileSink::ConstructSinkL
       
    54 // -----------------------------------------------------------------------------
       
    55 //
       
    56 void CMccFileSink::ConstructSinkL( const TDesC8& aInitData )
       
    57     {
       
    58     __FILESINK_CONTROLL( "CMccFileSink::ConstructSinkL" )
       
    59 
       
    60 	iFileComposer = CCamC3GPDataSink::NewL( this );
       
    61     iFileComposer->SetSizeLimit( iMaxFileSize );
       
    62     
       
    63     TPckgBuf<TFileName> initData;
       
    64     initData.Copy( aInitData );
       
    65     iFileName = initData();
       
    66     
       
    67     }
       
    68     
       
    69 // -----------------------------------------------------------------------------
       
    70 // CMccFileSink::CMccFileSink
       
    71 // -----------------------------------------------------------------------------
       
    72 //
       
    73 CMccFileSink::CMccFileSink() : 
       
    74     CMccDataSink( KMccFileSinkUid )
       
    75     {
       
    76     iVideoCodec.iFourCC = TFourCC( KMccFourCCIdH263 );
       
    77     // FJKI-7J58CB no use case for audio in file, hence removing the audio track capability 
       
    78     //             per request from customer
       
    79     // iAudioFourCC = TFourCC( KMccFourCCIdAMRNB );
       
    80     iAudioFourCC = TFourCC( KMMFFourCCCodeNULL );
       
    81     iFileName = KNullDesC;
       
    82     iMaxFileSize = 0; 
       
    83     iT1 = 0;
       
    84     iT2 = 0;
       
    85     iPausedDuration = 0;
       
    86     iPreviousTimestamp = 0;
       
    87     iAddToTimestamp = 0;
       
    88     iSizeLimitReached = EFalse;
       
    89     iNotifySizeLimitReached = EFalse;
       
    90     SetActiveUserIndex( 0 );
       
    91     }
       
    92         
       
    93 // -----------------------------------------------------------------------------
       
    94 // CMccFileSink::~CMccFileSink
       
    95 // -----------------------------------------------------------------------------
       
    96 //
       
    97 CMccFileSink::~CMccFileSink()
       
    98     {
       
    99     __FILESINK_CONTROLL( "CMccFileSink::~CMccFileSink" )
       
   100     // Cleanup and other ending operations...
       
   101     if ( iCurrentState == ERecording || iCurrentState == EPaused )
       
   102         {
       
   103         TRAP_IGNORE( CMccFileSink::SinkStopL() );
       
   104         }	
       
   105 	delete iFileComposer;
       
   106 	iTimestamps.Close();
       
   107 	
       
   108 	iUsers.ResetAndDestroy();
       
   109     }
       
   110 
       
   111 // -----------------------------------------------------------------------------
       
   112 // CMccFileSink::SetCurrentUser
       
   113 // -----------------------------------------------------------------------------
       
   114 //
       
   115 void CMccFileSink::SetCurrentUser( MAsyncEventHandler* aEventHandler )
       
   116     {
       
   117     iAsyncEventHandler = aEventHandler;
       
   118     }
       
   119 
       
   120 // -----------------------------------------------------------------------------
       
   121 // CMccFileSink::SinkPrimeL
       
   122 // -----------------------------------------------------------------------------
       
   123 //
       
   124 void CMccFileSink::SinkPrimeL()
       
   125 	{
       
   126 	__FILESINK_CONTROLL( "CMccFileSink::SinkPrimeL" )
       
   127 
       
   128     DoSinkPrimeL();	
       
   129 	}
       
   130 	
       
   131 // -----------------------------------------------------------------------------
       
   132 // CMccFileSink::SinkPlayL()
       
   133 // -----------------------------------------------------------------------------
       
   134 //
       
   135 void CMccFileSink::SinkPlayL()
       
   136     {
       
   137     __FILESINK_CONTROLL( "CMccFileSink::SinkPlayL" )  
       
   138     
       
   139     DoSinkPlayL();
       
   140     }
       
   141 
       
   142 // -----------------------------------------------------------------------------
       
   143 // CMccFileSink::SinkPauseL()
       
   144 // 
       
   145 // Pauses streaming by cancelling timers
       
   146 // -----------------------------------------------------------------------------
       
   147 //
       
   148 void CMccFileSink::SinkPauseL()
       
   149     {
       
   150     __FILESINK_CONTROLL( "CMccFileSink::SinkPauseL" )
       
   151 
       
   152     DoSinkPauseL();
       
   153 	}
       
   154 
       
   155 // -----------------------------------------------------------------------------
       
   156 // CMccFileSink::SinkStopL()
       
   157 // 
       
   158 // Stops streaming
       
   159 // -----------------------------------------------------------------------------
       
   160 //
       
   161 void CMccFileSink::SinkStopL()
       
   162     {
       
   163     __FILESINK_CONTROLL( "CMccFileSink::SinkStopL" )
       
   164     
       
   165     DoSinkStopL();		
       
   166     }
       
   167 
       
   168 // -----------------------------------------------------------------------------
       
   169 // CMccFileSink::SinkDataTypeCode
       
   170 // -----------------------------------------------------------------------------
       
   171 //
       
   172 TFourCC CMccFileSink::SinkDataTypeCode( TMediaId aMediaId )
       
   173 	{
       
   174     __FILESINK_CONTROLL( "CMccFileSink::SinkDataTypeCode" )
       
   175 
       
   176     if ( KUidMediaTypeVideo == aMediaId.iMediaType )
       
   177         {
       
   178         return iVideoCodec.iFourCC;
       
   179         }
       
   180     else if ( KUidMediaTypeAudio == aMediaId.iMediaType  )
       
   181         {
       
   182         return iAudioFourCC;
       
   183         }
       
   184     else
       
   185         {
       
   186         return TFourCC( KMMFFourCCCodeNULL );
       
   187         }
       
   188 	}
       
   189 	
       
   190 // -----------------------------------------------------------------------------
       
   191 // CMccFileSink::SetSinkDataTypeCode
       
   192 // -----------------------------------------------------------------------------
       
   193 //
       
   194 TInt CMccFileSink::SetSinkDataTypeCode( TFourCC aCodec, 
       
   195                             TMediaId aMediaId )
       
   196 	{
       
   197     __FILESINK_CONTROLL( "CMccFileSink::SetSinkDataTypeCode" )
       
   198 
       
   199     TInt retVal = KErrNone;
       
   200     if ( KUidMediaTypeVideo == aMediaId.iMediaType &&
       
   201     	aCodec == iVideoCodec.iFourCC )
       
   202         {
       
   203         retVal = KErrNone;
       
   204         }
       
   205     else if ( KUidMediaTypeAudio == aMediaId.iMediaType &&
       
   206     	aCodec == iAudioFourCC )
       
   207         {
       
   208         retVal = KErrNone;
       
   209         }
       
   210     else
       
   211         {
       
   212         retVal = KErrNotSupported;
       
   213         }
       
   214 
       
   215 	return retVal;
       
   216 	}	
       
   217 
       
   218 // -----------------------------------------------------------------------------
       
   219 // CMccFileSink::BufferEmptiedL
       
   220 // -----------------------------------------------------------------------------
       
   221 //
       
   222 void CMccFileSink::BufferEmptiedL( CMMFBuffer* /*aBuffer*/ )
       
   223 	{
       
   224     __FILESINK_MEDIA( "CMccFileSink::BufferEmptiedL" )
       
   225     User::Leave( KErrNotSupported );
       
   226 	}
       
   227 	
       
   228 // -----------------------------------------------------------------------------
       
   229 // CMccFileSink::CanCreateSinkBuffer
       
   230 // -----------------------------------------------------------------------------
       
   231 //
       
   232 TBool CMccFileSink::CanCreateSinkBuffer()
       
   233 	{
       
   234     __FILESINK_CONTROLL( "CMccFileSink::CanCreateSinkBuffer, EFalse" )
       
   235 	return EFalse;
       
   236 	}	
       
   237 
       
   238 // -----------------------------------------------------------------------------
       
   239 // CMccFileSink::CreateSinkBufferL
       
   240 // -----------------------------------------------------------------------------
       
   241 //
       
   242 CMMFBuffer* CMccFileSink::CreateSinkBufferL( 
       
   243 	TMediaId /*aMediaId*/, 
       
   244     TBool& /*aReference*/ )
       
   245 	{
       
   246 	__FILESINK_CONTROLL( "CMccFileSink::CreateSinkBufferL, return NULL" )
       
   247     CMMFBuffer* buffer = NULL;
       
   248 	User::Leave( KErrNotSupported );	
       
   249 	return buffer;	
       
   250 	}
       
   251 	
       
   252 // -----------------------------------------------------------------------------
       
   253 // CMccFileSink::SinkThreadLogon
       
   254 // -----------------------------------------------------------------------------
       
   255 //
       
   256 TInt CMccFileSink::SinkThreadLogon( MAsyncEventHandler& aEventHandler )
       
   257 	{
       
   258     __FILESINK_CONTROLL( "CMccFileSink::SinkThreadLogon" )
       
   259 
       
   260     TInt err( KErrNone );
       
   261     TMccFileSinkUser* userEntry = 
       
   262         MccUserArray<TMccFileSinkUser>::FindUserEntryForCurrent( iUsers, &aEventHandler );
       
   263     if ( !userEntry )
       
   264         {
       
   265         TRAP( err, AddUserL( &aEventHandler ) );
       
   266         }
       
   267     
       
   268     __FILESINK_CONTROLL_INT1( 
       
   269         "CMccFileSink::SinkThreadLogon, exit with err:", err )
       
   270         
       
   271     return err;
       
   272 	}
       
   273 	
       
   274 // -----------------------------------------------------------------------------
       
   275 // CMccFileSink::SinkThreadLogoff
       
   276 // -----------------------------------------------------------------------------
       
   277 //
       
   278 void CMccFileSink::SinkThreadLogoff()
       
   279 	{
       
   280 	__FILESINK_CONTROLL( "CMccFileSink::SinkThreadLogoff" )
       
   281 
       
   282     // If multiple different codecs are using the filesink and active user
       
   283     // is removed, reset active user information so that new active user
       
   284     // can be seleceted once someone else tries to use the sink
       
   285     if ( IsActiveUser( iAsyncEventHandler ) )
       
   286         {
       
   287         SetActiveUserIndex( KErrNotFound );
       
   288         }
       
   289          
       
   290     MccUserArray<TMccFileSinkUser>::RemoveCurrentUser( iUsers, iAsyncEventHandler );
       
   291     
       
   292     if ( iUsers.Count() > 0 )
       
   293         {
       
   294         SetCurrentUser( iUsers[ 0 ]->iEventHandler );
       
   295         }
       
   296     else
       
   297         {
       
   298         SetCurrentUser( NULL );
       
   299         }
       
   300 	}
       
   301 
       
   302 // -----------------------------------------------------------------------------
       
   303 // CMccFileSink::EmptyBufferL
       
   304 // -----------------------------------------------------------------------------
       
   305 //
       
   306 void CMccFileSink::EmptyBufferL( CMMFBuffer* aBuffer,
       
   307                   MDataSource* aProvider,
       
   308                   TMediaId aMediaId )
       
   309 	{
       
   310 	__FILESINK_MEDIA( "CMccFileSink::EmptyBufferL" )
       
   311 	
       
   312 	__ASSERT_ALWAYS( aBuffer && aProvider, User::Leave( KErrArgument ) );
       
   313 	
       
   314 	
       
   315     if ( iCurrentState != ERecording )
       
   316         {
       
   317         __FILESINK_MEDIA( "CMccFileSink::EmptyBufferL, IGNORED" )
       
   318         
       
   319         // Do not let the datapath to halt
       
   320         aProvider->BufferEmptiedL( aBuffer );
       
   321         return;
       
   322         }
       
   323 
       
   324     if ( iNotifySizeLimitReached )
       
   325         {
       
   326         __FILESINK_MEDIA( 
       
   327             "CMccFileSink::EmptyBufferL, IGNORED (notify size limit reached)" )
       
   328         MfcoSizeLimitReachedL();
       
   329         
       
   330         // Do not let the datapath to halt
       
   331         aProvider->BufferEmptiedL( aBuffer );
       
   332         return;
       
   333         }
       
   334         
       
   335 	CMMFDataBuffer* buffer = static_cast<CMMFDataBuffer*>(aBuffer);
       
   336 	CCMRMediaBuffer* outBuffer = NULL; 
       
   337 	                  
       
   338 	TTimeIntervalMicroSeconds timeToPlay = TimeToPlayL( buffer->TimeToPlay() );
       
   339     	    	
       
   340    	__FILESINK_MEDIA_INT1( "CMccFileSink::EmptyBufferL, timeToPlay = ", 
       
   341 	                       timeToPlay.Int64() )
       
   342 	
       
   343 	TBool dropBuffer( EFalse );                      
       
   344 	if ( aMediaId.iMediaType == KUidMediaTypeAudio )
       
   345 		{
       
   346     	__FILESINK_MEDIA( "CMccFileSink::EmptyBufferL, audio" )
       
   347     	    
       
   348     	outBuffer = new ( ELeave ) CCMRMediaBuffer(
       
   349         	buffer->Data(), CCMRMediaBuffer::EAudioAMRNB, buffer->BufferSize(),
       
   350             ETrue,  timeToPlay ); 
       
   351         CleanupStack::PushL( outBuffer );  
       
   352 		}
       
   353 	else if ( aMediaId.iMediaType == KUidMediaTypeVideo )
       
   354 		{
       
   355     	__FILESINK_MEDIA( "CMccFileSink::EmptyBufferL, video" )    
       
   356         
       
   357         TFourCC providerDataType = UpdateActiveUserL( aMediaId, *aProvider );
       
   358         
       
   359         CCMRMediaBuffer::TBufferType bufType = 
       
   360             ResolveBufferType( *buffer, providerDataType );	
       
   361         
       
   362         dropBuffer = CheckWritingPermission( *buffer, bufType );
       
   363         
       
   364     	outBuffer = new ( ELeave ) CCMRMediaBuffer(
       
   365         	buffer->Data(), bufType, buffer->BufferSize(),
       
   366             ETrue,  timeToPlay );    
       
   367             
       
   368         CleanupStack::PushL( outBuffer );   
       
   369 		}
       
   370 	else
       
   371 		{
       
   372     	__FILESINK_MEDIA( "CMccFileSink::EmptyBufferL, unknown media" ) 
       
   373 		User::Leave( KErrNotSupported );	
       
   374 		}
       
   375     
       
   376     if ( !dropBuffer )
       
   377         {
       
   378     	iFileComposer->WriteBufferL( outBuffer );
       
   379         }
       
   380         
       
   381 	CleanupStack::PopAndDestroy( outBuffer );
       
   382 	outBuffer= NULL;
       
   383 	aProvider->BufferEmptiedL( aBuffer );
       
   384 	}	
       
   385 
       
   386 // -----------------------------------------------------------------------------
       
   387 // CMccFileSink::BufferFilledL
       
   388 // -----------------------------------------------------------------------------
       
   389 //
       
   390 void CMccFileSink::BufferFilledL( CMMFBuffer* /*aBuffer*/ )
       
   391 	{
       
   392 	__FILESINK_MEDIA( "CMccFileSink::BufferFilledL" )
       
   393 	}	                  
       
   394 
       
   395 // -----------------------------------------------------------------------------
       
   396 // CMccFileSink::MfcoDiskFullL
       
   397 // -----------------------------------------------------------------------------
       
   398 //
       
   399 void CMccFileSink::MfcoDiskFullL()
       
   400 	{
       
   401 	__FILESINK_MEDIA( "CMccFileSink::MfcoDiskFullL" )
       
   402 	
       
   403 	// After size limit has been reached, there is no way to really continue
       
   404 	// recording to the same file, writebuffer returns without error but
       
   405 	// has no effect. Pause the sink anyway but fail if resume is tried.
       
   406 	// Creating new filewriter would be only way to recover from this but
       
   407 	// that would overwrite old recording.
       
   408 	iSizeLimitReached = ETrue;
       
   409 	
       
   410 	SendStreamEventToClient( KMccResourceNotAvailable, KErrNoMemory, ETrue );
       
   411 	
       
   412     TRAP_IGNORE( AutomaticPauseL() );
       
   413     
       
   414     iNotifySizeLimitReached = EFalse;
       
   415 	}	                  
       
   416 
       
   417 // -----------------------------------------------------------------------------
       
   418 // CMccFileSink::MfcoSizeLimitReachedL
       
   419 // -----------------------------------------------------------------------------
       
   420 //
       
   421 void CMccFileSink::MfcoSizeLimitReachedL()
       
   422 	{
       
   423 	__FILESINK_MEDIA( "CMccFileSink::MfcoSizeLimitReachedL" )
       
   424 	
       
   425 	iSizeLimitReached = ETrue;
       
   426 	
       
   427 	SendStreamEventToClient( KMccResourceNotAvailable, KErrNone, ETrue );
       
   428 
       
   429     TRAP_IGNORE( AutomaticPauseL() );
       
   430     
       
   431     iNotifySizeLimitReached = EFalse;
       
   432 	}	                  
       
   433 
       
   434 // -----------------------------------------------------------------------------
       
   435 // CMccFileSink::SetVideoCodecL
       
   436 // -----------------------------------------------------------------------------
       
   437 //
       
   438 void CMccFileSink::SetVideoCodecL( const TMccCodecInfo& aVideoCodec )
       
   439     {
       
   440    	__FILESINK_CONTROLL_STR8( 
       
   441 	    "CMccFileSink::SetVideoCodecL, sdpname:", aVideoCodec.iSdpName )
       
   442     
       
   443     TMccFileSinkUser* user = 
       
   444         MccUserArray<TMccFileSinkUser>::FindUserEntryForCurrent( iUsers, iAsyncEventHandler );
       
   445     if ( user )
       
   446         {
       
   447         user->iCodecInfo = aVideoCodec;
       
   448         }
       
   449     }
       
   450 
       
   451 // -----------------------------------------------------------------------------
       
   452 // CMccFileSink::SetAudioCodecL
       
   453 // -----------------------------------------------------------------------------
       
   454 //
       
   455 void CMccFileSink::SetAudioCodecL( const TMccCodecInfo& /*aAudioCodec*/ )
       
   456     {
       
   457     __FILESINK_MEDIA( "CMccFileSink::SetAudioCodecL" )
       
   458     }
       
   459     
       
   460 // -----------------------------------------------------------------------------
       
   461 // CMccFileSink::RecordTimeAvailableL
       
   462 // -----------------------------------------------------------------------------
       
   463 //
       
   464 void CMccFileSink::RecordTimeAvailableL( TTimeIntervalMicroSeconds& aTime )
       
   465 	{ 
       
   466 	__FILESINK_CONTROLL( "CMccFileSink::RecordTimeAvailableL" )
       
   467 	aTime = iFileComposer->GetRemainingTimeL();
       
   468 	}
       
   469 
       
   470 // -----------------------------------------------------------------------------
       
   471 // CMccFileSink::SetFileNameL
       
   472 // -----------------------------------------------------------------------------
       
   473 //
       
   474 void CMccFileSink::SetFileNameL( const TFileName aFileName )
       
   475 	{
       
   476 	__FILESINK_CONTROLL( "CMccFileSink::SetFileNameL" )
       
   477 	iFileName = aFileName;
       
   478 	}
       
   479 	
       
   480 // -----------------------------------------------------------------------------
       
   481 // CMccFileSink::SendStreamEventToClient
       
   482 // -----------------------------------------------------------------------------
       
   483 //	
       
   484 void CMccFileSink::SendStreamEventToClient( 
       
   485     TMccEventType aEventType, 
       
   486     TInt aError,
       
   487     TBool aToAllClients )
       
   488 	{
       
   489 	__FILESINK_CONTROLL_INT2( 
       
   490 	    "CMccFileSink::SendStreamEventToClient, type", aEventType, 
       
   491 	    " to all:", aToAllClients )
       
   492 	
       
   493     TMccEvent event( 0, 
       
   494                      0, 
       
   495                      0, 
       
   496                      MCC_ENDPOINT_ID( static_cast<MDataSink*>( this ) ), 
       
   497                      KMccEventCategoryStream, 
       
   498                      aEventType, 
       
   499                      aError, 
       
   500                      KNullDesC8 );
       
   501 
       
   502     if ( aToAllClients )
       
   503         {
       
   504         for ( TInt i = 0; i < iUsers.Count(); i++ )
       
   505             {
       
   506             FinalizeSendEvent( iUsers[ i ]->iEventHandler, event );
       
   507             }
       
   508         }
       
   509     else
       
   510         {
       
   511         FinalizeSendEvent( iAsyncEventHandler, event );
       
   512         }
       
   513 	}
       
   514 	
       
   515 // -----------------------------------------------------------------------------
       
   516 // CMccFileSink::TimeToPlayL
       
   517 // -----------------------------------------------------------------------------
       
   518 //	   	
       
   519 TTimeIntervalMicroSeconds CMccFileSink::TimeToPlayL( 
       
   520     TTimeIntervalMicroSeconds aCurrentTimestamp )
       
   521     { 
       
   522     CalculateAverageTimestampDifferenceL( aCurrentTimestamp );
       
   523 
       
   524     TTimeIntervalMicroSeconds timeToPlay( 0 );
       
   525     
       
   526     if ( aCurrentTimestamp >= iPausedDuration )
       
   527         {
       
   528         __FILESINK_CONTROLL("CMccFileSink::TimeToPlay aCurrentTimestamp \
       
   529 >= iPausedDuration" )
       
   530 
       
   531         timeToPlay = aCurrentTimestamp.Int64() - iPausedDuration.Int64();    
       
   532         }
       
   533     else
       
   534         {
       
   535         __FILESINK_CONTROLL("CMccFileSink::TimeToPlay aCurrentTimestamp \
       
   536 < iPausedDuration" )
       
   537         timeToPlay = aCurrentTimestamp; 
       
   538         }
       
   539    
       
   540     timeToPlay = ( timeToPlay.Int64() + iAddToTimestamp );
       
   541     
       
   542     __FILESINK_CONTROLL_INT1("CMccFileSink::TimeToPlay, \
       
   543 timeToPlay=", timeToPlay.Int64() )  
       
   544 
       
   545     iPreviousTimestamp = aCurrentTimestamp;
       
   546   
       
   547     return timeToPlay;
       
   548     }
       
   549 
       
   550 // -----------------------------------------------------------------------------
       
   551 // CMccFileSink::CalculateAverageTimestampDifferenceL
       
   552 // -----------------------------------------------------------------------------
       
   553 //  
       
   554 void CMccFileSink::CalculateAverageTimestampDifferenceL( 
       
   555     const TTimeIntervalMicroSeconds& aCurrentTimestamp )
       
   556     {
       
   557     TInt64 averageTimeStampDifference = 0;
       
   558     if ( iTimestamps.Count() == KMccMaxNumTimestamps )
       
   559        {
       
   560        
       
   561        for ( TInt i = iTimestamps.Count() - 1; i > 0; i-- )
       
   562                {
       
   563                averageTimeStampDifference += ( iTimestamps[ i ] - iTimestamps[ i - 1 ] );
       
   564                }
       
   565                
       
   566        averageTimeStampDifference = averageTimeStampDifference / ( KMccMaxNumTimestamps - 1 );
       
   567        }
       
   568     
       
   569     if ( aCurrentTimestamp > iPreviousTimestamp )
       
   570        {
       
   571        if ( iTimestamps.Count() >= KMccMaxNumTimestamps )
       
   572            {
       
   573            iTimestamps.Remove( 0 );
       
   574            }
       
   575        iTimestamps.AppendL( aCurrentTimestamp.Int64() );
       
   576        }
       
   577     else
       
   578        {
       
   579        TInt64 currDifference = iPreviousTimestamp.Int64() - aCurrentTimestamp.Int64();
       
   580        if ( averageTimeStampDifference != 0 && 
       
   581             currDifference > ( averageTimeStampDifference * KMccTimestampDifferenceMultiplier ) )
       
   582            {
       
   583            iAddToTimestamp += ( currDifference + averageTimeStampDifference );
       
   584            iTimestamps.Reset();
       
   585            
       
   586            __FILESINK_CONTROLL_INT1("CMccFileSink::TimeToPlay, iAddToTimestamp=", iAddToTimestamp )  
       
   587            }
       
   588        }
       
   589     }
       
   590 
       
   591 // -----------------------------------------------------------------------------
       
   592 // CMccFileSink::ResetTimers
       
   593 // -----------------------------------------------------------------------------
       
   594 //	  
       
   595 void CMccFileSink::ResetTimers()
       
   596     {
       
   597     iT1 = 0;
       
   598     iT2 = 0; 
       
   599     iPausedDuration = 0;  
       
   600     iPreviousTimestamp = 0;
       
   601     iAddToTimestamp = 0;
       
   602     iTimestamps.Reset();
       
   603     }
       
   604 
       
   605 // -----------------------------------------------------------------------------
       
   606 // CMccFileSink::SetPausedDuration
       
   607 // -----------------------------------------------------------------------------
       
   608 //	
       
   609 void CMccFileSink::SetPausedDuration( TTime aT1, TTime aT2 )
       
   610     {
       
   611     __FILESINK_CONTROLL( "CMccFileSink::SetPausedDuration" )
       
   612     __FILESINK_CONTROLL_INT2( 
       
   613         "CMccFileSink::SetPausedDuration, aT1=", aT1.Int64(),
       
   614         "aT2=", aT2.Int64() )
       
   615 
       
   616     if ( aT1 != 0 && aT1 < aT2 )
       
   617         {
       
   618         __FILESINK_CONTROLL_INT1("CMccFileSink::SetPausedDuration, \
       
   619 before iPausedDuration=", iPausedDuration.Int64() ) 
       
   620 
       
   621         iPausedDuration = ( iPausedDuration.Int64() + 
       
   622                             aT2.MicroSecondsFrom( aT1 ).Int64() );
       
   623                             
       
   624         __FILESINK_CONTROLL_INT1("CMccFileSink::SetPausedDuration, \
       
   625 after iPausedDuration=", iPausedDuration.Int64() ) 
       
   626         }
       
   627     }
       
   628 
       
   629 // -----------------------------------------------------------------------------
       
   630 // CMccFileSink::AutomaticPauseL
       
   631 // -----------------------------------------------------------------------------
       
   632 //
       
   633 void CMccFileSink::AutomaticPauseL()
       
   634     {
       
   635     __FILESINK_CONTROLL( "CMccFileSink::AutomaticPauseL" )
       
   636     
       
   637     for ( TInt i = 0; i < iUsers.Count(); i++ )
       
   638         {
       
   639         TMccEvent* controlEvent = new ( ELeave ) TMccEvent;
       
   640         CleanupStack::PushL( controlEvent );
       
   641         
       
   642         controlEvent->iEndpointId = MCC_ENDPOINT_ID( static_cast<MDataSink*>( this ) );
       
   643     	controlEvent->iEventCategory = KMccEventCategoryStreamControl;
       
   644     	controlEvent->iEventType = KMccStreamPaused;
       
   645     	controlEvent->iEventNumData = KMccAutomaticEvent;
       
   646 
       
   647         User::LeaveIfError( 
       
   648             FinalizeSendEvent( iUsers[ i ]->iEventHandler, *controlEvent ) );
       
   649         
       
   650         CleanupStack::PopAndDestroy( controlEvent );
       
   651         }
       
   652     
       
   653     __FILESINK_CONTROLL( "CMccFileSink::AutomaticPauseL, exit" )
       
   654     }  
       
   655 	
       
   656 // -----------------------------------------------------------------------------
       
   657 // CMccFileSink::FinalizeSendEvent
       
   658 // -----------------------------------------------------------------------------
       
   659 //	
       
   660 TInt CMccFileSink::FinalizeSendEvent( 
       
   661     MAsyncEventHandler* aEventHandler, 
       
   662     TMccEvent& aEvent )
       
   663 	{
       
   664 	TInt err( KErrNone );
       
   665 	if ( aEventHandler )
       
   666 	    {
       
   667 	    TMccInternalEvent internalEvent( KMccFileSinkUid, 
       
   668 		                                 EMccInternalEventNone,
       
   669 		                                 aEvent );
       
   670 		                         
       
   671 		err = aEventHandler->SendEventToClient( internalEvent );
       
   672 	    }
       
   673 	else
       
   674 		{
       
   675 		__FILESINK_CONTROLL( "CMccFileSink::FinalizeSend, aEventHandler=NULL" )
       
   676 		err = KErrNotReady;
       
   677 		}
       
   678     return err;
       
   679 	}
       
   680 
       
   681 // ---------------------------------------------------------------------------
       
   682 // CMccFileSink::GetCodecTypeStringLC
       
   683 // ---------------------------------------------------------------------------
       
   684 //
       
   685 HBufC8* CMccFileSink::GetCodecTypeStringLC( const TMccCodecInfo& aCodecInfo )    
       
   686     {
       
   687     __FILESINK_CONTROLL( "CMccFileSink::GetCodecTypeStringLC" )
       
   688     
       
   689     CMccCodecInformationFactory* factory = CMccCodecInformationFactory::NewL();
       
   690     CleanupStack::PushL( factory );
       
   691     CMccCodecInformation* codec = 
       
   692         factory->CreateCodecInformationL( aCodecInfo.iSdpName );
       
   693     CleanupStack::PushL( codec );
       
   694     codec->SetValues( aCodecInfo );
       
   695     HBufC8* fmtp = codec->GetFmtpL().AllocL();
       
   696     CleanupStack::PopAndDestroy( codec );
       
   697     CleanupStack::PopAndDestroy( factory );
       
   698     CleanupStack::PushL( fmtp );
       
   699     
       
   700     _LIT8( KMccCodecTypeFormat, "video/%S; %S" );
       
   701     HBufC8* codecType = HBufC8::NewL( 
       
   702         KMccCodecTypeFormat().Length() + fmtp->Length() + KMaxSdpNameLength );
       
   703         
       
   704     // Disabling PC-lint warnings 1025 and 64, which seems to be false warnings
       
   705     /*lint -e1025 -e64*/  
       
   706     codecType->Des().AppendFormat( KMccCodecTypeFormat(), &aCodecInfo.iSdpName, &*fmtp ); 
       
   707     CleanupStack::PopAndDestroy( fmtp );
       
   708     CleanupStack::PushL( codecType );
       
   709      
       
   710     __FILESINK_CONTROLL_STR8( "type string:", *codecType )
       
   711     
       
   712     return codecType;
       
   713     }
       
   714 
       
   715 // ---------------------------------------------------------------------------
       
   716 // CMccFileSink::ResolveBufferType
       
   717 // Dec spec info cannot be given multiple times for file writer so ignore
       
   718 // all later dec spec info buffers. H264 bytestream buffers needs to be
       
   719 // ignored until dec spec info buffer has been written.
       
   720 // ---------------------------------------------------------------------------
       
   721 //
       
   722 CCMRMediaBuffer::TBufferType CMccFileSink::ResolveBufferType( 
       
   723     CMMFDataBuffer& aBuffer,
       
   724     TFourCC aDataType )
       
   725     { 
       
   726     CCMRMediaBuffer::TBufferType type = CCMRMediaBuffer::EVideoH263;
       
   727     if ( aDataType == KMccFourCCIdAVC )
       
   728         {
       
   729         if ( TMccCodecInfo::IsAvcPpsOrSpsData( aBuffer.Data() ) )
       
   730             {
       
   731             __FILESINK_CONTROLL( "pps or sps" )
       
   732             type = CCMRMediaBuffer::EVideoH264BytestreamDecSpecInfo;
       
   733             }
       
   734         else
       
   735             {
       
   736             type = CCMRMediaBuffer::EVideoH264Bytestream;
       
   737             }
       
   738         }
       
   739     
       
   740     __FILESINK_CONTROLL_INT1( "CMccFileSink::ResolveBufferType, type:", type )
       
   741     
       
   742     return type;
       
   743     }
       
   744 
       
   745 // ---------------------------------------------------------------------------
       
   746 // CMccFileSink::CheckWritingPermissionL
       
   747 // 1) H264 dec spec info can be written only once to the file.
       
   748 // 2) Normal frames should not be written until IFrame has been written to file
       
   749 // as it will cause bad quality for the clip. 
       
   750 // 3) H264 bytestream cannot be written before dec spec info has been written.
       
   751 // ---------------------------------------------------------------------------
       
   752 //
       
   753 TBool CMccFileSink::CheckWritingPermission( 
       
   754     CMMFDataBuffer& aBuffer,
       
   755     const CCMRMediaBuffer::TBufferType& aBufferType )
       
   756     { 
       
   757     TBool ignoreBuffer( EFalse );
       
   758 
       
   759     if ( aBufferType == CCMRMediaBuffer::EVideoH264BytestreamDecSpecInfo )
       
   760         {
       
   761         if ( !iDecSpecInfoProvided )
       
   762             {
       
   763             iDecSpecInfoProvided = ETrue;
       
   764             ignoreBuffer = EFalse;
       
   765             }
       
   766         else
       
   767             {
       
   768             __FILESINK_CONTROLL( "Ignore as dec spec info already provided!" )
       
   769             ignoreBuffer = ETrue;
       
   770             }
       
   771         }
       
   772     else if ( iMccResources && !iKeyFrameProvided )
       
   773         {
       
   774         TBool keyFrame = iMccResources->IsKeyFrame( 
       
   775                 MCC_ENDPOINT_ID( static_cast<MDataSink*>( this ) ), aBuffer );
       
   776         if ( keyFrame )
       
   777             {
       
   778             __FILESINK_CONTROLL_INT1( "Key frame match for timestamp:", 
       
   779                                       aBuffer.TimeToPlay().Int64() )
       
   780             iKeyFrameProvided = ETrue;
       
   781             }
       
   782         else
       
   783             {
       
   784             __FILESINK_CONTROLL( "Ignore as key frame not yet provided!" )
       
   785             ignoreBuffer = ETrue;
       
   786             }
       
   787         }
       
   788     else if ( aBufferType == CCMRMediaBuffer::EVideoH264Bytestream )
       
   789         {
       
   790         if ( !iDecSpecInfoProvided )
       
   791             {
       
   792             __FILESINK_CONTROLL( "Ignore as dec spec info not yet provided!" )
       
   793             ignoreBuffer = ETrue;
       
   794             }
       
   795         }
       
   796     else
       
   797         {
       
   798         // NOP
       
   799         }
       
   800     
       
   801     __FILESINK_CONTROLL_INT1( "CMccFileSink::CheckWritingPermission, ignore:", 
       
   802                               ignoreBuffer )
       
   803     
       
   804     return ignoreBuffer;
       
   805     }
       
   806 
       
   807 // ---------------------------------------------------------------------------
       
   808 // CMccFileSink::SetStateL
       
   809 // ---------------------------------------------------------------------------
       
   810 //
       
   811 TBool CMccFileSink::SetStateL( TFileSinkState aState )
       
   812     {
       
   813     TBool controlSink( iCurrentState != aState );
       
   814     TBool transitionOk( iCurrentState == aState );
       
   815     switch ( aState )
       
   816         {
       
   817         case EReady:
       
   818             { 
       
   819             transitionOk = ETrue;
       
   820             iCurrentState = aState;
       
   821             break;
       
   822             }
       
   823         case EPaused:
       
   824             {
       
   825             if ( iCurrentState == ERecording )
       
   826                 {
       
   827                 transitionOk = ETrue;
       
   828                 iCurrentState = aState;
       
   829                 }
       
   830             break;
       
   831             }
       
   832         case ERecording:
       
   833             {
       
   834             if ( iCurrentState == EReady || iCurrentState == EPaused )
       
   835                 {
       
   836                 transitionOk = ETrue;
       
   837                 iCurrentState = aState;
       
   838                 }
       
   839             break;
       
   840             }
       
   841         case EStopped:
       
   842             {
       
   843             // State is not changed to stopped if there's several users
       
   844             transitionOk = ETrue;
       
   845             const TInt KMccFileSinkMultipleUsers = 2;
       
   846             if ( iUsers.Count() < KMccFileSinkMultipleUsers )
       
   847                 {
       
   848                 iCurrentState = aState;
       
   849                 }
       
   850             break;
       
   851             }
       
   852         default:
       
   853             {
       
   854             break;       
       
   855             }
       
   856         }
       
   857 
       
   858     __ASSERT_ALWAYS( transitionOk, User::Leave( KErrNotReady ) );
       
   859     
       
   860     return controlSink;    
       
   861     }
       
   862 
       
   863 // -----------------------------------------------------------------------------
       
   864 // CMccFileSink::DoSinkPrimeL
       
   865 // -----------------------------------------------------------------------------
       
   866 //
       
   867 void CMccFileSink::DoSinkPrimeL( TBool aSendEvent )
       
   868 	{
       
   869 	__FILESINK_CONTROLL( "CMccFileSink::DoSinkPrimeL" )
       
   870 
       
   871     // If disk is full at beginning, ignore error at this stage and send disk
       
   872     // full event when first buffer is tried to be written to file.
       
   873     //
       
   874     if ( SetStateL( EReady ) )
       
   875         {
       
   876         HBufC8* codecType = GetCodecTypeStringLC( ActiveUserL().iCodecInfo );
       
   877     	TRAPD( err, iFileComposer->OpenFileL( iFileName, 
       
   878     	                                      iAudioFourCC, 
       
   879     	                                      *codecType ) );  
       
   880 
       
   881         CleanupStack::PopAndDestroy( codecType );
       
   882     	if ( err == KErrDiskFull )
       
   883     	    {
       
   884     	    __FILESINK_CONTROLL( "CMccFileSink::SinkPrimeL, disk full" )
       
   885     	    iNotifySizeLimitReached = ETrue;
       
   886     	    err = KErrNone;
       
   887     	    }
       
   888     	User::LeaveIfError( err );
       
   889     	
       
   890     	iDecSpecInfoProvided = EFalse;
       
   891         }
       
   892 
       
   893     if ( aSendEvent )
       
   894         {
       
   895     	SendStreamEventToClient( KMccStreamPrepared );	
       
   896         }
       
   897 	}
       
   898 
       
   899 // -----------------------------------------------------------------------------
       
   900 // CMccFileSink::DoSinkPlayL
       
   901 // -----------------------------------------------------------------------------
       
   902 //
       
   903 void CMccFileSink::DoSinkPlayL( TBool aSendEvent )
       
   904     { 
       
   905     __ASSERT_ALWAYS( !iSizeLimitReached, User::Leave( KErrDiskFull ) );
       
   906     
       
   907     TMccEventType eventType = 
       
   908         iCurrentState == EPaused ? KMccStreamResumed : KMccStreamStarted;
       
   909     TFileSinkState oldState = iCurrentState;
       
   910     
       
   911     if ( SetStateL( ERecording ) )
       
   912         {    
       
   913         // First frame written to file should be keyframe
       
   914         iKeyFrameProvided = EFalse;
       
   915         
       
   916     	if ( oldState == EPaused )
       
   917             {
       
   918             iT2.HomeTime();
       
   919             __FILESINK_CONTROLL_INT1( "CMccFileSink::SinkPlayL, iT2=", iT2.Int64() )
       
   920             SetPausedDuration( iT1, iT2 );
       
   921             }
       
   922         }
       
   923 	
       
   924 	if ( aSendEvent )
       
   925 	    {
       
   926         SendStreamEventToClient( eventType );
       
   927 	    }
       
   928     }
       
   929 
       
   930 // -----------------------------------------------------------------------------
       
   931 // CMccFileSink::DoSinkPauseL
       
   932 // -----------------------------------------------------------------------------
       
   933 //
       
   934 void CMccFileSink::DoSinkPauseL( TBool aSendEvent )
       
   935     { 
       
   936     TFileSinkState oldState = iCurrentState;
       
   937     
       
   938     if ( SetStateL( EPaused ) )
       
   939         {  
       
   940         if ( oldState == ERecording )
       
   941             {
       
   942             iT1.HomeTime();  
       
   943             __FILESINK_CONTROLL_INT1( "CMccFileSink::SinkPauseL, iT1=", iT1.Int64() )
       
   944             }   
       
   945         }
       
   946     
       
   947 	if ( aSendEvent )
       
   948 	    {
       
   949 	    SendStreamEventToClient( KMccStreamPaused );
       
   950 	    }
       
   951     }
       
   952     
       
   953 // -----------------------------------------------------------------------------
       
   954 // CMccFileSink::DoSinkStopL
       
   955 // -----------------------------------------------------------------------------
       
   956 //
       
   957 void CMccFileSink::DoSinkStopL( TBool aSendEvent )
       
   958     {
       
   959     __FILESINK_CONTROLL( "CMccFileSink::DoSinkStopL" )
       
   960     
       
   961      if ( SetStateL( EStopped ) )
       
   962         {  
       
   963     	iFileComposer->SinkStopL();
       
   964         
       
   965         ResetTimers();
       
   966         }
       
   967 
       
   968     if ( aSendEvent )
       
   969         {
       
   970 	    SendStreamEventToClient( KMccStreamStopped );	
       
   971         }
       
   972     }	
       
   973 
       
   974 // -----------------------------------------------------------------------------
       
   975 // CMccFileSink::DoCodecChangeL
       
   976 // -----------------------------------------------------------------------------
       
   977 //
       
   978 void CMccFileSink::DoCodecChangeL()
       
   979     {
       
   980     __FILESINK_CONTROLL( "CMccFileSink::DoCodecChangeL" )
       
   981     
       
   982     TFileSinkState oldState = iCurrentState;
       
   983     
       
   984     DoSinkStopL( EFalse );
       
   985     DoSinkPrimeL( EFalse );
       
   986     
       
   987     if ( oldState == ERecording || oldState == EPaused )
       
   988         {
       
   989         DoSinkPlayL( EFalse );
       
   990         if ( oldState == EPaused )
       
   991             {
       
   992             DoSinkPauseL( EFalse );
       
   993             }
       
   994         }
       
   995     
       
   996     __FILESINK_CONTROLL( "CMccFileSink::DoCodecChangeL, exit" )
       
   997     }
       
   998 
       
   999 // -----------------------------------------------------------------------------
       
  1000 // CMccFileSink::AddUserL()
       
  1001 // -----------------------------------------------------------------------------
       
  1002 // 
       
  1003 void CMccFileSink::AddUserL( MAsyncEventHandler* aEventHandler )
       
  1004     {
       
  1005     TMccFileSinkUser* user = new ( ELeave ) TMccFileSinkUser( aEventHandler );
       
  1006     CleanupStack::PushL( user );
       
  1007     iUsers.AppendL( user );
       
  1008     CleanupStack::Pop( user );
       
  1009     }
       
  1010 
       
  1011 // -----------------------------------------------------------------------------
       
  1012 // CMccFileSink::ActiveUserL()
       
  1013 // -----------------------------------------------------------------------------
       
  1014 //
       
  1015 TMccFileSinkUser& CMccFileSink::ActiveUserL()
       
  1016     {
       
  1017     __ASSERT_ALWAYS( iUsers.Count() > 0, User::Leave( KErrNotReady ) );
       
  1018     TInt index( 0 );
       
  1019     if ( iActiveUserIndex != KErrNotFound && iActiveUserIndex < iUsers.Count() )
       
  1020         {
       
  1021         index = iActiveUserIndex;
       
  1022         }
       
  1023     return *iUsers[ index ];
       
  1024     }
       
  1025 
       
  1026 // -----------------------------------------------------------------------------
       
  1027 // CMccFileSink::IsActiveUser()
       
  1028 // -----------------------------------------------------------------------------
       
  1029 //
       
  1030 TBool CMccFileSink::IsActiveUser( MAsyncEventHandler* aUser )
       
  1031     {
       
  1032     TInt index = 
       
  1033         MccUserArray<TMccFileSinkUser>::FindUserEntryIndexForCurrent( iUsers, aUser );
       
  1034     return ( index != KErrNotFound && index == iActiveUserIndex );
       
  1035     }
       
  1036 
       
  1037 // -----------------------------------------------------------------------------
       
  1038 // CMccFileSink::UpdateActiveUserL()
       
  1039 // -----------------------------------------------------------------------------
       
  1040 //
       
  1041 TFourCC CMccFileSink::UpdateActiveUserL( TMediaId aMediaId, MDataSource& aDataProvider )
       
  1042     {
       
  1043     TBool doCodecChange( EFalse );
       
  1044     
       
  1045     TFourCC providerDataType = aDataProvider.SourceDataTypeCode( aMediaId );
       
  1046     
       
  1047     if ( iActiveUserIndex == KErrNotFound )
       
  1048         {
       
  1049         SetActiveUserIndex( 0 );
       
  1050         doCodecChange = ETrue;
       
  1051         
       
  1052         __FILESINK_CONTROLL_INT1( 
       
  1053             "CMccFileSink::UpdateActiveUserL, new active user index:", iActiveUserIndex )
       
  1054         }
       
  1055     else
       
  1056         {
       
  1057         if ( ActiveUserL().iCodecInfo.iFourCC != providerDataType )
       
  1058             {    
       
  1059             __FILESINK_CONTROLL_INT1( 
       
  1060                 "CMccFileSink::UpdateActiveUserL, provider fourcc:", 
       
  1061                 providerDataType.FourCC() )
       
  1062             
       
  1063             __FILESINK_CONTROLL_INT1( 
       
  1064                 "CMccFileSink::UpdateActiveUserL, active user fourcc:", 
       
  1065                 ActiveUserL().iCodecInfo.iFourCC.FourCC() )
       
  1066             
       
  1067             for ( TInt i = 0; i < iUsers.Count() && !doCodecChange; i++ )
       
  1068                 {
       
  1069                 if ( iUsers[ i ]->iCodecInfo.iFourCC == providerDataType )
       
  1070                     {
       
  1071                     SetActiveUserIndex( i );
       
  1072                     doCodecChange = ETrue;
       
  1073                     }
       
  1074                 }
       
  1075             }
       
  1076         }
       
  1077         
       
  1078     if ( doCodecChange )
       
  1079         {
       
  1080         SetCurrentUser( ActiveUserL().iEventHandler );
       
  1081         DoCodecChangeL();
       
  1082         }
       
  1083         
       
  1084     return providerDataType;
       
  1085     }
       
  1086 
       
  1087 // -----------------------------------------------------------------------------
       
  1088 // CMccFileSink::SetActiveUserIndex()
       
  1089 // -----------------------------------------------------------------------------
       
  1090 //
       
  1091 void CMccFileSink::SetActiveUserIndex( TInt aIndex )
       
  1092     {
       
  1093     __FILESINK_CONTROLL_INT1( "CMccFileSink::SetActiveUserIndex, index:", aIndex )
       
  1094             
       
  1095     iActiveUserIndex = aIndex;
       
  1096     }
       
  1097     
       
  1098 #ifndef EKA2
       
  1099 EXPORT_C TInt E32Dll( TDllReason )
       
  1100     {
       
  1101     return KErrNone;
       
  1102     }
       
  1103 #endif
       
  1104