Added a command-line option to tune SAT>IP servers without actually processing the stream.
This commit is contained in:
parent
fe672a54f9
commit
8de4b56c6f
@ -120,6 +120,11 @@ namespace skyscraper8.GS.GSE_BFBS
|
|||||||
if (!startIndicator && endIndicator)
|
if (!startIndicator && endIndicator)
|
||||||
gseLength -= 4;
|
gseLength -= 4;
|
||||||
|
|
||||||
|
if (span.GetAvailableBytes() < gseLength)
|
||||||
|
{
|
||||||
|
//broken gse packet, invalid length
|
||||||
|
return;
|
||||||
|
}
|
||||||
gsePacket.GseDataBytes = span.ReadBytes(gseLength);
|
gsePacket.GseDataBytes = span.ReadBytes(gseLength);
|
||||||
|
|
||||||
if (!startIndicator && endIndicator)
|
if (!startIndicator && endIndicator)
|
||||||
|
|||||||
@ -288,8 +288,17 @@ namespace skyscraper5
|
|||||||
QuickAndDirtySatIpClient qadsipc = new QuickAndDirtySatIpClient(args);
|
QuickAndDirtySatIpClient qadsipc = new QuickAndDirtySatIpClient(args);
|
||||||
qadsipc.Run();
|
qadsipc.Run();
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args[0].ToLowerInvariant().Equals("satip-playout"))
|
||||||
|
{
|
||||||
|
QuickAndDirtySatIpClient qadsipc = new QuickAndDirtySatIpClient(args);
|
||||||
|
qadsipc.SetPlayoutMode(args);
|
||||||
|
qadsipc.Run();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (args[0].ToLowerInvariant().Equals("shannon"))
|
if (args[0].ToLowerInvariant().Equals("shannon"))
|
||||||
{
|
{
|
||||||
if (args.Length != 2)
|
if (args.Length != 2)
|
||||||
@ -392,6 +401,7 @@ namespace skyscraper5
|
|||||||
Console.WriteLine(" or: .\\skyscraper8.exe \"C:\\path\\to\\file.ts\\");
|
Console.WriteLine(" or: .\\skyscraper8.exe \"C:\\path\\to\\file.ts\\");
|
||||||
Console.WriteLine(" or: .\\skyscraper8.exe \"C:\\path\\to\\my\\folder\\with\\ts\\files\\\" (for batch extraction)");
|
Console.WriteLine(" or: .\\skyscraper8.exe \"C:\\path\\to\\my\\folder\\with\\ts\\files\\\" (for batch extraction)");
|
||||||
Console.WriteLine(" or: .\\skyscraper8.exe satip IP_ADDRESS DISEQC POLARITY FREQUENCY SYSTEM SYMBOL_RATE (see README file)");
|
Console.WriteLine(" or: .\\skyscraper8.exe satip IP_ADDRESS DISEQC POLARITY FREQUENCY SYSTEM SYMBOL_RATE (see README file)");
|
||||||
|
Console.WriteLine(" or: .\\skyscraper8.exe satip-playout IP_ADDRESS DISEQC POLARITY FREQUENCY SYSTEM SYMBOL_RATE DESTINATION_PORT");
|
||||||
Console.WriteLine(" or: .\\skyscraper8.exe pcap-on - to write a configuration file that allows PCAP writing during scraping.");
|
Console.WriteLine(" or: .\\skyscraper8.exe pcap-on - to write a configuration file that allows PCAP writing during scraping.");
|
||||||
Console.WriteLine(" or: .\\skyscraper8.exe pcap-off - to write a configuration file that turns off PCAP writing during scraping.");
|
Console.WriteLine(" or: .\\skyscraper8.exe pcap-off - to write a configuration file that turns off PCAP writing during scraping.");
|
||||||
Console.WriteLine(" or: .\\skyscraper8.exe subts-on - to write a configuration file that allows extraction of nested TS.");
|
Console.WriteLine(" or: .\\skyscraper8.exe subts-on - to write a configuration file that allows extraction of nested TS.");
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
"profiles": {
|
"profiles": {
|
||||||
"skyscraper8": {
|
"skyscraper8": {
|
||||||
"commandName": "Project",
|
"commandName": "Project",
|
||||||
|
"commandLineArgs": "satip-playout auto 1 V 12597 S2 45000 6970",
|
||||||
"remoteDebugEnabled": false
|
"remoteDebugEnabled": false
|
||||||
},
|
},
|
||||||
"Container (Dockerfile)": {
|
"Container (Dockerfile)": {
|
||||||
|
|||||||
@ -74,6 +74,17 @@ namespace skyscraper8
|
|||||||
symbolRate = Int32.Parse(args[6]);
|
symbolRate = Int32.Parse(args[6]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetPlayoutMode(string[] args)
|
||||||
|
{
|
||||||
|
if (args.Length == 7)
|
||||||
|
{
|
||||||
|
logger.Fatal("What's the target port?");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
destinationPort = int.Parse(args[7]);
|
||||||
|
playoutMode = true;
|
||||||
|
}
|
||||||
|
|
||||||
private IPAddress AutodetectIPAddress()
|
private IPAddress AutodetectIPAddress()
|
||||||
{
|
{
|
||||||
SsdpDevice firstSatIpServer = SsdpClient.GetFirstSatIpServer(1000, null);
|
SsdpDevice firstSatIpServer = SsdpClient.GetFirstSatIpServer(1000, null);
|
||||||
@ -105,7 +116,7 @@ namespace skyscraper8
|
|||||||
SessionDescriptionProtocol sessionDescriptionProtocol = describe.GetSessionDescriptionProtocol();
|
SessionDescriptionProtocol sessionDescriptionProtocol = describe.GetSessionDescriptionProtocol();
|
||||||
|
|
||||||
packetQueue = new Queue<byte[]>();
|
packetQueue = new Queue<byte[]>();
|
||||||
RtspSetupResponse setup = rtspClient.GetSetup(url);
|
RtspSetupResponse setup = rtspClient.GetSetup(url, destinationPort);
|
||||||
if (setup.RtspStatusCode == 404)
|
if (setup.RtspStatusCode == 404)
|
||||||
{
|
{
|
||||||
logger.Fatal("Your SAT>IP server doesn't have a tuner available that can talk to the requested frequency.");
|
logger.Fatal("Your SAT>IP server doesn't have a tuner available that can talk to the requested frequency.");
|
||||||
@ -118,37 +129,59 @@ namespace skyscraper8
|
|||||||
dataStorage = new InMemoryScraperStorage();
|
dataStorage = new InMemoryScraperStorage();
|
||||||
if (objectStorage == null)
|
if (objectStorage == null)
|
||||||
objectStorage = new FilesystemStorage(new DirectoryInfo("."));
|
objectStorage = new FilesystemStorage(new DirectoryInfo("."));
|
||||||
context = new SkyscraperContext(new TsContext(), dataStorage, objectStorage);
|
if (!playoutMode)
|
||||||
context.EnableTimeout = true;
|
{
|
||||||
context.TimeoutSeconds = 60;
|
context = new SkyscraperContext(new TsContext(), dataStorage, objectStorage);
|
||||||
context.InitalizeFilterChain();
|
context.EnableTimeout = true;
|
||||||
|
context.TimeoutSeconds = 60;
|
||||||
|
context.InitalizeFilterChain();
|
||||||
|
}
|
||||||
|
|
||||||
RtspPlayResponse play = rtspClient.GetPlay(setup);
|
RtspPlayResponse play = rtspClient.GetPlay(setup);
|
||||||
DateTime lastTimestamp = DateTime.Now;
|
DateTime lastTimestamp = DateTime.Now;
|
||||||
|
bool initMessagePrinted = false;
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
if (packetQueue.Count >= 1)
|
if (playoutMode)
|
||||||
{
|
{
|
||||||
byte[] buffer;
|
Thread.Sleep(1000);
|
||||||
lock (packetQueue)
|
Keepalive(url);
|
||||||
{
|
if (!initMessagePrinted)
|
||||||
buffer = packetQueue.Dequeue();
|
{
|
||||||
}
|
logger.InfoFormat("Began SAT>IP playout to port {0}", destinationPort);
|
||||||
context.IngestSinglePacket(buffer);
|
initMessagePrinted = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Thread.Sleep(1);
|
if (packetQueue.Count >= 1)
|
||||||
}
|
{
|
||||||
|
byte[] buffer;
|
||||||
if (context.IsAbortConditionMet())
|
lock (packetQueue)
|
||||||
break;
|
{
|
||||||
|
buffer = packetQueue.Dequeue();
|
||||||
if (DateTime.Now.Second != lastTimestamp.Second)
|
}
|
||||||
{
|
context.IngestSinglePacket(buffer);
|
||||||
Keepalive(url);
|
if (!initMessagePrinted)
|
||||||
lastTimestamp = DateTime.Now;
|
{
|
||||||
|
logger.InfoFormat("Began SAT>IP stream.");
|
||||||
|
initMessagePrinted = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Thread.Sleep(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context.IsAbortConditionMet())
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (DateTime.Now.Second != lastTimestamp.Second)
|
||||||
|
{
|
||||||
|
Keepalive(url);
|
||||||
|
lastTimestamp = DateTime.Now;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -199,8 +232,12 @@ namespace skyscraper8
|
|||||||
fs.Write(buffer, 0, buffer.Length);
|
fs.Write(buffer, 0, buffer.Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
private int rtcps;
|
private int rtcps;
|
||||||
private void Setup_OnRtcpPacket(byte[] data, int length)
|
private IPAddress destinationIp;
|
||||||
|
private int destinationPort;
|
||||||
|
private bool playoutMode;
|
||||||
|
|
||||||
|
private void Setup_OnRtcpPacket(byte[] data, int length)
|
||||||
{
|
{
|
||||||
//rtcps++;
|
//rtcps++;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,347 +1,356 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using skyscraper5.Skyscraper;
|
using skyscraper5.Skyscraper;
|
||||||
using skyscraper5.Skyscraper.IO.CrazycatStreamReader;
|
using skyscraper5.Skyscraper.IO.CrazycatStreamReader;
|
||||||
using skyscraper8.SatIp.RtspRequests;
|
using skyscraper8.SatIp.RtspRequests;
|
||||||
using skyscraper8.SatIp.RtspResponses;
|
using skyscraper8.SatIp.RtspResponses;
|
||||||
|
|
||||||
namespace skyscraper8.SatIp
|
namespace skyscraper8.SatIp
|
||||||
{
|
{
|
||||||
internal class RtspClient : Validatable, IDisposable
|
internal class RtspClient : Validatable, IDisposable
|
||||||
{
|
{
|
||||||
private uint cseqCounter;
|
private uint cseqCounter;
|
||||||
private const string USER_AGENT = "sophiaNetRtspClient/1.0";
|
private const string USER_AGENT = "sophiaNetRtspClient/1.0";
|
||||||
|
|
||||||
public RtspClient(string ip, int port)
|
public RtspClient(string ip, int port)
|
||||||
{
|
{
|
||||||
IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Parse(ip), port);
|
IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Parse(ip), port);
|
||||||
ConstructStep2(ipEndPoint);
|
ConstructStep2(ipEndPoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
public RtspClient(IPAddress ip, int port)
|
public RtspClient(IPAddress ip, int port)
|
||||||
{
|
{
|
||||||
IPEndPoint ipEndPoint = new IPEndPoint(ip, port);
|
IPEndPoint ipEndPoint = new IPEndPoint(ip, port);
|
||||||
ConstructStep2(ipEndPoint);
|
ConstructStep2(ipEndPoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ConstructStep2(IPEndPoint ipEndPoint)
|
private void ConstructStep2(IPEndPoint ipEndPoint)
|
||||||
{
|
{
|
||||||
this.TcpClient = new TcpClient();
|
this.TcpClient = new TcpClient();
|
||||||
this.TcpClient.Connect(ipEndPoint);
|
this.TcpClient.Connect(ipEndPoint);
|
||||||
this.RootPath = string.Format("rtsp://{0}:{1}", ipEndPoint.Address.ToString(), ipEndPoint.Port.ToString());
|
this.RootPath = string.Format("rtsp://{0}:{1}", ipEndPoint.Address.ToString(), ipEndPoint.Port.ToString());
|
||||||
this.NetworkStream = TcpClient.GetStream();
|
this.NetworkStream = TcpClient.GetStream();
|
||||||
this.BufferedStream = new BufferedStream(this.NetworkStream);
|
this.BufferedStream = new BufferedStream(this.NetworkStream);
|
||||||
this.StreamReader = new StreamReader(this.BufferedStream);
|
this.StreamReader = new StreamReader(this.BufferedStream);
|
||||||
this.StreamWriter = new StreamWriter(this.BufferedStream);
|
this.StreamWriter = new StreamWriter(this.BufferedStream);
|
||||||
this.cseqCounter = 2;
|
this.cseqCounter = 2;
|
||||||
this.ListenIp = GetListenIp(this.TcpClient.Client.LocalEndPoint);
|
this.ListenIp = GetListenIp(this.TcpClient.Client.LocalEndPoint);
|
||||||
RtspOptionsResponse rtspOptionsResponse = GetOptions("/");
|
RtspOptionsResponse rtspOptionsResponse = GetOptions("/");
|
||||||
this.Valid = rtspOptionsResponse.Valid;
|
this.Valid = rtspOptionsResponse.Valid;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool AutoReconnect { get; set; }
|
public bool AutoReconnect { get; set; }
|
||||||
public IPAddress ListenIp { get; set; }
|
public IPAddress ListenIp { get; set; }
|
||||||
|
|
||||||
private IPAddress GetListenIp(EndPoint clientLocalEndPoint)
|
private IPAddress GetListenIp(EndPoint clientLocalEndPoint)
|
||||||
{
|
{
|
||||||
IPEndPoint ipEndPoint = clientLocalEndPoint as IPEndPoint;
|
IPEndPoint ipEndPoint = clientLocalEndPoint as IPEndPoint;
|
||||||
if (ipEndPoint == null)
|
if (ipEndPoint == null)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException(clientLocalEndPoint.GetType().Name);
|
throw new NotImplementedException(clientLocalEndPoint.GetType().Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ipEndPoint.Address.AddressFamily == AddressFamily.InterNetwork)
|
if (ipEndPoint.Address.AddressFamily == AddressFamily.InterNetwork)
|
||||||
{
|
{
|
||||||
return ipEndPoint.Address;
|
return ipEndPoint.Address;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ipEndPoint.Address.IsIPv4MappedToIPv6)
|
if (ipEndPoint.Address.IsIPv4MappedToIPv6)
|
||||||
{
|
{
|
||||||
return ipEndPoint.Address.MapToIPv4();
|
return ipEndPoint.Address.MapToIPv4();
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new NotImplementedException(String.Format("Don't know whether I can listen on IP {0}", ipEndPoint.ToString()));
|
throw new NotImplementedException(String.Format("Don't know whether I can listen on IP {0}", ipEndPoint.ToString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public string RootPath { get; set; }
|
public string RootPath { get; set; }
|
||||||
|
|
||||||
private TcpClient TcpClient { get; set; }
|
private TcpClient TcpClient { get; set; }
|
||||||
private NetworkStream NetworkStream { get; set; }
|
private NetworkStream NetworkStream { get; set; }
|
||||||
private BufferedStream BufferedStream { get; set; }
|
private BufferedStream BufferedStream { get; set; }
|
||||||
private StreamReader StreamReader { get; set; }
|
private StreamReader StreamReader { get; set; }
|
||||||
private StreamWriter StreamWriter { get; set; }
|
private StreamWriter StreamWriter { get; set; }
|
||||||
|
|
||||||
public RtspOptionsResponse GetOptions(string url)
|
public RtspOptionsResponse GetOptions(string url)
|
||||||
{
|
{
|
||||||
RtspOptionsRequest request = new RtspOptionsRequest();
|
RtspOptionsRequest request = new RtspOptionsRequest();
|
||||||
request.RequestPath = url;
|
request.RequestPath = url;
|
||||||
request.CSeq = cseqCounter++;
|
request.CSeq = cseqCounter++;
|
||||||
request.UserAgent = USER_AGENT;
|
request.UserAgent = USER_AGENT;
|
||||||
RtspResponseHeader header = GetResponse(request.ListHeaders(RootPath));
|
RtspResponseHeader header = GetResponse(request.ListHeaders(RootPath));
|
||||||
RtspOptionsResponse result = new RtspOptionsResponse(header);
|
RtspOptionsResponse result = new RtspOptionsResponse(header);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RtspDescribeResponse GetDescribe(string url)
|
public RtspDescribeResponse GetDescribe(string url)
|
||||||
{
|
{
|
||||||
RtspDescribeRequest request = new RtspDescribeRequest();
|
RtspDescribeRequest request = new RtspDescribeRequest();
|
||||||
request.RequestPath = url;
|
request.RequestPath = url;
|
||||||
request.CSeq = cseqCounter++;
|
request.CSeq = cseqCounter++;
|
||||||
request.UserAgent = USER_AGENT;
|
request.UserAgent = USER_AGENT;
|
||||||
request.Accept = "application/sdp";
|
request.Accept = "application/sdp";
|
||||||
RtspResponseHeader header = GetResponse(request.ListHeaders(RootPath));
|
RtspResponseHeader header = GetResponse(request.ListHeaders(RootPath));
|
||||||
RtspDescribeResponse result = new RtspDescribeResponse(header);
|
RtspDescribeResponse result = new RtspDescribeResponse(header);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RtspSetupResponse GetSetup(string url)
|
public RtspSetupResponse GetSetup(string url, int destinationPort = 0)
|
||||||
{
|
{
|
||||||
RtspSetupRequest request = new RtspSetupRequest();
|
RtspSetupRequest request = new RtspSetupRequest();
|
||||||
request.RequestPath = url;
|
request.RequestPath = url;
|
||||||
request.CSeq = cseqCounter++;
|
request.CSeq = cseqCounter++;
|
||||||
request.UserAgent = USER_AGENT;
|
request.UserAgent = USER_AGENT;
|
||||||
|
|
||||||
Socket rtpSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
|
int rtpPort = 0;
|
||||||
rtpSocket.Bind(new IPEndPoint(ListenIp, 0));
|
Socket rtpSocket = null;
|
||||||
int rtpPort = GetPortFromEndPoint(rtpSocket.LocalEndPoint);
|
if (destinationPort == 0)
|
||||||
|
{
|
||||||
Socket rtcpSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
|
rtpSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
|
||||||
rtcpSocket.Bind(new IPEndPoint(ListenIp, 0));
|
rtpSocket.Bind(new IPEndPoint(ListenIp, 0));
|
||||||
int rtcpPort = GetPortFromEndPoint(rtcpSocket.LocalEndPoint);
|
rtpPort = GetPortFromEndPoint(rtpSocket.LocalEndPoint);
|
||||||
|
}
|
||||||
request.SetRtpAvpUnicast(rtpPort, rtcpPort);
|
else
|
||||||
|
{
|
||||||
RtspResponseHeader response = GetResponse(request.ListHeaders(RootPath));
|
rtpPort = destinationPort;
|
||||||
RtspSetupResponse setupResponse = new RtspSetupResponse(response);
|
}
|
||||||
switch (response.statusCode)
|
|
||||||
{
|
Socket rtcpSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
|
||||||
case 200:
|
rtcpSocket.Bind(new IPEndPoint(ListenIp, 0));
|
||||||
setupResponse.RtpSocket = rtpSocket;
|
int rtcpPort = GetPortFromEndPoint(rtcpSocket.LocalEndPoint);
|
||||||
setupResponse.RtcpSocket = rtcpSocket;
|
|
||||||
setupResponse.SetupListeners();
|
request.SetRtpAvpUnicast(rtpPort, rtcpPort);
|
||||||
setupResponse.Valid = true;
|
|
||||||
break;
|
RtspResponseHeader response = GetResponse(request.ListHeaders(RootPath));
|
||||||
case 404:
|
RtspSetupResponse setupResponse = new RtspSetupResponse(response);
|
||||||
setupResponse.Valid = true;
|
switch (response.statusCode)
|
||||||
break;
|
{
|
||||||
default:
|
case 200:
|
||||||
throw new NotImplementedException(setupResponse.RtspStatusCode.ToString());
|
setupResponse.RtpSocket = rtpSocket;
|
||||||
}
|
setupResponse.RtcpSocket = rtcpSocket;
|
||||||
return setupResponse;
|
setupResponse.SetupListeners();
|
||||||
}
|
setupResponse.Valid = true;
|
||||||
|
break;
|
||||||
public RtspPlayResponse GetPlay(RtspSetupResponse setupData)
|
case 404:
|
||||||
{
|
setupResponse.Valid = true;
|
||||||
RtspPlayRequest request = new RtspPlayRequest();
|
break;
|
||||||
request.RequestPath = string.Format("/stream={0}", setupData.StreamId);
|
default:
|
||||||
request.Session = setupData.Session;
|
throw new NotImplementedException(setupResponse.RtspStatusCode.ToString());
|
||||||
request.UserAgent = USER_AGENT;
|
}
|
||||||
|
return setupResponse;
|
||||||
RtspPlayResponse response = new RtspPlayResponse(GetResponse(request.ListHeaders(RootPath)));
|
}
|
||||||
return response;
|
|
||||||
}
|
public RtspPlayResponse GetPlay(RtspSetupResponse setupData)
|
||||||
|
{
|
||||||
public RtspTeardownResponse GetTeardown(RtspSetupResponse setupData)
|
RtspPlayRequest request = new RtspPlayRequest();
|
||||||
{
|
request.RequestPath = string.Format("/stream={0}", setupData.StreamId);
|
||||||
RtspTeardownRequest request = new RtspTeardownRequest();
|
request.Session = setupData.Session;
|
||||||
request.RequestPath = string.Format("/stream={0}", setupData.StreamId);
|
request.UserAgent = USER_AGENT;
|
||||||
request.Session = setupData.Session;
|
|
||||||
request.UserAgent = USER_AGENT;
|
RtspPlayResponse response = new RtspPlayResponse(GetResponse(request.ListHeaders(RootPath)));
|
||||||
|
return response;
|
||||||
RtspTeardownResponse response = new RtspTeardownResponse(GetResponse(request.ListHeaders(RootPath)));
|
}
|
||||||
if (response.RtspStatusCode == 200)
|
|
||||||
{
|
public RtspTeardownResponse GetTeardown(RtspSetupResponse setupData)
|
||||||
setupData.InvokeCancellationTokens();
|
{
|
||||||
if (AutoReconnect)
|
RtspTeardownRequest request = new RtspTeardownRequest();
|
||||||
{
|
request.RequestPath = string.Format("/stream={0}", setupData.StreamId);
|
||||||
Reconnect();
|
request.Session = setupData.Session;
|
||||||
}
|
request.UserAgent = USER_AGENT;
|
||||||
}
|
|
||||||
return response;
|
RtspTeardownResponse response = new RtspTeardownResponse(GetResponse(request.ListHeaders(RootPath)));
|
||||||
}
|
if (response.RtspStatusCode == 200)
|
||||||
|
{
|
||||||
private int GetPortFromEndPoint(EndPoint endpoint)
|
setupData.InvokeCancellationTokens();
|
||||||
{
|
if (AutoReconnect)
|
||||||
IPEndPoint ipEndPoint = endpoint as IPEndPoint;
|
{
|
||||||
if (ipEndPoint == null)
|
Reconnect();
|
||||||
throw new NotImplementedException(endpoint.GetType().Name);
|
}
|
||||||
return ipEndPoint.Port;
|
}
|
||||||
}
|
return response;
|
||||||
|
}
|
||||||
private RtspResponseHeader GetResponse(string request)
|
|
||||||
{
|
private int GetPortFromEndPoint(EndPoint endpoint)
|
||||||
StreamWriter.Write(request);
|
{
|
||||||
StreamWriter.Flush();
|
IPEndPoint ipEndPoint = endpoint as IPEndPoint;
|
||||||
|
if (ipEndPoint == null)
|
||||||
RtspResponseHeader result = new RtspResponseHeader();
|
throw new NotImplementedException(endpoint.GetType().Name);
|
||||||
|
return ipEndPoint.Port;
|
||||||
string response = StreamReader.ReadLine();
|
}
|
||||||
if (!response.StartsWith("RTSP/"))
|
|
||||||
throw new RtspException("Invalid RTSP response.");
|
private RtspResponseHeader GetResponse(string request)
|
||||||
|
{
|
||||||
response = response.Substring(5);
|
StreamWriter.Write(request);
|
||||||
|
StreamWriter.Flush();
|
||||||
string versionString = response.Substring(0, 3);
|
|
||||||
result.rtspVersion = Version.Parse(versionString);
|
RtspResponseHeader result = new RtspResponseHeader();
|
||||||
response = response.Substring(4);
|
|
||||||
|
string response = StreamReader.ReadLine();
|
||||||
string statusCodeString = response.Substring(0,3);
|
if (!response.StartsWith("RTSP/"))
|
||||||
result.statusCode = ushort.Parse(statusCodeString);
|
throw new RtspException("Invalid RTSP response.");
|
||||||
|
|
||||||
response = response.Substring(4);
|
response = response.Substring(5);
|
||||||
result.statusLine = response;
|
|
||||||
|
string versionString = response.Substring(0, 3);
|
||||||
long contentLength = 0;
|
result.rtspVersion = Version.Parse(versionString);
|
||||||
|
response = response.Substring(4);
|
||||||
result.kv = new Dictionary<string, string>();
|
|
||||||
while (true)
|
string statusCodeString = response.Substring(0,3);
|
||||||
{
|
result.statusCode = ushort.Parse(statusCodeString);
|
||||||
string lineIn = StreamReader.ReadLine();
|
|
||||||
if (string.IsNullOrEmpty(lineIn))
|
response = response.Substring(4);
|
||||||
break;
|
result.statusLine = response;
|
||||||
|
|
||||||
int indexOf = lineIn.IndexOf(": ");
|
long contentLength = 0;
|
||||||
string key = lineIn.Substring(0, indexOf);
|
|
||||||
string value = lineIn.Substring(indexOf + 2);
|
result.kv = new Dictionary<string, string>();
|
||||||
result.kv.Add(key, value);
|
while (true)
|
||||||
|
{
|
||||||
if (key.Equals("Content-Length"))
|
string lineIn = StreamReader.ReadLine();
|
||||||
{
|
if (string.IsNullOrEmpty(lineIn))
|
||||||
contentLength = long.Parse(value);
|
break;
|
||||||
}
|
|
||||||
}
|
int indexOf = lineIn.IndexOf(": ");
|
||||||
|
string key = lineIn.Substring(0, indexOf);
|
||||||
if (contentLength > 0)
|
string value = lineIn.Substring(indexOf + 2);
|
||||||
{
|
result.kv.Add(key, value);
|
||||||
StreamReader.DiscardBufferedData();
|
|
||||||
byte[] buffer = new byte[contentLength];
|
if (key.Equals("Content-Length"))
|
||||||
int sucessfullyRead = BufferedStream.Read(buffer, 0, (int)contentLength);
|
{
|
||||||
if (sucessfullyRead != contentLength)
|
contentLength = long.Parse(value);
|
||||||
{
|
}
|
||||||
throw new IOException("incomplete read");
|
}
|
||||||
}
|
|
||||||
|
if (contentLength > 0)
|
||||||
result.payload = buffer;
|
{
|
||||||
}
|
StreamReader.DiscardBufferedData();
|
||||||
|
byte[] buffer = new byte[contentLength];
|
||||||
return result;
|
int sucessfullyRead = BufferedStream.Read(buffer, 0, (int)contentLength);
|
||||||
}
|
if (sucessfullyRead != contentLength)
|
||||||
|
{
|
||||||
public void Reconnect()
|
throw new IOException("incomplete read");
|
||||||
{
|
}
|
||||||
EndPoint clientRemoteEndPoint = this.TcpClient.Client.RemoteEndPoint;
|
|
||||||
IPEndPoint ipEndPoint = clientRemoteEndPoint as IPEndPoint;
|
result.payload = buffer;
|
||||||
if (ipEndPoint == null)
|
}
|
||||||
{
|
|
||||||
throw new NotImplementedException(clientRemoteEndPoint.GetType().ToString());
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.TcpClient.Close();
|
public void Reconnect()
|
||||||
this.TcpClient = new TcpClient();
|
{
|
||||||
this.TcpClient.Connect(ipEndPoint);
|
EndPoint clientRemoteEndPoint = this.TcpClient.Client.RemoteEndPoint;
|
||||||
this.RootPath = string.Format("rtsp://{0}:{1}", ipEndPoint.Address, ipEndPoint.Port);
|
IPEndPoint ipEndPoint = clientRemoteEndPoint as IPEndPoint;
|
||||||
this.NetworkStream = TcpClient.GetStream();
|
if (ipEndPoint == null)
|
||||||
this.BufferedStream = new BufferedStream(this.NetworkStream);
|
{
|
||||||
this.StreamReader = new StreamReader(this.BufferedStream);
|
throw new NotImplementedException(clientRemoteEndPoint.GetType().ToString());
|
||||||
this.StreamWriter = new StreamWriter(this.BufferedStream);
|
}
|
||||||
this.cseqCounter = 2;
|
|
||||||
this.ListenIp = GetListenIp(this.TcpClient.Client.LocalEndPoint);
|
this.TcpClient.Close();
|
||||||
}
|
this.TcpClient = new TcpClient();
|
||||||
|
this.TcpClient.Connect(ipEndPoint);
|
||||||
/// <summary>
|
this.RootPath = string.Format("rtsp://{0}:{1}", ipEndPoint.Address, ipEndPoint.Port);
|
||||||
/// Generates a SAT>IP Tuning string.
|
this.NetworkStream = TcpClient.GetStream();
|
||||||
/// </summary>
|
this.BufferedStream = new BufferedStream(this.NetworkStream);
|
||||||
/// <param name="diseqcChannel">The DiSEqC Command to send.</param>
|
this.StreamReader = new StreamReader(this.BufferedStream);
|
||||||
/// <param name="freq">The frequency to tune to in MHz.</param>
|
this.StreamWriter = new StreamWriter(this.BufferedStream);
|
||||||
/// <param name="isS2">Set this to true if tuning to DVB-S2/S2X, or false for DVB-S</param>
|
this.cseqCounter = 2;
|
||||||
/// <param name="symbolrate">The transponder's symbol rate in Ksyms.</param>
|
this.ListenIp = GetListenIp(this.TcpClient.Client.LocalEndPoint);
|
||||||
/// <param name="forceBbframeMode">Set this to true to force a STiD135 to BBFrame mode. Set this to false if you do not want this, or if the tuner isn't a STiD135. false is always safe here.</param>
|
}
|
||||||
/// <returns>A SAT>IP Tuning String</returns>
|
|
||||||
/// <exception cref="ArgumentOutOfRangeException">Thrown when an invalid DiSEqC Command is supplied.</exception>
|
/// <summary>
|
||||||
public static string MakeUrl(DiSEqC_Opcode diseqcChannel, int freq, bool isS2, int symbolrate, byte? mis = null, bool forceBbframeMode = false)
|
/// Generates a SAT>IP Tuning string.
|
||||||
{
|
/// </summary>
|
||||||
bool diseqcOk = false;
|
/// <param name="diseqcChannel">The DiSEqC Command to send.</param>
|
||||||
byte diseqc = 1;
|
/// <param name="freq">The frequency to tune to in MHz.</param>
|
||||||
if (diseqcChannel.HasFlag(DiSEqC_Opcode.DISEQC_OPTION_A) && diseqcChannel.HasFlag(DiSEqC_Opcode.DISEQC_POSITION_A))
|
/// <param name="isS2">Set this to true if tuning to DVB-S2/S2X, or false for DVB-S</param>
|
||||||
{
|
/// <param name="symbolrate">The transponder's symbol rate in Ksyms.</param>
|
||||||
diseqc = 1;
|
/// <param name="forceBbframeMode">Set this to true to force a STiD135 to BBFrame mode. Set this to false if you do not want this, or if the tuner isn't a STiD135. false is always safe here.</param>
|
||||||
diseqcOk = true;
|
/// <returns>A SAT>IP Tuning String</returns>
|
||||||
}
|
/// <exception cref="ArgumentOutOfRangeException">Thrown when an invalid DiSEqC Command is supplied.</exception>
|
||||||
if (diseqcChannel.HasFlag(DiSEqC_Opcode.DISEQC_OPTION_A) && diseqcChannel.HasFlag(DiSEqC_Opcode.DISEQC_POSITION_B))
|
public static string MakeUrl(DiSEqC_Opcode diseqcChannel, int freq, bool isS2, int symbolrate, byte? mis = null, bool forceBbframeMode = false)
|
||||||
{
|
{
|
||||||
diseqc = 2;
|
bool diseqcOk = false;
|
||||||
diseqcOk = true;
|
byte diseqc = 1;
|
||||||
}
|
if (diseqcChannel.HasFlag(DiSEqC_Opcode.DISEQC_OPTION_A) && diseqcChannel.HasFlag(DiSEqC_Opcode.DISEQC_POSITION_A))
|
||||||
if (diseqcChannel.HasFlag(DiSEqC_Opcode.DISEQC_OPTION_B) && diseqcChannel.HasFlag(DiSEqC_Opcode.DISEQC_POSITION_A))
|
{
|
||||||
{
|
diseqc = 1;
|
||||||
diseqc = 3;
|
diseqcOk = true;
|
||||||
diseqcOk = true;
|
}
|
||||||
}
|
if (diseqcChannel.HasFlag(DiSEqC_Opcode.DISEQC_OPTION_A) && diseqcChannel.HasFlag(DiSEqC_Opcode.DISEQC_POSITION_B))
|
||||||
if (diseqcChannel.HasFlag(DiSEqC_Opcode.DISEQC_OPTION_B) && diseqcChannel.HasFlag(DiSEqC_Opcode.DISEQC_POSITION_B))
|
{
|
||||||
{
|
diseqc = 2;
|
||||||
diseqc = 4;
|
diseqcOk = true;
|
||||||
diseqcOk = true;
|
}
|
||||||
}
|
if (diseqcChannel.HasFlag(DiSEqC_Opcode.DISEQC_OPTION_B) && diseqcChannel.HasFlag(DiSEqC_Opcode.DISEQC_POSITION_A))
|
||||||
if (!diseqcOk)
|
{
|
||||||
{
|
diseqc = 3;
|
||||||
throw new ArgumentOutOfRangeException(nameof(diseqcChannel));
|
diseqcOk = true;
|
||||||
}
|
}
|
||||||
|
if (diseqcChannel.HasFlag(DiSEqC_Opcode.DISEQC_OPTION_B) && diseqcChannel.HasFlag(DiSEqC_Opcode.DISEQC_POSITION_B))
|
||||||
char pol;
|
{
|
||||||
if (diseqcChannel.HasFlag(DiSEqC_Opcode.DISEQC_HORIZONTAL))
|
diseqc = 4;
|
||||||
{
|
diseqcOk = true;
|
||||||
pol = 'h';
|
}
|
||||||
}
|
if (!diseqcOk)
|
||||||
else
|
{
|
||||||
{
|
throw new ArgumentOutOfRangeException(nameof(diseqcChannel));
|
||||||
pol = 'v';
|
}
|
||||||
}
|
|
||||||
|
char pol;
|
||||||
StringBuilder sb = new StringBuilder();
|
if (diseqcChannel.HasFlag(DiSEqC_Opcode.DISEQC_HORIZONTAL))
|
||||||
sb.AppendFormat("/?src={0}", diseqc);
|
{
|
||||||
sb.AppendFormat("&freq={0}", freq);
|
pol = 'h';
|
||||||
sb.AppendFormat("&pol={0}", pol);
|
}
|
||||||
sb.AppendFormat("&msys={0}", isS2 ? "dvbs2" : "dvbs");
|
else
|
||||||
sb.AppendFormat("&sr={0}", symbolrate);
|
{
|
||||||
sb.AppendFormat("&pids=all");
|
pol = 'v';
|
||||||
|
}
|
||||||
//Thanks to the Digital Devices Customer Support for giving me this advice.
|
|
||||||
if (forceBbframeMode)
|
StringBuilder sb = new StringBuilder();
|
||||||
{
|
sb.AppendFormat("/?src={0}", diseqc);
|
||||||
sb.Append("&x_isi=0x80000000");
|
sb.AppendFormat("&freq={0}", freq);
|
||||||
}
|
sb.AppendFormat("&pol={0}", pol);
|
||||||
else if (mis.HasValue)
|
sb.AppendFormat("&msys={0}", isS2 ? "dvbs2" : "dvbs");
|
||||||
{
|
sb.AppendFormat("&sr={0}", symbolrate);
|
||||||
sb.AppendFormat("&x_isi={0}", mis.Value);
|
sb.AppendFormat("&pids=all");
|
||||||
}
|
|
||||||
|
//Thanks to the Digital Devices Customer Support for giving me this advice.
|
||||||
return sb.ToString();
|
if (forceBbframeMode)
|
||||||
}
|
{
|
||||||
|
sb.Append("&x_isi=0x80000000");
|
||||||
private bool disposed;
|
}
|
||||||
public void Dispose()
|
else if (mis.HasValue)
|
||||||
{
|
{
|
||||||
if (disposed)
|
sb.AppendFormat("&x_isi={0}", mis.Value);
|
||||||
throw new ObjectDisposedException(nameof(RtspClient));
|
}
|
||||||
|
|
||||||
ListenIp = null;
|
return sb.ToString();
|
||||||
RootPath = null;
|
}
|
||||||
if (TcpClient.Connected)
|
|
||||||
{
|
private bool disposed;
|
||||||
TcpClient.Close();
|
public void Dispose()
|
||||||
}
|
{
|
||||||
|
if (disposed)
|
||||||
TcpClient.Dispose();
|
throw new ObjectDisposedException(nameof(RtspClient));
|
||||||
NetworkStream = null;
|
|
||||||
BufferedStream = null;
|
ListenIp = null;
|
||||||
StreamReader = null;
|
RootPath = null;
|
||||||
StreamWriter = null;
|
if (TcpClient.Connected)
|
||||||
disposed = true;
|
{
|
||||||
}
|
TcpClient.Close();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
TcpClient.Dispose();
|
||||||
|
NetworkStream = null;
|
||||||
|
BufferedStream = null;
|
||||||
|
StreamReader = null;
|
||||||
|
StreamWriter = null;
|
||||||
|
disposed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -53,23 +53,29 @@ namespace skyscraper8.SatIp.RtspResponses
|
|||||||
if (listenersStarted)
|
if (listenersStarted)
|
||||||
throw new RtspException("Listener already started.");
|
throw new RtspException("Listener already started.");
|
||||||
|
|
||||||
rtpCancellation = new CancellationTokenSource();
|
if (RtpSocket != null)
|
||||||
|
{
|
||||||
|
rtpCancellation = new CancellationTokenSource();
|
||||||
|
}
|
||||||
rtcpCancellation = new CancellationTokenSource();
|
rtcpCancellation = new CancellationTokenSource();
|
||||||
|
|
||||||
Task.Run(async () =>
|
if (RtpSocket != null)
|
||||||
{
|
{
|
||||||
byte[] buffer = new byte[2048];
|
Task.Run(async () =>
|
||||||
|
{
|
||||||
while (!rtpCancellation.IsCancellationRequested)
|
byte[] buffer = new byte[2048];
|
||||||
{
|
|
||||||
Array.Clear(buffer);
|
while (!rtpCancellation.IsCancellationRequested)
|
||||||
int result = await RtpSocket.ReceiveAsync(buffer, rtpCancellation.Token);
|
{
|
||||||
OnRtpPacket?.Invoke(buffer, result);
|
Array.Clear(buffer);
|
||||||
}
|
int result = await RtpSocket.ReceiveAsync(buffer, rtpCancellation.Token);
|
||||||
|
OnRtpPacket?.Invoke(buffer, result);
|
||||||
exitedThread++;
|
}
|
||||||
}
|
|
||||||
);
|
exitedThread++;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
Task.Run(async () =>
|
Task.Run(async () =>
|
||||||
{
|
{
|
||||||
@ -92,8 +98,8 @@ namespace skyscraper8.SatIp.RtspResponses
|
|||||||
|
|
||||||
internal void InvokeCancellationTokens()
|
internal void InvokeCancellationTokens()
|
||||||
{
|
{
|
||||||
rtpCancellation.Cancel();
|
rtpCancellation?.Cancel();
|
||||||
rtcpCancellation.Cancel();
|
rtcpCancellation?.Cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
public event OnRtpPacket OnRtpPacket;
|
public event OnRtpPacket OnRtpPacket;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user