Symbian
Symbian OS Library

SYMBIAN OS V9.3

[Index] [Spacer] [Previous] [Next]



Example showing use of the SIP SDP Codec API

The following code fragments show how to create an SDP description with mandatory fields.

1

Create the CSdpDocument object. This includes all SDP fields in structural format:

CSdpDocument* sdpDocument = CSdpDocument::NewLC();

2

Define the session name field for the SDP description:

sdpDocument->SetSessionNameL(_L8("SipSession"));

3

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);

4

You must open the String Pool before you can use it. All predefined SDP constants are in the string table, which can be accessed through the string pool. Once you have finished with the SDP description, the String Pool must be closed.

SdpCodecStringPool::OpenL();
RStringPool pool = SdpCodecStringPool::StringPoolL();

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 );

5

Create the connection field and set into the SDP description:

_LIT8( KAddress, "10.47.16.5" );
CSdpConnectionField* connectionfield = CSdpConnectionField::NewL( netType, addressTypeIP4, KAddress );
sdpDocument->SetConnectionField(connectionfield);

6

Define the session part attribute for the SDP description. Because 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();

7

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

8

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

9

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

10

Close the String Pool, remove and delete the CSdpDocument object from the cleanup stack:

SdpCodecStringPool::Close();
CleanupStack::PopAndDestroy(); //sdpDocument

11

The SDP description created in the example above 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