private void ParseFormatParametersAttribute(SdpMediaDescription mediaDescription, string value) { var separatorIdx = value.IndexOf(' '); var payloadType = int.Parse(value.Substring(0, separatorIdx)); var formatParameters = value.Substring(separatorIdx + 1); var mfd = mediaDescription.MediaFormatDescriptions[payloadType]; mfd.FormatParameters = formatParameters; }
private void ParseRtpMapAttribute(SdpMediaDescription mediaDescription, string value) { var separatorIdx = value.IndexOf(' '); var payloadType = int.Parse(value.Substring(0, separatorIdx)); var encoding = value.Substring(separatorIdx + 1); var encodingParts = encoding.Split('/'); var mfd = mediaDescription.MediaFormatDescriptions[payloadType]; mfd.EncodingName = encodingParts[0]; if (int.TryParse(TryGet(encodingParts, 1), out var clockRate)) { mfd.ClockRate = clockRate; } mfd.EncodingParameters = TryGet(encodingParts, 2); }
/// <summary> /// https://tools.ietf.org/html/rfc4566#section-5.14 /// /// m=<media> <port> <proto> <fmt> ... /// /// A session description may contain a number of media descriptions. /// Each media description starts with an "m=" field and is terminated by /// either the next "m=" field or by the end of the session description. /// A media field has several sub-fields: /// </summary> /// <param name="mediaId"> /// Used for identifying media streams within a /// session description. /// /// https://tools.ietf.org/html/rfc5888#section-4 /// </param> /// <param name="media"> /// <media> is the media type. Currently defined media are "audio", /// "video", "text", "application", and "message", although this list /// may be extended in the future (see Section 8). /// </param> /// <param name="port"> /// <port> is the transport port to which the media stream is sent. The /// meaning of the transport port depends on the network being used as /// specified in the relevant "c=" field, and on the transport /// protocol defined in the <proto> sub-field of the media field. /// Other ports used by the media application (such as the RTP Control /// Protocol (RTCP) port [19]) MAY be derived algorithmically from the /// base media port or MAY be specified in a separate attribute (for /// example, "a=rtcp:" as defined in [22]). /// </param> /// <param name="protocol"> /// <proto> is the transport protocol. The meaning of the transport /// protocol is dependent on the address type field in the relevant /// "c=" field. Thus a "c=" field of IP4 indicates that the transport /// protocol runs over IP4. /// </param> public SdpMediaDescriptionBuilder AddMediaDescription(string mediaId, string media, int port, string protocol = "UDP/TLS/RTP/SAVPF") { var sdpMediaDescription = new SdpMediaDescription { MediaId = mediaId, Media = media, Port = port, Protocol = protocol }; _sessionDescription.MediaDescriptions.Add(sdpMediaDescription); var mediaDescriptionBuilder = new SdpMediaDescriptionBuilder(sdpMediaDescription, this); _mediaLineBuilders.Add(mediaDescriptionBuilder); return(mediaDescriptionBuilder); }
private void ParseSsrcAttribute(SdpMediaDescription mediaDescription, string value) { var parts = value.Split(' '); var mediaAttributes = mediaDescription.MediaSourceAttributes; mediaAttributes.Ssrc = uint.Parse(TryGet(parts, 0)); var ssrcParam = TryGet(parts, 1); switch (ssrcParam) { case "cname": mediaAttributes.CName = ssrcParam; break; case "msid": mediaAttributes.MsId = ssrcParam; mediaAttributes.MsIdAppData = TryGet(parts, 2); break; } }
private void ParseMediaDescription(SdpSessionDescription sessionDescription, string medialine, TextReader stringReader) { var mediaDescription = new SdpMediaDescription(); var parts = medialine.Split(' '); mediaDescription.Media = TryGet(parts, 0); mediaDescription.Port = int.Parse(TryGet(parts, 1)); mediaDescription.Protocol = TryGet(parts, 2); mediaDescription.MediaFormatDescriptions = parts.Skip(3) .Select(int.Parse) .ToDictionary(pt => pt, pt => new SdpMediaFormatDescription { PayloadType = pt }); var line = stringReader.ReadLine(); while (line != null) { ParseSdpLine(line, out var key, out var value); switch (key) { case "c": mediaDescription.Connection = ParseConnectionLine(value); break; case "a": ParseMediaDescriptionAttribute(mediaDescription, value); break; case "m": ParseMediaDescription(sessionDescription, value, stringReader); break; } line = stringReader.ReadLine(); } sessionDescription.MediaDescriptions.Add(mediaDescription); }
private static void ParseRtcpFeedbackCapabilityAttribute(SdpMediaDescription mediaDescription, string value) { var separatorIdx = value.IndexOf(' '); var payloadTypeStr = value.Substring(0, separatorIdx); var cap = value.Substring(separatorIdx + 1); if (payloadTypeStr == "*") { foreach (var mfd in mediaDescription.MediaFormatDescriptions.Values) { mfd.RtcpFeedbackCapability.Add(cap); } } else { var payloadType = int.Parse(payloadTypeStr); var mfd = mediaDescription.MediaFormatDescriptions[payloadType]; mfd.RtcpFeedbackCapability.Add(cap); } }
public SdpMediaDescriptionBuilder(SdpMediaDescription sdpMediaDescription, SdpBuilder sdpBuilder) { _sdpMediaDescription = sdpMediaDescription; _sdpBuilder = sdpBuilder; }
private void ParseMediaDescriptionAttribute(SdpMediaDescription mediaDescription, string attribute) { ParseAttributeKeyValue(attribute, out var key, out var value); switch (key) { case "control": mediaDescription.RtspControlUrl = new Uri(value, UriKind.RelativeOrAbsolute); break; case "framerate": mediaDescription.Framerate = decimal.Parse(value); break; case "sendrecv": mediaDescription.SendReceiveMode = SendReceiveMode.SendRecv; break; case "sendonly": mediaDescription.SendReceiveMode = SendReceiveMode.SendOnly; break; case "recvonly": mediaDescription.SendReceiveMode = SendReceiveMode.RecvOnly; break; case "inactive": mediaDescription.SendReceiveMode = SendReceiveMode.Inactive; break; case "mid": mediaDescription.MediaId = value; break; case "ice-ufrag": mediaDescription.IceAttributes.UsernameFragment = value; break; case "ice-pwd": mediaDescription.IceAttributes.Password = value; break; case "ice-options": mediaDescription.IceAttributes.Options = value; break; case "fingerprint": var fingerprintParts = value.Split(' '); mediaDescription.DtlsAttributes.HashFunc = TryGet(fingerprintParts, 0); mediaDescription.DtlsAttributes.Fingerprint = TryGet(fingerprintParts, 1); break; case "setup": mediaDescription.DtlsAttributes.Setup = value; break; case "rtpmap": ParseRtpMapAttribute(mediaDescription, value); break; case "fmtp": ParseFormatParametersAttribute(mediaDescription, value); break; case "rtcp-fb": ParseRtcpFeedbackCapabilityAttribute(mediaDescription, value); break; case "ssrc": ParseSsrcAttribute(mediaDescription, value); break; case "candidate": var parts = value.Split(' '); var sdpIceCandidate = new SdpIceCandidate(); sdpIceCandidate.Foundation = long.Parse(TryGet(parts, 0)); sdpIceCandidate.ComponentId = byte.Parse(TryGet(parts, 1)); sdpIceCandidate.Transport = TryGet(parts, 2); sdpIceCandidate.Priority = uint.Parse(TryGet(parts, 3)); sdpIceCandidate.ConnectionAddress = TryGet(parts, 4); sdpIceCandidate.Port = ushort.Parse(TryGet(parts, 5)); sdpIceCandidate.CandidateType = TryGet(parts, 7); mediaDescription.IceCandidates.Add(sdpIceCandidate); break; case "end-of-candidates": break; } }