diff -r 000000000000 -r f0cf47e981f9 mmsharing/mmshengine/src/musengmcesession.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mmsharing/mmshengine/src/musengmcesession.cpp Thu Dec 17 08:44:37 2009 +0200 @@ -0,0 +1,1458 @@ +/* +* 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 "mussettings.h" +#include "musengmcesession.h" +#include "musengsessiondurationtimer.h" +#include "musengsessionobserver.h" +#include "musengmceutils.h" +#include "musuid.hrh" +#include "musenglogger.h" +#include "musengclipsessionobserver.h" +#include "mussipprofilehandler.h" + +// SYSTEM +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +const TInt KMusEngTimerInterval = 1000000; // 1 second +const TInt KMusEngRtcpInactivityThreshold = 20; // seconds +const TInt KMusEngArrayGranularity3 = 3; + +const TInt KMusEngSipReasonCodeOk = 200; +const TInt KMusEngSipReasonCodeBusyHere = 486; +_LIT8( KMusEngSipReasonPhraseBusyHere, "Busy Here" ); +_LIT8( KMusEngSipReasonPhraseBusy, "Busy" ); + +const TUint KMusEngDedicatedVideoPort = 49152; +const TUint KMusEngDedicatedAudioPort = 57344; + +#define MUS_CODEC_ARR_CONST_CAST( codecArr ) \ +( const_cast< RPointerArray< CMceVideoCodec >& >( codecArr ) ) + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +CMusEngMceSession::~CMusEngMceSession() + { + MUS_LOG( "mus: [ENGINE] -> CMusEngMceSession::~CMusEngMceSession()" ) + delete iSipProfileHandler; + delete iSession; + delete iManager; + delete iUpdateTimer; + MUS_LOG( "mus: [ENGINE] <- CMusEngMceSession::~CMusEngMceSession()" ) + } + + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +EXPORT_C void CMusEngMceSession::TerminateL() + { + MUS_LOG( "mus: [ENGINE] -> CMusEngMceSession::TerminateL()" ) + __ASSERT_ALWAYS( iSession, User::Leave( KErrNotReady ) ); + iSession->TerminateL(); + MUS_LOG( "mus: [ENGINE] <- CMusEngMceSession::TerminateL()" ) + } + + +// ----------------------------------------------------------------------------- +// Returns estabilished session time. If not established return +// value is < 0 +// ----------------------------------------------------------------------------- +// +EXPORT_C TTimeIntervalSeconds CMusEngMceSession::GetSessionTime() const + { + if ( iSession && iSession->State() == CMceSession::EEstablished ) + { + TTime time; + TTimeIntervalSeconds seconds; + time.HomeTime(); + + time.SecondsFrom( iStartTime, seconds ); + + return seconds; + } + + return TTimeIntervalSeconds( KErrNotReady ); + + } + + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +EXPORT_C TBool CMusEngMceSession::ConnectionActive() const + { + if ( iSession ) + { + return iSession->ConnectionActive(); + } + return EFalse; + } + + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +EXPORT_C TBool CMusEngMceSession::ContainsAudioL() + { + __ASSERT_ALWAYS( iSession, User::Leave( KErrNotReady ) ); + + for ( TInt i = 0; i < iSession->Streams().Count(); ++i ) + { + if ( iSession->Streams()[i]->Type() == KMceAudio ) + { + return ETrue; + } + } + + return EFalse; + } + + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +EXPORT_C TBool CMusEngMceSession::IsMutedL() + { + // Precondition checked in ContainsAudioL + + if ( ContainsAudioL() && !iExplicitlyMuted ) + { + return EFalse; + } + + return ETrue; + } + + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +EXPORT_C CMusEngMceSession::TDisplayOrientation + CMusEngMceSession::OrientationL() + { + MUS_LOG( "mus: [ENGINE] -> CMusEngMceSession::RotationL()" ) + + __ASSERT_ALWAYS( iSession, User::Leave( KErrNotReady ) ); + + CMceDisplaySink* display = MusEngMceUtils::GetDisplayL( *iSession ); + + TDisplayOrientation displayOrientation; + CMceDisplaySink::TRotation rotation( display->RotationL() ); + + MUS_LOG1( "mus: [ENGINE] MCE rotation is %d", rotation ) + + if ( rotation == CMceDisplaySink::ENone ) + { + displayOrientation = CMusEngMceSession::EPortrait; + } + else + { + displayOrientation = CMusEngMceSession::ELandscape; + } + + MUS_LOG1( "mus: [ENGINE] <- CMusEngMceSession::RotationL() %d", + displayOrientation ) + + return displayOrientation; + } + + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +EXPORT_C void CMusEngMceSession::SetOrientationL( + TDisplayOrientation aOrientation ) + { + MUS_LOG1( "mus: [ENGINE] -> CMusEngMceSession::SetOrientationL() %d", + aOrientation ) + + __ASSERT_ALWAYS( iSession, User::Leave( KErrNotReady ) ); + + CMceDisplaySink* display = MusEngMceUtils::GetDisplayL( *iSession ); + + if ( aOrientation == EPortrait ) + { + display->SetRotationL( CMceDisplaySink::ENone ); + } + else + { + display->SetRotationL( CMceDisplaySink::EClockwise90Degree ); + } + + MUS_LOG( "mus: [ENGINE] <- CMusEngMceSession::SetOrientationL()" ) + } + + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +EXPORT_C void CMusEngMceSession::VolumeUpL() + { + __ASSERT_ALWAYS( iSession, User::Leave( KErrNotReady ) ); + + CMusEngSession::VolumeUpL(); + + SetSpeakerVolumeL( VolumeL() ); + } + + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +EXPORT_C void CMusEngMceSession::VolumeDownL() + { + __ASSERT_ALWAYS( iSession, User::Leave( KErrNotReady ) ); + + CMusEngSession::VolumeDownL(); + + SetSpeakerVolumeL( VolumeL() ); + } + + +// ----------------------------------------------------------------------------- +// +// +// ----------------------------------------------------------------------------- +// +EXPORT_C void CMusEngMceSession::SetVolumeL( TInt aVal ) + { + __ASSERT_ALWAYS( iSession, User::Leave( KErrNotReady ) ); + + CMusEngSession::SetVolumeL( aVal ); + + SetSpeakerVolumeL( VolumeL() ); + } + + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +EXPORT_C void CMusEngMceSession::EnableDisplayL( TBool aEnable ) + { + MUS_LOG1( "mus: [ENGINE] -> CMusEngMceSession::EnableDisplay() %d", + aEnable ) + + __ASSERT_ALWAYS( iSession, User::Leave( KErrNotReady ) ); + + CMceDisplaySink* display = MusEngMceUtils::GetDisplayL( *iSession ); + + if ( aEnable ) + { + if ( !display->IsEnabled() ) + { + display->EnableL(); + MUS_LOG( " Display enabled" ) + if ( !iExplicitlyMuted ) + { + // Since speaker is not explicitly muted, but disabled as + // a consequence of disabling bundled display, it must be + // unmuted. + DoMuteSpeakerL( EFalse ); + MUS_LOG( " Bundled speaker enabled" ) + } + } + else + { + MUS_LOG( " Display already enabled, ignore" ) + } + } + else + { + if ( display->IsEnabled() ) + { + display->DisableL(); + MUS_LOG( " Display disabled" ) + if ( !iExplicitlyMuted ) + { + // Speaker will not be explicitly muted, but disabled as + // a consequence of disabling bundled display. + DoMuteSpeakerL( ETrue ); + MUS_LOG( " Bundled speaker disabled" ) + } + } + else + { + MUS_LOG( " Display already disabled, ignore" ) + } + } + + + MUS_LOG( "mus: [ENGINE] <- CMusEngMceSession::EnableDisplay()") + } + + +// ----------------------------------------------------------------------------- +// Mutes playback of sended audio streams. Audio data is still streamed. +// ----------------------------------------------------------------------------- +// +EXPORT_C void CMusEngMceSession::MuteL() + { + MUS_LOG( "mus: [ENGINE] -> CMusEngMceSession::Mute()" ) + + __ASSERT_ALWAYS( iSession, User::Leave( KErrNotReady ) ); + + DoMuteSpeakerL( ETrue ); + + // Mark speaker as explicitly muted instead of muted because of disabling + // bundled display + iExplicitlyMuted = ETrue; + + MUS_LOG( "mus: [ENGINE] <- CMusEngMceSession::Mute()" ) + } + + +// ----------------------------------------------------------------------------- +// Unmutes playback of sended audio streams. +// ----------------------------------------------------------------------------- +// +EXPORT_C void CMusEngMceSession::UnmuteL() + { + MUS_LOG( "mus: [ENGINE] -> CMusEngMceSession::Unmute()" ) + + __ASSERT_ALWAYS( iSession, User::Leave( KErrNotReady ) ); + + DoMuteSpeakerL( EFalse ); + + // Mark speaker as explicitly unmuted instead of unmuted because of + // enabling bundled display + iExplicitlyMuted = EFalse; + + MUS_LOG( "mus: [ENGINE] <- CMusEngMceSession::Unmute()" ) + } + + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +CMusEngMceSession::CMusEngMceSession( const TRect& aRect, + MMusEngSessionObserver& aSessionObserver ) + : CMusEngSession( aRect ), + iSessionObserver( aSessionObserver ), + iSecondsFromLastRtcpReport ( 0 ), + // Although speaker is constructed as muted, it is not explicitly muted + iExplicitlyMuted( EFalse ) + { + } + + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +void CMusEngMceSession::ConstructL() + { + MUS_LOG( "mus: [ENGINE] -> CMusEngMceSession::ConstructL()" ) + CMusEngSession::ConstructL(); // Base class ConstructL -first + + // Creating new MCE Manager and set all needed observers to this class. + iManager = CMceManager::NewL( TUid::Uid( KMusUiUid ), + &iTransactionDataContainer ); + + iManager->SetSessionObserver( this ); + iManager->SetInSessionObserver( this ); + iManager->SetMediaObserver( this ); + iManager->SetRtpObserver( this ); + + // Check if operator specific behavior is expected + iOperatorVariant = ( MultimediaSharingSettings::OperatorVariantSettingL() == + MusSettingsKeys::EOperatorSpecific ); + + // Update timer initialization + iUpdateTimer = CMusEngSessionDurationTimer::NewL( *this ); + + iSipProfileHandler = CMusSipProfileHandler::NewL( *this ); + + MUS_LOG( "mus: [ENGINE] <- CMusEngMceSession::ConstructL()" ) + } + + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +void CMusEngMceSession::RectChangedL() + { + MUS_LOG( "mus: [ENGINE] -> CMusEngMceSession::RectChangedL()" ) + + // If session is not yet created, do nothing + if ( iSession && iSession->State() != CMceSession::ETerminated ) + { + // Rely on having just one display + CMceDisplaySink* display = MusEngMceUtils::GetDisplayL( *iSession ); + display->SetDisplayRectL( Rect() ); + } + + MUS_LOG( "mus: [ENGINE] <- CMusEngMceSession::RectChangedL()" ) + } + + +// ----------------------------------------------------------------------------- +// Setting session level sdp lines. Bandwith attribute is always used in +// operator variant mode and at receiver side (using force). +// However, bandwidth attribute is preferred to be used at media level +// (see SetMediaSdpLinesL method). It is set to session level only if other +// side is using also session level bandwidth. Media level preference exists +// because some other manufacturer's videosharing does not understand session +// level bandwidth attribute. +// ----------------------------------------------------------------------------- +// +void CMusEngMceSession::SetSessionSdpLinesL( + CMceSession& aSession, + TBool aForceBandwidthLine ) + { + MUS_LOG( "mus: [ENGINE] -> CMusEngMceSession::SetSessionSdpLinesL()" ) + + MDesC8Array* oldSessionSdpLines = aSession.SessionSDPLinesL(); + CleanupDeletePushL( oldSessionSdpLines ); + TBool bandwidthAtSessionLevel( ContainsText( oldSessionSdpLines, + KMusEngSessionSdpLineBandwidthLine() ) ); + CleanupStack::PopAndDestroy( oldSessionSdpLines ); + + CDesC8Array* newSessionSDPLines = + new ( ELeave ) CDesC8ArrayFlat( KMusEngArrayGranularity3 ); + CleanupStack::PushL( newSessionSDPLines ); + + if ( iOperatorVariant ) + { + newSessionSDPLines->AppendL( KMusEngSessionSdpLineApplication() ); + newSessionSDPLines->AppendL( KMusEngSessionSdpLineType() ); + } + else + { + newSessionSDPLines->AppendL( KMusEngSessionSdpLineXApplication() ); + } + + if ( bandwidthAtSessionLevel && ( iOperatorVariant || aForceBandwidthLine ) ) + { + MUS_LOG( "mus: [ENGINE] setting bandwidth to session level" ) + newSessionSDPLines->AppendL( KMusEngSessionSdpLineBandwidthField() ); + } + + aSession.SetSessionSDPLinesL( newSessionSDPLines ); + + CleanupStack::Pop( newSessionSDPLines ); + + MUS_LOG( "mus: [ENGINE] <- CMusEngMceSession::SetSessionSdpLinesL()" ) + } + +// ----------------------------------------------------------------------------- +// Setting media level sdp lines. Bandwidth is not set to media level if +// it is used already at session level. +// ----------------------------------------------------------------------------- +// +void CMusEngMceSession::SetMediaSdpLinesL( + CMceMediaStream& aStream, + TBool aForceBandwidthLine ) + { + MUS_LOG( "mus: [ENGINE] -> CMusEngMceSession::SetMediaSdpLinesL()" ) + + MDesC8Array* sessionSdpLines = aStream.Session()->SessionSDPLinesL(); + CleanupDeletePushL( sessionSdpLines ); + TBool bandwidthAtSessionLevel( ContainsText( sessionSdpLines, + KMusEngSessionSdpLineBandwidthLine() ) ); + CleanupStack::PopAndDestroy( sessionSdpLines ); + + if ( !bandwidthAtSessionLevel && ( iOperatorVariant || aForceBandwidthLine ) ) + { + MUS_LOG( "mus: [ENGINE] setting bandwidth to media level" ) + + //Add media attribute to sdp + const TInt KMusMediaSdpLinesGranularity = 1; + CDesC8Array* headers = + new ( ELeave ) CDesC8ArrayFlat( KMusMediaSdpLinesGranularity ); + CleanupStack::PushL( headers ); + headers->AppendL( KMusEngSessionSdpLineBandwidthField() ); + aStream.SetMediaAttributeLinesL( headers ); + CleanupStack::Pop( headers ); + } + + MUS_LOG( "mus: [ENGINE] <- CMusEngMceSession::SetMediaSdpLinesL()" ) + } + +// ----------------------------------------------------------------------------- +// Changes volume of all speaker sinks in the session structure +// ----------------------------------------------------------------------------- +// +void CMusEngMceSession::SetSpeakerVolumeL( TInt aNewVolume ) + { + TInt sessionState = iSession->State(); + + if ( sessionState != CMceSession::EIdle && + sessionState != CMceSession::EIncoming ) + { + for ( TInt i = 0; i < iSession->Streams().Count(); ++i ) + { + CMceSpeakerSink* speaker = + MusEngMceUtils::GetSpeaker( *( iSession->Streams()[i] ) ); + + if ( speaker && + aNewVolume >= 1 && + aNewVolume <= KMusEngMaxVolume ) + { + // MCE might have different scale for volume than MUS + // so adjust MUS volume to MCE scale before setting. + TInt maxVol = speaker->MaxVolumeL(); + TInt setVol = maxVol * aNewVolume / KMusEngMaxVolume; + setVol = Max(setVol, 1); + + MUS_LOG2( +"mus: [ENGINE] -> CMusEngMceSession::SetSpeakerVolumeL() orig:%d, adjusted:%d", +aNewVolume, setVol ); + + if ( setVol <= maxVol ) + { + speaker->SetVolumeL( setVol ); + } + } + } + } + } + + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +void CMusEngMceSession::AdjustStreamsAndCodecsL() + { + MUS_LOG( "mus: [ENGINE] -> CMusEngMceSession::AdjustStreamsAndCodecsL" ) + + __ASSERT_ALWAYS( iSession, User::Leave( KErrNotReady ) ); + + const RPointerArray& streams = iSession->Streams(); + + for ( TInt i = 0; i < streams.Count(); ++i ) + { + if ( streams[i]->Type() == KMceVideo ) + { + CMceVideoStream* videoStream = + static_cast( streams[i] ); + + AdjustVideoStreamL( *videoStream ); + + if ( videoStream->BoundStream() ) + { + AdjustVideoStreamL( static_cast + ( videoStream->BoundStreamL() ) ); + } + + } + else // audio + { + CMceAudioStream* audioStream = + static_cast( streams[i] ); + + AdjustAudioStreamL( *audioStream ); + + if ( audioStream->BoundStream() ) + { + AdjustAudioStreamL( static_cast + ( audioStream->BoundStreamL() ) ); + } + + } + } + + MUS_LOG( "mus: [ENGINE] <- CMusEngMceSession::AdjustStreamsAndCodecsL" ) + + } + + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +void CMusEngMceSession::AdjustVideoStreamL( CMceVideoStream& aVideoStream ) + { + MUS_LOG( "mus: [ENGINE] -> CMusEngMceSession::AdjustVideoStreamL" ) + + aVideoStream.SetLocalMediaPortL( KMusEngDedicatedVideoPort ); + + DoCodecSelectionL( aVideoStream ); + + const RPointerArray& codecs = aVideoStream.Codecs(); + + for ( TInt codecIndex = 0; codecIndex < codecs.Count(); ++codecIndex ) + { + AdjustVideoCodecL( *codecs[codecIndex] ); + } + + MUS_LOG( "mus: [ENGINE] <- CMusEngMceSession::AdjustVideoStreamL" ) + } + + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +void CMusEngMceSession::AdjustAudioStreamL( CMceAudioStream& aAudioStream ) + { + MUS_LOG( "mus: [ENGINE] -> CMusEngMceSession::AdjustAudioStreamL" ) + + aAudioStream.SetLocalMediaPortL( KMusEngDedicatedAudioPort ); + + const RPointerArray codecs = aAudioStream.Codecs(); + + for ( TInt codecIndex = 0; codecIndex < codecs.Count(); ++codecIndex ) + { + AdjustAudioCodecL( *codecs[codecIndex] ); + } + + MUS_LOG( "mus: [ENGINE] <- CMusEngMceSession::AdjustAudioStreamL" ) + } + + +// ----------------------------------------------------------------------------- +// Calls CMceInSession::RejectL() inside TRAP_IGNORE +// ----------------------------------------------------------------------------- +// +void CMusEngMceSession::Reject( CMceInSession& aSession, + const TDesC8& aReason, + TUint32 aCode ) + { + if ( aCode != 0 || aReason != KNullDesC8() ) + { + TRAP_IGNORE( aSession.RejectL( aReason, aCode, NULL, NULL, NULL ) ) + } + else + { + if ( iOperatorVariant ) + { + // In operator variant, session is rejected with 486 instead of 603. + // Also the reason phrase is supposed to be "Busy". + TRAP_IGNORE( aSession.RejectL( KMusEngSipReasonPhraseBusy(), + KMusEngSipReasonCodeBusyHere ) ) + } + else + { + // Normal case + TRAP_IGNORE( aSession.RejectL() ) + } + } + } + + +// ----------------------------------------------------------------------------- +// By default rejects all incoming sessions immediately without notifying UI +// ----------------------------------------------------------------------------- +// +void CMusEngMceSession::IncomingSession( + CMceInSession* aSession, + TMceTransactionDataContainer* /*aContainer*/ ) + { + MUS_LOG( "mus: [ENGINE] -> CMusEngMceSession::IncomingSession()" ) + + Reject( *aSession, + KMusEngSipReasonPhraseBusyHere(), + KMusEngSipReasonCodeBusyHere ); + + delete aSession; + aSession = NULL; + + MUS_LOG( "mus: [ENGINE] <- CMusEngMceSession::IncomingSession()" ) + } + + +// ----------------------------------------------------------------------------- +// By default rejects all incoming updates immediately without notifying UI +// ----------------------------------------------------------------------------- +// +void CMusEngMceSession::IncomingUpdate( + CMceSession& aOrigSession, + CMceInSession* aUpdatedSession, + TMceTransactionDataContainer* /*aContainer*/ ) + { + MUS_LOG( "mus: [ENGINE] -> CMusEngMceSession::IncomingUpdate()" ) + + if ( iSession && + iSession == &aOrigSession ) + { + // Old session is useless from now on + delete iSession; + iSession = aUpdatedSession; + MUS_LOG( "mus: [ENGINE] Unexpected update, reject" ) + Reject( *aUpdatedSession ); + } + else + { + // This should never happen + MUS_LOG( "mus: [ENGINE] Unknown update, reject and delete" ) + Reject( *aUpdatedSession ); + delete aUpdatedSession; + } + + MUS_LOG( "mus: [ENGINE] <- CMusEngMceSession::IncomingUpdate()" ) + } + + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +void CMusEngMceSession::StreamStateChanged( CMceMediaStream& aStream ) + { + MUS_LOG( "mus: [ENGINE] -> CMusEngMceSession::StreamStateChanged()" ) + + if ( !iSession ) + { + return; // We cannot do anything + } + + MUS_ENG_LOG_STREAM_STATE( aStream ) + + switch ( aStream.State() ) + { + case CMceMediaStream::EUninitialized: // Stream is created + { + // Unexpected state change + break; + } + case CMceMediaStream::EInitialized: // Stream is initialized + { + // Should be handled in sibling classes if needed + break; + } + case CMceMediaStream::EBuffering: // Stream is buffering + { + // Should be handled in sibling classes if needed + break; + } + case CMceMediaStream::EIdle: // Stream is not receiving RTP + { + // NOP + break; + } + case CMceMediaStream::EStreaming: // Stream is streaming + { + // If streaming stream is complete video out- or instream, inform UI + if ( aStream.Type() == KMceVideo && + aStream.Source() && + aStream.Sinks().Count() >= 0 && + ( aStream.Source()->Type() == KMceRTPSource || + aStream.Sinks()[0]->Type() == KMceRTPSink ) ) + { + iSessionObserver.StreamStreaming(); + } + break; + } + case CMceMediaStream::EDisabled: // Stream is explicitly disabled + { + break; + } + case CMceMediaStream::ENoResources: + { + // Stream has no needed resources to stream + break; + } + case CMceMediaStream::ETranscodingRequired: + { + // Stream requires non-realtime transcoding + // Should be handled in sibling classes + break; + } + case CMceMediaStream::ETranscoding: + { + // Stream is transcoding in non-realtime + // Should be handled in sibling classes + break; + } + default: + { + break; + } + } + + MUS_LOG( "mus: [ENGINE] <- CMusEngMceSession::StreamStateChanged()" ) + + } + + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +void CMusEngMceSession::StreamStateChanged( CMceMediaStream& aStream, + CMceMediaSource& /*aSource*/ ) + { + MUS_LOG( "mus: [ENGINE] -> CMusEngMceSession::StreamStateChanged( src )" ) + // Use default logic + StreamStateChanged( aStream ); + MUS_LOG( "mus: [ENGINE] <- CMusEngMceSession::StreamStateChanged( src )" ) + } + + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +void CMusEngMceSession::StreamStateChanged( CMceMediaStream& aStream, + CMceMediaSink& /*aSink*/ ) + { + MUS_LOG( "mus: [ENGINE] -> CMusEngMceSession::StreamStateChanged( sink )" ) + // Use default logic + StreamStateChanged( aStream ); + MUS_LOG( "mus: [ENGINE] <- CMusEngMceSession::StreamStateChanged( sink )" ) + } + + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +void CMusEngMceSession::SessionStateChanged( + CMceSession& aSession, + TMceTransactionDataContainer* aContainer ) + { + MUS_LOG( "mus: [ENGINE] -> CMusEngMceSession::SessionStateChanged()" ) + + if ( !aContainer ) + { + // Container should never be NULL, but if it is, handle as + // internal error + iSessionObserver.SessionFailed(); + return; + } + + // This is the only point to get statuscode and reasonphrase. With this call + // they are zeroed and thus cannot be got anymore. + TInt statusCode = aContainer->GetStatusCode(); + HBufC8* reasonPhrase = aContainer->GetReasonPhrase(); + + if ( reasonPhrase ) + { + HandleSessionStateChanged( aSession, statusCode, *reasonPhrase ); + delete reasonPhrase ; + } + else + { + HandleSessionStateChanged( aSession, statusCode, KNullDesC8() ); + } + + MUS_LOG( "mus: [ENGINE] <- CMusEngMceSession::SessionStateChanged()" ) + } + + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +void CMusEngMceSession::SessionConnectionStateChanged( CMceSession& aSession, + TBool aActive ) + { + MUS_LOG1( "mus: [ENGINE] CMusEngMceSession::\ + SessionConnectionStateChanged() active = %b", aActive ) + + if ( iSession && iSession == &aSession ) + { + if ( !aActive ) + { + MUS_LOG( "mus: [ENGINE] CMusEngMceSession::\ + SessionConnectionStateChanged: Notify observer" ) + iSessionObserver.SessionConnectionLost(); + } + } + + MUS_LOG( "mus: [ENGINE] <- CMusEngMceSession::\ + SessionConnectionStateChanged()" ) + } + + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// + +#if ( defined( _DEBUG ) && !defined( UNIT_TESTING ) ) +void CMusEngMceSession::Failed( CMceSession& aSession, TInt aError ) +#else +void CMusEngMceSession::Failed( CMceSession& aSession, TInt /*aError*/ ) +#endif + { + MUS_LOG1( "mus: [ENGINE] -> CMusEngMceSession::Failed() error #%d", + aError ) + + if ( iSession && iSession == &aSession ) + { + MUS_LOG( "mus: [ENGINE] CMusEngMceSession::Failed: Notify observer" ) + iSessionObserver.SessionFailed(); + } + + MUS_LOG( "mus: [ENGINE] <- CMusEngMceSession::Failed()" ) + } + + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +void CMusEngMceSession::UpdateFailed( + CMceSession& aSession, + TMceTransactionDataContainer* aContainer ) + { + MUS_LOG( "mus: [ENGINE] -> CMusEngMceSession::UpdateFailed()" ) + + if ( !aContainer ) + { + // Container should never be NULL, but if it is, handle as + // internal error + iSessionObserver.SessionFailed(); + return; + } + + if ( iSession && iSession == &aSession ) + { + MUS_LOG( "mus: [ENGINE] CMusEngMceSession::UpdateFailed: \ + Notify observer" ) + iSessionObserver.SessionFailed(); + } + + MUS_LOG( "mus: [ENGINE] <- CMusEngMceSession::UpdateFailed()" ) + } + + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +void CMusEngMceSession::SRReceived( CMceSession& aSession, + CMceMediaStream& aStream) + { + // No logging because of amount of reports + if ( iSession && + iSession == &aSession ) + { + for ( TInt i = 0; i < iSession->Streams().Count(); ++i ) + { + if ( &aStream == iSession->Streams()[i] ) + { + iSecondsFromLastRtcpReport = 0; + } + } + } + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +void CMusEngMceSession::RRReceived( CMceSession& aSession, + CMceMediaStream& aStream) + { + // No logging because of amount of reports + + if ( iSession && + iSession == &aSession ) + { + for ( TInt i = 0; i < iSession->Streams().Count(); ++i ) + { + if ( &aStream == iSession->Streams()[i] ) + { + iSecondsFromLastRtcpReport = 0; + } + } + } + } + + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +void CMusEngMceSession::InactivityTimeout( CMceMediaStream& aStream, + CMceRtpSource& /*aSource*/ ) + { + MUS_LOG( "mus: [ENGINE] -> CMusEngMceSession::InactivityTimeout()" ) + // This function may be deprecated in future and after that similar + // functionality can be obtained by observing stream state EIdle. + // Anyway it does not work yet and until then, informing UI about + // RTP inactivity is done in this function. + + if ( aStream.Type() == KMceVideo ) + { + iSessionObserver.StreamIdle(); + } + + MUS_LOG( "mus: [ENGINE] <- CMusEngMceSession::InactivityTimeout()" ) + } + + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +void CMusEngMceSession::SsrcAdded( CMceMediaStream& /*aStream*/, + CMceRtpSource& /*aSource*/, + TUint /*aSsrc*/ ) + { + MUS_LOG( "mus: [ENGINE] CMusEngMceSession::SsrcAdded( ... )" ) + // NOP, We are not at all interested about SSRCs + } + + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +void CMusEngMceSession::SsrcRemoved( CMceMediaStream& /*aStream*/, + CMceRtpSource& /*aSource*/, + TUint /*aSsrc*/ ) + { + MUS_LOG( "mus: [ENGINE] CMusEngMceSession::SsrcRemoved(... )" ) + // NOP, We are not at all interested about SSRCs + } + + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +TBool CMusEngMceSession::IsRoamingBetweenAPsAllowed() + { + TBool allowed( ETrue ); + if ( iSession && + iSession->State() != CMceSession::EIdle && + iSession->State() != CMceSession::ETerminated ) + { + allowed = EFalse; + } + return allowed; + } + + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +void CMusEngMceSession::HandleSessionStateChanged( CMceSession& aSession, + TInt aStatusCode, + const TDesC8& aReasonPhrase ) + { + MUS_LOG( "mus: [ENGINE] -> CMusEngMceSession::HandleSessionStateChanged" ) + + MUS_ENG_LOG_SESSION_STATE_AND_STATUS( aSession, aStatusCode, aReasonPhrase ) + + if ( iSession && iSession == &aSession ) + { + switch ( aSession.State() ) + { + case CMceSession::EIdle: + { + MUS_LOG( "mus: [ENGINE] Unexpected asynchronous \ + state transition, consider session as failed." ) + iSessionObserver.SessionFailed(); + break; + } + case CMceSession::EOffering : + { + break; + } + case CMceSession::EIncoming: + { + MUS_LOG( "mus: [ENGINE] Unexpected asynchronous \ + state transition, consider session as failed." ) + iSessionObserver.SessionFailed(); + break; + } + case CMceSession::EReserving : + { + // UpdateL called to incoming session during + // session establishment + break; + } + case CMceSession::EAnswering : // Answering an incoming call + { + break; + } + case CMceSession::EProceeding : + { + break; + } + case CMceSession::EEstablished: + { + // Check that session timer is not already running, which is + // the case when refreshing the session with session timer + if ( !iUpdateTimer->IsActive() ) + { + iStartTime.HomeTime(); // Start counting session duration + iUpdateTimer->Start( KMusEngTimerInterval ); + iSessionObserver.SessionEstablished(); + } + + break; + } + case CMceSession::ECancelling: + { + // MCE has for some reason started to cancel session + break; + } + case CMceSession::ETerminating: + { + // MCE has for some reason started to terminate session + break; + } + case CMceSession::ETerminated: + { + HandleTermination( aStatusCode, aReasonPhrase ); + break; + } + default: + { + MUS_LOG( "mus: [ENGINE] CMusEngMceSession::SessionStateChanged(), \ + default case" ) + break; + } + } + } + + MUS_LOG( "mus: [ENGINE] <- CMusEngMceSession::HandleSessionStateChanged" ) + } + + +// ----------------------------------------------------------------------------- +// This function should be called only if sibling classes cannot handle +// termination reason by themselves. +// ----------------------------------------------------------------------------- +// +void CMusEngMceSession::HandleTermination( TInt aStatusCode, + const TDesC8& /*aReasonPhrase*/ ) + { + MUS_LOG( "mus: [ENGINE] -> CMusEngMceSession::HandleTermination()" ) + + iSipProfileHandler->RefreshIapAvailabilities(); + + switch ( aStatusCode ) + { + case 0: + { + // Normal session termination or session by another end. + iSessionObserver.SessionTerminated(); + break; + } + case KMusEngSipReasonCodeOk: + { + // Normal session termination by this end: We have sent BYE + // and now received 200 OK to it. + iSessionObserver.SessionTerminated(); + break; + } + default: + { + // Termination reason cannot be determined, handle as internal + // error. + iSessionObserver.SessionFailed(); + break; + } + } + + MUS_LOG( "mus: [ENGINE] <- CMusEngMceSession::HandleTermination()" ) + } + + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +void CMusEngMceSession::AdjustVideoCodecL( CMceVideoCodec& aVideoCodec ) + { + MUS_LOG( "mus: [ENGINE] -> CMusEngMceSession::AdjustVideoCodecL()" ) + + aVideoCodec.SetMMFPriorityL( KAudioPrioritySwisPlayback ); + aVideoCodec.SetMMFPriorityPreferenceL( KAudioPrefSwisPlayback ); + MUS_LOG( "mus: [ENGINE] Video MMF priority and preference set" ) + + MUS_LOG( "mus: [ENGINE] <- CMusEngMceSession::AdjustVideoCodecL()" ) + } + + +// ----------------------------------------------------------------------------- +// 1. Sets MMF audio priority and preference +// ----------------------------------------------------------------------------- +// +void CMusEngMceSession::AdjustAudioCodecL( CMceAudioCodec& aAudioCodec ) + { + MUS_LOG( "mus: [ENGINE] -> CMusEngMceSession::AdjustAudioCodecL()" ) + + aAudioCodec.SetMMFPriorityL( KAudioPrioritySwisPlayback ); + aAudioCodec.SetMMFPriorityPreferenceL( KAudioPrefSwisPlayback ); + MUS_LOG( "mus: [ENGINE] Audio MMF priority and preference set" ) + + MUS_LOG( "mus: [ENGINE] <- CMusEngMceSession::AdjustAudioCodecL()" ) + } + + +// ----------------------------------------------------------------------------- +// Remove multiples of H.263 codec, prefer H263-2000 over H263-1998. +// Additionally select just the one with best quality from selected mode. +// ----------------------------------------------------------------------------- +// +void CMusEngMceSession::DoCodecSelectionL( CMceVideoStream& aVideoStream ) + { + MUS_LOG( "mus: [ENGINE] -> CMusEngMceSession::DoCodecSelectionL()" ) + + const RPointerArray& codecs = aVideoStream.Codecs(); + TBool codecModeBasedRemovalNeeded( EFalse ); + // Label:H263 + TBool H2632000CodecFound( EFalse ); + TBool H2631998CodecFound( EFalse ); + for ( TInt codecIndex = 0; codecIndex < codecs.Count(); ++codecIndex ) + { + const CMceVideoCodec& currentCodec = *codecs[codecIndex]; + if ( currentCodec.SdpName().FindF( KMceSDPNameH263 ) != KErrNotFound ) + { + if ( !currentCodec.SdpName().CompareF( KMceSDPNameH2632000 ) ) + { + H2632000CodecFound = ETrue; + codecModeBasedRemovalNeeded = H2631998CodecFound; + } + else if ( !currentCodec.SdpName().CompareF( KMceSDPNameH2631998 ) ) + { + H2631998CodecFound = ETrue; + codecModeBasedRemovalNeeded = H2632000CodecFound; + } + else + { + // NOP + } + } + } + if ( codecModeBasedRemovalNeeded ) + { + DoCodecModeBasedRemovalL( aVideoStream ); + } + + const RPointerArray& codecs2 = aVideoStream.Codecs(); + const CMceVideoCodec* bestBitrateCodec( NULL ); + for ( TInt codecIndex = 0; codecIndex < codecs2.Count(); ++codecIndex ) + { + const CMceVideoCodec& currentCodec = *codecs2[codecIndex]; + if ( currentCodec.SdpName().FindF( KMceSDPNameH263 ) != KErrNotFound ) + { + if ( !bestBitrateCodec || + currentCodec.MaxBitRate() > bestBitrateCodec->MaxBitRate() ) + { + bestBitrateCodec = ¤tCodec; + } + } + } + if ( bestBitrateCodec != NULL ) + { + DoBitrateBasedRemovalL( aVideoStream, *bestBitrateCodec ); + } + + /* Codec removal based on configuration */ + DoCodecConfigurationBasedRemovalL( aVideoStream ); + + MUS_LOG( "mus: [ENGINE] <- CMusEngMceSession::DoCodecSelectionL()" ) + } + + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +void CMusEngMceSession::UpdateTimerEvent() + { + // Update timer is used also to detect RTCP inactivity + ++iSecondsFromLastRtcpReport; + + iSessionObserver.SessionTimeChanged( GetSessionTime() ); + + if ( iSecondsFromLastRtcpReport >= KMusEngRtcpInactivityThreshold ) + { + iSessionObserver.InactivityTimeout(); + // Disable calling multiple times by reseting timer + iSecondsFromLastRtcpReport = 0; + } + + iUpdateTimer->Start( KMusEngTimerInterval ); + } + + +// ----------------------------------------------------------------------------- +// Enables or disables all the speaker sinks of all the audio streams +// ----------------------------------------------------------------------------- +// +void CMusEngMceSession::DoMuteSpeakerL( TBool aMute ) + { + MUS_LOG1( "mus: [ENGINE] -> CMusEngMceSession::MuteL( %d )", aMute ) + + const RPointerArray& streams = iSession->Streams(); + + for ( TInt i = 0; i < streams.Count(); ++i ) + { + CMceSpeakerSink* speaker = + MusEngMceUtils::GetSpeaker( *streams[i] ); + + if ( speaker ) + { + if( aMute ) + { + if ( speaker->IsEnabled() ) + { + speaker->DisableL(); + } + else + { + MUS_LOG( "mus: [ENGINE] Speaker already muted, NOP" ) + } + } + else + { + if ( !speaker->IsEnabled() ) + { + speaker->EnableL(); + } + else + { + MUS_LOG( "mus: [ENGINE] Speaker already unmuted, NOP" ) + } + } + } + } + + MUS_LOG( "mus: [ENGINE] <- CMusEngMceSession::MuteL( TBool aMute )" ) + } + +// ----------------------------------------------------------------------------- +// Checks if some of array items contains specific text +// (exact match not required) +// ----------------------------------------------------------------------------- +// +TBool CMusEngMceSession::ContainsText( MDesC8Array* aArray, const TDesC8& aItem ) + { + for ( TInt i = 0; aArray && i < aArray->MdcaCount(); i++ ) + { + if ( aArray->MdcaPoint( i ).FindF( aItem ) != KErrNotFound ) + { + return ETrue; + } + } + return EFalse; + } + + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +void CMusEngMceSession::DoBitrateBasedRemovalL( + CMceVideoStream& aVideoStream, + const CMceVideoCodec& aBestBitrateVideoCodec ) + { + MUS_LOG( "mus: [ENGINE] -> CMusEngMceSession::DoBitrateBasedRemovalL()" ) + + RPointerArray& codecs = + MUS_CODEC_ARR_CONST_CAST( aVideoStream.Codecs() ); + + TInt codecIndex = 0; + while ( codecIndex < codecs.Count() ) + { + CMceVideoCodec& currentCodec = *codecs[codecIndex++]; + if ( currentCodec.SdpName().FindF( KMceSDPNameH263 ) != KErrNotFound && + ¤tCodec != &aBestBitrateVideoCodec ) + { + MUS_LOG( "mus: [ENGINE] removing" ) + aVideoStream.RemoveCodecL( currentCodec ); + codecs = MUS_CODEC_ARR_CONST_CAST( aVideoStream.Codecs() ); + codecIndex = 0; + } + } + + MUS_LOG( "mus: [ENGINE] <- CMusEngMceSession::DoBitrateBasedRemovalL()" ) + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +void CMusEngMceSession::DoCodecModeBasedRemovalL( CMceVideoStream& aVideoStream ) + { + MUS_LOG( "mus: [ENGINE] -> CMusEngMceSession::DoCodecModeBasedRemovalL()" ) + + RPointerArray& codecs = + MUS_CODEC_ARR_CONST_CAST( aVideoStream.Codecs() ); + + TInt codecIndex = 0; + while ( codecIndex < codecs.Count() ) + { + CMceVideoCodec& currentCodec = *codecs[codecIndex++]; + if ( !currentCodec.SdpName().CompareF( KMceSDPNameH2631998 ) ) + { + MUS_LOG( "mus: [ENGINE] removing" ) + aVideoStream.RemoveCodecL( currentCodec ); + codecs = MUS_CODEC_ARR_CONST_CAST( aVideoStream.Codecs() ); + codecIndex = 0; + } + } + + MUS_LOG( "mus: [ENGINE] <- CMusEngMceSession::DoCodecModeBasedRemovalL()" ) + } + +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// +void CMusEngMceSession::DoCodecConfigurationBasedRemovalL( CMceVideoStream& aVideoStream ) + { + MUS_LOG( "mus: [ENGINE] -> CMusEngMceSession::DoCodecConfigurationBasedRemovalL()" ) + if( MultimediaSharingSettings::IsAvcDisabled()) + { + RPointerArray& codecs = + MUS_CODEC_ARR_CONST_CAST( aVideoStream.Codecs() ); + TInt codecIndex = 0; + while ( codecIndex < codecs.Count() ) + { + CMceVideoCodec& currentCodec = *codecs[codecIndex++]; + if ( !currentCodec.SdpName().CompareF( KMceSDPNameH264 ) ) + { + MUS_LOG( "mus: [ENGINE] - Removing avc from supported codec list" ) + aVideoStream.RemoveCodecL( currentCodec ); + codecs = MUS_CODEC_ARR_CONST_CAST( aVideoStream.Codecs() ); + codecIndex = 0; + } + } + } + MUS_LOG( "mus: [ENGINE] <- CMusEngMceSession::DoCodecConfigurationBasedRemovalL()" ) + }