diff -r 000000000000 -r 1bce908db942 multimediacommsengine/mmcesrv/mmcemediamanager/src/mcesdpsession.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/multimediacommsengine/mmcesrv/mmcemediamanager/src/mcesdpsession.cpp Tue Feb 02 01:04:58 2010 +0200 @@ -0,0 +1,1724 @@ +/* +* Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: +* +*/ + + + + +// INCLUDE FILES + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mcemediadefs.h" +#include "mcesdpsession.h" +#include "mcecomsession.h" +#include "mcecommediastream.h" +#include "mcemediastream.h" +#include "mcesdpcodec.h" +#include "mcemediamanager.h" +#include "mcemediadefs.h" +#include "mcesrvlogs.h" +#include "mcemmlogs.h" +#include "mcepreconditions.h" +#include "mcemediaobserver.h" +#include "mcemediastate.h" + + +_LIT8(KTBCP, "TBCP"); + +// ================= MEMBER FUNCTIONS ========================================== + +// ----------------------------------------------------------------------------- +// CMceSdpSession::NewL +// ----------------------------------------------------------------------------- +// +CMceSdpSession* CMceSdpSession::NewL( + CMceComSession& aSession, + CMceMediaManager& aManager ) + { + CMceSdpSession* self = NewLC( aSession, aManager ); + CleanupStack::Pop( self ); + return self; + } + +// ----------------------------------------------------------------------------- +// CMceSdpSession::NewLC +// ----------------------------------------------------------------------------- + CMceSdpSession* CMceSdpSession::NewLC( + CMceComSession& aSession, + CMceMediaManager& aManager ) + { + CMceSdpSession* self = new ( ELeave ) CMceSdpSession( aSession, aManager ); + CleanupStack::PushL( self ); + self->ConstructL(); + return self; + } + +// ----------------------------------------------------------------------------- +// CMceSdpSession::CMceSdpSession +// ----------------------------------------------------------------------------- +// +CMceSdpSession::CMceSdpSession( + CMceComSession& aSession, + CMceMediaManager& aManager ) + : iManager( aManager ), + iSessionId( 0 ), + iSessionVersion( 0 ), + iSession( &aSession ), + iStringTable( NULL ), + iOOldSchool( 0 ), + iIOldSchool( 0 ), + iOOldSchoolProceeding( 0 ), + iOOldSchoolCompleted( 0 ), + iIsMaster( ETrue ), + iOldLocalMediaPort( 0 ) + { + iSessionId = GetRandomNumber(); + iSessionVersion = GetRandomNumber(); + iIsSignallingRequired = KMceNoSignalling; + } + +// ----------------------------------------------------------------------------- +// CMceSdpSession::ConstructL +// ----------------------------------------------------------------------------- +void CMceSdpSession::ConstructL() + { + SetUserNameL(KMceSdpDefaultUserName); + SetSessionNameL(KMceSdpDefaultSessionName); + + iStringPool = SdpCodecStringPool::StringPoolL(); + iStringTable = &SdpCodecStringPool::StringTableL(); + } + +// ----------------------------------------------------------------------------- +// CMceSdpSession::~CMceSdpSession +// ----------------------------------------------------------------------------- +// +CMceSdpSession::~CMceSdpSession() + { + delete iInitialSession; + delete iSessionName; + delete iUserName; + delete iRemoteOrigin; + iSdpRemoteMediaFields.ResetAndDestroy(); + if ( MediaSession() ) + { + MediaSession()->DetachSDPSession(); + } + if ( Backup() ) + { + Backup()->DetachSDPSession(); + } + } + +// ----------------------------------------------------------------------------- +// CMceSdpSession::Manager +// ----------------------------------------------------------------------------- +// +CMceMediaManager& CMceSdpSession::Manager() const + { + return iManager; + } + +// ----------------------------------------------------------------------------- +// CMceSdpSession::SignallingRequired +// ----------------------------------------------------------------------------- +// +TInt& CMceSdpSession::SignallingRequired() + { + return iIsSignallingRequired; + } + +// ----------------------------------------------------------------------------- +// CMceSdpSession::CreateOfferL +// ----------------------------------------------------------------------------- +// +CSdpDocument* CMceSdpSession::CreateOfferL( + CMceComSession& aSession, + CMceSdpSession::TOfferType aType ) + { + MCEMM_DEBUG("CMceSdpSession::CreateOfferL(), Entry ") + + CSdpDocument* sdpDocument = NULL; + + if ( aType == CMceSdpSession::ERefresh ) + { + User::LeaveIfNull( iSdpDocument ); + EncodeSessionParamsL( aSession, *iSdpDocument, aType ); + if(iOldLocalMediaPort != iSdpDocument->MediaFields()[0]->Port()) + { + iSdpDocument->MediaFields()[0]->SetPortL( iOldLocalMediaPort ); + } + return iSdpDocument; + } + + if ( aType == CMceSdpSession::EFirst ) + { + sdpDocument = CSdpDocument::NewLC(); + } + else + { + sdpDocument = iSdpDocument; + CleanSessionParams( *iSdpDocument ); + } + + EncodeSessionParamsL( aSession, *sdpDocument, aType ); + + EncodeClientAttributesL( aSession, *sdpDocument ); + + //create offer based on receive, receive only or send stream + RPointerArray & streams = aSession.Streams(); + RPointerArray< CSdpMediaField >& mediaLines = sdpDocument->MediaFields(); + CSdpMediaField* mediaLine = NULL; + CMceSdpCodec* sdpCodec = NULL; + CMceComMediaStream* mediastream = NULL; + + if ( aSession.iPullModeUpdate && aType == CMceSdpSession::EUpdate ) + { + // matching the streams to media lines in Pull mode update case + MatchingStreamsToMLinesL( *sdpDocument, aSession ); + } + + for ( TInt index = 0; index < streams.Count(); index++ ) + { + mediastream = streams[ index ]; + TBool add = MediaLineLC( mediaLine, sdpCodec, mediastream, + mediaLines, streams ); + if ( mediaLine ) + { + + if (!add) + { + mediaLine->SetPortL( mediastream->iLocalMediaPort ); + } + mediastream = mediastream->OfferStream();//downlink + sdpCodec->PrepareForEncodeL( *mediastream, *mediaLine ); + sdpCodec->EncodeMediaOfferL( *mediastream, *mediaLine, *sdpDocument ); + if ( add ) + { + mediaLines.AppendL( mediaLine ); + CleanupStack::Pop( mediaLine ); + mediastream->SdpIndex() = mediaLines.Count() - 1; + } + + } + } + + User::LeaveIfError( sdpDocument->IsValid() ); + + if ( aType == CMceSdpSession::EFirst ) + { + CleanupStack::Pop( sdpDocument ); + } + + iOldLocalMediaPort = sdpDocument->MediaFields()[0]->Port(); + + MCEMM_DEBUG("CMceSdpSession::CreateOfferL(), Exit ") + + return sdpDocument; + } + +// ----------------------------------------------------------------------------- +// CMceSdpSession::MatchingStreamsAndMLinesL +// ----------------------------------------------------------------------------- +// +void CMceSdpSession::MatchingStreamsToMLinesL( + CSdpDocument& aSdpDocument, + CMceComSession& aSession ) + { + MCEMM_DEBUG("CMceSdpSession::MatchingStreamsToMLinesL(),entry ") + + //create offer based on receive, receive only or send stream + RPointerArray & streams = aSession.Streams(); + RPointerArray< CSdpMediaField >& mediaLines = aSdpDocument.MediaFields(); + + // set SDPindex for stream if related meida line is found + for ( TInt index = 0; index < streams.Count(); index++ ) + { + CMceComMediaStream* mediastream = streams[ index ]; + CMceSdpCodec* sdpCodecStream = NULL; + + sdpCodecStream = Manager().SdpCodec( *mediastream ); + if ( sdpCodecStream ) + { + TInt mediaIndex = 0; + while( mediaIndex < mediaLines.Count() ) + { + CSdpMediaField* mediaLine = mediaLines[ mediaIndex ]; + CMceSdpCodec* sdpCodecMediaLine = NULL; + sdpCodecMediaLine = Manager().SdpCodec( *mediaLine ); + if ( sdpCodecMediaLine && sdpCodecMediaLine->Media() == sdpCodecStream->Media() ) + { + mediastream->SdpIndex() = mediaIndex; + } + mediaIndex++; + } + } + MCEMM_DEBUG_DVALUE( "CMceSdpSession::MatchingStreamsToMLinesL(), stream index:", index ) + MCEMM_DEBUG_DVALUE( "CMceSdpSession::MatchingStreamsToMLinesL(), stream SdpIndex:", + mediastream->SdpIndex() ) + } + + // set port to 0 if there are unused media lines + for ( TInt index = 0; index < mediaLines.Count(); index++ ) + { + // set old session media lines port to 0 + CSdpMediaField* mediaLine = mediaLines[ index ]; + + TBool indexFoundFromStream = EFalse; + TInt streamIndex = 0; + while( !indexFoundFromStream && streamIndex < streams.Count() ) + { + CMceComMediaStream* mediastream = streams[ streamIndex ]; + if ( index == mediastream->SdpIndex() ) + { + indexFoundFromStream = ETrue; + } + streamIndex++; + } + if ( !indexFoundFromStream ) + { + MCEMM_DEBUG_DVALUE( "CMceSdpSession::MatchingStreamsToMLinesL(), \ + set media line to 0, index:", index ) + mediaLine->SetPortL( 0 ); + } + } + + MCEMM_DEBUG("CMceSdpSession::MatchingStreamsToMLinesL(),exit ") + } + +// ----------------------------------------------------------------------------- +// CMceSdpSession::DecodeAnswerL +// ----------------------------------------------------------------------------- +// +TInt CMceSdpSession::DecodeAnswerL( + CSdpDocument& aSdpDocument, + CMceComSession& aSession ) + { + MCEMM_DEBUG("CMceSdpSession::DecodeAnswerL(), Entry ") + + iSdpDocument = &aSdpDocument; + RPointerArray< CSdpMediaField >& mediaLines = iSdpDocument->MediaFields(); + if ( mediaLines.Count() == 0 ) + { + User::Leave( KErrArgument ); + } + + // store the remote o= field + StoreRemoteOriginL(); + // store the remote a= field + StoreRemoteMediaFieldsL(); + + TInt err = SetRemoteIpAddressL( aSession, aSdpDocument ); + if ( err != KErrNone ) + { + MCEMM_DEBUG("ERROR: Incompatible network address") + User::Leave( KErrArgument ); + } + + // handle media lines + RPointerArray & streams = aSession.Streams(); + + CSdpMediaField* mediaLine = NULL; + CMceSdpCodec* sdpCodec = NULL; + CMceComMediaStream* mediastream = NULL; + TInt index = 0; + + // Go through the answer's media lines. If there is a line for which there + // is no stream (remote has put wrong port to answer), set port to zero. + // Do this before the second for-loop, as DecodeMediaAnswerL may leave with + // KMceErrOldSchool, starting old school hold. In that case any further + // media lines would not be processed and if they had wrong port (non-zero + // port but no media stream), we'd use that in our next offer. + if ( !aSession.iPullModeUpdate ) + { + for ( index = 0; index < mediaLines.Count(); index++ ) + { + mediaLine = mediaLines[ index ]; + if ( Manager().SdpCodec( *mediaLine ) && + !MediaSlotInUse( index, streams ) ) + { + mediaLine->SetPortL( 0 ); + } + } + } + + for ( index = 0; index < mediaLines.Count(); index++ ) + { + mediaLine = mediaLines[ index ]; + sdpCodec = Manager().SdpCodec( *mediaLine ); + + if ( sdpCodec ) + { + if ( !aSession.iPullModeUpdate ) + { + TUint remotePort = mediaLine->Port(); + aSession.iRemoteIpAddress.SetPort( remotePort ); + + mediastream = MediaSlotInUse( index, streams ); + // Check for local Support of media and only decode media + // which we support or in use + if ( mediastream ) + { + mediastream = mediastream->AnswerStream();//uplink + __ASSERT_ALWAYS( mediastream , User::Leave( KErrArgument ) ); + + mediastream->SetRemoteMediaPort( remotePort ); + + if ( remotePort ) + { + TInt warnings = KErrNone; + sdpCodec->PrepareForDecodeL( *mediaLine, mediastream ); + warnings = sdpCodec->DecodeMediaAnswerL( *mediaLine, + *mediastream, + aSdpDocument ); + if ( warnings >= KMceSipBadRequest) + { + return warnings; + } + mediastream->DecodedL( KMceRoleOfferer ); + } + else //rejected + { + mediastream->SetDirection( SdpCodecStringConstants::EAttributeInactive ); + mediastream->SdpIndex() = KErrNotFound; + } + } + } + else + { + DecodePullModeUpdateMediaLineL( + aSdpDocument, aSession, *mediaLine, index, *sdpCodec ); + } + } + else + { + MCEMM_DEBUG_SVALUE("No SDP codec. m-line", mediaLine->Media().DesC() ) + } + } + + //check that all answers to offers were received + User::LeaveIfError( MediaSlotInUse( index, streams ) ? KErrArgument : KErrNone ); + + // set the o= field with the local information + EncodeSessionParamsL( aSession, *iSdpDocument ); + + // store session level attributes + DecodeClientAttributesL( aSdpDocument, aSession ); + + MCEMM_DEBUG("CMceSdpSession::DecodeAnswerL(), Exit ") + + return KErrNone; + } + +// ----------------------------------------------------------------------------- +// CMceSdpSession::DecodePullModeUpdateMediaLineL +// ----------------------------------------------------------------------------- +// +void CMceSdpSession::DecodePullModeUpdateMediaLineL( + CSdpDocument& aSdpDocument, + CMceComSession& aSession, + CSdpMediaField& aMediaLine, + TInt aIndex, + CMceSdpCodec& aSdpCodec ) + { + MCEMM_DEBUG("CMceSdpSession::DecodePullModeUpdateMediaLineL(), Entry ") + + RPointerArray & streams = aSession.Streams(); + CMceComMediaStream* mediastream = NULL; + + TUint remotePort = aMediaLine.Port(); + + aSession.iRemoteIpAddress.SetPort( remotePort ); + + // this media line might be from previous session, and it's + // port is 0, if so mediastream can't be found + mediastream = MediaSlotInUse( aIndex, streams ); + + MCEMM_DEBUG_DVALUE( "CMceSdpSession::DecodePullModeUpdateMediaLineL, remotePort:", + remotePort ) + if ( mediastream ) + { + MCEMM_DEBUG("CMceSdpSession::DecodePullModeUpdateMediaLineL(), stream found ") + + mediastream = mediastream->AnswerStream();//uplink + __ASSERT_ALWAYS( mediastream , User::Leave( KErrArgument ) ); + mediastream->SetRemoteMediaPort( remotePort ); + if ( remotePort ) + { + aSdpCodec.PrepareForDecodeL( aMediaLine, mediastream ); + aSdpCodec.DecodeMediaAnswerL( aMediaLine, *mediastream, aSdpDocument ); + mediastream->DecodedL( KMceRoleOfferer ); + } + else + { + mediastream->SetDirection( SdpCodecStringConstants::EAttributeInactive ); + mediastream->SdpIndex() = KErrNotFound; + } + } + + // if streams not found and port in meida line is not 0 + // leave with KErrNotFound + User::LeaveIfError( (!mediastream && remotePort) ? KErrNotFound : KErrNone ); + + MCEMM_DEBUG("CMceSdpSession::DecodePullModeUpdateMediaLineL(), Exit ") + } + +// ----------------------------------------------------------------------------- +// CMceSdpSession::DecodeOfferL +// ----------------------------------------------------------------------------- +// +TInt CMceSdpSession::DecodeOfferL( + CSdpDocument& aSdpDocument, + CMceComSession& aSession ) + { + MCEMM_DEBUG("CMceSdpSession::DecodeOfferL(), Entry ") + TInt result = KErrNone; + + iSdpDocument = &aSdpDocument; + + RPointerArray & mediaLines = iSdpDocument->MediaFields(); + if ( mediaLines.Count() == 0 ) + { + MCEMM_DEBUG("CMceSdpSession::DecodeOfferL(), ERROR: No media lines") + MCEMM_DEBUG("CMceSdpSession::DecodeOfferL(), Exit ") + return KMceSipWarnIncompatibleMediaFormat; + } + + // store the remote o= field + StoreRemoteOriginL(); + // store the remote a= field + StoreRemoteMediaFieldsL(); + //set remote ip address + result = SetRemoteIpAddressL( aSession, aSdpDocument ); + + if ( result != KErrNone ) + { + MCEMM_DEBUG("CMceSdpSession::DecodeOfferL(), ERROR: Incompatible network address") + MCEMM_DEBUG("CMceSdpSession::DecodeOfferL(), Exit ") + return result; + } + + DecodeConnectionFieldL( *iSdpDocument, aSession ); + + // handle media lines + RPointerArray& streams = aSession.Streams(); + CSdpMediaField* mediaLine = NULL; + CMceSdpCodec* sdpCodec = NULL; + CMceComMediaStream* mediastream = NULL; + + TInt streamCount( 0 ); + for ( TInt i = 0; i < streams.Count(); i++ ) + { + if ( streams[ i ]->iStreamType != CMceComMediaStream::ELocalStream ) + { + streamCount++; + } + } + + if ( streamCount > mediaLines.Count() ) + { + return KMceSipNotAcceptableHere; + } + + TInt index = 0; + + while( index < mediaLines.Count() ) + { + mediaLine = mediaLines[ index ]; + TUint remotePort = mediaLine->Port(); + if ( remotePort ) + { + sdpCodec = Manager().SdpCodec( *mediaLine ); + if ( sdpCodec ) + { + TInt warning = KErrNone; + + aSession.iRemoteIpAddress.SetPort( remotePort ); + + mediastream = MediaSlotInUse( index, streams ); + if ( !mediastream ) + { + sdpCodec->PrepareForDecodeL( *mediaLine, mediastream ); + warning = sdpCodec->DecodeMediaOfferL( *mediaLine, mediastream, + aSession, aSdpDocument ); + } + else + { + //update + mediastream = mediastream->AnswerStream();//uplink + sdpCodec->PrepareForDecodeL( *mediaLine, mediastream ); + warning = sdpCodec->DecodeMediaUpdateL( *mediaLine, *mediastream, + aSdpDocument ); + } + if ( warning >= KMceSipBadRequest ) + { + return warning; + } + + if ( warning != KErrNone ) + { + //media will be rejected when answer is created + if ( mediastream ) + { + TInt streamIndex = aSession.Streams().Find( &(*mediastream)() ); + __ASSERT_ALWAYS( streamIndex >= 0, User::Leave( KErrArgument ) ); + MCEMM_DEBUG_DVALUE("removing stream", streamIndex ) + aSession.Streams().Remove( streamIndex ); + delete mediastream; + } + } + else + { + __ASSERT_ALWAYS( mediastream, User::Leave( KErrArgument ) ); + mediastream->DecodedL( KMceRoleAnswerer ); + mediastream->SdpIndex() = index; + } + } + else + { + MCEMM_DEBUG_SVALUE("No SDP codec. m-line", mediaLine->Media().DesC() ) + } + } + index++; + } + + + if( streams.Count() > 0 ) + { + // at least one media line successfully decoded and corresponding + // server streams created or inactive media line received + MCEMM_DEBUG("Incoming OFFER successfully decoded") + } + else + { + MCEMM_DEBUG("ERROR: Negotiation failed") + result = KMceSipWarnMediaTypeNotAvailable; + } + + if ( result == KErrNone ) + { + // store session level attributes + DecodeClientAttributesL( aSdpDocument, aSession ); + } + + MCEMM_DEBUG_DVALUE("CMceSdpSession::DecodeOfferL(), Exit ", result ) + return result; + } + +// ----------------------------------------------------------------------------- +// CMceSdpSession::CreateAnswerL +// ----------------------------------------------------------------------------- +// +CSdpDocument& CMceSdpSession::CreateAnswerL( + CMceComSession& aSession, + TBool aInvalid ) + { + MCEMM_DEBUG("CMceSdpSession::CreateAnswerL(), Entry ") + + TOfferType type = !Backup() ? EFirst : EUpdate; + + CleanSessionParams( *iSdpDocument ); + + EncodeSessionParamsL( aSession, *iSdpDocument, type ); + + EncodeClientAttributesL( aSession, *iSdpDocument ); + + RPointerArray & mediaLines = iSdpDocument->MediaFields(); + + __ASSERT_ALWAYS( mediaLines.Count() > 0, User::Leave( KErrArgument ) ); + + RPointerArray& streams = aSession.Streams(); + CSdpMediaField* mediaLine = NULL; + CMceSdpCodec* sdpCodec = NULL; + CMceComMediaStream* mediastream = NULL; + TInt index = 0; + + if ( !aInvalid ) + { + + for ( index = 0; index < streams.Count(); index++ ) + { + mediastream = streams[ index ]; + TBool add = MediaLineLC( mediaLine, sdpCodec, mediastream, + mediaLines, streams ); + + User::LeaveIfError( add ? KErrNotFound : KErrNone ); + + if ( mediaLine ) + { + mediastream = mediastream->OfferStream();//downlink + sdpCodec->PrepareForEncodeL( *mediastream, *mediaLine ); + PrepareForAnswerEncodeL( *mediaLine ); + sdpCodec->EncodeMediaAnswerL( *mediastream, *mediaLine, *iSdpDocument ); + } + } + //reject removed streams + //ignore the Supported File Stream will be handled by other plugin + + for ( index = 0; index < mediaLines.Count(); index++ ) + { + mediaLine = mediaLines[ index ]; + sdpCodec = Manager().SdpCodec( *mediaLine ); + + if ( sdpCodec || mediaLine->FormatList() != KTBCP ) + { + if ( !MediaSlotInUse( index, streams ) ) + { + MCEMM_DEBUG_SVALUE("Rejecting media line", mediaLine->Media().DesC() ) + mediaLines[ index ]->RejectMedia(); + } + } + } + MCEMM_DEBUG("Negotiation successful! Answer created ") + } + else + { + MCEMM_DEBUG("Negotiation failed! Reject all media lines ") + // negotiation failed, reject all media lines in the offer + for (index = 0; index < mediaLines.Count(); index++) + { + mediaLines[ index ]->RejectMedia(); + } + } + + User::LeaveIfError( iSdpDocument->IsValid() ); + + iOldLocalMediaPort = iSdpDocument->MediaFields()[0]->Port(); + + MCEMM_DEBUG("CMceSdpSession::CreateAnswerL(), Exit ") + + return *iSdpDocument; + } + +// ----------------------------------------------------------------------------- +// CMceSdpSession::PrepareForAnswerEncodeL +// ----------------------------------------------------------------------------- +// +void CMceSdpSession::PrepareForAnswerEncodeL( CSdpMediaField& aMediaLine ) + { + TLex8 formats( aMediaLine.FormatList() ); + while( !formats.Eos() ) + { + TPtrC8 format = formats.NextToken(); + aMediaLine.RemoveFormatL( format ); + } + } + +// ----------------------------------------------------------------------------- +// CMceSdpSession::CreateMediaLineLC +// ----------------------------------------------------------------------------- +// +CSdpMediaField* CMceSdpSession::CreateMediaLineLC( + CMceComMediaStream& aStream ) const + { + RStringF protocol = SDP_STRING( SdpCodecStringConstants::EProtocolRtpAvp ); + + CSdpMediaField* medialine = + CSdpMediaField::NewLC( Manager().SdpCodec( aStream )->Media(), + aStream.iLocalMediaPort, + protocol, + KMceSdpNullFormatList ); + return medialine; + } + +// ----------------------------------------------------------------------------- +// CMceSdpSession::MediaLineLC +// ----------------------------------------------------------------------------- +// +TBool CMceSdpSession::MediaLineLC( + CSdpMediaField*& aMediaLine, + CMceSdpCodec*& sdpCodec, + CMceComMediaStream* aStream, + RPointerArray& aMediaLines, + RPointerArray& aStreams ) + { + + //filter out local streams + if ( !aStream || + !Manager().SdpCodec( *aStream ) ) + { + aMediaLine = NULL; + sdpCodec = NULL; + return EFalse; + } + + sdpCodec = Manager().SdpCodec( *aStream ); + + TInt mediaIndex = aStream->SdpIndex(); + + if ( mediaIndex == KErrNotFound ) + { + TInt index = 0; + TBool inUse = ETrue; + while( inUse && index < aMediaLines.Count() ) + { + CSdpMediaField* mediaLine = aMediaLines[ index ]; + if ( Manager().SdpCodec( *mediaLine ) ) + { + inUse = MCE_NOT_NULL_PTR( MediaSlotInUse( index, aStreams ) ); + } + mediaIndex = !inUse ? index : mediaIndex; + index++; + } + } + + + if ( mediaIndex == KErrNotFound )//all in use + { + aMediaLine = CreateMediaLineLC( *aStream ); + } + else + { + __ASSERT_ALWAYS( aMediaLines.Count() > mediaIndex , User::Leave( KErrArgument ) ); + aMediaLine = aMediaLines[ mediaIndex ]; + } + + __ASSERT_ALWAYS( Manager().SdpCodec( *aMediaLine ), User::Leave( KErrArgument ) ); + + return mediaIndex == KErrNotFound; + } + +// ----------------------------------------------------------------------------- +// CMceSdpSession::MediaSlotInUse +// ----------------------------------------------------------------------------- +// +CMceComMediaStream* CMceSdpSession::MediaSlotInUse( + TInt aMediaLine, + RPointerArray& aStreams ) + { + CMceComMediaStream* stream = NULL; + TInt index = 0; + while( !stream && index < aStreams.Count() ) + { + stream = aStreams[ index++ ]; + stream = Manager().SdpCodec( *stream ) && + stream->SdpIndex() == aMediaLine ? stream : NULL; + } + + return stream; + } + +// ----------------------------------------------------------------------------- +// CMceSdpSession::CleanSessionParams +// ----------------------------------------------------------------------------- +// +void CMceSdpSession::CleanSessionParams( CSdpDocument& aDocument ) const + { + MCEMM_DEBUG("CMceSdpSession::CleanSessionParams()") + aDocument.AttributeFields().ResetAndDestroy(); + aDocument.BandwidthFields().ResetAndDestroy(); + } + +// ----------------------------------------------------------------------------- +// CMceSdpSession::EncodeSessionParamsL +// ----------------------------------------------------------------------------- +// +void CMceSdpSession::EncodeSessionParamsL( + CMceComSession& aSession, + CSdpDocument& aDocument, + TOfferType aType ) + { + MCEMM_DEBUG("CMceSdpSession::EncodeSessionParamsL(), Entry ") + // Set session name: s= + aDocument.SetSessionNameL( *iSessionName ); + + if( aType == EFirst ) + { + // update the name in o= field only when creating intial offer/answer + HBufC8* originator = NULL; + if ( aSession.iType == CMceComSession::EOutSession ) + { + originator = aSession.iOriginator; + } + else + { + originator = aSession.iRecipient; + } + + if (originator && originator->Length() > 0) + { + CSIPToHeader* to = CSIPToHeader::DecodeL( *originator); + CleanupStack::PushL(to); + const TDesC8& username = to->SIPAddress().Uri8().Uri().Extract( EUriUserinfo ); + if ( username.Length() ) + { + SetUserNameL( username ); + } + else + { + const TDesC8& uripath = to->SIPAddress().Uri8().Uri().Extract( EUriPath ); + const TDesC8& uri = to->SIPAddress().Uri8().Uri().UriDes(); + + if ( uripath.Length() ) + { + SetUserNameL( uripath ); + } + else + { + SetUserNameL( uri ); + } + } + + CleanupStack::PopAndDestroy(to); + } + } + else if( aType == EUpdate ) + { + iSessionVersion++; + } + + CSdpOriginField* originField = + CSdpOriginField::NewL( UserName(), + iSessionId, + iSessionVersion, + aSession.iLocalIpAddress ); + + aDocument.SetOriginField( originField ); + + EncodeConnectionFieldL( aSession, aDocument ); + + MCEMM_DEBUG("CMceSdpSession::EncodeSessionParamsL(), Exit ") + } + +// ----------------------------------------------------------------------------- +// CMceSdpSession::SetRemoteIpAddressL +// ----------------------------------------------------------------------------- +// +TMceSipWarningCode CMceSdpSession::SetRemoteIpAddressL( + CMceComSession& aSession, + CSdpDocument& aSdpDocument ) + { + TMceSipWarningCode result = KErrNone; + + RPointerArray< CSdpMediaField >& mediaLines = aSdpDocument.MediaFields(); + + // get the remote ip address + CSdpConnectionField* connfield = aSdpDocument.ConnectionField(); + const TInetAddr* inetAddr = NULL; + + if( connfield ) + { + inetAddr = connfield->InetAddress(); + if( inetAddr ) + { + const TInetAddr inetAddress = *(connfield->InetAddress() ); + // if present, if not then should be media level + MCE_SET_REMOTE_IP_ADDR( &aSession, inetAddress ); + } + } + + if ( !inetAddr ) + { + TInt index = 0; + TBool found = ETrue; + while( found && index < mediaLines.Count() ) + { + RPointerArray& connfields = + mediaLines[index]->ConnectionFields(); + + if ( mediaLines[index++]->Port() > 0 ) + { + TInt cfindex = 0; + TBool cffound = EFalse; + while( !cffound && cfindex < connfields.Count() ) + { + inetAddr = connfields[cfindex++]->InetAddress(); + cffound = MCE_NOT_NULL_PTR( inetAddr ); + } + found = cffound; + } + } + } + + if ( inetAddr ) + { + MCE_SET_REMOTE_IP_ADDR( &aSession, *inetAddr ); + } + else + { + result = KMceSipWarnIncompatibleNetworkAddressFormat; + } + + return result; + } + +// ----------------------------------------------------------------------------- +// CMceSdpSession::SetSessionNameL +// ----------------------------------------------------------------------------- +// +void CMceSdpSession::SetSessionNameL( const TDesC8& aSessionName ) + { + HBufC8* tmp = aSessionName.AllocL(); + delete iSessionName; + iSessionName = tmp; + } + +// ----------------------------------------------------------------------------- +// CMceSdpSession::SetMediaSession +// ----------------------------------------------------------------------------- +// +void CMceSdpSession::SetMediaSession( CMceComSession* aSession ) + { + iSession = aSession; + } + +// ----------------------------------------------------------------------------- +// CMceSdpSession::MediaSession +// ----------------------------------------------------------------------------- +// +CMceComSession* CMceSdpSession::MediaSession() + { + return iSession; + } + +// ----------------------------------------------------------------------------- +// CMceSdpSession::SetBackup +// ----------------------------------------------------------------------------- +// +void CMceSdpSession::SetBackup( CMceComSession* aSession ) + { + iBackup = aSession; + } + +// ----------------------------------------------------------------------------- +// CMceSdpSession::Backup +// ----------------------------------------------------------------------------- +// +CMceComSession* CMceSdpSession::Backup() + { + return iBackup; + } + +// ----------------------------------------------------------------------------- +// CMceSdpSession::DetachMedia +// ----------------------------------------------------------------------------- +// +TBool CMceSdpSession::DetachMedia( CMceComSession& aSession ) + { + if ( &aSession == MediaSession() ) + { + SetMediaSession( NULL ); + } + else if ( &aSession == Backup() ) + { + SetBackup( NULL ); + } + else + { + return EFalse; + } + return ETrue; + } + +// ----------------------------------------------------------------------------- +// CMceSdpSession::SetUserNameL +// ----------------------------------------------------------------------------- +// +void CMceSdpSession::SetUserNameL( const TDesC8& aUserName ) + { + HBufC8* tmp = aUserName.AllocL(); + delete iUserName; + iUserName = tmp; + } + +// ----------------------------------------------------------------------------- +// CMceSdpSession::UserName +// ----------------------------------------------------------------------------- +// +const TDesC8& CMceSdpSession::UserName() const + { + return *iUserName; + } + +// ------------------------------------------------------------------------------ +// CMceSdpSession::StoreRemoteOriginL +// ------------------------------------------------------------------------------ +// +void CMceSdpSession::StoreRemoteOriginL() + { + CSdpOriginField* origin = iSdpDocument->OriginField(); + User::LeaveIfNull( origin ); + CSdpOriginField* tmp = origin->CloneL(); + delete iRemoteOrigin; + iRemoteOrigin = tmp; + } + +// ------------------------------------------------------------------------------ +// CMceSdpSession::StoreRemoteMediaFieldsL +// ------------------------------------------------------------------------------ +// +void CMceSdpSession::StoreRemoteMediaFieldsL() + { + iSdpRemoteMediaFields.ResetAndDestroy(); + for ( TInt i = 0; i < iSdpDocument->MediaFields().Count(); i++ ) + { + CSdpMediaField* field = iSdpDocument->MediaFields()[i]->CloneL(); + CleanupStack::PushL( field ); + iSdpRemoteMediaFields.AppendL( field ); + CleanupStack::Pop( field ); + } + } + +// ----------------------------------------------------------------------------- +// CMceSdpSession::DecodeConnectionFieldL +// ----------------------------------------------------------------------------- +// +void CMceSdpSession::DecodeConnectionFieldL( + CSdpDocument& aSdpDocument, + CMceComSession& aSession ) + { + CSdpConnectionField* nullAddress = + CSdpConnectionField::DecodeL( KMceSipNullAddressA ); + CleanupStack::PushL( nullAddress ); + + CMceSdpSession& sdpSession = aSession.SdpSession(); + CSdpConnectionField* connectionField = aSdpDocument.ConnectionField(); + + if ( connectionField && + ( connectionField->Address() == nullAddress->Address() ) ) + { + sdpSession.iIOldSchool = 1; + } + + else + { + sdpSession.iIOldSchool = 0; + } + + CleanupStack::PopAndDestroy( nullAddress ); + } + +// ----------------------------------------------------------------------------- +// CMceSdpSession::EncodeConnectionFieldL +// ----------------------------------------------------------------------------- +// +void CMceSdpSession::EncodeConnectionFieldL( + CMceComSession& aSession, + CSdpDocument& aSdpDocument ) + { + RPointerArray & mediaLines = aSdpDocument.MediaFields(); + TInt mediaLinesIndex = 0; + TBool found = EFalse; + TInt mCLineCount = 0; + while( mediaLinesIndex < mediaLines.Count() ) + { + RPointerArray& connfields = + mediaLines[mediaLinesIndex++]->ConnectionFields(); + + TInt connfieldsIndex = 0; + while( connfieldsIndex < connfields.Count() ) + { + if ( !connfieldsIndex ) + { + mCLineCount++; + } + + CSdpConnectionField* connectionField = connfields[connfieldsIndex++]; + + // if there are media level c= lines, copy the local address + // to be media c= lines + if ( iIOldSchool ) + { + connectionField->SetAddressL( + connectionField->NetType(), + connectionField->AddressType(), + KMceSipNullAddress ); + } + else + { + connectionField->SetInetAddressL( aSession.iLocalIpAddress ); + } + } + + // each media line have a media c= line + if ( mCLineCount == mediaLines.Count() ) + { + found = ETrue; + } + } + + if ( !found || aSdpDocument.ConnectionField() ) + { + + // rfc4566 5.7 Connection Data ("c="), media level c= lines are more + // important and will override session level c= line if both exists, copy + // the local address to be session level c= line when MO provide it also + CSdpConnectionField* connectionField = NULL; + if ( iIOldSchool ) + { + connectionField = CSdpConnectionField::DecodeL( KMceSipNullAddressA ); + } + else + { + connectionField = CSdpConnectionField::NewL( aSession.iLocalIpAddress ); + } + + aSdpDocument.SetConnectionField( connectionField ); + } + } + +// ----------------------------------------------------------------------------- +// CMceSdpSession::IsSessionRefresh +// ----------------------------------------------------------------------------- +// +TBool CMceSdpSession::IsSessionRefresh( CSdpDocument* aSdpDocument ) + { + TBool isRefresh = EFalse; + + if ( aSdpDocument ) + { + iSdpDocument = aSdpDocument; + } + + if ( iSdpDocument ) + { + CSdpOriginField* origin = iSdpDocument->OriginField(); + if( origin && iRemoteOrigin && *iRemoteOrigin == *origin ) + { + isRefresh = CompareMediaLines( iSdpRemoteMediaFields, + iSdpDocument->MediaFields() ); + } + } + + return isRefresh; + } + +// ----------------------------------------------------------------------------- +// CMceSdpSession::CompareMediaLines +// ----------------------------------------------------------------------------- +// +TBool CMceSdpSession::CompareMediaLines( + RPointerArray& aFieldsSrc, + RPointerArray& aFieldsDst ) const + { + TBool result = EFalse; + TInt srcCount = aFieldsSrc.Count(); + TInt dstCount = aFieldsDst.Count(); + + // Return if count of media fields are not equal. + if ( srcCount == dstCount ) + { + result = ETrue; + + // Return if every media field from source array + // cannot be found from destination array. + for ( TInt i = 0; i < srcCount && result; i++ ) + { + result = EFalse; + for ( TInt j = 0; j < dstCount && !result; j++ ) + { + if ( *aFieldsSrc[i] == *aFieldsDst[j] ) + { + result = ETrue; + } + } + } + } + + return result; + } + +// ----------------------------------------------------------------------------- +// CMceSdpSession::PrepareSessionRefreshL +// ----------------------------------------------------------------------------- +// +void CMceSdpSession::PrepareSessionRefreshL( CMceComSession& aSession ) + { + User::LeaveIfNull( iSdpDocument ); + EncodeSessionParamsL( aSession, *iSdpDocument ); + } + +// ----------------------------------------------------------------------------- +// CMceSdpSession::SdpCleanup +// ----------------------------------------------------------------------------- +// +void CMceSdpSession::SdpCleanup( + CSdpDocument* aPrevious, + CSdpDocument* aReplacement ) + { + if ( iSdpDocument && iSdpDocument == aPrevious ) + { + MCEMM_DEBUG("CMceSdpSession::SdpCleanup(), replacing") + iSdpDocument = aReplacement; + } + } + +// ----------------------------------------------------------------------------- +// CMceSdpSession::GetRandomNumber +// ----------------------------------------------------------------------------- +// +TInt64 CMceSdpSession::GetRandomNumber() + { + TTime currentTime; + currentTime.HomeTime(); + TInt64 value( currentTime.Int64() ); + return value; + } + +// ----------------------------------------------------------------------------- +// CMceSdpSession::NeedToNegotiate +// ----------------------------------------------------------------------------- +// +TBool CMceSdpSession::NeedToNegotiate( CMceComSession& aSession ) + { + TBool needToNegotiate = EFalse; + + RPointerArray& streams = aSession.Streams(); + + TInt index = 0; + while( !needToNegotiate && index < streams.Count() ) + { + CMceComMediaStream* stream = streams[ index++ ]; + for( int i = 0; i < stream->Preconditions().Count(); i++ ) + { + needToNegotiate = stream->Preconditions().Count() && + !stream->Preconditions()[i]->IsMet(); + } + } + + return needToNegotiate; + } + +// ----------------------------------------------------------------------------- +// CMceSdpSession::ReservationNeeded +// ----------------------------------------------------------------------------- +// +TBool CMceSdpSession::ReservationNeeded( CMceComSession& aSession ) + { + TBool reservationNeeded = EFalse; + + RPointerArray& streams = aSession.Streams(); + + TInt index = 0; + while( !reservationNeeded && index < streams.Count() ) + { + CMceComMediaStream* stream = streams[ index++ ]; + for( int i = 0; i < stream->Preconditions().Count(); i++ ) + { + reservationNeeded = ( stream->Preconditions().Count() && + stream->Preconditions()[i]->IsMet() ) ? EFalse : ETrue; + } + } + + return reservationNeeded; + } + +// ----------------------------------------------------------------------------- +// CMceSdpSession::ReserveL +// ----------------------------------------------------------------------------- +// +TMceReturnStatus CMceSdpSession::ReserveL( CMceComSession& aSession ) + { + //fake implementation + TMceReturnStatus status = KMceReady; + + RPointerArray& streams = aSession.Streams(); + + TInt index = 0; + while( index < streams.Count() ) + { + CMceComMediaStream* stream = streams[ index++ ]; + if ( stream->Preconditions().Count() ) + { + for( int i = 0; i < stream->Preconditions().Count(); i++ ) + { + stream->Preconditions()[ i ]->Reserved(); + } + } + } + + return status; + } + +// ----------------------------------------------------------------------------- +// CMceSdpSession::EncodeClientAttributesL +// ----------------------------------------------------------------------------- +// +void CMceSdpSession::EncodeClientAttributesL( + CMceComSession& aSession, + CSdpDocument& aDocument ) const + { + MCEMM_DEBUG("CMceSdpSession::EncodeClientAttributesL, Entry ") + CDesC8Array* clientAttributes = aSession.iLocalSessionSDPLines; + __ASSERT_ALWAYS( clientAttributes, User::Leave( KErrArgument ) ); + + CMceSdpCodec::EncodeClientSdpFieldsL( *clientAttributes, aDocument ); + + MCEMM_DEBUG("CMceSdpSession::EncodeClientAttributesL, Exit ") + } + +// ----------------------------------------------------------------------------- +// CMceSdpSession::DecodeClientAttributesL +// ----------------------------------------------------------------------------- +// +void CMceSdpSession::DecodeClientAttributesL( + CSdpDocument& aDocument, + CMceComSession& aSession ) const + { + MCEMM_DEBUG("CMceSdpSession::DecodeClientAttributesL, Entry ") + CDesC8Array* remoteAttributes = + new (ELeave) CDesC8ArrayFlat( KMceArrayGranularity ); + CleanupStack::PushL( remoteAttributes ); + + CBufFlat* encodeBuf = NULL; + + for ( TInt i = 0; i < aDocument.AttributeFields().Count(); i++ ) + { + + encodeBuf = CBufFlat::NewL( KMceExternalizeBufferExpandSize ); + CleanupStack::PushL( encodeBuf ); + RBufWriteStream writeStream( *encodeBuf, 0 ); + writeStream.PushL(); + + aDocument.AttributeFields()[ i ]->EncodeL( writeStream ); + MCEMM_DEBUG_SVALUE("found attribute", encodeBuf->Ptr( 0 ) ) + remoteAttributes->AppendL( encodeBuf->Ptr( 0 ) ); + + CleanupStack::PopAndDestroy(); // writeStream + CleanupStack::PopAndDestroy( encodeBuf ); // encodeBuf + } + + for ( TInt i = 0; i < aDocument.BandwidthFields().Count(); i++ ) + { + + encodeBuf = CBufFlat::NewL( KMceExternalizeBufferExpandSize ); + CleanupStack::PushL( encodeBuf ); + RBufWriteStream writeStream( *encodeBuf, 0 ); + writeStream.PushL(); + + aDocument.BandwidthFields()[ i ]->EncodeL( writeStream ); + MCEMM_DEBUG_SVALUE("found attribute", encodeBuf->Ptr( 0 ) ) + remoteAttributes->AppendL( encodeBuf->Ptr( 0 ) ); + + CleanupStack::PopAndDestroy(); // writeStream + CleanupStack::PopAndDestroy( encodeBuf ); // encodeBuf + } + + CleanupStack::Pop( remoteAttributes ); + MCE_DELETE( aSession.iRemoteSessionSDPLines ); + aSession.iRemoteSessionSDPLines = remoteAttributes; + MCEMM_DEBUG("CMceSdpSession::DecodeClientAttributesL, Exit ") + } + +// ----------------------------------------------------------------------------- +// CMceSdpSession::Consumes +// ----------------------------------------------------------------------------- +// +CMceComSession* CMceSdpSession::Consumes( TUint32 aSessionId ) + { + CMceComSession* session = MediaSession(); + CMceComSession* backup = Backup(); + CMceComSession* foundSession = NULL; + + foundSession = ( session && + session->iMccID != KMceNotAssigned && + session->iMccID == aSessionId ) ? + session : + ( backup && + backup->iMccID != KMceNotAssigned && + backup->iMccID == aSessionId ) ? + backup : + NULL; + + return foundSession; + } + +// ----------------------------------------------------------------------------- +// CMceSdpSession::StockMediaSessionL +// ----------------------------------------------------------------------------- +// +void CMceSdpSession::StockMediaSessionL() + { + MCEMM_DEBUG("CMceSdpSession::StockMediaSessionL, Entry ") + + if ( !iInitialSession && !Backup() ) + { + iInitialSession = MediaSession()->CloneL(); + MCEMM_DEBUG("Stocked") + } + + MCEMM_DEBUG("CMceSdpSession::StockMediaSessionL, Exit ") + } + + +// ----------------------------------------------------------------------------- +// CMceSdpSession::ForkL +// ----------------------------------------------------------------------------- +// +CMceSdpSession& CMceSdpSession::ForkL() + { + MCEMM_DEBUG("CMceSdpSession::ForkL, Entry ") + + __ASSERT_ALWAYS( MediaSession(), User::Leave( KErrArgument ) ); + __ASSERT_ALWAYS( IsMaster(), User::Leave( KErrArgument ) ); + __ASSERT_ALWAYS( !Backup(), User::Leave( KErrArgument ) ); + __ASSERT_ALWAYS( iInitialSession, User::Leave( KErrArgument ) ); + + CMceComSession* forkedMediaSession = + iInitialSession->CloneAndMergeLC( *MediaSession() ); + CMceSdpSession& forkedSession = Manager().CreateSessionL( *forkedMediaSession ); + + ContextSwitch( &forkedSession ); + + MediaSession()->MediaObserver().SessionCreatedL( forkedMediaSession ); + CleanupStack::Pop( forkedMediaSession ); + + MCEMM_DEBUG("CMceSdpSession::ForkL, Exit ") + + return forkedSession; + } + +// ----------------------------------------------------------------------------- +// CMceSdpSession::IsMaster +// ----------------------------------------------------------------------------- +// +TBool CMceSdpSession::IsMaster() + { + return iIsMaster; + } + +// ----------------------------------------------------------------------------- +// CMceSdpSession::ContextSwitch +// ----------------------------------------------------------------------------- +// +void CMceSdpSession::ContextSwitch( CMceSdpSession* aForkedSession ) + { + MCEMM_DEBUG("CMceSdpSession::ContextSwitch, Entry ") + + CMceSdpSession* oldMaster = this; + CMceSdpSession* newMaster = aForkedSession; + + if ( !newMaster && !oldMaster->IsMaster() ) + { + newMaster = this; + oldMaster = NULL; + CMceSdpSession::TIterator + masterCandidates( Manager().iMceSdpSessions, + CMceSdpSession::TIterator::EFilterMaster ); + + MCE_ITERATOR_FIND_NEXT( masterCandidates, oldMaster, + oldMaster->MediaSession()->iMccID == + newMaster->MediaSession()->iMccID ); + + } + + if ( oldMaster && newMaster ) + { + newMaster->iIsMaster = ETrue; + oldMaster->iIsMaster = EFalse; + delete newMaster->iInitialSession; + newMaster->iInitialSession = oldMaster->iInitialSession; + oldMaster->iInitialSession = NULL; + newMaster->iContext = oldMaster->iRequestedContext ? + oldMaster->iRequestedContext : + newMaster->iContext; + newMaster->iRequestedContext = NULL; + oldMaster->iRequestedContext = NULL; + + newMaster->MediaSession()->Merge( *oldMaster->MediaSession(), + KMceDeepMergeYes ); + + MCEMM_DEBUG("context switch performed") + } + else + { + MCEMM_DEBUG("no context switch performed!!") + } + + MCEMM_DEBUG("CMceSdpSession::ContextSwitch, Exit ") + } + +// ----------------------------------------------------------------------------- +// CMceSdpSession::ContextSwitchRequested +// ----------------------------------------------------------------------------- +// +TBool CMceSdpSession::ContextSwitchRequested() + { + return iContext && iRequestedContext && iRequestedContext != iContext; + } + +// ----------------------------------------------------------------------------- +// CMceSdpSession::Context +// ----------------------------------------------------------------------------- +// +CSIPDialogAssocBase* CMceSdpSession::Context() + { + return iContext; + } + +// ----------------------------------------------------------------------------- +// CMceSdpSession::AttachContext +// ----------------------------------------------------------------------------- +// +void CMceSdpSession::AttachContext( CSIPDialogAssocBase* aContext ) + { + if ( !iContext || !aContext ) + { + iContext = aContext; + } + else if ( aContext != iContext ) + { + iRequestedContext = aContext; + } + else + { + iRequestedContext = NULL; + } + } + +// ----------------------------------------------------------------------------- +// CMceSdpSession::TIterator::TIterator +// ----------------------------------------------------------------------------- +// +CMceSdpSession::TIterator::TIterator( + RPointerArray& aCodecs, + CMceSdpSession::TIterator::TFilter aFilter ) + : iFilter( aFilter ), + iSessions( aCodecs ), + iCurrentIndex( 0 ) + { + } + +// ----------------------------------------------------------------------------- +// CMceSdpSession::TIterator::IsEof +// ----------------------------------------------------------------------------- +// +TBool CMceSdpSession::TIterator::IsEof() + { + return iSessions.Count() == 0 || iCurrentIndex >= iSessions.Count(); + } + +// ----------------------------------------------------------------------------- +// CMceSdpSession::TIterator::Next +// ----------------------------------------------------------------------------- +// +TBool CMceSdpSession::TIterator::Next( CMceSdpSession*& aCandidate ) + { + CMceSdpSession* next = NULL; + + while( !next && !IsEof() ) + { + CMceSdpSession* session = iSessions[ iCurrentIndex ]; + TBool condition = EFalse; + switch( iFilter ) + { + case EFilterMaster: + { + condition = session->IsMaster(); + break; + } + default: + { + condition = ETrue; + break; + } + } + + next = condition ? session : NULL; + + iCurrentIndex++; + } + + aCandidate = next; + return aCandidate ? ETrue : EFalse; + } + +// ----------------------------------------------------------------------------- +// CMceSdpSession::Current +// ----------------------------------------------------------------------------- +// +TInt CMceSdpSession::TIterator::Current() + { + TInt current = KErrNotFound; + + if ( iSessions.Count() > 0 ) + { + current = iCurrentIndex-1; + current = current < 0 ? 0 : current; + } + return current; + } + +// ----------------------------------------------------------------------------- +// CMceSdpSession::Remove +// ----------------------------------------------------------------------------- +// +TInt CMceSdpSession::TIterator::Remove() + { + TInt current = Current(); + + if ( current != KErrNotFound ) + { + iSessions.Remove( current ); + iCurrentIndex = current; + } + + return current; + } + +// ----------------------------------------------------------------------------- +// CMceSdpSession::TIterator::Reset +// ----------------------------------------------------------------------------- +// +void CMceSdpSession::TIterator::Reset() + { + iCurrentIndex = 0; + } + +// ----------------------------------------------------------------------------- +// CMceSdpSession::TIterator::SetFilter +// ----------------------------------------------------------------------------- +// +void CMceSdpSession::TIterator::SetFilter( + CMceSdpSession::TIterator::TFilter aFilter ) + { + iFilter = aFilter; + } + +// ----------------------------------------------------------------------------- +// CMceSdpSession::TIterator::Count +// ----------------------------------------------------------------------------- +// +TInt CMceSdpSession::TIterator::Count() + { + TInt count = iSessions.Count(); + if ( iFilter ) + { + TInt currentIndex = iCurrentIndex; + Reset(); + CMceSdpSession* codec = NULL; + count = 0; + while( Next( codec ) ) + { + count++; + } + iCurrentIndex = currentIndex; + } + + return count; + }