/// <summary> /// <see fref="https://tools.ietf.org/html/rfc2326#page-80">Use of SDP for RTSP Session Descriptions</see> /// In brief an the given <see cref="SessionDescription"/> must contain a <see cref="Sdp.Lines.ConnectionLine"/> in the <see cref="Sdp.MediaDescription"/> /// </summary> /// <param name="sdp"></param> /// <param name="controlUri"></param> /// <param name="baseUri"></param> /// <returns></returns> public static bool SupportsAggregateMediaControl(this SessionDescription sdp, out Uri controlUri, Uri baseUri = null) { controlUri = null; SessionDescriptionLine controlLine = sdp.ControlLine; //If there is a control line in the SDP it contains the URI used to setup and control the media if (controlLine == null) { return(false); } //Get the control token string controlPart = controlLine.Parts.Where(p => p.Contains(AttributeFields.Control)).FirstOrDefault(); //If there is a controlPart in the controlLine if (false == string.IsNullOrWhiteSpace(controlPart)) { /* * If this attribute contains only an asterisk (*), then the URL is * treated as if it were an empty embedded URL, and thus inherits the * entire base URL. */ controlPart = controlPart.Split(Media.Sdp.SessionDescription.ColonSplit, 2, StringSplitOptions.RemoveEmptyEntries).Last(); //if unqualified then there is no aggregate control. if (controlPart == SessionDescription.WildcardString && baseUri == null) { return(false); } //The control uri may be in the control part //Try to parse it if (Uri.TryCreate(controlPart, UriKind.RelativeOrAbsolute, out controlUri)) { //If parsing suceeded then the result is true only if the controlUri is absolute if (controlUri.IsAbsoluteUri) { return(true); } } //Try to create a uri relative to the base uri given if (Uri.TryCreate(baseUri, controlUri, out controlUri)) { //If the operation succeeded then the result is true. return(true); } } //Another type of control line is present. return(false); }
public bool Equals(SessionDescriptionLine other) { return(other.Encoding.Equals(m_Encoding) && other.m_Type.Equals(m_Type) && other.m_Seperator.Equals(m_Seperator) && other.Length.Equals(Length) && //Calling ToString without taking account case ToString().Equals(other.ToString(), StringComparison.OrdinalIgnoreCase)); }
public static bool TryParse(string[] sdpLines, ref int index, out SessionDescriptionLine result) { try { result = Parse(sdpLines, ref index); return(result != null); } catch { result = null; return(false); } }
/// <summary> /// Copies an existing instance /// </summary> /// <param name="other">The instance to copy.</param> public SessionDescriptionLine(SessionDescriptionLine other) { if (other == null) { throw new ArgumentNullException(); } m_Encoding = other.m_Encoding; //Copies ValueType m_Type = other.m_Type; m_Seperator = other.m_Seperator; m_Parts = other.m_Parts; }
public SessionDescriptionLine(SessionDescriptionLine other, bool reference = true, string seperator = null) { if (other == null) { throw new ArgumentNullException(); } m_Encoding = other.m_Encoding; //Copies ValueType m_Type = other.m_Type; m_Seperator = seperator ?? other.m_Seperator; if (reference) { m_Parts = other.m_Parts; } else { m_Parts = new List <string>(other.m_Parts); } }
public void TestInitialObjectDescriptor() { Console.WriteLine(System.Reflection.MethodBase.GetCurrentMethod().Name); string testVector = @"v=0 o=- 1183588701 6 IN IP4 10.3.1.221 s=Elecard NWRenderer i=Elecard streaming u=http://www.elecard.com [email protected] c=IN IP4 239.255.0.1/64 b=CT:0 a=ISMA-compliance:2,2.0,2 a=mpeg4-iod: ""data:application/mpeg4-iod;base64,AoE8AA8BHgEBAQOBDAABQG5kYXRhOmFwcGxpY2F0aW9uL21wZWc0LW9kLWF1O2Jhc2U2NCxBVGdCR3dVZkF4Y0F5U1FBWlFRTklCRUFGM0FBQVBvQUFBRERVQVlCQkE9PQEbAp8DFQBlBQQNQBUAB9AAAD6AAAA+gAYBAwQNAQUAAMgAAAAAAAAAAAYJAQAAAAAAAAAAA2EAAkA+ZGF0YTphcHBsaWNhdGlvbi9tcGVnNC1iaWZzLWF1O2Jhc2U2NCx3QkFTZ1RBcUJYSmhCSWhRUlFVL0FBPT0EEgINAAAUAAAAAAAAAAAFAwAAQAYJAQAAAAAAAAAA"" m=video 10202 RTP/AVP 98 a=rtpmap:98 H264/90000 a=control:trackID=1 a=fmtp:98 packetization-mode=1; profile-level-id=4D001E; sprop-parameter-sets=Z00AHp5SAWh7IA==,aOuPIAAA a=mpeg4-esid:201 m=audio 10302 RTP/AVP 96 a=rtpmap:96 mpeg4-generic/48000/2 a=control:trackID=2 a=fmtp:96 streamtype=5; profile-level-id=255; mode=AAC-hbr; config=11900000000000000000; objectType=64; sizeLength=13; indexLength=3; indexDeltaLength=3 a=mpeg4-esid:101"; Media.Sdp.SessionDescription sd = new Media.Sdp.SessionDescription(testVector); Console.WriteLine(sd.ToString()); //Get the inital object descriptor line Media.Sdp.SessionDescriptionLine mpeg4IodLine = sd.Lines.Where(l => l.Type == 'a' && l.Parts.Any(p => p.Contains("mpeg4-iod"))).FirstOrDefault(); System.Diagnostics.Debug.Assert(mpeg4IodLine != null, "Cannot find InitialObjectDescriptor Line"); System.Diagnostics.Debug.Assert(mpeg4IodLine.Parts.Last() == "base64,AoE8AA8BHgEBAQOBDAABQG5kYXRhOmFwcGxpY2F0aW9uL21wZWc0LW9kLWF1O2Jhc2U2NCxBVGdCR3dVZkF4Y0F5U1FBWlFRTklCRUFGM0FBQVBvQUFBRERVQVlCQkE9PQEbAp8DFQBlBQQNQBUAB9AAAD6AAAA+gAYBAwQNAQUAAMgAAAAAAAAAAAYJAQAAAAAAAAAAA2EAAkA+ZGF0YTphcHBsaWNhdGlvbi9tcGVnNC1iaWZzLWF1O2Jhc2U2NCx3QkFTZ1RBcUJYSmhCSWhRUlFVL0FBPT0EEgINAAAUAAAAAAAAAAAFAwAAQAYJAQAAAAAAAAAA\"", "InitialObjectDescriptor Line Contents invalid."); }
public override bool Equals(object obj) { if (System.Object.ReferenceEquals(this, obj)) { return(true); } if (false == (obj is SessionDescriptionLine)) { return(false); } SessionDescriptionLine other = obj as SessionDescriptionLine; return(other.Encoding == m_Encoding && other.m_Type == m_Type && other.m_Seperator == m_Seperator && other.Length == Length && //Calling ToString without taking account case string.Compare(ToString(), other.ToString(), true) == 0); }
/// <summary> /// Parses the <see cref="MediaDescription.ControlLine"/> and if present /// </summary> /// <param name="mediaDescription"></param> /// <param name="source"></param> /// <returns></returns> public static Uri GetAbsoluteControlUri(this MediaDescription mediaDescription, Uri source, SessionDescription sessionDescription = null) { if (source == null) { throw new ArgumentNullException("source"); } if (mediaDescription == null) { return(source); } if (false == source.IsAbsoluteUri) { throw new InvalidOperationException("source.IsAbsoluteUri must be true."); } SessionDescriptionLine controlLine = mediaDescription.ControlLine; //If there is a control line in the SDP it contains the URI used to setup and control the media if (controlLine != null) { //Todo, make typed line for controlLine // GC: Rewrote this somewhat because it was destroying valid absolute URL provided by AXIS media server in the MediaDescription Control field. // This make break media servers which use a relative path. TODO: Test with other servers. string controlPart = ""; if (controlLine.Parts.Count() > 2) { foreach (string part in controlLine.Parts) { if (part == "control") { } else if (part == "rtsp") { controlPart += part + ":"; } else { controlPart += part; } } } else { controlPart = controlLine.Parts.Last(); } //If there is a controlPart in the controlLine if (false == string.IsNullOrWhiteSpace(controlPart)) { //Prepare the part // GC: Commented this out because it was destroying valid absolute URL provided by AXIS media server in the MediaDescription Control field. // This make break media servers which use a relative path. TODO: Test with other servers. //controlPart = controlPart.Split(Media.Sdp.SessionDescription.ColonSplit, 2, StringSplitOptions.RemoveEmptyEntries).Last(); //Create a uri Uri controlUri = new Uri(controlPart, UriKind.RelativeOrAbsolute); //Determine if its a Absolute Uri if (controlUri.IsAbsoluteUri) { return(controlUri); } //Return a new uri using the original string and the controlUri relative path. //Hopefully the direction of the braces matched.. //string.Join(source.OriginalString, controlUri.OriginalString); return(new Uri(source.OriginalString.EndsWith(SessionDescription.ForwardSlashString) ? source.OriginalString + controlUri.OriginalString : string.Join(SessionDescription.ForwardSlashString, source.OriginalString, controlUri.OriginalString))); //Todo, ensure that any parameters have also been restored... #region Explination //I wonder if Mr./(Dr) Fielding is happy... //Let source = //rtsp://alt1.v7.cache3.c.youtube.com/CigLENy73wIaHwmddh2T-s8niRMYDSANFEgGUgx1c2VyX3VwbG9hZHMM/0/0/0/1/video.3gp/trackID=0 //Call //return new Uri(source, controlUri); //Result = //rtsp://alt1.v7.cache3.c.youtube.com/CigLENy73wIaHwmddh2T-s8niRMYDSANFEgGUgx1c2VyX3VwbG9hZHMM/0/0/0/1/trackID=0 //Useless when the source doesn't end with '/', e.g. same problem with Uri constructor. //System.UriBuilder builder = new UriBuilder(source); //builder.Path += controlUri.ToString(); //"rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mov/trackID=1" #endregion } } //Try to take the session level control uri Uri sessionControlUri; //If there was a session description given and it supports aggregate media control then return that uri if (sessionDescription != null && sessionDescription.SupportsAggregateMediaControl(out sessionControlUri, source)) { return(sessionControlUri); } //There is no control line, just return the source. return(source); }
/// <summary> /// Parses the <see cref="MediaDescription.ControlLine"/> and if present /// </summary> /// <param name="mediaDescription"></param> /// <param name="source"></param> /// <returns></returns> public static Uri GetAbsoluteControlUri(this MediaDescription mediaDescription, Uri source, SessionDescription sessionDescription = null) { if (object.ReferenceEquals(source, null)) { throw new ArgumentNullException("source"); } if (Common.IDisposedExtensions.IsNullOrDisposed(mediaDescription)) { return(source); } if (source.IsAbsoluteUri.Equals(false)) { throw new InvalidOperationException("source.IsAbsoluteUri must be true."); } SessionDescriptionLine controlLine = mediaDescription.ControlLine; //If there is a control line in the SDP it contains the URI used to setup and control the media if (object.ReferenceEquals(controlLine, null).Equals(false)) { //Todo, make typed line for controlLine string controlPart = controlLine.Parts.Last(); //controlLine.Parts.Where(p => p.StartsWith(AttributeFields.Control)).FirstOrDefault(); //If there is a controlPart in the controlLine if (string.IsNullOrWhiteSpace(controlPart).Equals(false)) { //Prepare the part controlPart = controlPart.Split(Media.Sdp.SessionDescription.ColonSplit, 2, StringSplitOptions.RemoveEmptyEntries).Last(); //Create a uri Uri controlUri = new Uri(controlPart, UriKind.RelativeOrAbsolute); //Determine if its a Absolute Uri if (controlUri.IsAbsoluteUri) { return(controlUri); } //Return a new uri using the original string and the controlUri relative path. //Hopefully the direction of the braces matched.. //string.Join(source.OriginalString, controlUri.OriginalString); return(new Uri(source.OriginalString.EndsWith(SessionDescription.ForwardSlashString) ? source.OriginalString + controlUri.OriginalString : string.Join(SessionDescription.ForwardSlashString, source.OriginalString, controlUri.OriginalString))); //Todo, ensure that any parameters have also been restored... #region Explination //I wonder if Mr./(Dr) Fielding is happy... //Let source = //rtsp://alt1.v7.cache3.c.youtube.com/CigLENy73wIaHwmddh2T-s8niRMYDSANFEgGUgx1c2VyX3VwbG9hZHMM/0/0/0/1/video.3gp/trackID=0 //Call //return new Uri(source, controlUri); //Result = //rtsp://alt1.v7.cache3.c.youtube.com/CigLENy73wIaHwmddh2T-s8niRMYDSANFEgGUgx1c2VyX3VwbG9hZHMM/0/0/0/1/trackID=0 //Useless when the source doesn't end with '/', e.g. same problem with Uri constructor. //System.UriBuilder builder = new UriBuilder(source); //builder.Path += controlUri.ToString(); //"rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mov/trackID=1" #endregion } } //Try to take the session level control uri Uri sessionControlUri; //If there was a session description given and it supports aggregate media control then return that uri if (Common.IDisposedExtensions.IsNullOrDisposed(sessionDescription).Equals(false) && sessionDescription.SupportsAggregateMediaControl(out sessionControlUri, source)) { return(sessionControlUri); } //There is no control line, just return the source. return(source); }
public static SessionDescriptionLine Parse(params string[] lines) //index, count { int index = 0; return(SessionDescriptionLine.Parse(lines, ref index)); }