public async Task ConnectAsync(DateTime initialTimeStamp, CancellationToken token) { IRtspTransportClient rtspTransportClient = _transportClientProvider(); Volatile.Write(ref _rtspTransportClient, rtspTransportClient); await _rtspTransportClient.ConnectAsync(token); RtspRequestMessage optionsRequest = _requestMessageFactory.CreateOptionsRequest(); RtspResponseMessage optionsResponse = await _rtspTransportClient.ExecuteRequest(optionsRequest, token); if (optionsResponse.StatusCode == RtspStatusCode.Ok) { ParsePublicHeader(optionsResponse.Headers[WellKnownHeaders.Public]); } RtspRequestMessage describeRequest = _requestMessageFactory.CreateDescribeRequest(); RtspResponseMessage describeResponse = await _rtspTransportClient.EnsureExecuteRequest(describeRequest, token); string contentBaseHeader = describeResponse.Headers[WellKnownHeaders.ContentBase]; if (!string.IsNullOrEmpty(contentBaseHeader)) { _requestMessageFactory.ContentBase = new Uri(contentBaseHeader); } var parser = new SdpParser(); IEnumerable <RtspTrackInfo> tracks = parser.Parse(describeResponse.ResponseBody); bool anyTrackRequested = false; foreach (RtspMediaTrackInfo track in GetTracksToSetup(tracks)) { await SetupTrackAsync(initialTimeStamp, track, token); anyTrackRequested = true; } if (!anyTrackRequested) { throw new RtspClientException("Any suitable track is not found"); } RtspRequestMessage playRequest = (initialTimeStamp != default(DateTime) ? _requestMessageFactory.CreatePlayRequest(initialTimeStamp) : _requestMessageFactory.CreatePlayRequest()); RtspResponseMessage playResponse = await _rtspTransportClient.EnsureExecuteRequest(playRequest, token, 1); // TODO : Create a specific parse to convert the clock values Regex clockRegex = new Regex(@"clock=(?<startTime>\d{8}T\d{6}Z)\-(?<endTime>\d{8}T\d{6}Z)", RegexOptions.Singleline); foreach (string playResponseHeader in playResponse.Headers.GetValues("Range")) { Match clockMatches = clockRegex.Match(playResponseHeader); if (clockMatches.Success) { _mediaPayloadParser.BaseTime = DateTime.ParseExact(clockMatches.Groups["startTime"].Value, "yyyyMMddTHHmmssZ", CultureInfo.InvariantCulture, DateTimeStyles.None); } } }
public async Task <RtspResponseMessage> EnsureExecuteRequest(RtspRequestMessage requestMessage, CancellationToken token, int responseReadPortionSize = 0) { RtspResponseMessage responseMessage = await ExecuteRequest(requestMessage, token, responseReadPortionSize); if (responseMessage.StatusCode != RtspStatusCode.Ok) { throw new RtspBadResponseCodeException(responseMessage.StatusCode); } return(responseMessage); }
private async Task <RtspResponseMessage> GetResponseAsync(int responseReadPortionSize = 0) { int totalRead = await ReadUntilEndOfHeadersAsync(responseReadPortionSize); int startOfResponse = ArrayUtils.IndexOfBytes(_buffer, Constants.RtspProtocolNameBytes, 0, totalRead); if (startOfResponse == -1) { throw new RtspBadResponseException("\"RTSP\" start signature is not found"); } int endOfResponseHeaders = ArrayUtils.LastIndexOfBytes(_buffer, Constants.DoubleCrlfBytes, 0, totalRead) + Constants.DoubleCrlfBytes.Length; if (endOfResponseHeaders == -1) { throw new RtspBadResponseException("End of response headers is not found"); } var headersByteSegment = new ArraySegment <byte>(_buffer, startOfResponse, endOfResponseHeaders - startOfResponse); RtspResponseMessage rtspResponseMessage = RtspResponseMessage.Parse(headersByteSegment); string contentLengthString = rtspResponseMessage.Headers[WellKnownHeaders.ContentLength]; if (string.IsNullOrEmpty(contentLengthString)) { return(rtspResponseMessage); } if (!uint.TryParse(contentLengthString, out uint contentLength)) { throw new RtspParseResponseException($"Invalid content-length header: {contentLengthString}"); } if (contentLength == 0) { return(rtspResponseMessage); } if (contentLength > Constants.MaxResponseHeadersSize) { throw new RtspBadResponseException($"Response content is too large: {contentLength}"); } int dataPartSize = totalRead - headersByteSegment.Count; Buffer.BlockCopy(_buffer, endOfResponseHeaders, _buffer, 0, dataPartSize); await ReadExactAsync(_buffer, dataPartSize, (int)(contentLength - dataPartSize)); rtspResponseMessage.ResponseBody = new ArraySegment <byte>(_buffer, 0, (int)contentLength); return(rtspResponseMessage); }
public async Task ConnectAsync(CancellationToken token) { IRtspTransportClient rtspTransportClient = _transportClientProvider(); Volatile.Write(ref _rtspTransportClient, rtspTransportClient); await _rtspTransportClient.ConnectAsync(token); RtspRequestMessage optionsRequest = _requestMessageFactory.CreateOptionsRequest(); RtspResponseMessage optionsResponse = await _rtspTransportClient.ExecuteRequest(optionsRequest, token); if (optionsResponse.StatusCode == RtspStatusCode.Ok) { ParsePublicHeader(optionsResponse.Headers[WellKnownHeaders.Public]); } RtspRequestMessage describeRequest = _requestMessageFactory.CreateDescribeRequest(); RtspResponseMessage describeResponse = await _rtspTransportClient.EnsureExecuteRequest(describeRequest, token); string contentBaseHeader = describeResponse.Headers[WellKnownHeaders.ContentBase]; if (!string.IsNullOrEmpty(contentBaseHeader)) { _requestMessageFactory.ContentBase = new Uri(contentBaseHeader); } var parser = new SdpParser(); IEnumerable <RtspTrackInfo> tracks = parser.Parse(describeResponse.ResponseBody); bool anyTrackRequested = false; foreach (RtspMediaTrackInfo track in GetTracksToSetup(tracks)) { await SetupTrackAsync(track, token); Codec = track.Codec; anyTrackRequested = true; } if (!anyTrackRequested) { throw new RtspClientException("Any suitable track is not found"); } RtspRequestMessage playRequest = _requestMessageFactory.CreatePlayRequest(); await _rtspTransportClient.EnsureExecuteRequest(playRequest, token, 1); }
public async Task <RtspResponseMessage> ExecuteRequest(RtspRequestMessage requestMessage, CancellationToken token, int responseReadPortionSize = 0) { token.ThrowIfCancellationRequested(); await SendRequestAsync(requestMessage, token); RtspResponseMessage responseMessage = await GetResponseAsync(responseReadPortionSize); if (responseMessage.StatusCode != RtspStatusCode.Unauthorized) { return(responseMessage); } if (ConnectionParameters.Credentials.IsEmpty() || _authenticator != null) { throw new RtspBadResponseCodeException(responseMessage.StatusCode); } string authenticateHeader = responseMessage.Headers[WellKnownHeaders.WwwAuthenticate]; if (string.IsNullOrEmpty(authenticateHeader)) { throw new RtspBadResponseCodeException(responseMessage.StatusCode); } _authenticator = Authenticator.Create(ConnectionParameters.Credentials, authenticateHeader); requestMessage.UpdateSequenceNumber(); await SendRequestAsync(requestMessage, token); responseMessage = await GetResponseAsync(); if (responseMessage.StatusCode == RtspStatusCode.Unauthorized) { throw new RtspBadResponseCodeException(responseMessage.StatusCode); } return(responseMessage); }