Exemple #1
0
        /// <summary>
        /// The SETUP request for a URI specifies the transport mechanism to be
        /// used for the streamed media. A client can issue a SETUP request for a
        /// stream that is already playing to change transport parameters, which
        /// a server MAY allow. If it does not allow this, it MUST respond with
        /// error "455 Method Not Valid In This State". For the benefit of any
        /// intervening firewalls, a client must indicate the transport
        /// parameters even if it has no influence over these parameters, for
        /// example, where the server advertises a fixed multicast address.
        ///
        /// https://tools.ietf.org/html/rfc2326#section-10.4
        /// </summary>
        public async Task <RtspSetupResponse> SetupAsync(Uri rtspControlUri, int rtpPort, int rtcpPort)
        {
            var requestMessage = new RtspRequestMessage(rtspControlUri, "SETUP")
            {
                Headers = { new KeyValuePair <string, string>("Transport", $"RTP/AVP;unicast;client_port={rtpPort}-{rtcpPort}") }
            };

            var response = await SendAsync(requestMessage);

            var sessionHeader   = response.Headers.Get("Session");
            var transportHeader = response.Headers.Get("Transport");

            var sessionKeyValues = KeyValueParser.ParsePairs(sessionHeader, ';');
            var session          = sessionKeyValues[0].Key;
            var sessionTimeout   = sessionKeyValues.FirstOrDefault(l => l.Key == "timeout").Value;

            var transportKeyValues = KeyValueParser.ParsePairs(transportHeader, ';');

            var serverPortRange = transportKeyValues.FirstOrDefault(l => l.Key == "server_port").Value;
            var ssrc            = transportKeyValues.FirstOrDefault(l => l.Key == "ssrc").Value;

            return(new RtspSetupResponse
            {
                Session = session,
                SessionTimeoutSeconds = int.Parse(sessionTimeout),
                ServerPorts = serverPortRange?.Split('-').Select(int.Parse).ToArray(),
                Ssrc = Convert.ToUInt32(ssrc, 16),
                ResponseMessage = response
            });
        }
Exemple #2
0
        /// <summary>
        /// The PLAY method tells the server to start sending data via the
        /// mechanism specified in SETUP. A client MUST NOT issue a PLAY request
        /// until any outstanding SETUP requests have been acknowledged as
        /// successful.
        ///
        /// The PLAY request positions the normal play time to the beginning of
        /// the range specified and delivers stream data until the end of the
        /// range is reached. PLAY requests may be pipelined (queued); a server
        /// MUST queue PLAY requests to be executed in order. That is, a PLAY
        /// request arriving while a previous PLAY request is still active is
        /// delayed until the first has been completed.
        ///
        /// This allows precise editing.
        ///
        /// https://tools.ietf.org/html/rfc2326#section-10.5
        /// </summary>
        ///
        /// <param name="session">
        /// Session identifiers are opaque strings of arbitrary length. Linear
        /// white space must be URL-escaped. A session identifier MUST be chosen
        /// randomly and MUST be at least eight octets long to make guessing it
        /// more difficult. (See Section 16.)
        ///
        /// session-id   =   1*( ALPHA | DIGIT | safe )
        ///
        /// https://tools.ietf.org/html/rfc2326#section-3.4
        /// </param>
        ///
        /// <param name="nptRange">
        /// Normal play time (NPT) indicates the stream absolute position
        /// relative to the beginning of the presentation. The timestamp consists
        /// of a decimal fraction. The part left of the decimal may be expressed
        /// in either seconds or hours, minutes, and seconds. The part right of
        /// the decimal point measures fractions of a second.
        ///
        /// The beginning of a presentation corresponds to 0.0 seconds. Negative
        /// values are not defined. The special constant now is defined as the
        /// current instant of a live event. It may be used only for live events.
        ///
        /// NPT is defined as in DSM-CC: "Intuitively, NPT is the clock the
        /// viewer associates with a program. It is often digitally displayed on
        /// a VCR. NPT advances normally when in normal play mode (scale = 1),
        /// advances at a faster rate when in fast scan forward (high positive
        /// scale ratio), decrements when in scan reverse (high negative scale
        /// ratio) and is fixed in pause mode. NPT is (logically) equivalent to
        /// SMPTE time codes." [5]
        ///
        /// npt-range    =   ( npt-time "-" [ npt-time ] ) | ( "-" npt-time )
        /// npt-time     =   "now" | npt-sec | npt-hhmmss
        /// npt-sec      =   1*DIGIT [ "." *DIGIT ]
        /// npt-hhmmss   =   npt-hh ":" npt-mm ":" npt-ss [ "." *DIGIT ]
        /// npt-hh       =   1*DIGIT     ; any positive number
        /// npt-mm       =   1*2DIGIT    ; 0-59
        /// npt-ss       =   1*2DIGIT    ; 0-59
        ///
        ///     Examples:
        /// npt=123.45-125
        /// npt=12:05:35.3-
        /// npt=now-
        ///
        /// The syntax conforms to ISO 8601. The npt-sec notation is optimized
        /// for automatic generation, the ntp-hhmmss notation for consumption
        /// by human readers. The "now" constant allows clients to request to
        /// receive the live feed rather than the stored or time-delayed
        /// version. This is needed since neither absolute time nor zero time
        /// are appropriate for this case.
        ///
        /// https://tools.ietf.org/html/rfc2326#section-3.6
        /// </param>
        public async Task <RtspPlayResponse> PlayAsync(Uri rtspUri, string session, string nptRange)
        {
            var requestMessage = new RtspRequestMessage(rtspUri, "PLAY")
            {
                Headers =
                {
                    new KeyValuePair <string, string>("Session", session),
                    new KeyValuePair <string, string>("Range",   $"npt={nptRange}")
                }
            };

            var response = await SendAsync(requestMessage);

            var rtpInfoHeader = response.Headers.Get("RTP-Info");

            var rtpInfoParts = rtpInfoHeader.Split(',');
            var rtpInfos     = new List <RtpInfo>();

            foreach (var rtpInfoPart in rtpInfoParts)
            {
                var pairs = KeyValueParser.ParsePairs(rtpInfoPart, ';');

                var rtpInfo = new RtpInfo
                {
                    Url     = pairs.First(l => l.Key == "url").Value,
                    Seq     = Convert.ToUInt32(pairs.First(l => l.Key == "seq").Value),
                    RtpTime = Convert.ToUInt32(pairs.FirstOrDefault(l => l.Key == "rtptime").Value)
                };

                rtpInfos.Add(rtpInfo);
            }

            return(new RtspPlayResponse
            {
                RtpInfo = rtpInfos.ToArray(),
                ResponseMessage = response
            });
        }