The following sections explain how to create an SDP description with the required fields.
Open the String Pool
Access the predefined SDP constants in the string table
Close the String Pool after you finish with the SDP description
SdpCodecStringPool::OpenL(); RStringPool pool = SdpCodecStringPool::StringPoolL();
The following code snippet shows how to create the CSdpDocument object. This includes all SDP fields in the structural format:
CSdpDocument* sdpDocument = CSdpDocument::NewLC();
The following code snippet shows how to define the session name field for the SDP description:
sdpDocument->SetSessionNameL(_L8("SipSession"));
The following code snippet shows how to create an instance of the Origin field class and set into the SDP description:
TInt64 sessionId( TUint( 2890844526 ) ); TInt64 sessionVersion( TUint( 2890842807 ) ); TInetAddr address; const TUint32 KInetAddr = INET_ADDR(10,47,16,5); address.SetAddress( KInetAddr ); CSdpOriginField* originfield = CSdpOriginField::NewL(_L8("username"), sessionId, sessionversion, address); sdpDocument->SetOriginField(originfield);
The following code snippet shows how to fetch the predefined network type and the address type for the connection field from the String Pool:
RStringF netType = pool.StringF( SdpCodecStringConstants::ENetType, SdpCodecStringConstants::Table );RStringF addressTypeIP4 = pool.StringF( SdpCodecStringConstants::EAddressTypeIP4, SdpCodecStringConstants::Table );
The following code snippet shows how to create the connection field and set the SDP parameters of the SIP message into the SDP description:
_LIT8( KAddress, "10.47.16.5" ); CSdpConnectionField* connectionfield = CSdpConnectionField::NewL( netType, addressTypeIP4, KAddress ); sdpDocument->SetConnectionField(connectionfield);
The following code snippet shows how to define the session part attribute for the SDP description. The direction-attribute is not one of the predefined attributes in the string table, it must be defined dynamically to the String Pool.
_LIT8(KSDPAttributeDirectionBoth,"both"); RStringF modifier = pool.OpenFStringL(_L8("direction")); CleanupClosePushL(modifier); CSdpAttributeField* attrField = CSdpAttributeField::NewL(modifier, KSDPAttributeDirectionBoth); User::LeaveIfError((sdpDocument->AttributeFields()).Append(attrField)); CleanupStack::PopAndDestroy();
The following code snippet shows how to create the first media field:
RStringF mediaVideo = pool.StringF( SdpCodecStringConstants::EMediaVideo, SdpCodecStringPool::StringTableL()); RStringF protocol = pool.StringF(SdpCodecStringConstants::EProtocolRtpAvp, SdpCodecStringPool::StringTableL()); CSdpMediaField* media1 = CSdpMediaField::NewLC(mediaVideo, 49152, protocol, _L8("96"));
Add the sendonly attribute (“a=sendonly”) to the first media field:
RStringF sendonlyAttr = iPool.StringF( SdpCodecStringConstants:: EAttributeSendonly, SdpCodecStringPool::StringTableL() ); CSdpAttributeField* attr1 = CSdpAttributeField::NewLC(sendonlyAttr, _L8("")); User::LeaveIfError((media1->AttributeFields()).Append(attr1)); CleanupStack::Pop(); //attr1
Add the rtpmap attribute (“a=rtpmap:96 H263-2000/90000”) to the first media field and then add the rtpmap specific attribute (“a=ptime:15”):
_LIT8( KEncodingName, "H263-2000" ); _LIT8( KClockRate, "90000" ); _LIT8( KEncodingParam, "" ); TSdpRtpmapValue rtpmapValue( KEncodingName(), KClockRate(), KEncodingParam() ); HBufC8* rtpmapBuf = rtpmapValue.EncodeL(); CleanupStack::PushL(rtpmapBuf); RStringF rtpmapStr = pool.StringF( SdpCodecStringConstants::EAttributeRtpmap, SdpCodecStringPool::StringTableL() ); CSdpFmtAttributeField* rtpmapAttribute = CSdpFmtAttributeField::NewLC(rtpmapStr, _L8("96"), *rtpmapBuf); User::LeaveIfError(media1->FormatAttributeFields().Append (rtpmapAttribute)); CleanupStack::Pop(); // rtpmapAttribute CleanupStack::PopAndDestroy(); // rtpmapBuf // add a rtpmap specific attribute RStringF ptimeAttrStr = iPool.StringF( SdpCodecStringConstants:: EAttributePtime, SdpCodecStringPool::StringTableL() ); CSdpAttributeField* ptimeAttr = CSdpAttributeField::NewLC(ptimeAttrStr, _L8("15")); ptimeAttr->AssignTo(*(media1->FormatAttributeFields())[0]); User::LeaveIfError(media1->AttributeFields().Append(ptimeAttr)); CleanupStack::Pop(); //ptimeAttr
The following code snippet shows how to create the second media field:
RStringF mediaAudio = pool.StringF( SdpCodecStringConstants:: EMediaAudio, SdpCodecStringPool::StringTableL()); CSdpMediaField* media2 = CSdpMediaField::NewLC(mediaAudio, 57344, protocol, _L8("97"));
Create the sendonly attribute for the second media field:
CSdpAttributeField* attr2 = CSdpAttributeField::NewLC(sendonlyAttr, _L8("")); User::LeaveIfError((media2->AttributeFields()).Append(attr2)); CleanupStack::Pop();
Create the rtpmap attribute (“a=rtpmap:97 AMR/8000”) for the second media field:
_LIT8( KEncodingName1, "AMR" ); _LIT8( KClockRate1, "8000" ); TSdpRtpmapValue rtpmapValue1( KEncodingName1(), KClockRate1(), KEncodingParam() ); HBufC8* rtpmapBuf1 = rtpmapValue1.EncodeL(); CleanupStack::PushL(rtpmapBuf1); CSdpFmtAttributeField* rtpmapAttribute1 = CSdpFmtAttributeField::NewLC(rtpmapStr, _L8("97"), *rtpmapBuf1); User::LeaveIfError(media2->FormatAttributeFields().Append (rtpmapAttribute1)); CleanupStack::Pop(); // rtpmapAttribute1 CleanupStack::PopAndDestroy(); //rtpmapBuf1
The following code snippet shows how to assign the media fields to the CSdpDocument object and then remove the buffers from the cleanup stack:
User::LeaveIfError(doc->MediaFields().Append(media1)); User::LeaveIfError(doc->MediaFields().Append(media2)); CleanupStack::Pop(); //media2 CleanupStack::Pop(); //media1
To close the String Pool the CSdpDocument object must be removed and deleted from the cleanup stack. The following code snippet shows how to remove and delete the CSdpDocument object from the cleanup stack and close the String Pool:
CleanupStack::PopAndDestroy(); //sdpDocument SdpCodecStringPool::Close();
The SDP description created in the preceding example has the following fields:
v=0 o=username 2890844526 2890842807 IN IP4 10.47.16.5 s=SipSession c=IN IP4 10.47.16.5 t=0 0 a=direction:both m=video 49152 RTP/AVP 96 a=sendonly a=rtpmap:96 H263-2000/90000 m=audio 57344 RTP/AVP 97 a=sendonly a=rtpmap:97 AMR/8000