diff -r 000000000000 -r 1bce908db942 multimediacommscontroller/mmccsubcontroller/src/mccrtpmanager.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/multimediacommscontroller/mmccsubcontroller/src/mccrtpmanager.cpp Tue Feb 02 01:04:58 2010 +0200 @@ -0,0 +1,745 @@ +/* +* Copyright (c) 2004-2007 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: RTP Manager +* +*/ + + + + +// INCLUDE FILES +#include +#include "mccrtpmanager.h" +#include "mccinternalcodecs.h" +#include "mccrtpdatasink.h" +#include "mccrtpdatasource.h" +#include "mmccevents.h" +#include "mccsubcontrollerlogs.h" +#include "mccrtcpreceiver.h" +#include "mccrtpkeepalivecontainer.h" +#include "mccresources.h" +#include "mccqoshandler.h" +#include "mccinternaldef.h" + +// LOCAL CONSTANTS AND MACROS + +// Default IP type-of-service value. +const TInt KDefaultIpTOS = 184; + +// ============================= LOCAL FUNCTIONS =============================== + +// ============================ MEMBER FUNCTIONS =============================== + +// ----------------------------------------------------------------------------- +// CMccRtpManager::CMccRtpManager +// C++ default constructor can NOT contain any code, that +// might leave. +// ----------------------------------------------------------------------------- +// +CMccRtpManager::CMccRtpManager( + MAsyncEventHandler& aHandler, + MMccResources& aMccResources, + TUint32 aMccSessionId ) : + iRtpSessionId( KNullId ), + iStreamArray( RArray() ), + iEventHandler( aHandler ), + iMccResources( aMccResources ), + iIpTOS( KDefaultIpTOS ), + iLocalPort( KDefaultRtpPort ), + iMccSessionId( aMccSessionId ), + iDummyRcvStreamId( KNullId ) + { + + } + +// ----------------------------------------------------------------------------- +// CMccRtpManager::ConstructL +// Symbian 2nd phase constructor can leave. +// ----------------------------------------------------------------------------- +// +void CMccRtpManager::ConstructL() + { + __SUBCONTROLLER( "CMccRtpManager::ConstructL" ) + + iRtpApi = CRtpAPI::NewL( *this ); + iRtcpReceiver = CMccRtcpReceiver::NewL( this, iEventHandler, iMccResources, *iRtpApi ); + iQosHandler = CMccQosHandler::NewL( *this ); + + __SUBCONTROLLER( "CMccRtpManager::ConstructL exit" ) + } + +// ----------------------------------------------------------------------------- +// CMccRtpManager::NewL +// Static constructor. +// ----------------------------------------------------------------------------- +// +CMccRtpManager* CMccRtpManager::NewL( + MAsyncEventHandler& aHandler, + MMccResources& aMccResources, + TUint32 aMccSessionId + ) + { + CMccRtpManager* self = new (ELeave) CMccRtpManager( aHandler, aMccResources, + aMccSessionId ); + CleanupStack::PushL( self ); + self->ConstructL(); + CleanupStack::Pop( self ); + return self; + } + +// ----------------------------------------------------------------------------- +// CMccRtpManager::~CMccRtpManager +// Destructor +// ----------------------------------------------------------------------------- +// +CMccRtpManager::~CMccRtpManager() + { + __SUBCONTROLLER( "CMccRtpManager::~CMccRtpManager" ) + + delete iRtcpReceiver; + delete iRtpKeepaliveMechanism; + + if ( KNullId != iDummyRcvStreamId && iRtpApi ) + { + iRtpApi->CloseStream( iDummyRcvStreamId ); + } + + if( KNullId != iRtpSessionId && iRtpApi ) + { + iRtpApi->CloseSession( iRtpSessionId ); + iRtpApi->Close(); + } + + delete iSecSession; + delete iRtpApi; + delete iQosHandler; + + iStreamArray.Close(); + + delete iCName; + __SUBCONTROLLER( "CMccRtpManager::~CMccRtpManager, exit" ) + } + +// ----------------------------------------------------------------------------- +// CMccRtpManager::CreateSessionL +// Creates RTP session and adds session to SessionArray +// ----------------------------------------------------------------------------- +// +void CMccRtpManager::CreateSessionL( + TUint& aPort, + TBool aEnableRTCP, + TBool aSecurity, + TBool aIncreaseDefaultSocketSize ) + { + __SUBCONTROLLER( "CMccRtpManager::CreateSessionL" ) + + if( KNullId != iRtpSessionId ) + { + User::Leave( KErrAlreadyExists ); + } + + TCreateSessionParams params; + params.iPriority = TCreateSessionParams::EPriorityStandard; + aEnableRTCP = ETrue; + + if ( aIncreaseDefaultSocketSize ) + { + params.iSocketBufSize = KMccIncreasedRtpSocketSize; + } + __SUBCONTROLLER_INT1( "CMccRtpManager::CreateSessionL, socket size:", + params.iSocketBufSize ) + + TInetAddr localAddress = iRtpApi->GetLocalIPAddressL(); + + if ( aSecurity ) + { + iSecSession = CSRTPSession::NewL( localAddress ); + iRtpSessionId = iRtpApi->CreateSessionL( params, aPort, aEnableRTCP, + NULL, *iSecSession ); + } + else + { + iRtpSessionId = iRtpApi->CreateSessionL( params, aPort, aEnableRTCP, NULL ); + } + + if( KNullId == iRtpSessionId ) + { + User::Leave( KErrCouldNotConnect ); + } + + __ASSERT_ALWAYS( !iRtpKeepaliveMechanism, User::Leave( KErrAlreadyExists ) ); + iRtpKeepaliveMechanism = + CMccRtpKeepaliveContainer::NewL( iEventHandler, + *iRtpApi, + iRtpSessionId ); + + iLocalPort = aPort; + iRtcpEnabled = aEnableRTCP; + + __SUBCONTROLLER( "CMccRtpManager::CreateSessionL, keepalive initialized" ) + + iRtcpReceiver->HandleReceiving( iRtpSessionId, iRtcpEnabled ); + + __SUBCONTROLLER( "CMccRtpManager::CreateSessionL, exit" ) + } + +// ----------------------------------------------------------------------------- +// CMccRtpManager::CloseSession +// Closes RTP session +// ----------------------------------------------------------------------------- +// +void CMccRtpManager::CloseSession() + { + __SUBCONTROLLER( "CMccRtpManager::CloseSession" ) + if ( KNullId != iRtpSessionId ) + { + if ( iRtpKeepaliveMechanism ) + { + iRtpKeepaliveMechanism->StopAll(); + } + + iRtpApi->CloseSession( iRtpSessionId ); + iRtpApi->Close(); + iStreamArray.Reset(); + + iRtpSessionId = KNullId; + + if ( iQosHandler->QoSEnabled() ) + { + iQosHandler->DisableQoS(); + } + } + __SUBCONTROLLER( "CMccRtpManager::CloseSession, exit" ) + } + +// ----------------------------------------------------------------------------- +// CMccRtpManager::GetRtpReference +// Returns RTPApi reference +// ----------------------------------------------------------------------------- +// +CRtpAPI* CMccRtpManager::GetRtpReferenceL( ) + { + if ( !IsOpen() ) + { + User::Leave( KErrNotFound ); + } + return iRtpApi; + } + +// ----------------------------------------------------------------------------- +// CMccRtpManager::SetRemoteAddress +// Sets RTP Remote Address +// ----------------------------------------------------------------------------- +// +TInt CMccRtpManager::SetRemoteAddress( const TInetAddr& aRemoteAddress ) + { + __SUBCONTROLLER( "CMccRtpManager::SetRemoteAddress" ) + TInt err( KErrNotFound ); + if ( KNullId != iRtpSessionId ) + { + // Do only if address has changed + err =( iRemoteAddress.Address() == aRemoteAddress.Address() && + iRemoteAddress.Port() == aRemoteAddress.Port() ) ? KErrNone : err; + if ( err ) + { + __SUBCONTROLLER_INT1( "CMccRtpManager::SetRemoteAddress, setting addr:", + aRemoteAddress.Address() ) + __SUBCONTROLLER_INT1( "CMccRtpManager::SetRemoteAddress, setting port:", + aRemoteAddress.Port() ) + + err = iRtpApi->SetRemoteAddress( iRtpSessionId, aRemoteAddress ); + if ( !err ) + { + iRemoteAddress.SetAddress( aRemoteAddress.Address() ); + iRemoteAddress.SetPort( aRemoteAddress.Port() ); + if ( iRtpKeepaliveMechanism ) + { + err = iRtpKeepaliveMechanism->RemoteAddressSet(); + } + } + } + } + __SUBCONTROLLER_INT1( "CMccRtpManager::SetRemoteAddress, exit with err", err ) + return err; + } + +// ----------------------------------------------------------------------------- +// CMccRtpManager::SetRemoteRtcpAddress +// Sets RTP Remote Address +// ----------------------------------------------------------------------------- +// +TInt CMccRtpManager::SetRemoteRtcpAddr( const TInetAddr& aRemoteAddress ) + { + __SUBCONTROLLER( "CMccRtpManager::SetRemoteRtcpAddress" ) + TInt err( KErrNotFound ); + if ( KNullId != iRtpSessionId ) + { + // Do only if address has changed + err =( iRemoteRtcpAddr.Address() == aRemoteAddress.Address() && + iRemoteRtcpAddr.Port() == aRemoteAddress.Port() ) ? KErrNone : err; + __SUBCONTROLLER_INT1( "Remote RtcpPort", aRemoteAddress.Port() ) + __SUBCONTROLLER_INT1( "Saved Remote RtcpPort", iRemoteAddress.Port() ) + if ( err ) + { + __SUBCONTROLLER_INT1( "CMccRtpManager::SetRemoteAddress, setting addr:", + aRemoteAddress.Address() ) + __SUBCONTROLLER_INT1( "CMccRtpManager::SetRemoteAddress, setting port:", + aRemoteAddress.Port() ) + + err = iRtpApi->SetRemoteRtcpAddress( iRtpSessionId, aRemoteAddress ); + if ( !err ) + { + iRemoteRtcpAddr.SetAddress( aRemoteAddress.Address() ); + iRemoteRtcpAddr.SetPort( aRemoteAddress.Port() ); + __SUBCONTROLLER_INT1( "Remote RtcpPort", aRemoteAddress.Port() ) + } + } + } + __SUBCONTROLLER_INT1( "CMccRtpManager::SetRemoteAddress, exit with err", err ) + return err; + } +// ----------------------------------------------------------------------------- +// CMccRtpManager::SetIpTOS +// Sets TOS flag, must be called before StartSession +// ----------------------------------------------------------------------------- +// +void CMccRtpManager::SetIpTOS( TInt aIpTOS ) + { + iIpTOS = aIpTOS; + } + +// ----------------------------------------------------------------------------- +// CMccRtpManager::StartSession +// Starts RTP session +// ----------------------------------------------------------------------------- +// +void CMccRtpManager::StartSessionL() + { + __SUBCONTROLLER( "CMccRtpManager::StartSessionL" ) + if ( KNullId != iRtpSessionId ) + { + __SUBCONTROLLER( "CMccRtpManager::StartSessionL, session exists" ) + + RSocket* socketPtr = iRtpApi->GetRtpSocket( iRtpSessionId ); + + if( !socketPtr ) + { + __SUBCONTROLLER( "CMccRtpManager::StartSessionL, no socket!" ) + #ifdef TEST_EUNIT + // The stub for RTP API returns a NULL socket pointer. Just pretend + // everything is fine. + return; + #else + User::Leave( KErrNotReady ); + #endif + } + else + { + User::LeaveIfError( iRtpApi->StartSession( iRtpSessionId ) ); + + __SUBCONTROLLER_INT1( "CMccRtpManager::StartSessionL, iptos:", iIpTOS ) + + User::LeaveIfError( socketPtr->SetOpt( KSoIpTOS, KSolInetIp, iIpTOS ) ); + User::LeaveIfError( socketPtr->SetOpt( KSoUdpReceiveICMPError, KSolInetUdp, 1 ) ); + + if ( !iQosHandler->QoSEnabled() ) + { + // These has to be set before enabling QoS + iQosHandler->SetSubConnectionParams( iConnection, + iSocketServ, + *socketPtr ); + + // If we cannot enable QoS for some reason, we should not + // consider it as a fatal error. If error happens, then + // disable qos. This will clean up some unneeded resources. + // Also this leads to retries when streams are created. + TRAPD( err, iQosHandler->EnableQosL() ); + if ( KErrNone != err ) + { + __SUBCONTROLLER_INT1( "CMccRtpManager::StartSessionL QOS:", err ) + + iQosHandler->DisableQoS(); + } + } + } + } + else + { + User::Leave( KErrNotFound ); + } + + __SUBCONTROLLER( "CMccRtpManager::StartSessionL, exit" ) + } + +// ----------------------------------------------------------------------------- +// CMccRtpManager::Initialize +// Opens RTPApi and starts connection +// ----------------------------------------------------------------------------- +// +void CMccRtpManager::InitializeL( TRequestStatus& aStatus, TInt aIapId ) + { + TInt err = iRtpApi->OpenL( iRtpSdes, NULL, &iSocketServ, &iConnection ); + if ( KErrNone == err ) + { + User::LeaveIfError( iRtpApi->StartConnection( aStatus, aIapId ) ); + } + else + { + User::Leave( err ); + } + } + +// ----------------------------------------------------------------------------- +// CMccRtpManager::CheckStreamExists +// Checks that stream exists +// ----------------------------------------------------------------------------- +// +TBool CMccRtpManager::CheckStreamExists( const TRtpId& aStreamId ) const + { + TInt index = iStreamArray.Find( aStreamId ); + + if( KErrNotFound == index ) + { + return EFalse; + } + else + { + return ETrue; + } + } + +// ----------------------------------------------------------------------------- +// CMccRtpManager::IsOpen +// Checks that RTPApi is opened +// ----------------------------------------------------------------------------- +// +TBool CMccRtpManager::IsOpen() const + { + if ( iRtpApi->GetRtpSocket( iRtpSessionId ) ) + { + return ETrue; + } + else + { + return EFalse; + } + } + +// ----------------------------------------------------------------------------- +// CMccRtpManager::RemoveStreamFromArray +// Removes RTP stream from stream array +// ----------------------------------------------------------------------------- +// +void CMccRtpManager::RemoveStreamFromArray( const TRtpId& aStreamId ) + { + const TInt index( iStreamArray.Find( aStreamId ) ); + if( KErrNotFound != index ) + { + iStreamArray.Remove( index ); + } + } + +// ----------------------------------------------------------------------------- +// CMccRtpManager::SessionId +// Returns the Session ID for this object +// ----------------------------------------------------------------------------- +// +TRtpId CMccRtpManager::SessionId() const + { + return iRtpSessionId; + } + +// ----------------------------------------------------------------------------- +// CMccRtpManager::ErrorNotify +// Error callback. +// ----------------------------------------------------------------------------- +// +void CMccRtpManager::ErrorNotify( TInt aErrCode ) + { + if ( KErrNone != aErrCode ) + { + __SUBCONTROLLER_INT1( "CMccRtpManager::ErrorNotify, error", aErrCode ) + + // Report all errors coming from here as rtp category stream errors + // In HW when remote end drops from network, this function will be + // called with KErrHostUnreach (-191) and in some cases this will return + // as KErrGeneral with DTMF's. KErrCouldNotConnect error is received in + // ICMP port unreachable situation. In these cases, handle just the + // KErrHostUnreach and KErrCouldNotConnect. + if ( KErrHostUnreach == aErrCode || KErrCouldNotConnect == aErrCode ) + { + TMccEvent event; + event.iErrorCode = KErrHostUnreach; + event.iEventCategory = KMccEventCategoryRtp; + event.iEventType = KMccStreamError; + + // Use whatever internal uid + TMccInternalEvent internalEvent( KMccRtpSourceUid, + EMccInternalEventNone, + event ); + + iEventHandler.SendEventToClient( internalEvent ); + } + } + } + +// ----------------------------------------------------------------------------- +// CMccRtpManager::CreateTransmitStreamL +// Creates a new transmit stream based on given parameters +// ----------------------------------------------------------------------------- +// +TUint32 CMccRtpManager::CreateTransmitStreamL( MDataSink& aSink, + const TMccCodecInfo& aCodecInfo ) + { + TUint32 streamId( 0 ); + + if( aCodecInfo.iPayloadType < KMccPayloadTypeMax ) + { + CMccRtpDataSink& dSink = static_cast( aSink ); + TMccRtpSessionParams sessParams( iRtpApi, + iRtpSessionId, + iRtcpEnabled, + iRtpKeepaliveMechanism, + iSecSession ); + + dSink.SetSessionParamsL( sessParams ); + + TMccCodecInfoBuffer infoBuffer( aCodecInfo ); + dSink.ConfigureL( infoBuffer ); + + UpdateL( &aCodecInfo ); + } + else + { + User::Leave( KErrArgument ); + } + return streamId; + } + +// ----------------------------------------------------------------------------- +// CMccRtpManager::CreateReceiveStreamL +// Creates a new receive stream based on given parameters +// ----------------------------------------------------------------------------- +// +TUint32 CMccRtpManager::CreateReceiveStreamL( MDataSource& aSource, + const TMccCodecInfo& aCodecInfo ) + { + TUint32 streamId( 0 ); + + if( aCodecInfo.iPayloadType < KMccPayloadTypeMax ) + { + CMccRtpDataSource& dSource = static_cast( aSource ); + TMccRtpSessionParams sessParams( iRtpApi, + iRtpSessionId, + iRtcpEnabled, + iRtpKeepaliveMechanism, + iSecSession ); + + dSource.SetSessionParamsL( sessParams ); + + TMccCodecInfoBuffer infoBuffer( aCodecInfo ); + dSource.ConfigureL( infoBuffer ); + + UpdateL( &aCodecInfo ); + } + else + { + User::Leave( KErrArgument ); + } + + return streamId; + } + +// ----------------------------------------------------------------------------- +// CMccRtpManager::SetRTCPSendReceive +// Enables/disables automatic transmission and receiving of RTCP packets +// in a session. +// ----------------------------------------------------------------------------- +// +TInt CMccRtpManager::SetRTCPSendReceive( TBool aEnableRtcp ) + { + __SUBCONTROLLER( "CMccRtpManager::SetRTCPSendReceive" ) + + // Check that session exists + TInt err( KErrNotFound ); + if ( iRtpSessionId != KNullId ) + { + __SUBCONTROLLER_INT1( "CMccRtpManager::SetRTCPSendReceive, enable:", aEnableRtcp ) + + iRtcpEnabled = aEnableRtcp; + + err = iRtcpReceiver->HandleReceiving( iRtpSessionId, iRtcpEnabled ); + if ( !err ) + { + __SUBCONTROLLER( "CMccRtpManager::SetRTCPSendReceive, calling rtp api" ) + err = iRtpApi->SuspendRtcpSending( iRtpSessionId, aEnableRtcp ); + } + } + return err; + } + +// ----------------------------------------------------------------------------- +// CMccRtpManager::SetLinkId +// ----------------------------------------------------------------------------- +// +void CMccRtpManager::SetLinkId( TUint32 aLinkId ) + { + iLinkId = aLinkId; + } + +// ----------------------------------------------------------------------------- +// CMccRtpManager::UpdateL +// Creates dummy receive stream if rtp session does not have any receive +// stream (RTP source) or removes the dummy receive stream if RTP source +// exists. +// ----------------------------------------------------------------------------- +// +void CMccRtpManager::UpdateL( const TMccCodecInfo* aCodecInfo ) + { + __SUBCONTROLLER( "CMccRtpManager::UpdateL" ) + + MDataSource* source = 0; + MDataSink* sink = 0; + TInt err = + iMccResources.FindResource( iLinkId, 0, KMccRtpSourceUid, &source, &sink ); + + if ( !err && source ) + { + if ( iDummyRcvStreamId != KNullId ) + { + __SUBCONTROLLER( "CMccRtpManager::UpdateL, dummy rcv stream not needed" ) + + iRtpApi->CloseStream( iDummyRcvStreamId ); + iDummyRcvStreamId = KNullId; + } + } + else + { + if ( iDummyRcvStreamId == KNullId && aCodecInfo ) + { + __SUBCONTROLLER( "CMccRtpManager::UpdateL, dummy rcv stream needed" ) + + TRcvStreamParams rcvParams; + rcvParams.iPayloadType = aCodecInfo->iPayloadType; + iDummyRcvStreamId = iRtpApi->CreateReceiveStreamL( iRtpSessionId, rcvParams ); + if ( KNullId == iDummyRcvStreamId ) + { + __SUBCONTROLLER( "CMccRtpDataSource::UpdateL, could not create dummy rcv stream" ) + + User::Leave( KErrCouldNotConnect ); + } + } + } + + __SUBCONTROLLER( "CMccRtpManager::UpdateL, exit" ) + } + +// ----------------------------------------------------------------------------- +// CMccRtpManager::GetLocalIpAddressesL +// ----------------------------------------------------------------------------- +// +void CMccRtpManager::GetLocalIpAddressesL( TMccCreateLink& aClientData ) + { + __SUBCONTROLLER( "CMccRtpManager::GetLocalIpAddressesL" ) + + __ASSERT_ALWAYS( KNullId != iRtpSessionId && iRtpApi, User::Leave( KErrNotReady ) ); + + RSocket* rtpSocket( iRtpApi->GetRtpSocket( iRtpSessionId ) ); + RSocket* rtcpSocket( iRtpApi->GetRtcpSocket( iRtpSessionId ) ); + TInetAddr localAddr( iRtpApi->GetLocalIPAddressL() ); + + if ( rtpSocket ) + { + if ( KAfInet6 == localAddr.Family() ) + { + aClientData.iLocalAddress.SetAddress( localAddr.Ip6Address() ); + } + else + { + aClientData.iLocalAddress.SetAddress( localAddr.Address() ); + } + + aClientData.iLocalAddress.SetPort( rtpSocket->LocalPort() ); + } + else + { + User::Leave( KErrGeneral ); + } + + if ( iRtcpReceiver && rtcpSocket ) + { + if ( KAfInet6 == localAddr.Family() ) + { + aClientData.iLocalRtcpAddress.SetAddress( localAddr.Ip6Address() ); + } + else + { + aClientData.iLocalRtcpAddress.SetAddress( localAddr.Address() ); + } + + aClientData.iLocalRtcpAddress.SetPort( rtcpSocket->LocalPort() ); + } + + __SUBCONTROLLER( "CMccRtpManager::GetLocalIpAddressesL, exit" ) + } + +// ----------------------------------------------------------------------------- +// CMccRtpManager::SetCNameL +// ----------------------------------------------------------------------------- +// +void CMccRtpManager::SetCNameL( const TDesC8& aCName ) + { + HBufC8* cname = aCName.AllocLC(); + delete iCName; + iCName = cname; + CleanupStack::Pop( cname ); + + iRtpSdes.iCName.Set( *iCName ); + + iRtpApi->SetLocalSdes( iRtpSdes ); + } + +// ----------------------------------------------------------------------------- +// CMccRtpManager::MccSessionId +// ----------------------------------------------------------------------------- +// +TUint32 CMccRtpManager::MccSessionId() const + { + return iMccSessionId; + } + +// ----------------------------------------------------------------------------- +// CMccRtpManager::QoSParamEvent() +// From MMccQosEventObserver +// ----------------------------------------------------------------------------- +// +void CMccRtpManager::QoSParamEvent( TInt aError, TUint32 /*aEvent*/ ) + { + __SUBCONTROLLER_INT1( "CMccRtpManager::QoSParamEvent aError:", aError ) + + aError = aError; + } + +// ----------------------------------------------------------------------------- +// CMccRtpManager::QoSConnEvent() +// From MMccQosEventObserver +// ----------------------------------------------------------------------------- +// +void CMccRtpManager::QoSConnEvent( TInt aError, TUint32 /*aEvent*/ ) + { + __SUBCONTROLLER_INT1( "CMccRtpManager::QoSConnEvent aError:", aError ) + + aError = aError; + } +