multimediacommsengine/mmcesrv/mmcemediamanager/src/mcesdpsession.cpp
changeset 0 1bce908db942
child 3 513a8b745b2f
--- /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 <e32base.h>
+#include <e32std.h>
+
+#include <sdporiginfield.h>
+#include <sdpconnectionfield.h>
+#include <sdpfmtattributefield.h>
+#include <sdpmediafield.h>
+#include <sdpattributefield.h>
+#include <sdpcodecstringpool.h>
+#include <sdpdocument.h>
+#include <sdpbandwidthfield.h>
+#include <siptoheader.h>
+
+#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 <CMceComMediaStream>& 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 <CMceComMediaStream>& 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 <CMceComMediaStream>& 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 <CMceComMediaStream>& 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 <CSdpMediaField>& 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<CMceComMediaStream>& 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 <CSdpMediaField>& mediaLines = iSdpDocument->MediaFields();
+    
+    __ASSERT_ALWAYS( mediaLines.Count() > 0, User::Leave( KErrArgument ) );
+
+    RPointerArray<CMceComMediaStream>& 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<CSdpMediaField>& aMediaLines,
+    RPointerArray<CMceComMediaStream>& 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<CMceComMediaStream>& 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<CSdpConnectionField>& 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 <CSdpMediaField>& mediaLines = aSdpDocument.MediaFields();
+    TInt mediaLinesIndex = 0;
+    TBool found = EFalse;
+    TInt mCLineCount = 0;
+    while( mediaLinesIndex < mediaLines.Count() )
+        {
+        RPointerArray<CSdpConnectionField>& 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<CSdpMediaField>& aFieldsSrc,
+    RPointerArray<CSdpMediaField>& 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<CMceComMediaStream>& 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<CMceComMediaStream>& 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<CMceComMediaStream>& 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<CSdpDocument>( *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<CMceSdpSession>& 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;
+    }