/*
* Copyright (c) 2006 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 "mcemediadefs.h"
#include "mcemediasdpcodec.h"
#include "mcecomcodec.h"
#include "mcemmlogs.h"
#include "mcepreconditions.h"
#include "mcesdpsession.h"
#include "mcesip.h"
#include "mcemediamanager.h"
#include "mcenatpluginmanager.h"

#include <sdpconnectionfield.h>
#include <sdpdocument.h>
#include <sdpcodecstringconstants.h>
#include <sdpcodecstringpool.h>
#include <sdpmediafield.h>
#include <sdpattributefield.h>
#include <sdprtpmapvalue.h>
#include <sdpfmtattributefield.h>
#include <sdporiginfield.h>
#include <sdpbandwidthfield.h>
#include <mmcccodecinformation.h>
#include <sdpcodecstringpool.h>
#include <delimitedpathsegment8.h>


// ================= MEMBER FUNCTIONS =======================

// -----------------------------------------------------------------------------
// CMceMediaSdpCodec::CMceMediaSdpCodec
// -----------------------------------------------------------------------------
CMceMediaSdpCodec::CMceMediaSdpCodec( RStringF aMedia )
    : CMceSdpCodec( aMedia )
    {
    }


// -----------------------------------------------------------------------------
// CMceMediaSdpCodec::~CMceMediaSdpCodec
// -----------------------------------------------------------------------------
CMceMediaSdpCodec::~CMceMediaSdpCodec()
    {
    }



// -----------------------------------------------------------------------------
// CMceMediaSdpCodec::EncodeMediaOfferL
// -----------------------------------------------------------------------------
//
void CMceMediaSdpCodec::EncodeMediaOfferL( 
    CMceComMediaStream& aStream, 
    CSdpMediaField& aMediaLine, 
    CSdpDocument& aSdpDocument )
    { 
    MCEMM_DEBUG("CMceMediaSdpCodec::EncodeMediaOfferL(), Entry ")
    
    // get all the codecs to be offered for this media stream.
    const RPointerArray<CMceComCodec>& allCodecs = CodecsL( aStream );

    CMceComCodec* codec = NULL;
    CMceComCodec::TIterator codecs( allCodecs, CMceComCodec::TIterator::EFilterIsNegotiated );
    
    // Set the fmt list containing all supported payload 
    // types supported by this media
    // i.e. all the rtpmap fields in the pointer array
    HBufC8* fmtlist = CreateFormatListL( codecs );
    CleanupStack::PushL( fmtlist ); 
    codecs.Reset();

    aMediaLine.SetFormatListL( *fmtlist );
    CleanupStack::PopAndDestroy( fmtlist ); 
    
    MCEMM_DEBUG_SVALUE("encoded formatlist", aMediaLine.FormatList() )
    
    // For each codec supported by this stream create a rtpmap field
    // e.g. a=rtpmap: 97 AMR/8000
    // and ptime and maxptime
    // e.g. a=ptime:20 a=maxptime:40
    while( codecs.Next( codec ) )
        {
        CSdpFmtAttributeField* rtpmap = EncodeRtpmapAttributeLC( *codec );

        EncodeMediaAttributesL( *codec, aMediaLine, *rtpmap );

        aMediaLine.FormatAttributeFields().AppendL( rtpmap );
        CleanupStack::Pop( rtpmap );
        
        EncodeFmtpAttributeL( *codec, aMediaLine );
        
        }  
    
    //encode direction
    EncodeDirectionL( aStream, aMediaLine, aSdpDocument, EMceRoleOfferer );
    
    //encode client attributes if any
    EncodeClientAttributesL( aStream, aMediaLine );
        
    //encode secure session if any
    EncodeSecureSessionL( aStream, aMediaLine, EMceRoleOfferer );
    
    //encode preconditions if any
    EncodePreconditionsL( aStream, aMediaLine, EMceRoleOfferer );
    
    //encode rtcp port 
    EncodelocalRtcpAttrL( aMediaLine, aStream );
    
    MCEMM_DEBUG("CMceMediaSdpCodec::EncodeMediaOfferL(), Exit ")
    }


// -----------------------------------------------------------------------------
// CMceMediaSdpCodec::DecodeMediaAnswerL
// -----------------------------------------------------------------------------
//
TMceSipWarningCode CMceMediaSdpCodec::DecodeMediaAnswerL( 
    CSdpMediaField& aMediaLine, 
    CMceComMediaStream& aStream,
    CSdpDocument& aSdpDocument )
    {
    MCEMM_DEBUG("CMceMediaSdpCodec::DecodeMediaAnswerL(), Entry ")
    
    //should have secure session created

    const RPointerArray<CMceComCodec>& allCodecs = CodecsL( aStream );
    CMceComCodec::TIterator codecs( allCodecs );
    
    //decode direction or old school hold if necessary                                            
    DecodeDirectionL( aMediaLine, aStream, aSdpDocument, EMceRoleOfferer );
	        
    __ASSERT_ALWAYS( codecs.Count() > 0, User::Leave( KErrNotReady ) );
    __ASSERT_ALWAYS( aMediaLine.Port() != 0 , User::Leave( KErrNotReady ) );

    //decode based on rtpmaps + their media attributes
    TInt decoded = DecodePayloadsL( aMediaLine, aStream, EMceRoleOfferer );

    if ( !decoded )
        {
        MCEMM_DEBUG("ERROR: No codecs decoded")
        User::Leave( KErrNotReady );
        }

	 // check if remote RTCP port is set according to RFC 3605
    DecodeRemoteRtcpFieldL( aMediaLine, aStream );
    aStream.SetRemoteMediaPort( aMediaLine.Port() );

    MCEMM_DEBUG_DVALUE("decoded remote port", aStream.RemoteMediaPort() )
    //decode based on fmtps
    DecodeFmtpLinesL( aMediaLine, codecs, EMceRoleOfferer );

	 //decode secure session if any
    DecodeSecureSessionL( aMediaLine, aStream, EMceRoleOfferer );
    
    //decode preconditions if any
    TMceSipWarningCode warnings = 
        DecodePreconditionsL( aMediaLine, aStream, EMceRoleOfferer );
    
    //decode client attributes if any
    DecodeClientAttributesL( aMediaLine, aStream );

    MCEMM_DEBUG("CMceMediaSdpCodec::DecodeMediaAnswerL(), Exit ")
    return warnings;
    }    
    
// -----------------------------------------------------------------------------
// CMceMediaSdpCodec::DecodeMediaOfferL
// -----------------------------------------------------------------------------
//
TMceSipWarningCode CMceMediaSdpCodec::DecodeMediaOfferL( 
    CSdpMediaField& aMediaLine,
    CMceComMediaStream*& aStream,
    CMceComSession& aSession,
    CSdpDocument& aSdpDocument )
    {
    MCEMM_DEBUG("CMceMediaSdpCodec::DecodeMediaOfferL(), Entry ")
    
    TMceSipWarningCode warning = ValidateSdpL( aMediaLine, aSdpDocument );
    if ( warning != KErrNone )
        {
        return warning;
        }
    
    TInt type = Type( aMediaLine, aSdpDocument.AttributeFields() );

    // create server stream based on the media direction 
    // attribute (sendonly, sendrcv, rcvonly)
    aStream = CreateStreamLC( type );
    aStream->InitializeL( aSession );
    	
    //decode direction or old school hold if necessary                                            
    DecodeDirectionL( aMediaLine, *aStream, aSdpDocument, EMceRoleAnswerer );
    	
    const RPointerArray<CMceComCodec>& allCodecs = CodecsL( *aStream );
    CMceComCodec::TIterator codecs( allCodecs );
    
    //decode based on rtpmaps + their media attributes
    TInt decoded = DecodePayloadsL( aMediaLine, *aStream, EMceRoleAnswerer );
    
    if ( decoded )
        {

        // check if remote RTCP port is set according to RFC 3605
        DecodeRemoteRtcpFieldL( aMediaLine, *aStream );
        aStream->SetRemoteMediaPort( aMediaLine.Port() );

        MCEMM_DEBUG_DVALUE("decoded remote port", aStream->RemoteMediaPort() )
        
        //decode based on fmtps
        DecodeFmtpLinesL( aMediaLine, codecs, EMceRoleAnswerer );
        
        //decode session level media attributes        
        DecodeSessionMediaAttributesL( *aStream, aSdpDocument );
        
        
        //decode secure session if any
       	DecodeSecureSessionL( aMediaLine, *aStream, EMceRoleAnswerer );
       	//decode preconditions if any
        warning = DecodePreconditionsL( aMediaLine, *aStream, EMceRoleAnswerer );
	
		    
        //Decode client attributes if any
        DecodeClientAttributesL( aMediaLine, *aStream );
		
        aSession.Streams().AppendL( aStream );
        CleanupStack::Pop( aStream );
        
        }
    else
        {
        MCEMM_DEBUG("No acceptable codecs found for current media line ")
            
        // we did not find any acceptable codecs for this stream, return warning
        
        CleanupStack::PopAndDestroy( aStream );
        aStream = NULL;
        warning = KMceSipWarnIncompatibleMediaFormat;
        }
    
    MCEMM_DEBUG("CMceMediaSdpCodec::DecodeMediaOfferL(), Exit ")
    
    return warning;
    
    }
    
// -----------------------------------------------------------------------------
// CMceMediaSdpCodec::DecodeMediaUpdateL
// -----------------------------------------------------------------------------
//
TMceSipWarningCode CMceMediaSdpCodec::DecodeMediaUpdateL( 
    CSdpMediaField& aMediaLine, 
    CMceComMediaStream& aStream,
    CSdpDocument& aSdpDocument )
    {
    
    MCEMM_DEBUG("CMceMediaSdpCodec::DecodeMediaUpdateL(), Entry ")
    
    TMceSipWarningCode warning = ValidateSdpL( aMediaLine, aSdpDocument );
    if ( warning != KErrNone )
        {
        return warning;
        }

    const RPointerArray<CMceComCodec>& allCodecs = CodecsL( aStream );
    CMceComCodec::TIterator codecs( allCodecs );
    
    aStream.SetRemoteMediaPort( aMediaLine.Port() );
    MCEMM_DEBUG_DVALUE("decoded remote port", aStream.RemoteMediaPort() )
    
    //should have secure media session existed
    
    //decode based on rtpmaps + their media attributes
    TInt decoded = DecodePayloadsL( aMediaLine, aStream, EMceRoleAnswerer );
    
    if ( decoded )
        {
        // check if remote RTCP port is set according to RFC 3605
        DecodeRemoteRtcpFieldL( aMediaLine, aStream );
        

        //decode based on fmtps
        DecodeFmtpLinesL( aMediaLine, codecs, EMceRoleAnswerer );

        //decode direction or old school hold if necessary                                            
        UpdateDirectionL( aMediaLine, aStream, aSdpDocument );

        //decode secure session if any
       	DecodeSecureSessionL( aMediaLine, aStream, EMceRoleAnswerer, KMceMediaCodecUpdate );


		//decode preconditions if any
        warning = DecodePreconditionsL( aMediaLine, aStream, EMceRoleAnswerer );
        
        //decode client attributes if any
        DecodeClientAttributesL( aMediaLine, aStream );
    
	    }
    else
        {
        MCEMM_DEBUG("ERROR: No codecs decoded")
        warning = KMceSipWarnIncompatibleMediaFormat;
        }
    
    MCEMM_DEBUG("CMceMediaSdpCodec::DecodeMediaUpdateL(), Exit ")
    return warning;
    }

// -----------------------------------------------------------------------------
// CMceAudioSdpCodec::EncodeMediaAnswerL
// -----------------------------------------------------------------------------
//
void CMceMediaSdpCodec::EncodeMediaAnswerL( 
    CMceComMediaStream& aStream,
    CSdpMediaField& aMediaLine,
    CSdpDocument& aSdpDocument )
    {
    MCEMM_DEBUG("CMceMediaSdpCodec::EncodeMediaAnswerL(), Entry ")
    
    const RPointerArray<CMceComCodec>& allCodecs = CodecsL( aStream );  
    CMceComCodec* codec = NULL;
    CMceComCodec::TIterator codecs( allCodecs, CMceComCodec::TIterator::EFilterIsNegotiated );

    if ( codecs.Count() > 0 ) 
        {
        
        // Set the fmt list containing all supported payload 
        // types supported by this media
        // i.e. all the rtpmap fields in the pointer array
        HBufC8* fmtlist = CreateFormatListL( codecs );
        CleanupStack::PushL( fmtlist ); 
        codecs.Reset();

        aMediaLine.SetFormatListL( *fmtlist );
        CleanupStack::PopAndDestroy( fmtlist ); 
        
        MCEMM_DEBUG_SVALUE("encoded formatlist", aMediaLine.FormatList() )
        
        aMediaLine.SetPortL( aStream.iLocalMediaPort );
        MCEMM_DEBUG_DVALUE("encoded local port", aMediaLine.Port() )
        
        // add the direction attribute
        EncodeDirectionL( aStream, aMediaLine, aSdpDocument, EMceRoleAnswerer );

        while( codecs.Next( codec ) )
            {
            CSdpFmtAttributeField* rtpmap = EncodeRtpmapAttributeLC( *codec );

            EncodeMediaAttributesL( *codec, aMediaLine, *rtpmap );

            aMediaLine.FormatAttributeFields().AppendL( rtpmap );
            CleanupStack::Pop( rtpmap );
            
            EncodeFmtpAttributeL( *codec, aMediaLine );
            
            }

        //encode secure session if any
        EncodeSecureSessionL( aStream, aMediaLine, EMceRoleAnswerer );
        
        //encode preconditions if any
        EncodePreconditionsL( aStream, aMediaLine, EMceRoleAnswerer );
        
        }
    else
        { // there was no selected codec for this stream
        MCEMM_DEBUG("ERROR: No selected codec found! Reject ")
        aMediaLine.RejectMedia();
        }
        
    // encode client attributes
    EncodeClientAttributesL( aStream, aMediaLine );

	// encode rtcp attributes
	EncodelocalRtcpAttrL( aMediaLine, aStream );
    MCEMM_DEBUG("CMceMediaSdpCodec::EncodeMediaAnswerL(), Exit ")
    }

// -----------------------------------------------------------------------------
// CMceMediaSdpCodec::TypeL
// -----------------------------------------------------------------------------
//
TInt CMceMediaSdpCodec::Type( 
    CSdpMediaField& aMedia, 
    RPointerArray<CSdpAttributeField>& aSessionAttributes ) const
    {
    TInt type = Direction( aMedia, aSessionAttributes );
    type = type == KErrNotFound ? SdpCodecStringConstants::EAttributeSendrecv : type; 
    return type;
    }

// -----------------------------------------------------------------------------
// CMceMediaSdpCodec::PrepareForDecodeL
// -----------------------------------------------------------------------------
//
void CMceMediaSdpCodec::PrepareForDecodeL( 
    CSdpMediaField& /*aMediaLine*/,
    CMceComMediaStream* aStream )
    {
    MCEMM_DEBUG("CMceMediaSdpCodec::PrepareForDecodeL(), Entry ")
    
    if ( aStream )
        {
        const RPointerArray<CMceComCodec>& allCodecs = CodecsL( *aStream );
        CMceComCodec* codec = NULL;
        CMceComCodec::TIterator codecs( allCodecs );
        while( codecs.Next( codec ) )
            {
            codec->iIsNegotiated = EFalse;
            }
        }
        
    MCEMM_DEBUG("CMceMediaSdpCodec::PrepareForDecodeL(), Exit ")
    }

// -----------------------------------------------------------------------------
// CMceMediaSdpCodec::DecodeRtpmapLinesL
// -----------------------------------------------------------------------------
//
TInt CMceMediaSdpCodec::DecodeRtpmapLinesL( 
    CSdpMediaField& aMediaLine,
    CMceComMediaStream& aStream,
    TMceNegotiationRole aRole ) const
    {
    MCEMM_DEBUG("CMceMediaSdpCodec::DecodeRtpmapLinesL(), Entry ")
    TInt decoded = 0;
	
    const RPointerArray<CMceComCodec>& allCodecs = CodecsL( aStream );
    CMceComCodec* codec = NULL;
    CMceComCodec::TIterator codecs( allCodecs );
    
    RArray<TUint> payloadTypesInMediaLine;
    CleanupClosePushL( payloadTypesInMediaLine );
   
    User::LeaveIfError( DecodeFormatList( aMediaLine, payloadTypesInMediaLine ) );
 
    RPointerArray< CSdpFmtAttributeField >& formatLines =  
                                            aMediaLine.FormatAttributeFields();
    
	for ( TInt i = 0; i < formatLines.Count(); i++ )
		{
		CSdpFmtAttributeField* formatLine = formatLines[ i ];
        if ( formatLine->Attribute() == 
                    SDP_STRING( SdpCodecStringConstants::EAttributeRtpmap ) )
            //codec
            {
            TPtrC8 fmtpVal = GetCorrespondingFmtpLineL( aMediaLine, *formatLine );
            
            MCE_ITERATOR_FIND_NEXT( 
                codecs, codec, 
                codec->Decodes( formatLine->Value(), fmtpVal ) );
                
            codecs.Reset();
            
            if ( !codec && aRole == EMceRoleOfferer )
                {
                // No exact match, do less strict matching for better interoperability
                MCE_ITERATOR_FIND_NEXT( 
                codecs, codec, 
                codec->Decodes( formatLine->Value(), fmtpVal, EFalse ) );
                codecs.Reset();
                }
                
            if ( codec )
                {
                MCEMM_DEBUG_SVALUE("decoding codec", codec->iSdpName )
                
                const TDesC8& payloadTypeInRtpMap = formatLine->Format();
                TUint rtpMapPT = ConvertDesToUintL( payloadTypeInRtpMap );
                
                TInt val = payloadTypesInMediaLine.Find( rtpMapPT );
                if ( val != KErrNotFound )
                    {
                    TUint payload = ConvertDesToUintL( formatLine->Format() );
                    if ( !IsPayloadTypeSupported( codec->iSdpName, payload ) ) 
                    	{
						// not supported payload, ignore this codec
                    	continue;
                    	}
                    if ( !codec->iIsNegotiated )
                        {
                        codec->iPayloadType = payload;
                        }
                    codec->iIsNegotiated = ETrue;   
                    //decode media attributes
                    DecodeMediaAttributesL( aMediaLine, *codec, *formatLine );
                    decoded++;
                    }
                else
                    {
                    // Discarding as there was no matching pt in medialine for
                    // this rtmpmap line
                    codec->iIsNegotiated = EFalse;
                    if ( aStream.BoundStream() )
                        {
                        CMceComCodec* sync = NULL;
                        sync = aStream.BoundStreamL().FindCodecL( *codec );
                        if ( sync )
                            {
                            sync->iIsNegotiated = EFalse; 
                            }
                        }
                    }
                }
            else if ( aRole == EMceRoleAnswerer )
                {
                if ( DecodeRtpmapLineL( *formatLine, aMediaLine, aStream, fmtpVal ) )
                    {
                    decoded++;
                    }
                }
            else
                {
                // NOP
                }
                    
            }
		}

    CleanupStack::PopAndDestroy( &payloadTypesInMediaLine );
        
    MCEMM_DEBUG_DVALUE("decoded codecs", decoded )
    MCEMM_DEBUG("CMceMediaSdpCodec::DecodeRtpmapLinesL(), Exit ")
    return decoded;	
    }

// -----------------------------------------------------------------------------
// CMceMediaSdpCodec::DecodeRtpmapLinesL
// -----------------------------------------------------------------------------
//
TInt CMceMediaSdpCodec::DecodeRtpmapLinesL( 
    CSdpMediaField& aMediaLine,
    CMceComMediaStream& aStream ) const
    {
    MCEMM_DEBUG("CMceMediaSdpCodec::DecodeRtpmapLinesL(), Entry ")
    TInt decoded = 0;

     // Read format level attributes
    RPointerArray< CSdpFmtAttributeField >& formatLines =  
                                            aMediaLine.FormatAttributeFields();
    
    // For all codec specific lines in the offer        
    for ( TInt i = 0; i < formatLines.Count(); i++ )
        {
        CSdpFmtAttributeField* formatLine = formatLines[i];
        if ( formatLine->Attribute() == SDP_STRING( SdpCodecStringConstants::EAttributeRtpmap ) &&
             DecodeRtpmapLineL( *formatLine, aMediaLine, aStream ) )
            {
            decoded++;
            }
        }

    MCEMM_DEBUG_DVALUE("decoded codecs", decoded )
    MCEMM_DEBUG("CMceMediaSdpCodec::DecodeRtpmapLinesL(), Exit ")
    return decoded;
    }

// -----------------------------------------------------------------------------
// CMceMediaSdpCodec::DecodeStaticPayloadsL
// -----------------------------------------------------------------------------
//
TInt CMceMediaSdpCodec::DecodeStaticPayloadsL( 
    CSdpMediaField& aMediaLine,
    CMceComMediaStream& aStream,
    RArray<TUint>& aPayloadTypes,
    TMceNegotiationRole aRole ) const
    {
    MCEMM_DEBUG("CMceMediaSdpCodec::DecodeStaticPayloadsL(), Entry ")
    TInt decoded = 0;

    DecodeFormatListL( aMediaLine, aPayloadTypes );
    TInt index = 0;
    
    while( index < aPayloadTypes.Count() )
        {
        TUint payload = aPayloadTypes[ index++ ];
        if ( payload < KMinDynamicPT )
            {
            CMceComCodec* codec = FindCodec( payload, aStream );
            if ( aRole == EMceRoleAnswerer )
                {
                if ( !codec )
                    {
                    codec = CreateCodecLC( payload, aMediaLine );
                    if ( codec )
                        {
                        codec->InitializeL( aStream );
                        codec->iIsNegotiated = ETrue;
                        MCEMM_DEBUG_SVALUE("adding codec", codec->iSdpName )
                        aStream.AddCodecL( codec );
                        CleanupStack::Pop( codec );
                        decoded++;
                        }
                    }
                else
                    {
                    codec->iIsNegotiated = ETrue;
                    decoded++;
                    }
                }
            else if ( codec && aRole == EMceRoleOfferer )
                {
                codec->iIsNegotiated = ETrue;
                decoded++;
                }
            }
        }
        
    MCEMM_DEBUG_DVALUE("decoded codecs", decoded )
    MCEMM_DEBUG("CMceMediaSdpCodec::DecodeStaticPayloadsL(), Exit ")
    return decoded;
    }

// -----------------------------------------------------------------------------
// CMceMediaSdpCodec::FindCodec
// -----------------------------------------------------------------------------
//
CMceComCodec* CMceMediaSdpCodec::FindCodec( 
    TInt aPayloadType, 
    CMceComMediaStream& aStream ) const
    {
    TInt error = KErrNone;
    
    RPointerArray< CMceComCodec > allCodecs;
    
    TRAP( error, allCodecs = CodecsL( aStream ) );  
    CMceComCodec* codec = NULL;
    if( error == KErrNone )
    	{
    	CMceComCodec::TIterator codecs( allCodecs );
    
    	MCE_ITERATOR_FIND_NEXT( codecs, codec, codec->iPayloadType == aPayloadType );	
    	}

    return codec;
    }

// -----------------------------------------------------------------------------
// CMceMediaSdpCodec::DecodeRtpmapLineL
// -----------------------------------------------------------------------------
//
CMceComCodec* CMceMediaSdpCodec::DecodeRtpmapLineL( 
    CSdpFmtAttributeField& aRtpMaptLine,
    CSdpMediaField& aMediaLine,
    CMceComMediaStream& aStream,
    const TDesC8& aFmtpValue ) const
    {
    MCEMM_DEBUG("CMceMediaSdpCodec::DecodeFmtpLineL(), Entry ")
    
    RArray<TUint> payloadTypesInMediaLine;
    CleanupClosePushL( payloadTypesInMediaLine );
   
    User::LeaveIfError( DecodeFormatList( aMediaLine, payloadTypesInMediaLine ) );
    	
    const TDesC8& payloadTypeInRtpMap = aRtpMaptLine.Format();
    
    TUint rtpMapPT = ConvertDesToUintL( payloadTypeInRtpMap );
    CMceComCodec* codec = NULL;
    
    // Ingoring if there is no matching pt in medialine for this rtmpmap line
    if ( payloadTypesInMediaLine.Find( rtpMapPT ) != KErrNotFound )
        {
        codec = CreateCodecLC( aRtpMaptLine );
        if ( codec )
            {
            codec->InitializeL( aStream );
            if ( !codec->SetFmtpProposalL( aFmtpValue ) )
                {
                // Fmtp not valid, ignore codec
                CleanupStack::PopAndDestroy( codec );
                codec = NULL;
                }
            else
                {
                // check if ptime or maxptime attributes are present
                DecodeMediaAttributesL( aMediaLine, *codec, aRtpMaptLine );
                codec->iIsNegotiated = ETrue;
                MCEMM_DEBUG_SVALUE("adding codec", codec->iSdpName )
                aStream.AddCodecL( codec );
                CleanupStack::Pop( codec );
                }
            }    
        }

    CleanupStack::PopAndDestroy( &payloadTypesInMediaLine );

    MCEMM_DEBUG("CMceMediaSdpCodec::DecodeFmtpLineL(), Exit ")
    return codec;        
    }
    
// -----------------------------------------------------------------------------
// CMceMediaSdpCodec::DecodeFmtpLinesL
// -----------------------------------------------------------------------------
//
void CMceMediaSdpCodec::DecodeFmtpLinesL( 
    CSdpMediaField& aMediaLine,
    CMceComCodec::TIterator& aCodecs,
    TMceNegotiationRole aRole ) const
    {
    MCEMM_DEBUG("CMceMediaSdpCodec::DecodeFmtpLinesL(), Entry ")

    RPointerArray< CSdpFmtAttributeField >& formatLines =  
        aMediaLine.FormatAttributeFields();
    
    CMceComCodec* codec = NULL;
    while( aCodecs.Next( codec ) )
        {
   	    TBool first = ETrue;
        // for all codec specific lines in the offer
        TBool found = EFalse;
    	for ( TInt j = 0; j < formatLines.Count(); j++ )
    		{
    		CSdpFmtAttributeField* formatLine = formatLines[ j ];
    		if ( formatLine->Attribute() == 
    		            SDP_STRING( SdpCodecStringConstants::EAttributeFmtp ) )
    			{
    			TUint payloadType = ConvertDesToUintL( formatLine->Format() );
				if ( codec->iPayloadType == payloadType )
				    {
                    MCEMM_DEBUG_SVALUE("decoding format", formatLine->Format() )
					const TDesC8& fmtpValue = formatLine->Value();
                    MCEMM_DEBUG_SVALUE("decoding fmtp", fmtpValue )
                    found = ETrue;
                    TBool isAnswerer( aRole == EMceRoleAnswerer );
					if ( first )
					    {
					    codec->SetFmtpFromIncomingSdpL( 
					                fmtpValue, isAnswerer, KMceCodecFmtpReset );
					    first = EFalse;
					    }
                    else
                        {
        				codec->SetFmtpFromIncomingSdpL( 
        				            fmtpValue, isAnswerer, KMceCodecFmtpAppend );
                        }
				    }
    			}
    		}
    	if ( !found )
        	{
            // No fmtp line found, use default values
            codec->SetDefaultFmtpAttributeL();
            }
        MCEMM_DEBUG_SVALUE("decoded fmtp", *codec->iFmtpAttr )         
        }
   	    
    MCEMM_DEBUG("CMceMediaSdpCodec::DecodeFmtpLinesL(), Exit ")
    }

// -----------------------------------------------------------------------------
// CMceMediaSdpCodec::EncodeFmtpAttributeL
// -----------------------------------------------------------------------------
//
void CMceMediaSdpCodec::EncodeFmtpAttributeL( 
    CMceComCodec& aCodec,
    CSdpMediaField& aMedia ) const
    {
    MCEMM_DEBUG("CMceMediaSdpCodec::EncodeFmtpAttributeL(), Entry ")
    
    RStringF attributeFmtp = 
        SDP_STRING( SdpCodecStringConstants::EAttributeFmtp );
    
    if( aCodec.iFmtpAttr && aCodec.iFmtpAttr->Size() != 0 )
        {
        MCE_DEFINE_DECSTR( payload, aCodec.iPayloadType )

        HBufC8* fmtpAttr = aCodec.FtmpForOutgoingSdpLC();
        CSdpFmtAttributeField* fmtpLine = 
            CSdpFmtAttributeField::NewL( attributeFmtp, payload, *fmtpAttr );
        CleanupStack::PopAndDestroy( fmtpAttr );
        CleanupStack::PushL( fmtpLine );                         
        aMedia.FormatAttributeFields().AppendL( fmtpLine );
        CleanupStack::Pop( fmtpLine );
        
        MCEMM_DEBUG_SVALUE( "encoded fmtp", fmtpLine->Value() )
        }
        
    MCEMM_DEBUG("CMceMediaSdpCodec::EncodeFmtpAttributeL(), Exit ")
    }
        
// -----------------------------------------------------------------------------
// CMceMediaSdpCodec::CreateFormatListL
// Creates fmtlist that can be used as media field fmt list -attribute
// (other items were commented in a header).
// Status : Draft 
// -----------------------------------------------------------------------------
//
HBufC8* CMceMediaSdpCodec::CreateFormatListL( 
    CMceComCodec::TIterator& aCodecs ) const
    {
    MCEMM_DEBUG("CMceMediaSdpCodec::CreateFmtListL(), Entry ")
    
    HBufC8* fmtList = HBufC8::NewLC( KMceSdpFormatListLength );
    TPtr8 fmtListPtr( fmtList->Des() );

    CMceComCodec* codec = NULL;
    for ( TInt count = 0; count <= aCodecs.Count()-1; count++ )
    	{
    	aCodecs.Next( codec );
    	MCE_DEFINE_DECSTR( payload, codec->iPayloadType )
    	fmtListPtr.Append( payload );
       	if ( count != aCodecs.Count()-1)
       		{
       		fmtListPtr.Append( KMceSipBlank );
       		}
    	}
    
    CleanupStack::Pop( fmtList );
    
    MCEMM_DEBUG("CMceMediaSdpCodec::CreateFmtListL(), Exit ")
    
    return fmtList;
    }

// -----------------------------------------------------------------------------
// CMceMediaSdpCodec::DecodeFormatListL
// -----------------------------------------------------------------------------
//
void CMceMediaSdpCodec::DecodeFormatListL( 
    CSdpMediaField& aMedia, 
    RArray<TUint>& aPayloadTypes ) const
    {
    MCEMM_DEBUG("CMceMediaSdpCodec::DecodeFormatListL(), Entry ")
    
    User::LeaveIfError( DecodeFormatList( aMedia, aPayloadTypes ) );
        
    MCEMM_DEBUG("CMceMediaSdpCodec::DecodeFormatListL(), Exit ")   
    }

// -----------------------------------------------------------------------------
// CMceMediaSdpCodec::DecodeFormatList
// -----------------------------------------------------------------------------
//
TInt CMceMediaSdpCodec::DecodeFormatList( 
    CSdpMediaField& aMedia, 
    RArray<TUint>& aPayloadTypes ) const
    {
    MCEMM_DEBUG("CMceMediaSdpCodec::DecodeFormatList(), Entry ")
    
    TInt index = 0;
    const TDesC8& payloadlist = aMedia.FormatList();
    MCEMM_DEBUG_SVALUE( "decoded format list", payloadlist )
    TLex8 payloads( payloadlist );
    TInt error = KErrNone;
    
    while( error == KErrNone && !payloads.Eos() && index < KMceMaxPayloadTypes )
        {
        TPtrC8 payload = payloads.NextToken();
        TUint convertedUnit = 0;
        TLex8 lexConv( payload );
        TInt err = lexConv.Val( convertedUnit, EDecimal );
        if( err != KErrNone )
        	{
        	error = err;
        	break;
        	}
        error = aPayloadTypes.Append( convertedUnit );
        index++;
        }

    MCEMM_DEBUG("CMceMediaSdpCodec::DecodeFormatList(), Exit ")
    
    return error;
    }
    
// -----------------------------------------------------------------------------
// CMceMediaSdpCodec::DecodeRemoteRtcpFieldL
//
// a=rtcp:53020 IN IP4 126.16.64.4
// -----------------------------------------------------------------------------
//
void CMceMediaSdpCodec::DecodeRemoteRtcpFieldL( 
    CSdpMediaField& aMediaLine, 
    CMceComMediaStream& aStream ) const
    {   
    MCEMM_DEBUG( "CMceMediaSdpCodec::ParseRemoteRtcpFieldL(), Entry" )

    RStringF rtcpAttributeName = iStringPool.OpenFStringL( KMceSdpAttrRtcp );
    CleanupClosePushL( rtcpAttributeName );
    _LIT8( KMatchIN,"*IN*" );       
    _LIT8( KMatchIp,"*IP*" );
    
    RPointerArray<CSdpAttributeField>& attrfields = 
        aMediaLine.AttributeFields();
    
    for ( TInt i = 0; i < attrfields.Count(); i++ )
        {
        CSdpAttributeField* attribute = attrfields[i];        
        if ( attribute->Attribute() == rtcpAttributeName ) 
            {
            const TDesC8& value = attribute->Value();
            TUint rtcpPort( 0 );
            
            if ( value.Match( KMatchIN ) != KErrNotFound )
                {
                // found remote IP4 RTCP address
                const TUint8 KAddrOffsetFromNetType = 4;
                TInt addr_offset = 
                    value.Match( KMatchIp ) + KAddrOffsetFromNetType;
                TPtrC8 remoteRtcpAddr = value.Mid( addr_offset );
                
                const TUint8 KPortOffsetFromIP = 1;
                TInt port_offset = 
                    value.Match( KMatchIN ) - KPortOffsetFromIP;
                TPtrC8 remoteRtcpPort = value.Left( port_offset );
                
                TLex8 lexPT( remoteRtcpPort );
                User::LeaveIfError( lexPT.Val( rtcpPort, EDecimal ) );
                // copy the address into correct format
                TBuf16 <KMaxAddressLength> input;
                input.Copy( remoteRtcpAddr );      
                
                MCEMM_DEBUG_SVALUE( "Found RTCP address", input )
                
                aStream.SetRemoteRtcpMediaAddrL( input );
                }
            else
                {
                // only port present
                TLex8 lexPT( value );
                User::LeaveIfError ( lexPT.Val( rtcpPort, EDecimal ) );
                }

			aStream.SetRemoteRtcpMediaPort( rtcpPort );
            
            MCEMM_DEBUG_DVALUE( "RTCP Port", rtcpPort )
            }
        }
    
    CleanupStack::PopAndDestroy( &rtcpAttributeName );
      
    MCEMM_DEBUG( "CMceMediaSdpCodec::ParseRemoteRtcpFieldL(), Exit" )    
    }
    
// -----------------------------------------------------------------------------
// CMceMediaSdpCodec::EncodelocalRtcpAttrL
//
// a=rtcp:53020 IN IP4 126.16.64.4
// -----------------------------------------------------------------------------
//
void CMceMediaSdpCodec::EncodelocalRtcpAttrL( 
    CSdpMediaField& aMediaLine, 
    CMceComMediaStream& aStream ) const
    {   
    MCEMM_DEBUG("CMceMediaSdpCodec::EncodelocalRtcpAttrL, Entry ")
    if ( aStream.Session() && aStream.Session()->UseRtcp() )
		{
		MCEMM_DEBUG("RTCP attribute to be added")
    	TBuf8<KMceSdpMaxMediaLineLength> rtcpAttrValue;
		rtcpAttrValue.Num( aStream.iLocalMediaPort + 1, EDecimal );
		 if ( !aStream.Session()->iLocalIpAddress.IsUnspecified() )
			{
			CSdpConnectionField* connectionField = 
			    CSdpConnectionField::NewL( aStream.Session()->iLocalIpAddress );
			CleanupStack::PushL( connectionField );
			rtcpAttrValue.Append( KMceSdpSpace );   
		    rtcpAttrValue.Append( connectionField->NetType().DesC() );  
		    rtcpAttrValue.Append( KMceSdpSpace );        
		 	rtcpAttrValue.Append( connectionField->AddressType().DesC() );
		 	rtcpAttrValue.Append( KMceSdpSpace );      
		 	rtcpAttrValue.Append( connectionField->Address() );
		 	CleanupStack::PopAndDestroy( connectionField );
			}
		RStringF attributeRtcp = 
            SdpCodecStringPool::StringPoolL().OpenFStringL( KMceSdpAttrRtcp );
		CleanupClosePushL( attributeRtcp );

		CSdpAttributeField* rtcpLine = 
		            CSdpAttributeField::NewLC( attributeRtcp, rtcpAttrValue );
		        
		MCEMM_DEBUG_SVALUE("encoded rtcpPort", aStream.iLocalMediaPort + 1 )

		aMediaLine.AttributeFields().AppendL( rtcpLine );

		CleanupStack::Pop( rtcpLine ); 
		CleanupStack::PopAndDestroy( ); //attributeRtcp 
		}
    MCEMM_DEBUG("CMceMediaSdpCodec::EncodelocalRtcpAttrL, Exit ")    
    }    
    
// -----------------------------------------------------------------------------
// CMceMediaSdpCodec::CleanAttributes
// -----------------------------------------------------------------------------
//
void CMceMediaSdpCodec::CleanAttributes( CSdpMediaField& aMedia )
    {
    MCEMM_DEBUG("CMceMediaSdpCodec::CleanAttributes(), Entry ")
    
    //clean attributes
    aMedia.AttributeFields().ResetAndDestroy();
        
    //clean format attributes
    aMedia.FormatAttributeFields().ResetAndDestroy();
       
    aMedia.BandwidthFields().ResetAndDestroy();
    
    MCEMM_DEBUG("CMceMediaSdpCodec::CleanAttributes(), Exit ")
    }

// -----------------------------------------------------------------------------
// CMceMediaSdpCodec::DecodeSecureSessionL
// -----------------------------------------------------------------------------
//
void CMceMediaSdpCodec::DecodeSecureSessionL( 
    CSdpMediaField& aMediaLine,
    CMceComMediaStream& aStream, 
    TMceNegotiationRole aRole,
    TBool aUpdate )
    {
    
    CMceSecureMediaSession* secureSession = aStream.Session()->SecureSession();

    if ( aRole == EMceRoleAnswerer && !aUpdate )
        {
        aStream.Session()->SecureSessionL().DecodeSecureDesSdpOfferL( aStream, aMediaLine );
        if ( !aStream.Session()->iIsSecureSession )
            {
            aStream.Session()->DeleteSecureSession();
            }
        }
    else if ( secureSession && aRole == EMceRoleAnswerer && aUpdate )
        {
        // for long session
        if ( secureSession->iKeyNeedUpdated )
        	{
        	secureSession->DecodeSecureDesSdpUpdateL( aStream, aMediaLine ) ;
        	}
        }
    else if ( secureSession && aRole == EMceRoleOfferer )
        {
       	// for Long Session
        	//sendonly receive only sendandreceive
     	secureSession->DecodeSecureDesSdpAnswerL( aStream, aMediaLine ) ;
       	}        
    }

// -----------------------------------------------------------------------------
// CMceMediaSdpCodec::EncodeSecureSessionL
// -----------------------------------------------------------------------------
//
void CMceMediaSdpCodec::EncodeSecureSessionL( 
    CMceComMediaStream& aStream, 
    CSdpMediaField& aMediaLine,
    TMceNegotiationRole aRole )
    {
    CMceSecureMediaSession* secureSession = aStream.Session()->SecureSession();

    if ( secureSession )
        {
        if ( aRole == EMceRoleOfferer )
            {
            secureSession->EncodeSecureDesSdpOfferL( aStream, aMediaLine );
            }
        else
            {
            secureSession->EncodeSecureDesSdpAnswerL( aStream, aMediaLine );
            }
        }
    }

// -----------------------------------------------------------------------------
// CMceMediaSdpCodec::DecodeDirectionL
// -----------------------------------------------------------------------------
//
void CMceMediaSdpCodec::DecodeDirectionL( CSdpMediaField& aMediaLine,
                                          CMceComMediaStream& aStream,
                                          CSdpDocument& aSdpDocument,
                                          TMceNegotiationRole aRole ) const
	{
    MCEMM_DEBUG("CMceMediaSdpCodec::DecodeDirectionL(), Entry ")

    TInt rmt_direction = 
        Direction( aMediaLine, aSdpDocument.AttributeFields() );
    TInt loc_direction = aStream.Direction();
    
    CSdpConnectionField* connectionField = aSdpDocument.ConnectionField();
    
    CMceSdpSession& sSession = aStream.Session()->SdpSession();
        
    CSdpConnectionField* nullAddress =
        CSdpConnectionField::DecodeL( KMceSipNullAddressA );
    				 
    CleanupStack::PushL( nullAddress );

    TUint oldSchool = sSession.iOOldSchool;
    TBool isNullAddress = EFalse;
    if ( connectionField )
        {
        isNullAddress = (connectionField->Address() == nullAddress->Address());
        }

    CleanupStack::PopAndDestroy( nullAddress );

    //trying to guess other party direction if have got no direction
    if ( rmt_direction == KErrNotFound || 
         ( rmt_direction == SdpCodecStringConstants::EAttributeSendonly && 
           loc_direction == SdpCodecStringConstants::EAttributeSendonly ) )
    
	    {
	    if ( aRole == EMceRoleOfferer )
	      	{
	   		// did we try old school hold?
	    	if ( oldSchool )           
	      	    {
	      	    if ( !isNullAddress )
	      	      	{
	      	  		// ignore that other party didn't understand us
	      	        // and full cancel of old school process
	         	    sSession.iOOldSchool = 0;
	            	sSession.iOOldSchoolProceeding = 0;
	                sSession.iOOldSchoolCompleted = 0;
	      	      	}
	       		
	       		rmt_direction = SdpCodecStringConstants::EAttributeRecvonly;
	       		oldSchool = 0;
	      	    }    
            else  //  didn't try old school yet
                {
                if ( isNullAddress )
                    {
                    // assuming that other party wanna put us on hold
	                rmt_direction = SdpCodecStringConstants::EAttributeSendonly; 
                    }
	            else if ( loc_direction == 
	                          SdpCodecStringConstants::EAttributeSendonly &&
	               		  aStream.Session()->Modifier( KMceMediaDirection ) ==
	              			  KMceMediaDirectionWithAddress )
                    {
                    // failed to put other party on hold, trying old school
                    sSession.iOOldSchool = 1;    
                    User::Leave( KMceErrOldSchool );
                    }
                else
                    {
                    // NOP
                    }
                }
	      	}
        else // answerer
            {
            if ( isNullAddress )
                {
                // other party puts us on hold
                rmt_direction = SdpCodecStringConstants::EAttributeSendonly;
                sSession.iIOldSchool = 1;
                oldSchool = sSession.iIOldSchool;
                }
	        else
	            {
	            rmt_direction = SdpCodecStringConstants::EAttributeSendrecv;
	            }   	
            }
	    }

    sSession.iIOldSchool = oldSchool;

	// if unable to determine other party direction then just ignore that
    if ( rmt_direction != KErrNotFound )
        {
    	// now checking for permitted directions
    	// inverse direction
        TInt inv_dir = rmt_direction;
        switch (inv_dir)
        	{
          	case SdpCodecStringConstants::EAttributeRecvonly: 
          		{
          		inv_dir=SdpCodecStringConstants::EAttributeSendonly; 
          		break;		
          		}      
          	case SdpCodecStringConstants::EAttributeSendonly: 
          		{
          		inv_dir=SdpCodecStringConstants::EAttributeRecvonly; 
          		break;		
          		}
          	default:
          		{
          		break;		
          		}
        	}

		// all directions are permitted for answerer and 
		// inactive is always accepted
    	if ( aRole == EMceRoleOfferer && 
    	     rmt_direction != SdpCodecStringConstants::EAttributeInactive )
    		{
    		// other party has incompatible direction. terminate session.
           	if ( loc_direction != SdpCodecStringConstants::EAttributeSendrecv 
           	     && 
           	     loc_direction != inv_dir )
           	    {
           	    User::Leave( KErrArgument );
           	    }
    		}

    	if ( loc_direction != inv_dir )
    	    {
    	    aStream.SetDirection( rmt_direction, KMceNoEndpointAdjustment );
    	    }
    	}

    MCEMM_DEBUG_SVALUE("decoded direction", 
    					SDP_STRING( aStream.Direction() ).DesC() )
    MCEMM_DEBUG("CMceMediaSdpCodec::DecodeDirectionL(), Exit ")
 	}

// -----------------------------------------------------------------------------
// CMceMediaSdpCodec::UpdateDirectionL
// -----------------------------------------------------------------------------
//
    
void CMceMediaSdpCodec::UpdateDirectionL( 
    CSdpMediaField& aMediaLine, 
    CMceComMediaStream& aStream,
    CSdpDocument& aSdpDocument ) const
	{
    TInt direction = Direction( aMediaLine, aSdpDocument.AttributeFields() );
    CSdpConnectionField* connectionField = aSdpDocument.ConnectionField();
    if ( connectionField == NULL )
        {
    	connectionField = ( aMediaLine.ConnectionFields()[0] )	;
    	}

    if ( connectionField->Address() == KMceSipNullAddress )	
        {
        direction = SdpCodecStringConstants::EAttributeSendonly;    
        }
    UpdateStreamL( aStream, direction );
    aStream.SetDirection( direction, KMceNoEndpointAdjustment );
	}

// -----------------------------------------------------------------------------
// CMceMediaSdpCodec::EncodeDirectionL
// -----------------------------------------------------------------------------
//
void CMceMediaSdpCodec::EncodeDirectionL( 
    CMceComMediaStream& aStream, 
    CSdpMediaField& aMedia,
    CSdpDocument& aSdpDocument,
    TMceNegotiationRole aRole ) const
    {
    MCEMM_DEBUG("CMceMediaSdpCodec::EncodeDirectionL(), Entry ")
        
    CMceSdpSession& sSession = aStream.Session()->SdpSession();

    if ( aRole == EMceRoleOfferer && 
    	 sSession.iOOldSchool &&  
    	 aStream.Direction() != SdpCodecStringConstants::EAttributeSendrecv )
    	     	 
        {
        CSdpConnectionField* connField = 
            CSdpConnectionField::DecodeL( KMceSipNullAddressA );
        aSdpDocument.SetConnectionField( connField );
        MCEMM_DEBUG("using old school")
        }
    
    else
        {
        RStringF direction = SDP_STRING( aStream.Direction() );

        CSdpAttributeField* mediaAttr = 
            CSdpAttributeField::NewLC( direction, KNullDesC8 );
            
        MCEMM_DEBUG_SVALUE("encoded direction", mediaAttr->Attribute().DesC() )
            
        aMedia.AttributeFields().AppendL( mediaAttr );
        CleanupStack::Pop( mediaAttr );
        }
    
    MCEMM_DEBUG("CMceMediaSdpCodec::EncodeDirectionL(), Exit ")
    }
    
// -----------------------------------------------------------------------------
// CMceMediaSdpCodec::EncodePreconditionsL
// -----------------------------------------------------------------------------
//
void CMceMediaSdpCodec::EncodePreconditionsL( 
    CMceComMediaStream& aStream,
    CSdpMediaField& aMediaLine,
    TMceNegotiationRole aRole ) const
    {
    CMceSecureMediaSession* secureSession = aStream.Session()->SecureSession();

    if ( aStream.Session()->Modifier( KMcePreconditions ) == KMcePreconditionsSupported &&
            !secureSession)
        {
        if ( ( aRole == EMceRoleOfferer && 
               aStream.Session()->iUseLocalPreconditions ) ||
             ( aRole == EMceRoleAnswerer && 
               aStream.Session()->iUseRemotePreconditions ) )
            {
             TMcePreconditions* precondition = aStream.PreconditionsL( KMcePreconditions );
             if ( precondition )
	        	{
	        	precondition->EncodeL( aMediaLine );
	        	}
            }
        }
  	if ( aStream.Session()->Modifier( KMceSecPreconditions ) == KMcePreconditionsE2ESupported )
        {
        TMcePreconditions* precondition = aStream.PreconditionsL( KMceSecPreconditions );
        if ( precondition )
        	{
        	precondition->EncodeL( aMediaLine );
        	}
        }    
    }

// -----------------------------------------------------------------------------
// CMceMediaSdpCodec::DecodePreconditionsL
// -----------------------------------------------------------------------------
//
TMceSipWarningCode CMceMediaSdpCodec::DecodePreconditionsL( 
    CSdpMediaField& aMediaLine,
    CMceComMediaStream& aStream,
    TMceNegotiationRole aRole ) const
    {
	MCEMM_DEBUG("CMceMediaSdpCodec::DecodePreconditionsL EntryL")
	TMceSipWarningCode warning = KErrNone;
	
    if ( aStream.Session()->Modifier( KMcePreconditions ) == KMcePreconditionsSupported  )
    	{
    	if ( ( aRole == EMceRoleOfferer && 
               aStream.Session()->iUseLocalPreconditions ) ||
             ( aRole == EMceRoleAnswerer && 
               aStream.Session()->iUseRemotePreconditions )  )
    		{
    		aStream.PreconditionsL( KMcePreconditions )->DecodeL( aMediaLine );	
    		
	        }
        }   
	if ((aRole == EMceRoleOfferer && 
     	aStream.Session()->iClientCryptoSuites.Count()
     	&& aStream.Session()->Modifier( KMceSecPreconditions ) 
     	== KMcePreconditionsE2ESupported )
     	|| ( aRole ==EMceRoleAnswerer && (
     		aStream.Session()->iRemoteSecPreconditionsRequired ||
     		 aStream.Session()->iClientCryptoSuites.Count() )))
      
     	{
		TMcePreconditions* precondition = 
			aStream.PreconditionsL( KMceSecPreconditions, &aMediaLine );
	
    	if ( !precondition )
    		{
    		return KErrNone;
    		}
    	if ( warning && aStream.Preconditions().Count() )
    		{
    			//normal segmented precondition cases
    		aStream.Session()->iRemoteSecPreconditionsRequired = EFalse;
    		aStream.Session()->Modifier( KMceSecPreconditions ) = 
    			KMcePreconditionsNotUsed;
    		MCEMM_DEBUG("Secure preconds not used")	
    		MCEMM_DEBUG("CMceMediaSdpCodec::DecodePreconditionsL Exit")	
    		return KErrNone;
    		}
    
    	if ( !precondition->IsMet() )
    		{
    		MCEMM_DEBUG("Decode Secure Precondition")	
    		warning = precondition->DecodeL( aMediaLine );	
    		}
    	warning = warning == KMceSipPreconditionFailure ? 
     			warning : KErrNone;
     	MCEMM_DEBUG_DVALUE ("Decode Secure Precondition warning", warning ) 
     	}        
   	MCEMM_DEBUG("CMceMediaSdpCodec::DecodePreconditionsL Exit")	
	return warning;
    }

// -----------------------------------------------------------------------------
// CMceMediaSdpCodec::EncodeClientAttributesL
// -----------------------------------------------------------------------------
//
void CMceMediaSdpCodec::EncodeClientAttributesL( 
    CMceComMediaStream& aStream,
    CSdpMediaField& aMediaLine ) const
    {
    MCEMM_DEBUG("CMceMediaSdpCodec::EncodeClientAttributesL, Entry" )
    
    CDesC8Array* clientAttributes = aStream.iLocalMediaSDPLines;
    __ASSERT_ALWAYS( clientAttributes, User::Leave( KErrArgument ) );

    CMceSdpCodec::EncodeClientSdpFieldsL<CSdpMediaField>( *clientAttributes, aMediaLine );
    
        
    MCEMM_DEBUG("CMceMediaSdpCodec::EncodeClientAttributesL, Exit" )
    }    

// -----------------------------------------------------------------------------
// CMceMediaSdpCodec::DecodeClientAttributesL
// -----------------------------------------------------------------------------
//
void CMceMediaSdpCodec::DecodeClientAttributesL( 
    CSdpMediaField& aMediaLine, 
    CMceComMediaStream& aStream ) const
    {
    MCEMM_DEBUG("CMceMediaSdpCodec::DecodeClientAttributesL, Entry" )
    CDesC8Array* remoteAttributes = 
        new (ELeave) CDesC8ArrayFlat( KMceArrayGranularity );
    CleanupStack::PushL( remoteAttributes );
    CBufFlat* encodeBuf = NULL;
    
    for ( TInt i = 0; i < aMediaLine.AttributeFields().Count(); i++ )
        {
    	encodeBuf = CBufFlat::NewL( KMceExternalizeBufferExpandSize );
    	CleanupStack::PushL( encodeBuf );
    	RBufWriteStream writeStream( *encodeBuf, 0 );
	    writeStream.PushL();
        
        aMediaLine.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 < aMediaLine.BandwidthFields().Count(); i++ )
        {
        
    	encodeBuf = CBufFlat::NewL( KMceExternalizeBufferExpandSize );
    	CleanupStack::PushL( encodeBuf );
    	RBufWriteStream writeStream( *encodeBuf, 0 );
	    writeStream.PushL();
        
        aMediaLine.BandwidthFields()[ i ]->EncodeL( writeStream );
        MCEMM_DEBUG_SVALUE("found attribute", encodeBuf->Ptr( 0 ) )
        remoteAttributes->AppendL( encodeBuf->Ptr( 0 ) );
    	
    	CleanupStack::PopAndDestroy(); // writeStream
        CleanupStack::PopAndDestroy( encodeBuf ); // encodeBuf
        }
        
    if ( aStream.BoundStream() )
        {
        MCEMM_DEBUG("copy attributes to bound stream" )
        // copy attributes to bound stream
        CMceComMediaStream& boundStream = aStream.BoundStreamL();
        CDesC8Array* copyAttributes = 
            new (ELeave) CDesC8ArrayFlat( KMceArrayGranularity );
        CleanupStack::PushL( copyAttributes );
        for ( TInt i = 0; i < remoteAttributes->MdcaCount(); i++ )
            {
            copyAttributes->AppendL( remoteAttributes->MdcaPoint( i ) );
            }
        CleanupStack::Pop( copyAttributes );
        MCE_DELETE( boundStream.iRemoteMediaSDPLines );
        boundStream.iRemoteMediaSDPLines = copyAttributes;
        }
        
    CleanupStack::Pop( remoteAttributes );
    MCE_DELETE( aStream.iRemoteMediaSDPLines );
    aStream.iRemoteMediaSDPLines = remoteAttributes;
    MCEMM_DEBUG("CMceMediaSdpCodec::DecodeClientAttributesL, Exit" )
    }

// -----------------------------------------------------------------------------
// CMceMediaSdpCodec::ValidateSdp
// -----------------------------------------------------------------------------
//
TMceSipWarningCode CMceMediaSdpCodec::ValidateSdpL( 
    CSdpMediaField& aMediaLine,
    CSdpDocument& /*aSdpDocument*/ )
    {
    TMceSipWarningCode warning = KErrNone;
    RArray<TUint> payloadTypes;
    TInt error = KErrNone;
    RPointerArray< CSdpFmtAttributeField >& formatLines =  
                                            aMediaLine.FormatAttributeFields();

    TInt dynamicPayloadsCount = 0;
    TInt rtpmapCount = 0;
    
    error = DecodeFormatList( aMediaLine, payloadTypes );
    
    User::LeaveIfError( error );
    
    if ( error == KErrNone )
        {
        TInt index = 0;
        while( index < payloadTypes.Count() )
            {
            dynamicPayloadsCount = payloadTypes[ index++ ] >= KMinDynamicPT ?
                                   dynamicPayloadsCount + 1 : dynamicPayloadsCount;
            }
        index = 0;
        while( index < formatLines.Count() )
            {
            rtpmapCount = formatLines[ index++ ]->Attribute() == 
                                SDP_STRING( SdpCodecStringConstants::EAttributeRtpmap ) ?
                          rtpmapCount + 1 : rtpmapCount;
            }
        
        if ( dynamicPayloadsCount > 0 && rtpmapCount == 0 )
            {
            warning = KMceSipBadRequest;
            }
        }
    else
        {
        warning = KMceSipServerInternalError;
        }
    
    payloadTypes.Close();
    
    return warning;
    }

// -----------------------------------------------------------------------------
// CMceMediaSdpCodec::DecodePayloadsL
// -----------------------------------------------------------------------------
//
TInt CMceMediaSdpCodec::DecodePayloadsL( 
    CSdpMediaField& aMediaLine,
    CMceComMediaStream& aStream,
    TMceNegotiationRole aRole ) const
    {
    TInt decoded( 0 );
    
    RArray<TUint> payloadTypes;
    CleanupClosePushL( payloadTypes );
    
    if ( aRole == EMceRoleAnswerer )
        {
        decoded = DecodeRtpmapLinesL( aMediaLine, aStream, EMceRoleAnswerer );
        decoded += DecodeStaticPayloadsL( aMediaLine, aStream, payloadTypes, EMceRoleAnswerer );
        }
    else
        { 
        // static payloads are decoded first if role is offerer
        decoded = DecodeStaticPayloadsL( aMediaLine, aStream, payloadTypes, EMceRoleOfferer );
        decoded += DecodeRtpmapLinesL( aMediaLine, aStream, EMceRoleOfferer );
        }
        
    UpdateSdpCodecIndexesL( aStream, payloadTypes );
    CleanupStack::PopAndDestroy( &payloadTypes );
    
    return decoded;
    }
    
// -----------------------------------------------------------------------------
// CMceMediaSdpCodec::UpdateSdpCodecIndexesL
// -----------------------------------------------------------------------------
//
void CMceMediaSdpCodec::UpdateSdpCodecIndexesL( 
    CMceComMediaStream& aStream,
    RArray<TUint>& aPayloadTypes ) const
    {
    TInt index( 0 );
    TInt codecSdpIndex( 0 );
    while( index < aPayloadTypes.Count() )
        {
        TUint payload = aPayloadTypes[ index++ ];
        CMceComCodec* codec = FindCodec( payload, aStream );
        if ( codec )
            {
            codec->iCodecSdpIndex = codecSdpIndex++;
            }  
        }
    }

// -----------------------------------------------------------------------------
// CMceMediaSdpCodec::GetCorrespondingFmtpLineL
// -----------------------------------------------------------------------------
//
TPtrC8 CMceMediaSdpCodec::GetCorrespondingFmtpLineL( 
    CSdpMediaField& aMediaLine, 
    CSdpFmtAttributeField& aRtpMapFormatLine ) const
    {
    const TDesC8& payloadTypeInRtpMap = aRtpMapFormatLine.Format();
    TUint rtpMapPT = ConvertDesToUintL( payloadTypeInRtpMap );
    
    RPointerArray< CSdpFmtAttributeField >& formatLines =  
        aMediaLine.FormatAttributeFields();
    
    TPtrC8 fmtp( KNullDesC8() );
    TBool found( EFalse );
    for ( TInt j = 0; j < formatLines.Count() && !found; j++ )
    	{
    	CSdpFmtAttributeField* formatLine = formatLines[ j ];
    	if ( formatLine->Attribute() == 
    	            SDP_STRING( SdpCodecStringConstants::EAttributeFmtp ) )
    		{
    		TUint fmtpPT = ConvertDesToUintL( formatLine->Format() );
    		if ( rtpMapPT == fmtpPT )
    		    {
    		    fmtp.Set( formatLine->Value() );
    		    found = ETrue;
    		    }
    		}
    	}
    return fmtp;
    }
    
// End of file
