📄 sdp.cxx
字号:
RTP_DataFrame::PayloadTypes pt = (RTP_DataFrame::PayloadTypes)str.Left(pos).AsUnsigned();
// find the format that matches the payload type
PINDEX fmt = 0;
while (formats[fmt].GetPayloadType() != pt) {
fmt++;
if (fmt >= formats.GetSize()) {
PTRACE(2, "SDP\tMedia attribute " << attr << " found for unknown RTP type " << pt);
return;
}
}
SDPMediaFormat & format = formats[fmt];
// extract the attribute argument
str = str.Mid(pos+1).Trim();
// handle rtpmap attribute
if (attr *= "rtpmap") {
PStringArray tokens = str.Tokenise('/');
if (tokens.GetSize() < 2) {
PTRACE(2, "SDP\tMalformed rtpmap attribute for " << pt);
return;
}
format.SetEncodingName(tokens[0]);
format.SetClockRate(tokens[1].AsUnsigned());
if (tokens.GetSize() > 2)
format.SetParameters(tokens[2]);
return;
}
// handle fmtp attributes
if (attr *= "fmtp") {
format.SetFMTP(str);
return;
}
// unknown attriutes
PTRACE(2, "SDP\tUnknown media attribute " << ostr);
return;
}
void SDPMediaDescription::PrintOn(const OpalTransportAddress & commonAddr, ostream & str) const
{
PIPSocket::Address commonIP;
commonAddr.GetIpAddress(commonIP);
PIPSocket::Address transportIP;
transportAddress.GetIpAddress(transportIP);
PString connectString;
if (commonIP != transportIP)
connectString = GetConnectAddressString(transportAddress);
PrintOn(str, connectString);
}
void SDPMediaDescription::PrintOn(ostream & str) const
{
PIPSocket::Address ip;
transportAddress.GetIpAddress(ip);
PrintOn(str, GetConnectAddressString(transportAddress));
}
void SDPMediaDescription::PrintOn(ostream & str, const PString & connectString) const
{
//
// if no media formats, then do not output the media header
// this avoids displaying an empty media header with no payload types
// when (for example) video has been disabled
//
if (formats.GetSize() == 0)
return;
PIPSocket::Address ip;
WORD port;
transportAddress.GetIpAndPort(ip, port);
// output media header
str << "m="
<< media << " "
<< port << " "
<< transport;
if (transport == SDP_MEDIA_TRANSPORT) {
// output RTP payload types
PINDEX i;
for (i = 0; i < formats.GetSize(); i++)
str << ' ' << (int)formats[i].GetPayloadType();
str << "\r\n";
// output attributes for each payload type
for (i = 0; i < formats.GetSize(); i++)
str << formats[i];
if (packetTime)
str << "a=ptime:" << packetTime << "\r\n";
// media format direction
switch (direction) {
case SDPMediaDescription::RecvOnly:
str << "a=recvonly" << "\r\n";
break;
case SDPMediaDescription::SendOnly:
str << "a=sendonly" << "\r\n";
break;
case SDPMediaDescription::SendRecv:
str << "a=sendrecv" << "\r\n";
break;
case SDPMediaDescription::Inactive:
str << "a=inactive" << "\r\n";
break;
default:
break;
}
}
else {
PINDEX i;
for (i = 0; i < formats.GetSize(); i++)
str << ' ' << formats[i].GetEncodingName();
str << "\r\n";
}
if (!connectString.IsEmpty())
str << "c=" << connectString << "\r\n";
}
OpalMediaFormatList SDPMediaDescription::GetMediaFormats(unsigned sessionID) const
{
OpalMediaFormatList list;
PINDEX i;
for (i = 0; i < formats.GetSize(); i++) {
OpalMediaFormat opalFormat = formats[i].GetMediaFormat();
if (opalFormat.IsEmpty())
PTRACE(2, "SIP\tRTP payload type " << formats[i].GetPayloadType() << " not matched to audio codec");
else {
if (opalFormat.GetDefaultSessionID() == sessionID) {
PTRACE(2, "SIP\tRTP payload type " << formats[i].GetPayloadType() << " matched to codec " << opalFormat);
list += opalFormat;
}
}
}
return list;
}
void SDPMediaDescription::CreateRTPMap(unsigned sessionID, RTP_DataFrame::PayloadMapType & map) const
{
OpalMediaFormatList list;
PINDEX i;
for (i = 0; i < formats.GetSize(); i++) {
OpalMediaFormat opalFormat = formats[i].GetMediaFormat();
if (!opalFormat.IsEmpty() &&
opalFormat.GetDefaultSessionID() == sessionID &&
opalFormat.GetPayloadType() != formats[i].GetPayloadType()) {
map.insert(RTP_DataFrame::PayloadMapType::value_type(opalFormat.GetPayloadType(), formats[i].GetPayloadType()));
PTRACE(2, "SIP\tAdding RTP translation from " << opalFormat.GetPayloadType() << " to " << formats[i].GetPayloadType());
}
}
}
void SDPMediaDescription::AddSDPMediaFormat(SDPMediaFormat * sdpMediaFormat)
{
formats.Append(sdpMediaFormat);
}
void SDPMediaDescription::AddMediaFormat(const OpalMediaFormat & mediaFormat, const RTP_DataFrame::PayloadMapType & map)
{
RTP_DataFrame::PayloadTypes payloadType = mediaFormat.GetPayloadType();
const char * encodingName = mediaFormat.GetEncodingName();
unsigned clockRate = mediaFormat.GetClockRate();
RTP_DataFrame::PayloadMapType payloadTypeMap = map;
if (payloadTypeMap.size() != 0) {
RTP_DataFrame::PayloadMapType::iterator r = payloadTypeMap.find(payloadType);
if (r != payloadTypeMap.end())
payloadType = r->second;
}
if (payloadType >= RTP_DataFrame::MaxPayloadType || encodingName == NULL || *encodingName == '\0')
return;
PINDEX i;
for (i = 0; i < formats.GetSize(); i++) {
if (formats[i].GetPayloadType() == payloadType ||
(strcasecmp(formats[i].GetEncodingName(), encodingName) == 0
&& formats[i].GetClockRate() == clockRate))
return;
}
AddSDPMediaFormat(new SDPMediaFormat(payloadType, encodingName, mediaFormat.GetClockRate()));
}
void SDPMediaDescription::AddMediaFormats(const OpalMediaFormatList & mediaFormats, unsigned session, const RTP_DataFrame::PayloadMapType & map)
{
for (PINDEX i = 0; i < mediaFormats.GetSize(); i++) {
OpalMediaFormat mediaFormat = mediaFormats[i];
if (mediaFormat.GetDefaultSessionID() == session &&
mediaFormat.GetPayloadType() != RTP_DataFrame::IllegalPayloadType)
AddMediaFormat(mediaFormat, map);
}
}
//////////////////////////////////////////////////////////////////////////////
const char * const SDPSessionDescription::ConferenceTotalBandwidthModifier = "CT";
const char * const SDPSessionDescription::ApplicationSpecificBandwidthModifier = "AS";
SDPSessionDescription::SDPSessionDescription(const OpalTransportAddress & address)
: sessionName(SIP_DEFAULT_SESSION_NAME),
ownerUsername('-'),
ownerAddress(address),
defaultConnectAddress(address)
{
protocolVersion = 0;
ownerSessionId = ownerVersion = PTime().GetTimeInSeconds();
direction = SDPMediaDescription::Undefined;
bandwidthModifier = "";
bandwidthValue = 0;
}
void SDPSessionDescription::PrintOn(ostream & str) const
{
OpalTransportAddress connectionAddress(defaultConnectAddress);
BOOL useCommonConnect = TRUE;
// see common connect address is needed
{
OpalTransportAddress descrAddress;
PINDEX matched = 0;
PINDEX descrMatched = 0;
PINDEX i;
for (i = 0; i < mediaDescriptions.GetSize(); i++) {
if (i == 0)
descrAddress = mediaDescriptions[i].GetTransportAddress();
if (mediaDescriptions[i].GetTransportAddress() == connectionAddress)
++matched;
if (mediaDescriptions[i].GetTransportAddress() == descrAddress)
++descrMatched;
}
if (connectionAddress != descrAddress) {
if ((descrMatched > matched))
connectionAddress = descrAddress;
else
useCommonConnect = FALSE;
}
}
// encode mandatory session information
str << "v=" << protocolVersion << "\r\n"
"o=" << ownerUsername << ' '
<< ownerSessionId << ' '
<< ownerVersion << ' '
<< GetConnectAddressString(ownerAddress)
<< "\r\n"
"s=" << sessionName << "\r\n";
// make sure the "c=" line (if required) is before the "t=" otherwise the proxy
// used by FWD will reject the call with an SDP parse error. This does not seem to be
// required by the RFC so it is probably a bug in the proxy
if (useCommonConnect)
str << "c=" << GetConnectAddressString(connectionAddress) << "\r\n";
if(bandwidthModifier != "" && bandwidthValue != 0) {
str << "b=" << bandwidthModifier << ":" << bandwidthValue << "\r\n";
}
str << "t=" << "0 0" << "\r\n";
switch (direction) {
case SDPMediaDescription::RecvOnly:
str << "a=recvonly" << "\r\n";
break;
case SDPMediaDescription::SendOnly:
str << "a=sendonly" << "\r\n";
break;
case SDPMediaDescription::SendRecv:
str << "a=sendrecv" << "\r\n";
break;
case SDPMediaDescription::Inactive:
str << "a=inactive" << "\r\n";
break;
default:
break;
}
// encode media session information
PINDEX i;
for (i = 0; i < mediaDescriptions.GetSize(); i++) {
if (useCommonConnect)
mediaDescriptions[i].PrintOn(connectionAddress, str);
else
str << mediaDescriptions[i];
}
}
PString SDPSessionDescription::Encode() const
{
PStringStream str;
PrintOn(str);
return str;
}
BOOL SDPSessionDescription::Decode(const PString & str)
{
// break string into lines
PStringArray lines = str.Lines();
// parse keyvalue pairs
SDPMediaDescription * currentMedia = NULL;
PINDEX i;
for (i = 0; i < lines.GetSize(); i++) {
PString & line = lines[i];
PINDEX pos = line.Find('=');
if (pos != P_MAX_INDEX) {
PString key = line.Left(pos).Trim();
PString value = line.Mid(pos+1).Trim();
if (key.GetLength() == 1) {
// media name and transport address (mandatory)
if (key[0] == 'm') {
currentMedia = new SDPMediaDescription(defaultConnectAddress);
if (currentMedia->Decode(value)) {
mediaDescriptions.Append(currentMedia);
PTRACE(3, "SDP\tAdding media session with " << currentMedia->GetSDPMediaFormats().GetSize() << " formats");
}
else
delete currentMedia;
}
/////////////////////////////////
//
// Session description
//
/////////////////////////////////
else if (currentMedia == NULL) {
PINDEX thePos;
switch (key[0]) {
case 'v' : // protocol version (mandatory)
protocolVersion = value.AsInteger();
break;
case 'o' : // owner/creator and session identifier (mandatory)
ParseOwner(value);
break;
case 's' : // session name (mandatory)
sessionName = value;
break;
case 'c' : // connection information - not required if included in all media
defaultConnectAddress = ParseConnectAddress(value);
break;
case 't' : // time the session is active (mandatory)
case 'i' : // session information
case 'u' : // URI of description
case 'e' : // email address
case 'p' : // phone number
break;
case 'b' : // bandwidth information
thePos = value.Find(':');
if (thePos != P_MAX_INDEX) {
bandwidthModifier = value.Left(thePos);
bandwidthValue = value.Mid(thePos+1).AsInteger();
}
break;
case 'z' : // time zone adjustments
case 'k' : // encryption key
case 'r' : // zero or more repeat times
break;
case 'a' : // zero or more session attribute lines
if (value *= "sendonly")
SetDirection (SDPMediaDescription::SendOnly);
else if (value *= "recvonly")
SetDirection (SDPMediaDescription::RecvOnly);
else if (value *= "sendrecv")
SetDirection (SDPMediaDescription::SendRecv);
else if (value *= "inactive")
SetDirection (SDPMediaDescription::Inactive);
break;
default:
PTRACE(1, "SDP\tUnknown session information key " << key[0]);
}
}
/////////////////////////////////
//
// media information
//
/////////////////////////////////
else {
switch (key[0]) {
case 'i' : // media title
case 'b' : // bandwidth information
case 'k' : // encryption key
break;
case 'c' : // connection information - optional if included at session-level
break;
case 'a' : // zero or more media attribute lines
currentMedia->SetAttribute(value);
break;
default:
PTRACE(1, "SDP\tUnknown mediainformation key " << key[0]);
}
}
}
}
}
return TRUE;
}
void SDPSessionDescription::ParseOwner(const PString & str)
{
PStringArray tokens = str.Tokenise(" ");
if (tokens.GetSize() != 6) {
PTRACE(1, "SDP\tOrigin has " << tokens.GetSize() << " elements");
}
else {
ownerUsername = tokens[0];
ownerSessionId = tokens[1].AsUnsigned();
ownerVersion = tokens[2].AsUnsigned();
ownerAddress = defaultConnectAddress = ParseConnectAddress(tokens, 3);
}
}
SDPMediaDescription * SDPSessionDescription::GetMediaDescription(
SDPMediaDescription::MediaType rtpMediaType) const
{
// look for matching media type
PINDEX i;
for (i = 0; i < mediaDescriptions.GetSize(); i++) {
if (mediaDescriptions[i].GetMediaType() == rtpMediaType)
return &mediaDescriptions[i];
}
return NULL;
}
SDPMediaDescription::Direction SDPSessionDescription::GetDirection(unsigned sessionID) const
{
PINDEX i;
for (i = 0; i < mediaDescriptions.GetSize(); i++) {
if ((mediaDescriptions[i].GetMediaType() == SDPMediaDescription::Video && sessionID == OpalMediaFormat::DefaultVideoSessionID) || (mediaDescriptions[i].GetMediaType() == SDPMediaDescription::Audio && sessionID == OpalMediaFormat::DefaultAudioSessionID)) {
if (mediaDescriptions[i].GetDirection() != SDPMediaDescription::Undefined)
return mediaDescriptions[i].GetDirection();
else
return direction;
}
}
return direction;
}
// End of file ////////////////////////////////////////////////////////////////
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -