diff -r 000000000000 -r f0cf47e981f9 mmsharing/mmshengine/src/musengclipsession.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mmsharing/mmshengine/src/musengclipsession.cpp Thu Dec 17 08:44:37 2009 +0200 @@ -0,0 +1,1078 @@ +/* +* Copyright (c) 2005 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: +* +*/ + + +// USER +#include "musengclipsession.h" +#include "musengclipsessionobserver.h" +#include "musengsessionobserver.h" +#include "musengmceoutsession.h" +#include "musenglivesession.h" +#include "musengmceutils.h" +#include "musenglogger.h" + +// SYSTEM +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +// CONSTANTS + +const TInt64 KMicroSecondsInOneSecond = 1000000; +const TInt KMusEngAmrBitRate = KMceAmrNbBitrate475; +const TUint KMusEngAllowedAmrBitrates = KMceAllowedAmrNbBitrate475; + +const TInt KFastWindingFactor = 4; + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +EXPORT_C CMusEngClipSession* CMusEngClipSession::NewL( + const TRect& aRect, + MMusEngSessionObserver& aSessionObserver, + MMusEngOutSessionObserver& aOutSessionObserver, + MMusEngClipSessionObserver& aClipSessionObserver, + TUint aSipProfileId ) + { + CMusEngClipSession* self = new( ELeave ) CMusEngClipSession( + aSessionObserver, + aOutSessionObserver, + aClipSessionObserver, + aRect ); + CleanupStack::PushL( self ); + self->ConstructL( aSipProfileId ); + CleanupStack::Pop( self ); + return self; + } + + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +CMusEngClipSession::~CMusEngClipSession() + { + MUS_LOG( "mus: [ENGINE] -> CMusEngClipSession::~CMusEngClipSession()" ) + MUS_LOG( "mus: [ENGINE] <- CMusEngClipSession::~CMusEngClipSession()" ) + } + + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +EXPORT_C void CMusEngClipSession::SetClipL( const TDesC& aFileName ) + { + MUS_LOG( "mus: [ENGINE] -> CMusEngClipSession::SetClipL(...)" ) + + __ASSERT_ALWAYS( !IsProtectedFileL( aFileName ), + User::Leave( KErrPermissionDenied ) ); + + if ( iSession ) + { + CMceFileSource* file = MusEngMceUtils::GetFileSourceL( *iSession ); + file->UpdateL( aFileName ); + } + + iFileName = aFileName; + + MUS_LOG( "mus: [ENGINE] <- CMusEngClipSession::SetClipL(...)" ) + + } + + +// ----------------------------------------------------------------------------- +// Since MCE does not at the moment support SetFastForwardL function, this +// functionality is implemented by taking a timestamp when forwarding is +// started and calculating a new position when it is ended. +// ----------------------------------------------------------------------------- +// +EXPORT_C void CMusEngClipSession::FastForwardL( TBool aUseFFWD ) + { + MUS_LOG1( "mus: [ENGINE] -> CMusEngClipSession::FastForward(%d)", aUseFFWD ) + + __ASSERT_ALWAYS( iSession, User::Leave( KErrNotReady ) ); + + CMceFileSource* file = MusEngMceUtils::GetFileSourceL( *iSession ); + + if ( aUseFFWD ) + { + // Ignore if we are already fastforwarding + if ( iFFWDStartTime.Int64() > 0 ) + { + return; + } + + // Stop rewinding if ongoing, else just pause file source + if ( iFRWDStartTime.Int64() > 0 ) + { + FastRewindL( EFalse ); + } + else + { + file->DisableL(); + } + + // Get timestamp for starttime + iFFWDStartTime.HomeTime(); + } + else + { + // Leave if we are not fastforwarding + if ( iFFWDStartTime.Int64() == 0 ) + { + User::Leave( KErrAlreadyExists ); + } + + // Set new position + file->SetPositionL( PositionMicroSecondsL( ETrue ) ); + MUS_LOG( " SetPositionL returned without error " ) + + // Reset timer + iFFWDStartTime = TTime( 0 ); + } + + MUS_LOG1( "mus: [ENGINE] <- CMusEngClipSession::FastForward(%d)", aUseFFWD ) + } + + +// ----------------------------------------------------------------------------- +// Since MCE does not at the moment support SetFastRewindL function, this +// functionality is implemented by taking a timestamp when rewinding is +// started and calculating a new position when it is ended. +// ----------------------------------------------------------------------------- +// +EXPORT_C void CMusEngClipSession::FastRewindL( TBool aUseFRWD ) + { + MUS_LOG1( "mus: [ENGINE] -> CMusEngClipSession::FastRewind(%d)", aUseFRWD ) + + __ASSERT_ALWAYS( iSession, User::Leave( KErrNotReady ) ); + + CMceFileSource* file = MusEngMceUtils::GetFileSourceL( *iSession ); + + if ( aUseFRWD ) + { + // Ignore if we are already fastrewinding + if ( iFRWDStartTime.Int64() > 0 ) + { + return; + } + + // Stop fastforwarding if ongoing, else just pause file source + if ( iFFWDStartTime.Int64() > 0 ) + { + FastForwardL( EFalse ); + } + else + { + file->DisableL(); + } + + // Get timestamp for starttime + iFRWDStartTime.HomeTime(); + } + else + { + // Leave if we are not fastrewinding + if ( iFRWDStartTime.Int64() == 0 ) + { + User::Leave( KErrAlreadyExists ); + } + + // Set new position + file->SetPositionL( PositionMicroSecondsL( ETrue ) ); + MUS_LOG( " SetPositionL returned without error " ) + + // Reset timer + iFRWDStartTime = TTime( 0 ); + } + + MUS_LOG1( "mus: [ENGINE] <- CMusEngClipSession::FastRewind(%d)", aUseFRWD ) + } + + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +EXPORT_C TTimeIntervalSeconds CMusEngClipSession::PositionL() + { + MUS_LOG( "mus: [ENGINE] -> CMusEngClipSession::PositionL()" ) + + TTimeIntervalMicroSeconds currentPosition = PositionMicroSecondsL(); + + MUS_LOG1( "mus: [ENGINE] <- CMusEngClipSession::PositionL(), pos:%d", + currentPosition.Int64() ) + return TTimeIntervalSeconds( static_cast( + currentPosition.Int64() / KMicroSecondsInOneSecond ) ); + } + + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +EXPORT_C TTimeIntervalSeconds CMusEngClipSession::DurationL() + { + MUS_LOG( "mus: [ENGINE] -> CMusEngClipSession::DurationL()" ) + + __ASSERT_ALWAYS( iSession, User::Leave( KErrNotReady ) ); + + CMceFileSource* file = MusEngMceUtils::GetFileSourceL( *iSession ); + + TTimeIntervalMicroSeconds duration = file->DurationL(); + + MUS_LOG( "mus: [ENGINE] <- CMusEngClipSession::DurationL()" ) + return TTimeIntervalSeconds( + static_cast( duration.Int64() / KMicroSecondsInOneSecond ) ); + + } + + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +EXPORT_C void CMusEngClipSession::SetPositionL ( + const TTimeIntervalSeconds& aPosition ) + { + MUS_LOG1( "mus: [ENGINE] -> CMusEngClipSession::SetPositionL (%d)", + aPosition.Int() ) + + __ASSERT_ALWAYS( iSession, User::Leave( KErrNotReady ) ); + + CMceFileSource* file = MusEngMceUtils::GetFileSourceL( *iSession ); + + TTimeIntervalMicroSeconds position( + KMicroSecondsInOneSecond * static_cast(aPosition.Int()) ); + + if ( position == 0 ) + { + iRewindedToBeginning = ETrue; + } + + file->SetPositionL( position ); + + MUS_LOG( "mus: [ENGINE] <- CMusEngClipSession::SetPositionL ()" ) + } + + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +EXPORT_C void CMusEngClipSession::TranscodeL( const TFileName& aFileName ) + { + MUS_LOG( "mus: [ENGINE] -> CMusEngClipSession::TranscodeL(...)" ) + + __ASSERT_ALWAYS( iSession, User::Leave( KErrNotReady ) ); + + CMceFileSource* file = MusEngMceUtils::GetFileSourceL( *iSession ); + + const RPointerArray& streams = iSession->Streams(); + + for ( TInt i = 0; i < streams.Count(); ++i ) + { + if ( streams[i]->State() == CMceMediaStream::ETranscodingRequired ) + { + if ( streams[i]->Type() == KMceAudio ) + { + AddAmrCodecL( static_cast( *streams[i] ) ); + } + else + { + AddVideoCodecL( static_cast( *streams[i] ) ); + } + } + } + + file->TranscodeL( aFileName ); + + iTranscodingOngoing = ETrue; + + iTranscodingDestFileName = aFileName; + + MUS_LOG( "mus: [ENGINE] <- CMusEngClipSession::TranscodeL(...)" ) + } + + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +EXPORT_C void CMusEngClipSession::CancelTranscodeL() + { + MUS_LOG( "mus: [ENGINE] -> CMusEngClipSession::CancelTranscodeL()" ) + + __ASSERT_ALWAYS( iSession, User::Leave( KErrNotReady ) ); + + CMceFileSource* file = MusEngMceUtils::GetFileSourceL( *iSession ); + + TRAPD( err, file->CancelTranscodeL() ); + err = err; // Silence warning in UREL build + MUS_LOG1( "mus: [ENGINE] - cancel result %d", err ) + // Even if cancel fails, try to delete the partial clip + + MUS_LOG( "mus: [ENGINE] - delete the partially converted clip" ) + RFs fs; + User::LeaveIfError( fs.Connect() ); + CleanupClosePushL( fs ); + + CFileMan* fileMan = CFileMan::NewL( fs ); + CleanupStack::PushL( fileMan ); + + MUS_LOG_TDESC8( "mus: [ENGINE] - trascoding destination filename", + iTranscodingDestFileName ) + err = fileMan->Delete( iTranscodingDestFileName ); + MUS_LOG1( "mus: [ENGINE] - file delete result %d", err ) + + CleanupStack::PopAndDestroy( fileMan ); + CleanupStack::PopAndDestroy(); // fs + + MUS_LOG( "mus: [ENGINE] <- CMusEngClipSession::CancelTranscodeL()" ) + } + + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +EXPORT_C void CMusEngClipSession::PlayL() + { + MUS_LOG( "mus: [ENGINE] -> CMusEngClipSession::PlayL()" ) + + __ASSERT_ALWAYS( iSession && + iFFWDStartTime.Int64() == 0 && + iFRWDStartTime.Int64() == 0, + User::Leave( KErrNotReady ) ); + + + CMceFileSource* file = MusEngMceUtils::GetFileSourceL( *iSession ); + + if ( !file->IsEnabled() ) + { + file->EnableL(); + + iClipEnded = EFalse; + // No need to enable audio separarely + } + else + { + MUS_LOG( "mus: [ENGINE] File is already enabled, ignore request" ) + } + + MUS_LOG( "mus: [ENGINE] <- CMusEngClipSession::PlayL()" ) + } + + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +EXPORT_C void CMusEngClipSession::PauseL() + { + MUS_LOG( "mus: [ENGINE] -> CMusEngClipSession::PauseL()" ) + + __ASSERT_ALWAYS( iSession && + iFFWDStartTime.Int64() == 0 && + iFRWDStartTime.Int64() == 0, + User::Leave( KErrNotReady ) ); + + + CMceFileSource* file = MusEngMceUtils::GetFileSourceL( *iSession ); + + if ( file->IsEnabled() ) + { + file->DisableL(); + + // No need to disable audio separarely + } + else + { + MUS_LOG( "mus: [ENGINE] File is already disabled, ignore request" ) + } + + MUS_LOG( "mus: [ENGINE] <- CMusEngClipSession::PauseL()" ) + } + + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +EXPORT_C TBool CMusEngClipSession::IsPlayingL() + { + __ASSERT_ALWAYS( iSession, User::Leave( KErrNotReady ) ); + + return ( MusEngMceUtils::GetFileSourceL( *iSession )->IsEnabled() ); + } + + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +void CMusEngClipSession::CompleteSessionStructureL( + CMceStreamBundle& aLocalBundle ) + { + MUS_LOG( "mus: [ENGINE] -> CMusEngClipSession::CompleteSessionStructureL()" ) + + __ASSERT_ALWAYS( iSession, User::Leave( KErrNotReady ) ); + __ASSERT_ALWAYS( iFileName != KNullDesC(), User::Leave( KErrNotReady ) ); + + // Create outgoing video stream + CMceVideoStream* videoStream = CMceVideoStream::NewLC(); + + CMceRtpSink* rtpsink = CMceRtpSink::NewLC(); + videoStream->AddSinkL( rtpsink ); + CleanupStack::Pop( rtpsink ); + + CMceFileSource* fileSource = CMceFileSource::NewLC( *iManager, + iFileName ); + fileSource->DisableL(); // Start session in pause mode. + videoStream->SetSourceL( fileSource ); + CleanupStack::Pop( fileSource ); + + iSession->AddStreamL( videoStream ); + CleanupStack::Pop( videoStream ); + + ConstructAudioStructureL( aLocalBundle ); + + MUS_LOG( "mus: [ENGINE] <- CMusEngClipSession::CompleteSessionStructureL()" ) + } + + +// ----------------------------------------------------------------------------- +// Checks that that there is no need for transcoding before calling +// overridden base class variant of this function. +// ----------------------------------------------------------------------------- +// +void CMusEngClipSession::EstablishSessionL() + { + MUS_LOG( "mus: [ENGINE] -> CMusEngClipSession::EstablishSessionL()" ) + + __ASSERT_ALWAYS( iSession, User::Leave( KErrNotReady ) ); + + const RPointerArray& streams = iSession->Streams(); + + TBool transcodingRequired = EFalse; + + if ( iVideoCodecList ) + { + MUS_LOG_TDESC8( "iVideoCodecList: ", iVideoCodecList->Des() ) + } + + CMceVideoStream* videoStream = NULL; + for ( TInt i = 0; i < streams.Count(); ++i ) + { + if ( streams[i]->State() == CMceMediaStream::ETranscodingRequired ) + { + transcodingRequired = ETrue; + } + else if ( streams[i]->Type() == KMceVideo && + !IsH264Supported() ) + { + MUS_LOG( " -> video stream found!!!" ) + videoStream = static_cast( streams[i] ); + + //transcoding of H264 is not needed only if we know explicitly + //that the peer supports it (from OPTIONS response) + + const RPointerArray& codecs = videoStream->Codecs(); + for ( TInt codecIndex = 0; codecIndex < codecs.Count(); ++codecIndex ) + { + if ( codecs[codecIndex]->SdpName() == KMceSDPNameH264() ) + { + transcodingRequired = ETrue; + MUS_LOG( " -> Removing H264 codec from video stream" ) + videoStream->RemoveCodecL( *codecs[codecIndex] ); + codecIndex = 0; + } + } + + if ( codecs.Count() == 0) + { + // At least one codec should be in the stream list. + MUS_LOG( " -> Adding codec, since codecs list is empty " ) + AddVideoCodecL( *videoStream ); + } + } + } + + if ( transcodingRequired ) + { + iClipSessionObserver.TranscodingNeeded(); + } + else + { + CMusEngMceOutSession::EstablishSessionL(); + // Now session state is right to adjust volume + SetSpeakerVolumeL( VolumeL() ); + } + + MUS_LOG( "mus: [ENGINE] <- CMusEngClipSession::EstablishSessionL()" ) + } + +// ----------------------------------------------------------------------------- +// Implemented for MMceStreamObserver +// ----------------------------------------------------------------------------- +// +void CMusEngClipSession::StreamStateChanged( CMceMediaStream& aStream ) + { + MUS_LOG( "mus: [ENGINE] -> CMusEngClipSession::StreamStateChanged()" ) + + if ( !iSession ) + { + return; + } + + DetermineBufferingPeriod( aStream ); + + CMusEngMceSession::StreamStateChanged( aStream ); + + MUS_LOG( "mus: [ENGINE] <- CMusEngClipSession::StreamStateChanged()" ) + } + +// ----------------------------------------------------------------------------- +// Implemented for MMceStreamObserver +// ----------------------------------------------------------------------------- +// +void CMusEngClipSession::StreamStateChanged( CMceMediaStream& aStream, + CMceMediaSource& aSource ) + { + MUS_LOG( "mus: [ENGINE] -> CMusEngClipSession::StreamStateChanged( src )" ) + + if ( !iSession ) + { + return; + } + + MUS_ENG_LOG_STREAM_STATE( aStream ) + + DetermineBufferingPeriod( aStream ); + + if ( aStream.State() == CMceMediaStream::ETranscoding ) + { + CMceFileSource* file = static_cast(aStream.Source()); + TInt progressPercentage = 0; + TRAP_IGNORE( progressPercentage = file->TranscodingProgressL() ) + iClipSessionObserver.TranscodingProgressed( progressPercentage ); + } + else if ( aStream.State() == CMceMediaStream::EInitialized ) + { + if ( iTranscodingOngoing ) + { + MUS_LOG( "mus: [ENGINE] Transcoding completed." ) + + // Filename has been updated in MCE side but unfortunately + // there's no getter for the filename in API. + iFileName = iTranscodingDestFileName; + + iTranscodingOngoing = EFalse; + + iClipSessionObserver.TranscodingCompletedInit(); + + TRAPD( error, EstablishSessionL() ) + if ( error != KErrNone ) + { + iSessionObserver.SessionFailed(); + } + + // Next call does not return before session establishment + iClipSessionObserver.TranscodingCompletedFinalize(); + } + } + else if ( aStream.State() == CMceMediaStream::ETranscodingRequired && + iTranscodingOngoing ) + { + MUS_LOG( "mus: [ENGINE] Transcoding failed." ) + + iClipSessionObserver.TranscodingFailed(); + iTranscodingOngoing = EFalse; + } + else if ( HasClipEnded() ) + { + MUS_LOG( "mus: [ENGINE] Clip ended." ) + + iDelayFileEndingPos = 0; + iClipEnded = ETrue; + + iClipSessionObserver.EndOfClip(); + } + else + { + // Cannot handle, forward to the ancestor class + CMusEngMceSession::StreamStateChanged( aStream, aSource ); + } + + MUS_LOG( "mus: [ENGINE] <- CMusEngClipSession::StreamStateChanged( src )" ) + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +CMusEngClipSession::CMusEngClipSession( + MMusEngSessionObserver& aSessionObserver, + MMusEngOutSessionObserver& aOutSessionObserver, + MMusEngClipSessionObserver& aClipSessionObserver, + const TRect& aRect ) + : CMusEngMceOutSession( aRect, + aSessionObserver, + aOutSessionObserver ), + iClipSessionObserver( aClipSessionObserver ) + { + } + + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +void CMusEngClipSession::ConstructL( TUint aSipProfileId ) + { + MUS_LOG( "mus: [ENGINE] -> CMusEngClipSession::ConstructL(...)" ) + + CMusEngMceOutSession::ConstructL( aSipProfileId ); + + MUS_LOG( "mus: [ENGINE] <- CMusEngClipSession::ConstructL(...)" ) + } + + +// ----------------------------------------------------------------------------- +// Check is file DRM protected. +// +// ----------------------------------------------------------------------------- +// +TBool CMusEngClipSession::IsProtectedFileL( const TDesC& aClipFile ) + { + MUS_LOG( "mus: [ENGINE] -> CMusEngClipSession::IsProtectedFileL(...)" ) + + TBool isDRMProtected = EFalse; + DRMCommon* drmapi = DRMCommon::NewL(); + CleanupStack::PushL( drmapi ); + + User::LeaveIfError( drmapi->Connect() ); + //Check DRM file protection + User::LeaveIfError( drmapi->IsProtectedFile( aClipFile, isDRMProtected ) ); + drmapi->Disconnect(); + + CleanupStack::PopAndDestroy( drmapi ); + + MUS_LOG( "mus: [ENGINE] <- CMusEngClipSession::IsProtectedFileL(...)" ) + return isDRMProtected; + } + + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +void CMusEngClipSession::AddAmrCodecL( CMceAudioStream& aAudioStream ) + { + MUS_LOG( "mus: [ENGINE] -> CMusEngClipSession::AddAmrCodecL" ) + + // Remove old codecs + + while ( aAudioStream.Codecs().Count() > 0 ) + { + aAudioStream.RemoveCodecL( *aAudioStream.Codecs()[0] ); + } + + // Create AMR codec instance + + const RPointerArray& supportedCodecs = + iManager->SupportedAudioCodecs(); + + CMceAudioCodec* amr = NULL; + + for ( TInt i = 0; i < supportedCodecs.Count(); ++i ) + { + if ( supportedCodecs[i]->SdpName() == KMceSDPNameAMR() ) + { + amr = supportedCodecs[i]->CloneL(); + CleanupStack::PushL( amr ); + + User::LeaveIfError( + amr->SetAllowedBitrates( KMusEngAllowedAmrBitrates ) ); + User::LeaveIfError( amr->SetBitrate( KMusEngAmrBitRate ) ); + aAudioStream.AddCodecL( amr ); + + CleanupStack::Pop( amr ); + break; // We must have only one codec + } + } + + __ASSERT_ALWAYS( amr, User::Leave( KErrNotFound ) ); + + MUS_LOG( "mus: [ENGINE] <- CMusEngClipSession::AddAmrCodecL" ) + } + + +// ----------------------------------------------------------------------------- +// Create codec instance, H264 is used only if other end supports it for sure, +// otherwise H263 is used. +// ----------------------------------------------------------------------------- +// +void CMusEngClipSession::AddVideoCodecL( CMceVideoStream& aVideoStream ) + { + MUS_LOG( "mus: [ENGINE] -> CMusEngClipSession::AddVideoCodecL" ) + + // Remove old codecs + + while ( aVideoStream.Codecs().Count() > 0 ) + { + aVideoStream.RemoveCodecL( *aVideoStream.Codecs()[0] ); + } + + const RPointerArray& supportedCodecs = + iManager->SupportedVideoCodecs(); + + CMceVideoCodec* addedCodec = NULL; + + TPtrC8 addedCodecName = + IsH264Supported() ? KMceSDPNameH264() : KMceSDPNameH2632000(); + + MUS_LOG_TDESC8( "mus: [ENGINE] adding codec : ", addedCodecName ); + + for ( TInt i = 0; i < supportedCodecs.Count(); ++i ) + { + if ( supportedCodecs[i]->SdpName() == addedCodecName ) + { + addedCodec = supportedCodecs[i]->CloneL(); + CleanupStack::PushL( addedCodec ); + aVideoStream.AddCodecL( addedCodec ); + CleanupStack::Pop( addedCodec ); + break; // We must have only one codec + } + } + + __ASSERT_ALWAYS( addedCodec, User::Leave( KErrNotFound ) ); + + MUS_LOG( "mus: [ENGINE] <- CMusEngClipSession::AddVideoCodecL" ) + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +TBool CMusEngClipSession::HasClipEnded() + { + MUS_LOG( "mus: [ENGINE] -> CMusEngClipSession::HasClipEnded()" ) + + TBool hasClipEnded = EFalse; + + if ( iSession ) + { + + CMceVideoStream* videoOut = NULL; + + TRAPD( error, + videoOut = MusEngMceUtils::GetVideoOutStreamL( *iSession ) ); + if( error != KErrNone ) + { + MUS_LOG1( "mus: [ENGINE] Error in GetVideoOutStreamL #%d", error ) + return hasClipEnded; + } + + CMceFileSource* filesource = NULL; + TRAP( error, filesource = MusEngMceUtils::GetFileSourceL( *iSession ) ) + + if ( error == KErrNone ) + { + TTimeIntervalMicroSeconds position; + TTimeIntervalMicroSeconds duration; + TRAP( error, position = filesource->PositionL() ); + TRAPD( error1, duration = filesource->DurationL() ); + if ( error != KErrNone || error1 != KErrNone ) + { + return hasClipEnded; + } + + MUS_LOG2( "mus: [ENGINE] position = %Ld, duration = %Ld", + position.Int64(), + duration.Int64() ) + + TRAP( error, hasClipEnded = + ( position.Int64() == 0 && + !filesource->IsEnabled() && + videoOut->State() == CMceMediaStream::EDisabled ) ) + if( hasClipEnded ) + { + MUS_LOG( "mus: [ENGINE] End of clip" ) + } + } + } + + MUS_LOG( "mus: [ENGINE] <- CMusEngClipSession::HasClipEnded()" ) + return hasClipEnded; + } + + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +TTimeIntervalMicroSeconds CMusEngClipSession::PositionMicroSecondsL( + TBool aActualPosition ) + { + __ASSERT_ALWAYS( iSession, User::Leave( KErrNotReady ) ); + + CMceFileSource* file = MusEngMceUtils::GetFileSourceL( *iSession ); + + TTimeIntervalMicroSeconds position = file->PositionL(); + TTimeIntervalMicroSeconds duration = file->DurationL(); + + TTimeIntervalMicroSeconds calculatedPosition; + + // Adjust position if we are fastforwarding or -rewinding + if ( iFFWDStartTime.Int64() != 0 ) + { + TTime now; + now.HomeTime(); + calculatedPosition = KFastWindingFactor * + now.MicroSecondsFrom( iFFWDStartTime ).Int64() + + position.Int64(); + if ( calculatedPosition > duration ) + { + calculatedPosition = duration; + } + } + else if ( iFRWDStartTime.Int64() != 0 ) + { + TTime now; + now.HomeTime(); + calculatedPosition = position.Int64() - + KFastWindingFactor * + now.MicroSecondsFrom( iFRWDStartTime ).Int64(); + if ( calculatedPosition < 0 ) + { + calculatedPosition = 0; + } + + if ( calculatedPosition == 0 ) + { + iRewindedToBeginning = ETrue; + } + } + else + { + calculatedPosition = position; + } + + if ( !aActualPosition ) + { + calculatedPosition = + GetVideoSinkRelativeFilePos( calculatedPosition, duration ); + } + + return calculatedPosition; + } + + +// ----------------------------------------------------------------------------- +// If member file contains audio, add appropriate amount of audio streams to +// session structure +// ----------------------------------------------------------------------------- +// +void CMusEngClipSession::ConstructAudioStructureL( + CMceStreamBundle& aLocalBundle ) + { + MUS_LOG( "mus: [ENGINE] -> CMusEngClipSession::ConstructAudioStructureL()" ) + + __ASSERT_ALWAYS( iSession, User::Leave( KErrNotReady ) ); + + // There is no clip audio present in operator variant + if ( iOperatorVariant ) + { + MUS_LOG( " Operator variant, no audio constructed" ) + MUS_LOG( "mus: [ENGINE] <- CMusEngClipSession::ConstructAudioStructureL()" ) + return; + } + + CMceFileSource* fileSource = MusEngMceUtils::GetFileSourceL( *iSession ); + + TInt audioElementCount = fileSource->MediaElementCountL( KMceAudio ); + + MUS_LOG1( "mus: [ENGINE] File contains %d audio elements", + audioElementCount ) + + for ( TInt i = 0; i < audioElementCount; ++i ) + { + fileSource->SetCurrentMediaElementL( KMceAudio, i ); + + MUS_LOG1( "mus: [ENGINE] Current audio element set to : %d ", i ) + + // Set up an audio outstream. + CMceAudioStream* audioOut = CMceAudioStream::NewLC(); + + CMceRtpSink* rtpSink = CMceRtpSink::NewLC(); + audioOut->AddSinkL( rtpSink ); + CleanupStack::Pop( rtpSink ); + + audioOut->SetSourceL( fileSource ); + + iSession->AddStreamL( audioOut ); + CleanupStack::Pop( audioOut ); + + MUS_LOG( "mus: [ENGINE] Audio outstream created" ) + + // Set up an audio stream to local speaker + audioOut = CMceAudioStream::NewLC(); + + MusEngMceUtils::AddSpeakerL( *audioOut ); + + audioOut->SetSourceL( fileSource ); + + iSession->AddStreamL( audioOut ); + CleanupStack::Pop( audioOut ); + + MUS_LOG( "mus: [ENGINE] Local audio stream created" ) + + aLocalBundle.AddStreamL( *audioOut ); + + MUS_LOG( "mus: [ENGINE] Local audio stream added to bundle" ) + } + + MUS_LOG( "mus: [ENGINE] <- CMusEngClipSession::ConstructAudioStructureL()" ) + } + +// ----------------------------------------------------------------------------- +// Calculates how long MCE buffers based on time between buffering and streaming +// events. +// ----------------------------------------------------------------------------- +// +void CMusEngClipSession::DetermineBufferingPeriod( CMceMediaStream& aStream ) + { + MUS_LOG( "mus: [ENGINE] -> CMusEngClipSession::DetermineBufferingPeriod()" ) + + // Determine file position modifier from time difference between buffering + // and streaming events + if ( aStream.State() == CMceMediaStream::EBuffering ) + { + iBufferingStartedTime.HomeTime(); + } + + if ( aStream.State() == CMceMediaStream::EStreaming ) + { + if ( iBufferingStartedTime.Int64() != 0 ) + { + TTime currentTime; + currentTime.HomeTime(); + + TTimeIntervalMicroSeconds bufferingPeriod = + currentTime.MicroSecondsFrom( iBufferingStartedTime ); + + const TInt KMusMinimumBufferingPeriod( 500000 ); + if ( bufferingPeriod > KMusMinimumBufferingPeriod ) + { + iBufferingPeriod = bufferingPeriod; + } + + MUS_LOG1( "mus: [ENGINE] current buffering period:%d", + iBufferingPeriod.Int64() ) + + iBufferingStartedTime = 0; + } + } + + MUS_LOG( "mus: [ENGINE] <- CMusEngClipSession::DetermineBufferingPeriod()" ) + } + +// ----------------------------------------------------------------------------- +// Modifies file position if position has reached end before clip has ended. +// File position is not going in sync with local video playback as playback +// buffers media before starting playing. +// ----------------------------------------------------------------------------- +// +TTimeIntervalMicroSeconds CMusEngClipSession::GetVideoSinkRelativeFilePos( + const TTimeIntervalMicroSeconds& aActualPosition, + const TTimeIntervalMicroSeconds& aDuration ) + { + MUS_LOG1( "mus: [ENGINE] PositionMicroSecondsL, pos before mod:%d", + aActualPosition.Int64() ) + + TTimeIntervalMicroSeconds tempCalculatedPosition( aActualPosition ); + + if ( iDelayFileEndingPos != 0 ) + { + iDelayFileEndingPos = aDuration; + tempCalculatedPosition = iDelayFileEndingPos; + } + else + { + // FRWD can go to zero even if clip has not ended, do not modify + // time in such situation. + if ( aActualPosition == 0 && + !iClipEnded && + iFRWDStartTime.Int64() == 0 && + !iRewindedToBeginning ) + { + const TInt KMusDelayEndingModifier = 2; + iDelayFileEndingPos = aDuration.Int64() - + iBufferingPeriod.Int64() / KMusDelayEndingModifier; + tempCalculatedPosition = iDelayFileEndingPos; + if ( iPreviousPos > tempCalculatedPosition ) + { + tempCalculatedPosition = iPreviousPos; + } + } + else + { + iDelayFileEndingPos = 0; + } + + if ( iRewindedToBeginning && aActualPosition > 0 ) + { + iRewindedToBeginning = EFalse; + } + + if ( tempCalculatedPosition < 0 ) + { + tempCalculatedPosition = 0; + } + } + + iPreviousPos = tempCalculatedPosition; + + return tempCalculatedPosition; + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +TBool CMusEngClipSession::IsH264Supported() const + { + return ( iVideoCodecList && iVideoCodecList->FindF( KMceSDPNameH264() ) >= 0 ); + } + +// End of file +