public static ImmutableList <MediaTrack> FromSdp(SessionDescription sdp, Uri baseUri, MimeType filter = null) { var builder = ImmutableList.CreateBuilder <MediaTrack>(); string sdpConnectionAddr = baseUri.Host; if (sdp.Connection != null && IsAddressSet(sdp.Connection.Address)) { sdpConnectionAddr = sdp.Connection.Address; } sdp.MediaDescriptions.ForEach(md => { Uri controlUri = baseUri; string type = md.Media.ToString().ToLower(); string subType = "unknown"; // Prefer the media description's connection address over the sdp connection address. var connectionAddr = md.Connection != null && !string.IsNullOrEmpty(md.Connection.Address) ? md.Connection.Address : sdpConnectionAddr; var rtmpmaps = md.GetRtpMaps(); // Via spec there can be multiple types and rtpmaps, but // we will assume a single one since all cameras/encoders // appear to only provide one per Media Description. var rtpmap = rtmpmaps.IsEmpty ? FromPayloadType(md.MediaFormats[0]) : rtmpmaps.First(); subType = rtpmap.EncodingName; var control = md.Attributes.Where(a => "control" == a.Name).DefaultIfEmpty(null).First(); if (control != null) { controlUri = ResolveUri(baseUri, new Uri(control.Value, UriKind.RelativeOrAbsolute)); } var mimeType = MimeType.Create(type, rtpmap.EncodingName); if (mimeType.Is(APPLICATION_SPOOFED)) { // The MediaGateway and Vxpro us spoofing to determine the client's intentions of // either playing live or recorded data. Because of the current design they do not // have a way to know the client's intentions until a play call is issued that contains // and RTSP Range header with an absolute start-time. // // To handle metadata, in a pretty hacky way, a new media description is added to the SDP // of type application/vnd.pelco.spoofed to indicate to a client that the data is bogus // The client should continue processing up until the play call is made. At this point the // MediaGateway or VxPro will issues a redirect to the actual source. // // We will make a bogus metadata track to allow the client to continue processing. builder.Add(MediaTrack.CreateBuilder() .Address(Dns.GetHostAddresses(baseUri.Host)[0]) .Port(md.Port) .Type(mimeType) .Uri(controlUri) .Build()); } else if ((filter != null && mimeType.Is(filter)) || (filter == null)) { // If a filter is defined only return tracks that match the // defined filter type; otherwise, return all tracks. if (IsAddressSet(connectionAddr)) { // If defined as 0.0.0.0 or ::0 then replace with the SDP connection address. connectionAddr = sdpConnectionAddr; } var addrs = Dns.GetHostAddresses(connectionAddr); builder.Add(MediaTrack.CreateBuilder() .Address(Dns.GetHostAddresses(connectionAddr)[0]) .Port(md.Port) .RtpMap(rtpmap) .Type(mimeType) .Uri(controlUri) .Build()); } }); return(builder.ToImmutable()); }