public static SDP ParseSDPDescription(string sdpDescription)
{
try
{
if (sdpDescription != null && sdpDescription.Trim().Length > 0)
{
SDP sdp = new SDP();
sdp.m_rawSdp = sdpDescription;
SDPMediaAnnouncement activeAnnouncement = null;
string[] sdpLines = Regex.Split(sdpDescription, CRLF);
foreach (string sdpLine in sdpLines)
{
string sdpLineTrimmed = sdpLine.Trim();
if (sdpLineTrimmed.StartsWith("v="))
{
if (!Decimal.TryParse(sdpLineTrimmed.Substring(2), out sdp.Version))
{
logger.LogWarning(
"The Version value in an SDP description could not be parsed as a decimal: " +
sdpLine + ".");
}
}
else if (sdpLineTrimmed.StartsWith("o="))
{
string[] ownerFields = sdpLineTrimmed.Substring(2).Split(' ');
sdp.Username = ownerFields[0];
sdp.SessionId = ownerFields[1];
Int32.TryParse(ownerFields[2], out sdp.AnnouncementVersion);
sdp.NetworkType = ownerFields[3];
sdp.AddressType = ownerFields[4];
sdp.AddressOrHost = ownerFields[5];
}
else if (sdpLineTrimmed.StartsWith("s="))
{
sdp.SessionName = sdpLineTrimmed.Substring(2);
}
else if (sdpLineTrimmed.StartsWith("c="))
{
if (sdp.Connection == null)
{
sdp.Connection = SDPConnectionInformation.ParseConnectionInformation(sdpLineTrimmed);
}
if (activeAnnouncement != null)
{
activeAnnouncement.Connection =
SDPConnectionInformation.ParseConnectionInformation(sdpLineTrimmed);
}
}
else if (sdpLineTrimmed.StartsWith("b="))
{
if (activeAnnouncement != null)
{
activeAnnouncement.BandwidthAttributes.Add(sdpLineTrimmed.Substring(2));
}
else
{
sdp.BandwidthAttributes.Add(sdpLineTrimmed.Substring(2));
}
}
else if (sdpLineTrimmed.StartsWith("t="))
{
sdp.Timing = sdpLineTrimmed.Substring(2);
}
else if (sdpLineTrimmed.StartsWith("m="))
{
Match mediaMatch = Regex.Match(sdpLineTrimmed.Substring(2),
@"(?<type>\w+)\s+(?<port>\d+)\s+(?<transport>\S+)(\s*)(?<formats>.*)$");
if (mediaMatch.Success)
{
SDPMediaAnnouncement announcement = new SDPMediaAnnouncement();
announcement.Media = SDPMediaTypes.GetSDPMediaType(mediaMatch.Result("${type}"));
Int32.TryParse(mediaMatch.Result("${port}"), out announcement.Port);
announcement.Transport = mediaMatch.Result("${transport}");
announcement.ParseMediaFormats(mediaMatch.Result("${formats}"));
sdp.Media.Add(announcement);
activeAnnouncement = announcement;
}
else
{
logger.LogWarning("A media line in SDP was invalid: " + sdpLineTrimmed.Substring(2) +
".");
}
}
else if (sdpLineTrimmed.StartsWith("a=" + GROUP_ATRIBUTE_PREFIX))
{
sdp.Group = sdpLineTrimmed.Substring(sdpLineTrimmed.IndexOf(':') + 1);
}
else if (sdpLineTrimmed.StartsWith("a=" + ICE_UFRAG_ATTRIBUTE_PREFIX))
{
if (activeAnnouncement != null)
{
activeAnnouncement.IceUfrag = sdpLineTrimmed.Substring(sdpLineTrimmed.IndexOf(':') + 1);
}
else
{
sdp.IceUfrag = sdpLineTrimmed.Substring(sdpLineTrimmed.IndexOf(':') + 1);
}
}
else if (sdpLineTrimmed.StartsWith("a=" + ICE_PWD_ATTRIBUTE_PREFIX))
{
if (activeAnnouncement != null)
{
activeAnnouncement.IcePwd = sdpLineTrimmed.Substring(sdpLineTrimmed.IndexOf(':') + 1);
}
else
{
sdp.IcePwd = sdpLineTrimmed.Substring(sdpLineTrimmed.IndexOf(':') + 1);
}
}
else if (sdpLineTrimmed.StartsWith("a=" + DTLS_FINGERPRINT_ATTRIBUTE_PREFIX))
{
if (activeAnnouncement != null)
{
activeAnnouncement.DtlsFingerprint =
sdpLineTrimmed.Substring(sdpLineTrimmed.IndexOf(':') + 1);
}
else
{
sdp.DtlsFingerprint = sdpLineTrimmed.Substring(sdpLineTrimmed.IndexOf(':') + 1);
}
}
else if (sdpLineTrimmed.StartsWith($"a={END_ICE_CANDIDATES_ATTRIBUTE}"))
{
// Do nothing.
}
else if (sdpLineTrimmed.StartsWith(SDPMediaAnnouncement.MEDIA_FORMAT_ATTRIBUE_PREFIX))
{
if (activeAnnouncement != null)
{
Match formatAttributeMatch = Regex.Match(sdpLineTrimmed,
SDPMediaAnnouncement.MEDIA_FORMAT_ATTRIBUE_PREFIX +
@"(?<id>\d+)\s+(?<attribute>.*)$");
if (formatAttributeMatch.Success)
{
int formatID;
if (Int32.TryParse(formatAttributeMatch.Result("${id}"), out formatID))
{
activeAnnouncement.AddFormatAttribute(formatID,
formatAttributeMatch.Result("${attribute}"));
}
else
{
logger.LogWarning("Invalid media format attribute in SDP: " + sdpLine);
}
}
else
{
activeAnnouncement.AddExtra(sdpLineTrimmed);
}
}
else
{
logger.LogWarning(
"There was no active media announcement for a media format attribute, ignoring.");
}
}
else if (sdpLineTrimmed.StartsWith(SDPMediaAnnouncement.MEDIA_FORMAT_PARAMETERS_ATTRIBUE_PREFIX)
)
{
if (activeAnnouncement != null)
{
Match formatAttributeMatch = Regex.Match(sdpLineTrimmed,
SDPMediaAnnouncement.MEDIA_FORMAT_PARAMETERS_ATTRIBUE_PREFIX +
@"(?<id>\d+)\s+(?<attribute>.*)$");
if (formatAttributeMatch.Success)
{
int formatID;
if (Int32.TryParse(formatAttributeMatch.Result("${id}"), out formatID))
{
activeAnnouncement.AddFormatParameterAttribute(formatID,
formatAttributeMatch.Result("${attribute}"));
}
else
{
logger.LogWarning("Invalid media format parameter attribute in SDP: " +
sdpLine);
}
}
else
{
activeAnnouncement.AddExtra(sdpLineTrimmed);
}
}
else
{
logger.LogWarning(
"There was no active media announcement for a media format parameter attribute, ignoring.");
}
}
else if (sdpLineTrimmed.StartsWith("a=" + ICE_CANDIDATE_ATTRIBUTE_PREFIX))
{
if (activeAnnouncement != null)
{
if (activeAnnouncement.IceCandidates == null)
{
activeAnnouncement.IceCandidates = new List <string>();
}
activeAnnouncement.IceCandidates.Add(
sdpLineTrimmed.Substring(sdpLineTrimmed.IndexOf(':') + 1));
}
else
{
if (sdp.IceCandidates == null)
{
sdp.IceCandidates = new List <string>();
}
sdp.IceCandidates.Add(sdpLineTrimmed.Substring(sdpLineTrimmed.IndexOf(':') + 1));
}
}
//2018-12-21 rj2: add a=crypto
else if (sdpLineTrimmed.StartsWith(SDPSecurityDescription.CRYPTO_ATTRIBUE_PREFIX))
{
if (activeAnnouncement != null)
{
try
{
activeAnnouncement.AddCryptoLine(sdpLineTrimmed);
}
catch (FormatException fex)
{
logger.LogWarning("Error Parsing SDP-Line(a=crypto) " + fex);
}
}
}
else if (MediaStreamStatusType.IsMediaStreamStatusAttribute(sdpLine.Trim(),
out var mediaStreamStatus))
{
if (activeAnnouncement != null)
{
activeAnnouncement.MediaStreamStatus = mediaStreamStatus;
}
else
{
sdp.SessionMediaStreamStatus = mediaStreamStatus;
}
}
else if (sdpLineTrimmed.StartsWith("a=" + MEDIA_ID_ATTRIBUTE_PREFIX))
{
if (activeAnnouncement != null)
{
activeAnnouncement.MediaID = sdpLineTrimmed.Substring(sdpLineTrimmed.IndexOf(':') + 1);
}
else
{
logger.LogWarning("A media ID can only be set on a media announcement.");
}
}
else if (sdpLineTrimmed.StartsWith(SDPMediaAnnouncement.MEDIA_FORMAT_SSRC_GROUP_ATTRIBUE_PREFIX)
)
{
if (activeAnnouncement != null)
{
string[] fields = sdpLineTrimmed.Substring(sdpLineTrimmed.IndexOf(':') + 1).Split(' ');
// Set the ID.
if (fields.Length > 0)
{
activeAnnouncement.SsrcGroupID = fields[0];
}
// Add attributes for each of the SSRC values.
for (int i = 1; i < fields.Length; i++)
{
if (uint.TryParse(fields[i], out var ssrc))
{
activeAnnouncement.SsrcAttributes.Add(
new SDPSsrcAttribute(ssrc, null, activeAnnouncement.SsrcGroupID));
}
}
}
else
{
logger.LogWarning("A ssrc-group ID can only be set on a media announcement.");
}
}
else if (sdpLineTrimmed.StartsWith(SDPMediaAnnouncement.MEDIA_FORMAT_SSRC_ATTRIBUE_PREFIX))
{
if (activeAnnouncement != null)
{
string[] ssrcFields = sdpLineTrimmed.Substring(sdpLineTrimmed.IndexOf(':') + 1)
.Split(' ');
if (ssrcFields.Length > 0 && uint.TryParse(ssrcFields[0], out var ssrc))
{
var ssrcAttribute =
activeAnnouncement.SsrcAttributes.FirstOrDefault(x => x.SSRC == ssrc);
if (ssrcAttribute == null)
{
ssrcAttribute = new SDPSsrcAttribute(ssrc, null, null);
activeAnnouncement.SsrcAttributes.Add(ssrcAttribute);
}
if (ssrcFields.Length > 1)
{
if (ssrcFields[1].StartsWith(SDPSsrcAttribute.MEDIA_CNAME_ATTRIBUE_PREFIX))
{
ssrcAttribute.Cname =
ssrcFields[1].Substring(ssrcFields[1].IndexOf(':') + 1);
}
}
}
}
else
{
logger.LogWarning("A ssrc attribute can only be set on a media announcement.");
}
}
else
{
if (activeAnnouncement != null)
{
activeAnnouncement.AddExtra(sdpLineTrimmed);
}
else
{
sdp.AddExtra(sdpLineTrimmed);
}
}
}
return(sdp);
}
else
{
return(null);
}
}
catch (Exception excp)
{
logger.LogError("Exception ParseSDPDescription. " + excp.Message);
throw excp;
}
}