Beispiel #1
0
    /// <summary>
    /// Test that an SDP payload with multiple media announcements (in this test audio and video) are correctly
    /// parsed.
    /// </summary>
    public void ParseMultipleMediaAnnouncementsUnitTest()
    {
        Console.WriteLine(System.Reflection.MethodBase.GetCurrentMethod().Name);

        string sdpStr = "v=0" + Media.Sdp.SessionDescription.NewLine +
                        "o=- 13064410510996677 3 IN IP4 10.1.1.2" + Media.Sdp.SessionDescription.NewLine +
                        "s=Bria 4 release 4.1.1 stamp 74246" + Media.Sdp.SessionDescription.NewLine +
                        "c=IN IP4 10.1.1.2" + Media.Sdp.SessionDescription.NewLine +
                        "b=AS:2064" + Media.Sdp.SessionDescription.NewLine +
                        "t=0 0" + Media.Sdp.SessionDescription.NewLine +
                        "m=audio 49290 RTP/AVP 0" + Media.Sdp.SessionDescription.NewLine +
                        "a=sendrecv" + Media.Sdp.SessionDescription.NewLine +
                        "m=video 56674 RTP/AVP 96" + Media.Sdp.SessionDescription.NewLine +
                        "b=TIAS:2000000" + Media.Sdp.SessionDescription.NewLine +
                        "a=rtpmap:96 VP8/90000" + Media.Sdp.SessionDescription.NewLine +
                        "a=sendrecv" + Media.Sdp.SessionDescription.NewLine +
                        "a=rtcp-fb:* nack pli";

        Media.Sdp.SessionDescription sdp = new Media.Sdp.SessionDescription(sdpStr);

        System.Diagnostics.Debug.WriteLine(sdp.ToString());

        System.Diagnostics.Debug.Assert(2 == sdp.MediaDescriptions.Count());
        System.Diagnostics.Debug.Assert(49290 == sdp.MediaDescriptions.Where(x => x.MediaType == Media.Sdp.MediaType.audio).First().MediaPort);
        System.Diagnostics.Debug.Assert(56674 == sdp.MediaDescriptions.Where(x => x.MediaType == Media.Sdp.MediaType.video).First().MediaPort);
    }
Beispiel #2
0
        /// <summary>
        /// Creates a copy of another SessionDescription
        /// </summary>
        /// <param name="other">The SessionDescription to copy</param>
        public SessionDescription(SessionDescription other, bool reference = false)
        {
            SessionDescriptionVersion = other.SessionDescriptionVersion;

            OriginatorAndSessionIdentifier = other.OriginatorAndSessionIdentifier;

            m_NameLine = other.m_NameLine;

            if (reference)
            {
                m_TimeDescriptions = other.m_TimeDescriptions;

                m_MediaDescriptions = other.m_MediaDescriptions;

                m_Lines = other.m_Lines;
            }
            else
            {
                m_TimeDescriptions = new List <TimeDescription>(other.TimeDescriptions);

                m_MediaDescriptions = new List <MediaDescription>(other.m_MediaDescriptions);

                m_Lines = new List <SessionDescriptionLine>(other.Lines);
            }
        }
Beispiel #3
0
    public void ParseSDPUnitTest()
    {
        Console.WriteLine(System.Reflection.MethodBase.GetCurrentMethod().Name);

        string sdpStr =
            "v=0" + Media.Sdp.SessionDescription.NewLine +
            "o=root 3285 3285 IN IP4 10.0.0.4" + Media.Sdp.SessionDescription.NewLine +
            "s=session" + Media.Sdp.SessionDescription.NewLine +
            "c=IN IP4 10.0.0.4" + Media.Sdp.SessionDescription.NewLine +
            "t=0 0" + Media.Sdp.SessionDescription.NewLine +
            "m=audio 12228 RTP/AVP 0 101" + Media.Sdp.SessionDescription.NewLine +
            "a=rtpmap:0 PCMU/8000" + Media.Sdp.SessionDescription.NewLine +
            "a=rtpmap:101 telephone-event/8000" + Media.Sdp.SessionDescription.NewLine +
            "a=fmtp:101 0-16" + Media.Sdp.SessionDescription.NewLine +
            "a=silenceSupp:off - - - -" + Media.Sdp.SessionDescription.NewLine +
            "a=ptime:20" + Media.Sdp.SessionDescription.NewLine +
            "a=sendrecv";

        Media.Sdp.SessionDescription sdp = new Media.Sdp.SessionDescription(sdpStr);

        System.Diagnostics.Debug.WriteLine(sdp.ToString());

        System.Diagnostics.Debug.Assert("10.0.0.4" == sdp.ConnectionLine.Parts[2], "The connection address was not parsed  correctly.");  // ToDo: Be better if "Part[3]" was referred to by ConnectionAddress.
        System.Diagnostics.Debug.Assert(Media.Sdp.MediaType.audio == sdp.MediaDescriptions.First().MediaType, "The media type not parsed correctly.");
        System.Diagnostics.Debug.Assert(12228 == sdp.MediaDescriptions.First().MediaPort, "The connection port was not parsed correctly.");
        System.Diagnostics.Debug.Assert(0 == sdp.MediaDescriptions.First().PayloadTypes.First(), "The first media format was incorrect.");         // ToDo: Can't cope with multiple media formats?
        //Assert.IsTrue(sdp.Media[0].MediaFormats[0].FormatID == 0, "The highest priority media format ID was incorrect.");
        //Assert.IsTrue(sdp.Media[0].MediaFormats[0].Name == "PCMU", "The highest priority media format name was incorrect.");
        //Assert.IsTrue(sdp.Media[0].MediaFormats[0].ClockRate == 8000, "The highest priority media format clockrate was incorrect.");
        System.Diagnostics.Debug.Assert("rtpmap:0 PCMU/8000" == sdp.MediaDescriptions.First().RtpMapLine.Parts[0], "The rtpmap line for the PCM format was not parsed correctly.");  // ToDo "Parts" should be put into named properties where possible.
    }
Beispiel #4
0
    public void ParseICESessionAttributesUnitTest()
    {
        Console.WriteLine(System.Reflection.MethodBase.GetCurrentMethod().Name);

        string sdpStr =
            "v=0" + Media.Sdp.SessionDescription.NewLine +
            "o=jdoe 2890844526 2890842807 IN IP4 10.0.1.1" + Media.Sdp.SessionDescription.NewLine +
            "s=" + Media.Sdp.SessionDescription.NewLine +
            "c=IN IP4 192.0.2.3" + Media.Sdp.SessionDescription.NewLine +
            "t=0 0" + Media.Sdp.SessionDescription.NewLine +
            "a=ice-pwd:asd88fgpdd777uzjYhagZg" + Media.Sdp.SessionDescription.NewLine +
            "a=ice-ufrag:8hhY" + Media.Sdp.SessionDescription.NewLine +
            "m=audio 45664 RTP/AVP 0" + Media.Sdp.SessionDescription.NewLine +
            "b=RS:0" + Media.Sdp.SessionDescription.NewLine +
            "b=RR:0" + Media.Sdp.SessionDescription.NewLine +
            "a=rtpmap:0 PCMU/8000" + Media.Sdp.SessionDescription.NewLine +
            "a=candidate:1 1 UDP 2130706431 10.0.1.1 8998 typ host" + Media.Sdp.SessionDescription.NewLine +
            "a=candidate:2 1 UDP 1694498815 192.0.2.3 45664 typ srflx raddr 10.0.1.1 rport 8998";

        Media.Sdp.SessionDescription sdp = new Media.Sdp.SessionDescription(sdpStr);

        System.Diagnostics.Debug.WriteLine(sdp.ToString());

        //ToDo: Add ICE attributes.
        //System.Diagnostics.Debug.Assert("8hhY" == sdp.IceUfrag, "The ICE username was not parsed correctly.");
        //System.Diagnostics.Debug.Assert("asd88fgpdd777uzjYhagZg" == sdp.IcePwd, "The ICE password was not parsed correctly.");
    }
Beispiel #5
0
        //E.g. This index can be used in GetTimeDescription(index)
        public static int GetIndexFor(this SessionDescription sdp, TimeDescription td)
        {
            if (sdp == null || td == null)
            {
                return(-1);
            }

            return(sdp.m_TimeDescriptions.IndexOf(td));
        }
Beispiel #6
0
        //Naming is weird, this returns the logical 0 based index of the given description within the sessionDescription's property of the same type.

        //E.g. This index can be used in GetMediaDescription(index)
        public static int GetIndexFor(this SessionDescription sdp, MediaDescription md)
        {
            if (sdp == null || md == null)
            {
                return(-1);
            }

            return(sdp.m_MediaDescriptions.IndexOf(md));
        }
Beispiel #7
0
        /// <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);
        }
Beispiel #8
0
        public string ToString(SessionDescription sdp = null)
        {
            StringBuilder builder = new StringBuilder();

            builder.Append(TimeDescriptionLine.ToString());

            foreach (Lines.SessionRepeatTimeLine repeatTime in RepeatLines)
            {
                builder.Append(repeatTime.ToString());
            }

            return(builder.ToString());
        }
Beispiel #9
0
    public void ParseBriaSDPUnitTest()
    {
        Console.WriteLine(System.Reflection.MethodBase.GetCurrentMethod().Name);

        string sdpStr = "v=0\r\no=- 5 2 IN IP4 10.1.1.2\r\ns=CounterPath Bria\r\nc=IN IP4 144.137.16.240\r\nt=0 0\r\nm=audio 34640 RTP/AVP 0 8 101\r\na=sendrecv\r\na=rtpmap:101 telephone-event/8000\r\na=fmtp:101 0-15\r\na=alt:1 1 : STu/ZtOu 7hiLQmUp 10.1.1.2 34640\r\n";

        Media.Sdp.SessionDescription sdp = new Media.Sdp.SessionDescription(sdpStr);

        System.Diagnostics.Debug.WriteLine(sdp.ToString());

        System.Diagnostics.Debug.Assert("144.137.16.240" == sdp.ConnectionLine.Parts[2], "The connection address was not parsed correctly.");
        System.Diagnostics.Debug.Assert(34640 == sdp.MediaDescriptions.First().MediaPort, "The connection port was not parsed correctly.");
        System.Diagnostics.Debug.Assert(0 == sdp.MediaDescriptions.First().PayloadTypes.First(), "The highest priority media format ID was incorrect.");
    }
Beispiel #10
0
    public void TestSessionDescriptionSpecifyingFeedback()
    {
        string testVector = @"v=0
o=- 1 1 IN IP4 127.0.0.1
s=Test
a=type:broadcast
t=0 0
c=IN IP4 0.0.0.0
m=video 0 RTP/AVP 96
a=rtpmap:96 H264/90000
a=fmtp:96 packetization-mode=1;profile-level-id=640028;sprop-parameter-sets=Z2QAKKy0BQHv+A0CAAAcIAACvyHsQPoAALQN3//x2IH0AAFoG7//4UA=,aM48bJCRjhwfHDgkEwlzioJgqFA1wx+cVBMFQoGuGPyCoYGjBx5gh+hEICRA48w79CIQEiBx5h38;
a=control:track0
a=rtcp-fb:96 nack";

        using (Media.Sdp.SessionDescription sd = new Media.Sdp.SessionDescription(testVector))
        {
            Console.WriteLine(sd.ToString());

            //Verify the line count
            System.Diagnostics.Debug.Assert(sd.Lines.Count() == 11, "Did not find all lines");

            //Check for the MediaDescription
            System.Diagnostics.Debug.Assert(sd.MediaDescriptions.Count() == 1, "Cannot find MediaDescription");

            var md = sd.MediaDescriptions.First();

            System.Diagnostics.Debug.Assert(md != null, "Cannot find MediaDescription");

            //Count the line in the media description (including itself)
            System.Diagnostics.Debug.Assert(md.Lines.Count() == 5, "Cannot find corrent amount of lines in MediaDescription");

            var fmtp = md.FmtpLine;

            System.Diagnostics.Debug.Assert(fmtp != null, "Cannot find FmtpLine in MediaDescription");

            string expected = "a=fmtp:96 packetization-mode=1;profile-level-id=640028;sprop-parameter-sets=Z2QAKKy0BQHv+A0CAAAcIAACvyHsQPoAALQN3//x2IH0AAFoG7//4UA=,aM48bJCRjhwfHDgkEwlzioJgqFA1wx+cVBMFQoGuGPyCoYGjBx5gh+hEICRA48w79CIQEiBx5h38;\r\n";

            System.Diagnostics.Debug.Assert(string.Compare(fmtp.ToString(), expected, StringComparison.InvariantCultureIgnoreCase) == 0, "Did not output correct FmtpLine line");

            var rtpMap = md.RtpMapLine;

            System.Diagnostics.Debug.Assert(rtpMap != null, "Cannot find RtpMapLine in MediaDescription");

            expected = "a=rtcp-fb:96 nack\r\n";

            System.Diagnostics.Debug.Assert(string.Compare(sd.AttributeLines.Last().ToString(), expected, StringComparison.InvariantCultureIgnoreCase) == 0, "Did not output correct feedback line");

            System.Diagnostics.Debug.Assert(sd.AttributeLines.Last() == md.AttributeLines.Last(), "Both last attribute lines should be equal to each other");
        }
    }
Beispiel #11
0
    public void CreateSessionDescriptionModifySessionVersionUnitTest()
    {
        Console.WriteLine(System.Reflection.MethodBase.GetCurrentMethod().Name);

        using (Media.Sdp.SessionDescription sdp = new Media.Sdp.SessionDescription(0, "v√ƒ", "Bandit"))
        {
            //update version was specified false so the verison of the document should have updated.
            System.Diagnostics.Debug.Assert(sdp.DocumentVersion == 0, "Did not find Correct SessionVersion");

            //Add a connection line, updating the version
            sdp.Add(new Media.Sdp.Lines.SessionConnectionLine()
            {
                ConnectionNetworkType = "IN",
                ConnectionAddressType = "*",
                ConnectionAddress     = "0.0.0.0"
            });

            System.Diagnostics.Debug.Assert(sdp.Lines.Count() == 4, "Did not have correct amount of Lines");

            long sessionVersion = 9223372036802072014;

            //update version was specified false so the verison of the document should have updated.
            System.Diagnostics.Debug.Assert(sdp.DocumentVersion == 1, "Did not find Correct SessionVersion");

            sdp.DocumentVersion = sessionVersion;

            string expected = "v=0\r\no=v√ƒ  9223372036802072014   \r\ns=Bandit\r\nc=IN * 0.0.0.0\r\n";

            System.Diagnostics.Debug.Assert(string.Compare(sdp.ToString(), expected) == 0, "Did not output correct result.");

            //Try to get a token to update the document
            var token = sdp.BeginUpdate();

            //Do another update to test modification doesn't freeze?
            ++sdp.DocumentVersion;

            //End the update
            sdp.EndUpdate(token, true);

            //update version was specified false so the verison of the document should have updated.
            System.Diagnostics.Debug.Assert(sdp.DocumentVersion == sessionVersion + 1, "Did not find Correct SessionVersion");

            //Do another update
            ++sdp.DocumentVersion;

            System.Diagnostics.Debug.Assert(sdp.DocumentVersion == sessionVersion + 2, "Did not find Correct SessionVersion");
        }
    }
Beispiel #12
0
    public void CreateSessionDescriptionUnitTest()
    {
        Console.WriteLine(System.Reflection.MethodBase.GetCurrentMethod().Name);

        string originatorAndSession = String.Format("{0} {1} {2} {3} {4} {5}", "-", "62464", "0", "IN", "IP4", "10.1.1.2");

        string profile = "RTP/AVP";

        Media.Sdp.MediaType mediaType = Media.Sdp.MediaType.audio;

        int mediaPort = 15000;

        int mediaFormat = 0;

        string sessionName = "MySessionName";

        //The document will have a DocumentVersion of 0 by default.
        //Version will be set (v=) which will try to update the version but there is no originator.
        //Originator is set which causes an update in version but because there was no originator the version is 0
        //Once the originator is set (which maintains the DocumentVersion)
        //It can then be increased, the constructor does not do this for you.
        using (var audioDescription = new Media.Sdp.SessionDescription(mediaFormat, originatorAndSession, sessionName))
        {
            //Ensure the correct SessionDescriptionVersion was set
            System.Diagnostics.Debug.Assert(audioDescription.SessionDescriptionVersion == 0, "Did not find Correct SessionDescriptionVersion");

            //When created the version of the `o=` line should be 1.
            System.Diagnostics.Debug.Assert(audioDescription.DocumentVersion == 0, "Did not find Correct SessionVersion");

            //Add the MediaDescription
            audioDescription.Add(new Media.Sdp.MediaDescription(Media.Sdp.MediaType.audio, mediaPort, profile, 0), false);

            //update version was specified false so the verison of the document should not change
            System.Diagnostics.Debug.Assert(audioDescription.DocumentVersion == 0, "Did not find Correct SessionVersion");

            //Determine what the output should look like
            string expected = string.Format("v=0\r\no={0}\r\ns={1}\r\nm={2} {3} RTP/AVP {4}\r\n", originatorAndSession, sessionName, mediaType, mediaPort, mediaFormat);

            //Make a string from the instance
            string actual = audioDescription.ToString();

            //Check the result of the comparsion
            System.Diagnostics.Debug.Assert(string.Compare(expected, actual) == 0, "Did not output expected result");
        }
    }
Beispiel #13
0
    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.");
    }
        /// <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);
        }
        public string ToString(SessionDescription sdp = null)
        {
            StringBuilder buffer = new StringBuilder();

            //Check if the mapping matches..., should not be done at this level.
            //All instance still need the sdp in ToString to check if the encoding matches?

            //if (sdp != null)
            //{
            //    //Todo, maybe use m_Type because the line may not be typed as a ConnectionLine yet.
            //    Sdp.Lines.SessionConnectionLine connectionLine = sdp.Lines.OfType<Sdp.Lines.SessionConnectionLine>().FirstOrDefault();

            //    /*
            //    If multiple addresses are specified in the "c=" field and multiple
            //    ports are specified in the "m=" field, a one-to-one mapping from
            //    port to the corresponding address is implied.  For example:

            //      c=IN IP4 224.2.1.1/127/2
            //      m=video 49170/2 RTP/AVP 31
            //    */
            //    if (connectionLine != null && connectionLine.HasMultipleAddresses)
            //    {
            //        int numberOfAddresses = connectionLine.NumberOfAddresses;

            //        if (numberOfAddresses > 1)
            //        {
            //            //buffer.Append(Sdp.Lines.SessionMediaDescriptionLine.MediaDescriptionType.ToString() + Sdp.SessionDescription.EqualsSign + string.Join(SessionDescription.Space.ToString(), MediaType, MediaPort.ToString() + ((char)Common.ASCII.ForwardSlash).ToString() + numberOfAddresses.ToString(), MediaProtocol, MediaFormat) + SessionDescription.NewLineString);

            //            buffer.Append(Sdp.Lines.SessionMediaDescriptionLine.MediaDescriptionType);

            //            buffer.Append(Sdp.SessionDescription.EqualsSign);

            //            buffer.Append(
            //            string.Join(SessionDescription.Space.ToString(), MediaType, MediaPort.ToString() + ((char)Common.ASCII.ForwardSlash).ToString() + numberOfAddresses.ToString(), MediaProtocol, MediaFormat)
            //            );

            //            buffer.Append(SessionDescription.NewLineString)

            //            goto LinesOnly;
            //        }
            //    }
            //}

            //Note if Unassigned MediaFormat is used that this might have to be a 'char' to be exactly what was given
            buffer.Append(MediaDescriptionLine.ToString());

            //LinesOnly:
            foreach (SessionDescriptionLine l in m_Lines.Where(l => l.m_Type != Sdp.Lines.SessionBandwidthLine.BandwidthType && l.m_Type != Sdp.Lines.SessionAttributeLine.AttributeType))
            {
                buffer.Append(l.ToString());
            }

            foreach (SessionDescriptionLine l in m_Lines.Where(l => l.m_Type == Sdp.Lines.SessionBandwidthLine.BandwidthType))
            {
                buffer.Append(l.ToString());
            }

            foreach (SessionDescriptionLine l in m_Lines.Where(l => l.m_Type == Sdp.Lines.SessionAttributeLine.AttributeType))
            {
                buffer.Append(l.ToString());
            }

            return(buffer.ToString());
        }
Beispiel #16
0
        //Should have a date when or should return the date playable, which would then be used by another method to compare against a time.
        public static bool IsPlayable(this MediaDescription mediaDescription, SessionDescription sessionDescription) //, DateTime? check = null) ,TimeSpan within = TimeSpan.Zero
        {
            if (Common.IDisposedExtensions.IsNullOrDisposed(mediaDescription) || Common.IDisposedExtensions.IsNullOrDisposed(sessionDescription))
            {
                return(false);
            }

            //Get index of mediaDesription

            //Check TimeDescription @ index.

            TimeDescription td = GetTimeDescription(mediaDescription, sessionDescription);

            //Assume true
            if (Common.IDisposedExtensions.IsNullOrDisposed(td))
            {
                return(true);
            }

            //Unbound start and end ?
            if (td.IsPermanent)
            {
                return(true);
            }

            //Notes multiple calls to UtcNow... (avoid with a within parameter)?
            try
            {
                //Ensure not a bounded end and that the end time is less than now
                if (false.Equals(td.StopTime.Equals(0))
                    &&
                    td.NtpStopDateTime >= DateTime.UtcNow)
                {
                    return(false);
                }

                //Ensure start time is not bounded and that the start time is greater than now
                if (false.Equals(td.StartTime.Equals(0))
                    &&
                    td.NtpStartDateTime > DateTime.UtcNow)
                {
                    return(false);
                }

                //Check repeat times.

                //td.RepeatTimes;
            }
            //Todo, should not access property again during exception especially when out of range is potential.
            catch
            {
                //Out of range values for conversion, assume true if end is unbounded
                if (false.Equals(td.StopTime.Equals(0)))
                {
                    return(false);
                }
            }
            finally
            {
                td = null;
            }

            return(true);
        }
Beispiel #17
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 (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);
        }
Beispiel #18
0
    public void IssueSessionDescriptionWithMediaDescriptionWithPortRange()
    {
        Console.WriteLine(System.Reflection.MethodBase.GetCurrentMethod().Name);

        string testVector = @"v=0
o=- 3 8 IN IP4 10.16.1.22
s=stream1
i=H264 session of stream1
u=http://10.16.1.22
c=IN IP4 239.1.1.22/64/1
t=0 0
m=video 5006/1 RTP/AVP 102
i=Video stream
c=IN IP4 239.1.1.22/64/1
a=fmtp:102 width=1280;height=720;depth=0;framerate=30000;fieldrate=30000;
a=framerate:30
a=rtpmap:102 H264/90000";

        using (Media.Sdp.SessionDescription sd = new Media.Sdp.SessionDescription(testVector))
        {
            Console.WriteLine(sd.ToString());

            //Verify the line count
            System.Diagnostics.Debug.Assert(sd.Lines.Count() == 13, "Did not find all lines");

            //Check for the MediaDescription
            System.Diagnostics.Debug.Assert(sd.MediaDescriptions.Count() == 1, "Cannot find MediaDescription");

            var md = sd.MediaDescriptions.First();

            System.Diagnostics.Debug.Assert(md != null, "Cannot find MediaDescription");

            //Count the line in the media description (including itself)
            System.Diagnostics.Debug.Assert(md.Lines.Count() == 6, "Cannot find corrent amount of lines in MediaDescription");

            var fmtp = md.FmtpLine;

            System.Diagnostics.Debug.Assert(fmtp != null, "Cannot find FmtpLine in MediaDescription");

            var rtpMap = md.RtpMapLine;

            System.Diagnostics.Debug.Assert(rtpMap != null, "Cannot find RtpMapLine in MediaDescription");

            //Verify and set the port range.
            System.Diagnostics.Debug.Assert(md.PortRange.HasValue, "Cannot find MediaDescription.PortRange");

            System.Diagnostics.Debug.Assert(md.PortRange == 1, "Did not find the correct MediaDescription.PortRange");

            //Remove the port range.
            md.PortRange = null;

            System.Diagnostics.Debug.Assert(md.PortRange.HasValue == false, "Did not find the correct MediaDescription.PortRange");

            string expectedMediaDescription = "m=video 5006 RTP/AVP 102\r\ni=Video stream\r\nc=IN IP4 239.1.1.22/64/1\r\na=fmtp:102 width=1280;height=720;depth=0;framerate=30000;fieldrate=30000;\r\na=framerate:30\r\na=rtpmap:102 H264/90000\r\n";

            string actualMediaDescription = md.ToString();

            //Check the result of the comparsion
            System.Diagnostics.Debug.Assert(string.Compare(expectedMediaDescription, actualMediaDescription) == 0, "Did not output expected result");
        }
    }
Beispiel #19
0
    /// <summary>
    /// Tests various attributes of the <see cref="Media.Sdp.MediaDescription"/> class.
    /// </summary>
    public void TestMediaDescription()
    {
        Console.WriteLine(System.Reflection.MethodBase.GetCurrentMethod().Name);

        string testVector = @"v=0
o=- 1419841619185835 1 IN IP4 192.168.1.208
s=IP Camera Video
i=videoMain
a=tool:LIVE555 Streaming Media v2014.02.10
a=type:broadcast
a=control:*
a=range:npt=0-
a=x-qt-text-nam:IP Camera Video
a=x-qt-text-inf:videoMain
t=0
r=604800 3600 0 90000
r=7d 1h 0 25h
m=video 0 RTP/AVP 96
c=IN IP4 0.0.0.0
b=AS:96
a=rtpmap:96 H264/90000
a=fmtp:96 packetization-mode=1;profile-level-id=000000;sprop-parameter-sets=Z0IAHpWoKA9k,aM48gA==
a=control:track1
m=audio 0 RTP/AVP 0
c=IN IP4 0.0.0.0
b=AS:64
a=control:track2";

        Media.Sdp.SessionDescription sessionDescription = new Media.Sdp.SessionDescription(testVector);

        //Ensure 2 media descriptions were found
        System.Diagnostics.Debug.Assert(sessionDescription.MediaDescriptions.Count() == 2, "Did not find all Media Descriptions '2'");

        System.Diagnostics.Debug.Assert(sessionDescription.MediaDescriptions.First().MediaFormat == "96", "Did not find correct MediaFormat '96'");

        System.Diagnostics.Debug.Assert(sessionDescription.MediaDescriptions.First().MediaType == Media.Sdp.MediaType.video, "Did not find correct MediaType 'video'");

        System.Diagnostics.Debug.Assert(sessionDescription.MediaDescriptions.Last().MediaFormat == "0", "Did not find correct MediaFormat '0'");

        System.Diagnostics.Debug.Assert(sessionDescription.MediaDescriptions.Last().MediaType == Media.Sdp.MediaType.audio, "Did not find correct MediaType 'audio;");

        System.Diagnostics.Debug.Assert(false == sessionDescription.MediaDescriptions.Any(m => m.ControlLine == null), "All MediaDescriptons must have a ControlLine which is not null.");

        //Check time descriptions repeat times
        System.Diagnostics.Debug.Assert(sessionDescription.TimeDescriptions.Count() == 1, "Must have 1 TimeDescription");

        System.Diagnostics.Debug.Assert(sessionDescription.TimeDescriptions.First().SessionStartTime == 0, "Did not parse SessionStartTime");

        System.Diagnostics.Debug.Assert(sessionDescription.TimeDescriptions.First().SessionStopTime == 0, "Did not parse SessionStopTime");

        System.Diagnostics.Debug.Assert(sessionDescription.TimeDescriptions.First().RepeatTimes.Count == 2, "First TimeDescription must have 2 RepeatTime entries.");

        //Todo RepeatTimes should be an Object with the properties  (RepeatInterval, ActiveDuration, Offsets[start / stop])
        //r=<repeat interval> <active duration> <offsets from start-time>

        System.Diagnostics.Debug.Assert(sessionDescription.TimeDescriptions.First().RepeatTimes[0] == "604800 3600 0 90000", "Did not parse RepeatTimes");

        System.Diagnostics.Debug.Assert(sessionDescription.TimeDescriptions.First().RepeatTimes[1] == "7d 1h 0 25h", "Did not parse RepeatTimes");

        System.Diagnostics.Debug.Assert(sessionDescription.Length == sessionDescription.ToString().Length, "Did not calculate length correctly");

        System.Diagnostics.Debug.Assert(string.Compare(sessionDescription.ToString(), testVector) < 0, "Did not output exactly same string");
    }
Beispiel #20
0
        public static TimeDescription GetTimeDescription(this MediaDescription mediaDescription, SessionDescription sessionDescription)
        {
            if (Common.IDisposedExtensions.IsNullOrDisposed(mediaDescription) || Common.IDisposedExtensions.IsNullOrDisposed(sessionDescription))
            {
                return(null);
            }

            //Get index of mediaDescription

            //Needs a better way to get the index of the media description
            int index = sessionDescription.GetIndexFor(mediaDescription);  //Array.IndexOf(sessionDescription.MediaDescriptions.ToArray(), mediaDescription);

            if (index == -1)
            {
                return(null);
            }

            return(sessionDescription.GetTimeDescription(index));
        }
        public static TimeDescription GetTimeDescription(this MediaDescription mediaDescription, SessionDescription sessionDescription)
        {
            if (mediaDescription == null || sessionDescription == null)
            {
                return(null);
            }

            //Get index of mediaDescription

            //Needs a better way to get the index of the media description
            int index = sessionDescription.GetIndexFor(mediaDescription);  //Array.IndexOf(sessionDescription.MediaDescriptions.ToArray(), mediaDescription);

            if (index == -1)
            {
                return(null);
            }

            return(sessionDescription.GetTimeDescription(index));
        }
        //Should have a date when or should return the date playable, which would then be used by another method to compare against a time.
        public static bool IsPlayable(this MediaDescription mediaDescription, SessionDescription sessionDescription) //, DateTime? check = null) ,TimeSpan within = TimeSpan.Zero
        {
            if (mediaDescription == null || sessionDescription == null)
            {
                return(false);
            }

            //Get index of mediaDesription

            //Check TimeDescription @ index.

            TimeDescription td = GetTimeDescription(mediaDescription, sessionDescription);

            if (td == null)
            {
                return(true);
            }

            //Unbound start and end ?
            if (td.IsPermanent)
            {
                return(true);
            }

            //Notes multiple calls to UtcNow... (avoid with a within parameter)?
            try
            {
                //Ensure not a bounded end and that the end time is less than now
                if (td.StopTime != 0
                    &&
                    td.NtpStopDateTime >= DateTime.UtcNow)
                {
                    return(false);
                }

                //Ensure start time is not bounded and that the start time is greater than now
                if (td.StartTime != 0
                    &&
                    td.NtpStartDateTime > DateTime.UtcNow)
                {
                    return(false);
                }

                //Check repeat times.

                //td.RepeatTimes;
            }
            catch
            {
                //Out of range values for conversion, assume true if end is unbounded
                if (td.StopTime != 0)
                {
                    return(false);
                }
            }
            finally
            {
                td = null;
            }

            return(true);
        }
Beispiel #23
0
        public static bool SupportsAggregateMediaControl(this SessionDescription sdp, Uri baseUri = null)
        {
            Uri result;

            return(SupportsAggregateMediaControl(sdp, out result, baseUri));
        }