Got an RTSP Client that works in theory.
This commit is contained in:
parent
1a3453059f
commit
4f1c0c8b10
@ -42,6 +42,23 @@ namespace skyscraper5
|
|||||||
string url = RtspClient.MakeUrl(DiSEqC_Opcode.DISEQC_OPTION_A | DiSEqC_Opcode.DISEQC_POSITION_A | DiSEqC_Opcode.DISEQC_HORIZONTAL, 11954, true, 27500);
|
string url = RtspClient.MakeUrl(DiSEqC_Opcode.DISEQC_OPTION_A | DiSEqC_Opcode.DISEQC_POSITION_A | DiSEqC_Opcode.DISEQC_HORIZONTAL, 11954, true, 27500);
|
||||||
RtspDescribeResponse describe = rtspClient.GetDescribe(url);
|
RtspDescribeResponse describe = rtspClient.GetDescribe(url);
|
||||||
SessionDescriptionProtocol sessionDescriptionProtocol = describe.GetSessionDescriptionProtocol();
|
SessionDescriptionProtocol sessionDescriptionProtocol = describe.GetSessionDescriptionProtocol();
|
||||||
|
|
||||||
|
int rtcps = 0;
|
||||||
|
int rtps = 0;
|
||||||
|
|
||||||
|
RtspSetupResponse setup = rtspClient.GetSetup(url);
|
||||||
|
setup.OnRtcpPacket += ((data, length) =>
|
||||||
|
rtcps++);
|
||||||
|
setup.OnRtpPacket += (data, length) =>
|
||||||
|
rtps++;
|
||||||
|
|
||||||
|
RtspPlayResponse play = rtspClient.GetPlay(setup);
|
||||||
|
|
||||||
|
Thread.Sleep(5000);
|
||||||
|
|
||||||
|
rtspClient.GetTeardown(setup);
|
||||||
|
Console.WriteLine("{0} RTCPs",rtcps);
|
||||||
|
Console.WriteLine("{0} RTPs",rtps);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Main(string[] args)
|
static void Main(string[] args)
|
||||||
|
|||||||
@ -87,6 +87,74 @@ namespace skyscraper8.SatIp
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public RtspSetupResponse GetSetup(string url)
|
||||||
|
{
|
||||||
|
RtspSetupRequest request = new RtspSetupRequest();
|
||||||
|
request.RequestPath = url;
|
||||||
|
request.CSeq = cseqCounter++;
|
||||||
|
request.UserAgent = USER_AGENT;
|
||||||
|
|
||||||
|
Socket rtpSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
|
||||||
|
rtpSocket.Bind(new IPEndPoint(ListenIp, 0));
|
||||||
|
int rtpPort = GetPortFromEndPoint(rtpSocket.LocalEndPoint);
|
||||||
|
|
||||||
|
Socket rtcpSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
|
||||||
|
rtcpSocket.Bind(new IPEndPoint(ListenIp, 0));
|
||||||
|
int rtcpPort = GetPortFromEndPoint(rtcpSocket.LocalEndPoint);
|
||||||
|
|
||||||
|
request.SetRtpAvpUnicast(rtpPort, rtcpPort);
|
||||||
|
|
||||||
|
RtspResponseHeader response = GetResponse(request.ListHeaders(RootPath));
|
||||||
|
RtspSetupResponse setupResponse = new RtspSetupResponse(response);
|
||||||
|
if (response.statusCode == 200)
|
||||||
|
{
|
||||||
|
setupResponse.RtpSocket = rtpSocket;
|
||||||
|
setupResponse.RtcpSocket = rtcpSocket;
|
||||||
|
setupResponse.SetupListeners();
|
||||||
|
setupResponse.Valid = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
setupResponse.Valid = false;
|
||||||
|
throw new NotImplementedException(setupResponse.RtspStatusCode.ToString());
|
||||||
|
}
|
||||||
|
return setupResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RtspPlayResponse GetPlay(RtspSetupResponse setupData)
|
||||||
|
{
|
||||||
|
RtspPlayRequest request = new RtspPlayRequest();
|
||||||
|
request.RequestPath = string.Format("/stream={0}", setupData.StreamId);
|
||||||
|
request.Session = setupData.Session;
|
||||||
|
request.UserAgent = USER_AGENT;
|
||||||
|
|
||||||
|
RtspPlayResponse response = new RtspPlayResponse(GetResponse(request.ListHeaders(RootPath)));
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RtspTeardownResponse GetTeardown(RtspSetupResponse setupData)
|
||||||
|
{
|
||||||
|
RtspTeardownRequest request = new RtspTeardownRequest();
|
||||||
|
request.RequestPath = string.Format("/stream={0}", setupData.StreamId);
|
||||||
|
request.Session = setupData.Session;
|
||||||
|
request.UserAgent = USER_AGENT;
|
||||||
|
|
||||||
|
RtspTeardownResponse response = new RtspTeardownResponse(GetResponse(request.ListHeaders(RootPath)));
|
||||||
|
if (response.RtspStatusCode == 200)
|
||||||
|
{
|
||||||
|
setupData.InvokeCancellationTokens();
|
||||||
|
}
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int GetPortFromEndPoint(EndPoint endpoint)
|
||||||
|
{
|
||||||
|
IPEndPoint ipEndPoint = endpoint as IPEndPoint;
|
||||||
|
if (ipEndPoint == null)
|
||||||
|
throw new NotImplementedException(endpoint.GetType().Name);
|
||||||
|
return ipEndPoint.Port;
|
||||||
|
}
|
||||||
|
|
||||||
private RtspResponseHeader GetResponse(string request)
|
private RtspResponseHeader GetResponse(string request)
|
||||||
{
|
{
|
||||||
StreamWriter.Write(request);
|
StreamWriter.Write(request);
|
||||||
|
|||||||
64
skyscraper8/SatIp/RtspRequests/RtspPlayRequest.cs
Normal file
64
skyscraper8/SatIp/RtspRequests/RtspPlayRequest.cs
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace skyscraper8.SatIp.RtspRequests
|
||||||
|
{
|
||||||
|
internal class RtspPlayRequest : RtspRequest
|
||||||
|
{
|
||||||
|
public RtspPlayRequest() : base("PLAY")
|
||||||
|
{
|
||||||
|
Range = "npt=0.000-";
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint CSeq
|
||||||
|
{
|
||||||
|
set
|
||||||
|
{
|
||||||
|
base.args["CSeq"] = Convert.ToString(value);
|
||||||
|
}
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return uint.Parse(base.args["CSeq"]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string UserAgent
|
||||||
|
{
|
||||||
|
set
|
||||||
|
{
|
||||||
|
base.args["User-Agent"] = value;
|
||||||
|
}
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return base.args["User-Agent"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint Session
|
||||||
|
{
|
||||||
|
set
|
||||||
|
{
|
||||||
|
base.args["Session"] = value.ToString();
|
||||||
|
}
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return uint.Parse(base.args["Session"]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Range
|
||||||
|
{
|
||||||
|
set
|
||||||
|
{
|
||||||
|
base.args["Range"] = value;
|
||||||
|
}
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return base.args["Range"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
57
skyscraper8/SatIp/RtspRequests/RtspSetupRequest.cs
Normal file
57
skyscraper8/SatIp/RtspRequests/RtspSetupRequest.cs
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace skyscraper8.SatIp.RtspRequests
|
||||||
|
{
|
||||||
|
internal class RtspSetupRequest : RtspRequest
|
||||||
|
{
|
||||||
|
public RtspSetupRequest() : base("SETUP")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint CSeq
|
||||||
|
{
|
||||||
|
set
|
||||||
|
{
|
||||||
|
base.args["CSeq"] = Convert.ToString(value);
|
||||||
|
}
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return uint.Parse(base.args["CSeq"]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string UserAgent
|
||||||
|
{
|
||||||
|
set
|
||||||
|
{
|
||||||
|
base.args["User-Agent"] = value;
|
||||||
|
}
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return base.args["User-Agent"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Transport
|
||||||
|
{
|
||||||
|
set
|
||||||
|
{
|
||||||
|
base.args["Transport"] = value;
|
||||||
|
}
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return base.args["Transport"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetRtpAvpUnicast(int rtpPort, int rtcpPort)
|
||||||
|
{
|
||||||
|
Transport = String.Format("RTP/AVP;unicast;client_port={0}-{1}", rtpPort, rtcpPort);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
51
skyscraper8/SatIp/RtspRequests/RtspTeardownRequest.cs
Normal file
51
skyscraper8/SatIp/RtspRequests/RtspTeardownRequest.cs
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace skyscraper8.SatIp.RtspRequests
|
||||||
|
{
|
||||||
|
internal class RtspTeardownRequest : RtspRequest
|
||||||
|
{
|
||||||
|
public RtspTeardownRequest() : base("TEARDOWN")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint CSeq
|
||||||
|
{
|
||||||
|
set
|
||||||
|
{
|
||||||
|
base.args["CSeq"] = Convert.ToString(value);
|
||||||
|
}
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return uint.Parse(base.args["CSeq"]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string UserAgent
|
||||||
|
{
|
||||||
|
set
|
||||||
|
{
|
||||||
|
base.args["User-Agent"] = value;
|
||||||
|
}
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return base.args["User-Agent"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint Session
|
||||||
|
{
|
||||||
|
set
|
||||||
|
{
|
||||||
|
base.args["Session"] = value.ToString();
|
||||||
|
}
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return uint.Parse(base.args["Session"]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
47
skyscraper8/SatIp/RtspResponses/RtspPlayResponse.cs
Normal file
47
skyscraper8/SatIp/RtspResponses/RtspPlayResponse.cs
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace skyscraper8.SatIp.RtspResponses
|
||||||
|
{
|
||||||
|
internal class RtspPlayResponse : RtspResponse
|
||||||
|
{
|
||||||
|
public RtspPlayResponse(RtspResponseHeader header) : base(header)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint CSeq
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return uint.Parse(base.args["CSeq"]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint Session
|
||||||
|
{
|
||||||
|
set
|
||||||
|
{
|
||||||
|
base.args["Session"] = value.ToString();
|
||||||
|
}
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return uint.Parse(base.args["Session"]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string RtpInfo
|
||||||
|
{
|
||||||
|
set
|
||||||
|
{
|
||||||
|
base.args["RTP-Info"] = value.ToString();
|
||||||
|
}
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return base.args["RTP-Info"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
112
skyscraper8/SatIp/RtspResponses/RtspSetupResponse.cs
Normal file
112
skyscraper8/SatIp/RtspResponses/RtspSetupResponse.cs
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net.Sockets;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace skyscraper8.SatIp.RtspResponses
|
||||||
|
{
|
||||||
|
internal class RtspSetupResponse : RtspResponse
|
||||||
|
{
|
||||||
|
public RtspSetupResponse(RtspResponseHeader header) : base(header)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public Socket RtpSocket { get; set; }
|
||||||
|
public Socket RtcpSocket { get; set; }
|
||||||
|
|
||||||
|
public uint CSeq
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return uint.Parse(base.args["CSeq"]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint Session
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
string s = base.args["Session"];
|
||||||
|
string[] strings = s.Split(';');
|
||||||
|
return uint.Parse(strings[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint StreamId
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return uint.Parse(base.args["com.ses.streamID"]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte exitedThread;
|
||||||
|
private CancellationTokenSource rtpCancellation;
|
||||||
|
private CancellationTokenSource rtcpCancellation;
|
||||||
|
private Thread rtpThread;
|
||||||
|
private Thread rtcpThread;
|
||||||
|
private bool listenersStarted;
|
||||||
|
internal void SetupListeners()
|
||||||
|
{
|
||||||
|
if (listenersStarted)
|
||||||
|
throw new RtspException("Listener already started.");
|
||||||
|
|
||||||
|
rtpCancellation = new CancellationTokenSource();
|
||||||
|
rtcpCancellation = new CancellationTokenSource();
|
||||||
|
rtpThread = new Thread(RtpThread);
|
||||||
|
rtcpThread = new Thread(RtcpThread);
|
||||||
|
rtpThread.Start();
|
||||||
|
rtcpThread.Start();
|
||||||
|
listenersStarted = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RtpThread()
|
||||||
|
{
|
||||||
|
Task.Run(async () =>
|
||||||
|
{
|
||||||
|
byte[] buffer = new byte[2048];
|
||||||
|
|
||||||
|
while (!rtpCancellation.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
Array.Clear(buffer);
|
||||||
|
int result = await RtpSocket.ReceiveAsync(buffer, rtpCancellation.Token);
|
||||||
|
OnRtpPacket?.Invoke(buffer, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
exitedThread++;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RtcpThread()
|
||||||
|
{
|
||||||
|
Task.Run(async () =>
|
||||||
|
{
|
||||||
|
byte[] buffer = new byte[2048];
|
||||||
|
while (!rtcpCancellation.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
Array.Clear(buffer);
|
||||||
|
ValueTask<int> task = RtcpSocket.ReceiveAsync(buffer, rtcpCancellation.Token);
|
||||||
|
int taskResult = task.Result;
|
||||||
|
OnRtcpPacket?.Invoke(buffer, taskResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
exitedThread++;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void InvokeCancellationTokens()
|
||||||
|
{
|
||||||
|
rtpCancellation.Cancel();
|
||||||
|
rtcpCancellation.Cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
public event OnRtpPacket OnRtpPacket;
|
||||||
|
public event OnRtpPacket OnRtcpPacket;
|
||||||
|
}
|
||||||
|
|
||||||
|
public delegate void OnRtpPacket(byte[] data, int length);
|
||||||
|
}
|
||||||
35
skyscraper8/SatIp/RtspResponses/RtspTeardownResponse.cs
Normal file
35
skyscraper8/SatIp/RtspResponses/RtspTeardownResponse.cs
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace skyscraper8.SatIp.RtspResponses
|
||||||
|
{
|
||||||
|
internal class RtspTeardownResponse : RtspResponse
|
||||||
|
{
|
||||||
|
public RtspTeardownResponse(RtspResponseHeader header) : base(header)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint CSeq
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return uint.Parse(base.args["CSeq"]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint Session
|
||||||
|
{
|
||||||
|
set
|
||||||
|
{
|
||||||
|
base.args["Session"] = value.ToString();
|
||||||
|
}
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return uint.Parse(base.args["Session"]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user