public override RtspResponse SetUp(RtspRequest request) { var builder = RtspResponse.CreateBuilder().Status(RtspResponse.Status.Ok); var transport = request.Transport; if (transport == null) { return(builder.Status(RtspResponse.Status.BadRequest).Build()); } else if (transport.Type != TransportType.RtspInterleaved) { return(builder.Status(RtspResponse.Status.UnsupportedTransport).Build()); } lock (this) { PortPair channels = new PortPair(_currentChannel, _currentChannel + 1); _currentChannel += 2; var session = new InterleavedTestSession(request.Context, _spy, channels, PAYLOAD_TYPE); _sessionManager.RegisterSession(session); transport = TransportHeader.CreateBuilder() .Type(TransportType.RtspInterleaved) .InterleavedChannels(channels) .Build(); return(builder.AddHeader(RtspHeaders.Names.TRANSPORT, transport.ToString()) .AddHeader(RtspHeaders.Names.SESSION, session.Id) .Build()); } }
public override RtspResponse SetUp(RtspRequest request) { var builder = RtspResponse.CreateBuilder(); var queryParams = HttpUtility.ParseQueryString(request.URI.Query); var sourceId = queryParams["sourceId"]; if (sourceId == null || !_sourceMgr.ContainsSource(sourceId)) { return(builder.Status(RtspResponse.Status.NotFound).Build()); } var transport = request.Transport; if (transport == null) { return(builder.Status(RtspResponse.Status.BadRequest).Build()); } if (transport.Type != Pelco.Media.RTSP.TransportType.UdpUnicast) { return(builder.Status(RtspResponse.Status.UnsupportedTransport).Build()); } if (transport.ClientPorts == null || !transport.ClientPorts.IsSet) { return(builder.Status(RtspResponse.Status.BadRequest).Build()); } var rtpPort = transport.ClientPorts.RtpPort; var address = transport.Destination != null?Dns.GetHostAddresses(transport.Destination)[0] : request.RemoteEndpoint.Address; var rtspSession = new RtspSession(_sourceMgr.GetSource(sourceId).GetPipelineSource(), PAYLOAD_TYPE, new IPEndPoint(address, rtpPort)); if (!_sessionMgr.RegisterSession(rtspSession)) { return(builder.Status(RtspResponse.Status.InternalServerError) .AddHeader(RtspHeaders.Names.CONTENT_TYPE, "text/plain") .Body("Unable to register Rtsp session with system") .Build()); } var session = Session.FromParts(rtspSession.Id, RtspSession.RTSP_SESSION_TIMEOUT); transport = TransportHeader.CreateBuilder() .Type(Pelco.Media.RTSP.TransportType.UdpUnicast) .ClientPorts(transport.ClientPorts) .ServerPorts(rtpPort + 3, rtpPort + 4) // Just create dummy ports. .Build(); return(builder.Status(RtspResponse.Status.Ok) .AddHeader(RtspHeaders.Names.TRANSPORT, transport.ToString()) .AddHeader(RtspHeaders.Names.SESSION, session.ToString()) .Build()); }
public void TestInterleaved() { var transport = TransportHeader.CreateBuilder() .Type(TransportType.RtspInterleaved) .InterleavedChannels(0, 1) .Build(); var response = _fixture.Client.Request().Transport(transport).SetUp(); Assert.True(response.ResponseStatus.Is(RtspResponse.Status.Ok)); transport = response.Transport; Assert.NotNull(transport); Assert.Equal(TransportType.RtspInterleaved, transport.Type); Assert.Equal(0, transport.InterleavedChannels.RtpPort); Assert.Equal(1, transport.InterleavedChannels.RtcpPort); var session = response.Session; Assert.NotNull(session); Assert.NotEmpty(session.ID); Assert.Equal(60u, session.Timeout); var sink = new Sink(); var pipeline = MediaPipeline.CreateBuilder() .Source(_fixture.Client.GetChannelSource(transport.InterleavedChannels.RtpPort)) .Transform(new DefaultRtpDepacketizer()) .Sink(sink) .Build(); pipeline.Start(); _fixture.Client.Request().Session(session.ID).PlayAsync((res) => { Assert.True(res.ResponseStatus.Is(RtspResponse.Status.Ok)); }); sink.WaitForCompletion(TimeSpan.FromSeconds(20)); _fixture.Client.Request().Session(session.ID).TeardownAsync((res) => { }); pipeline.Stop(); var sessData = _spy.GetData(session.ID); Assert.Equal(sessData.Buffers.Count, sink.ReceivedBuffers.Count); Assert.True(Enumerable.SequenceEqual(sessData.Buffers, sink.ReceivedBuffers)); }
private bool GetRedirectUri(RtspClient client, MediaTrack track, out Uri uri) { var transport = TransportHeader.CreateBuilder() .Type(TransportType.RtspInterleaved) .InterleavedChannels(0, 1) .Build(); var method = RtspRequest.RtspMethod.SETUP; var res = CheckResponse(client.Send(RtspRequest.CreateBuilder() .Method(method) .Uri(track.ControlUri) .AddHeader(RtspHeaders.Names.TRANSPORT, transport.ToString()) .Build()), method); if (!res.Headers.ContainsKey(RtspHeaders.Names.SESSION)) { uri = null; return(false); } var rtspSession = Session.Parse(res.Headers[RtspHeaders.Names.SESSION]); method = RtspRequest.RtspMethod.PLAY; res = CheckResponse(client.Send(RtspRequest.CreateBuilder() .Method(method) .Uri(track.ControlUri) .AddHeader(RtspHeaders.Names.SESSION, rtspSession.ID) .Build()), method); var status = res.ResponseStatus; if (status.Is(RtspResponse.Status.MovedPermanently) || status.Is(RtspResponse.Status.MovedTemporarily)) { // We received a redirect lets get the uri and return it. if (res.Headers.ContainsKey(RtspHeaders.Names.LOCATION)) { var value = res.Headers[RtspHeaders.Names.LOCATION]; return(Uri.TryCreate(value, UriKind.RelativeOrAbsolute, out uri)); } } uri = null; return(false); }
private RtpSession Setup(MediaTrack track, RtpChannelSink sink, bool interleaved) { lock (SourceLock) { IRtpSource rtpSource = null; try { TransportHeader transport = null; if (interleaved) { transport = TransportHeader.CreateBuilder() .Type(Media.RTSP.TransportType.RtspInterleaved) .InterleavedChannels(0, 1) .Build(); } else { // TODO(frank.lamar): Add multicast support. rtpSource = new RtpUdpSource(track.Address); transport = TransportHeader.CreateBuilder() .Type(Media.RTSP.TransportType.UdpUnicast) .ClientPorts(rtpSource.RtpPort, rtpSource.RtcpPort) .Build(); } var response = CheckResponse(_client.Send(RtspRequest.CreateBuilder() .Method(RtspRequest.RtspMethod.SETUP) .Uri(track.ControlUri) .AddHeader(RtspHeaders.Names.TRANSPORT, transport.ToString()) .Build()), RtspRequest.RtspMethod.SETUP); if (!response.Headers.ContainsKey(RtspHeaders.Names.SESSION)) { throw new RtspClientException("Rtsp SETUP response does not contain a session id"); } var rtspSession = Session.Parse(response.Headers[RtspHeaders.Names.SESSION]); transport = response.Transport; if (interleaved) { if (transport.Type != Media.RTSP.TransportType.RtspInterleaved) { throw new RtspClientException($"Server does not support interleaved. Response Transport='{transport}'"); } var channels = transport.InterleavedChannels != null ? transport.InterleavedChannels : new PortPair(0, 1); sink.Channel = channels.RtpPort; // Ensure that the sink contains the correct Interleaved channel id. rtpSource = new RtpInterleavedSource(_client.GetChannelSource(channels.RtpPort), _client.GetChannelSource(channels.RtcpPort)); } var pipeline = MediaPipeline.CreateBuilder() .Source(rtpSource.RtpSource) .TransformIf(transport.SSRC != null, new SsrcFilter(transport.SSRC)) .Sink(sink) .Build(); var session = new RtpSession(track, rtspSession, rtpSource); session.Pipelines.Add(pipeline); session.Start(); CheckAndStartRefreshTimer(session.Session.Timeout); return(session); } catch (Exception e) { if (rtpSource != null) { rtpSource?.Stop(); } if (e is RtspClientException) { throw e; } throw new RtspClientException($"Unable to set up media track {track.ID}", e); } } }