232 lines
7.7 KiB
C#
232 lines
7.7 KiB
C#
using System;
|
|
using System.Net;
|
|
using System.Net.Sockets;
|
|
using System.Threading;
|
|
using Inspectron.HawkEye.RTSP.Messages;
|
|
|
|
namespace Inspectron.HawkEye.RTSP
|
|
{
|
|
public class UDPSocket
|
|
{
|
|
|
|
private UdpClient data_socket = null;
|
|
private UdpClient control_socket = null;
|
|
|
|
private Thread data_read_thread = null;
|
|
private Thread control_read_thread = null;
|
|
|
|
public int data_port = 50000;
|
|
public int control_port = 50001;
|
|
|
|
bool is_multicast = false;
|
|
IPAddress data_mcast_addr;
|
|
IPAddress control_mcast_addr;
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="UDPSocket"/> class.
|
|
/// Creates two new UDP sockets using the start and end Port range
|
|
/// </summary>
|
|
public UDPSocket(int start_port, int end_port)
|
|
{
|
|
|
|
is_multicast = false;
|
|
|
|
// open a pair of UDP sockets - one for data (video or audio) and one for the status channel (RTCP messages)
|
|
data_port = start_port;
|
|
control_port = start_port + 1;
|
|
|
|
bool ok = false;
|
|
while (ok == false && (control_port < end_port))
|
|
{
|
|
// Video/Audio port must be odd and command even (next one)
|
|
try
|
|
{
|
|
data_socket = new UdpClient(data_port);
|
|
control_socket = new UdpClient(control_port);
|
|
ok = true;
|
|
}
|
|
catch (SocketException)
|
|
{
|
|
// Fail to allocate port, try again
|
|
if (data_socket != null)
|
|
data_socket.Close();
|
|
if (control_socket != null)
|
|
control_socket.Close();
|
|
|
|
// try next data or control port
|
|
data_port += 2;
|
|
control_port += 2;
|
|
}
|
|
|
|
if (ok)
|
|
{
|
|
data_socket.Client.ReceiveBufferSize = 100 * 1024;
|
|
data_socket.Client.SendBufferSize = 65535; // default is 8192. Make it as large as possible for large RTP packets which are not fragmented
|
|
|
|
control_socket.Client.DontFragment = false;
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="UDPSocket"/> class.
|
|
/// Used with Multicast mode with the Multicast Address and Port
|
|
/// </summary>
|
|
public UDPSocket(String data_multicast_address, int data_multicast_port, String control_multicast_address, int control_multicast_port)
|
|
{
|
|
|
|
is_multicast = true;
|
|
|
|
// open a pair of UDP sockets - one for data (video or audio) and one for the status channel (RTCP messages)
|
|
this.data_port = data_multicast_port;
|
|
this.control_port = control_multicast_port;
|
|
|
|
try
|
|
{
|
|
IPEndPoint data_ep = new IPEndPoint(IPAddress.Any, data_port);
|
|
IPEndPoint control_ep = new IPEndPoint(IPAddress.Any, control_port);
|
|
|
|
data_mcast_addr = IPAddress.Parse(data_multicast_address);
|
|
control_mcast_addr = IPAddress.Parse(control_multicast_address);
|
|
|
|
data_socket = new UdpClient();
|
|
data_socket.Client.Bind(data_ep);
|
|
data_socket.JoinMulticastGroup(data_mcast_addr);
|
|
|
|
control_socket = new UdpClient();
|
|
control_socket.Client.Bind(control_ep);
|
|
control_socket.JoinMulticastGroup(control_mcast_addr);
|
|
|
|
|
|
data_socket.Client.ReceiveBufferSize = 100 * 1024;
|
|
data_socket.Client.SendBufferSize = 65535; // default is 8192. Make it as large as possible for large RTP packets which are not fragmented
|
|
|
|
|
|
control_socket.Client.DontFragment = false;
|
|
|
|
}
|
|
catch (SocketException)
|
|
{
|
|
// Fail to allocate port, try again
|
|
if (data_socket != null)
|
|
data_socket.Close();
|
|
if (control_socket != null)
|
|
control_socket.Close();
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Starts this instance.
|
|
/// </summary>
|
|
public void Start()
|
|
{
|
|
if (data_socket == null || control_socket == null)
|
|
{
|
|
throw new InvalidOperationException("UDP Forwader host was not initialized, can't continue");
|
|
}
|
|
|
|
if (data_read_thread != null)
|
|
{
|
|
throw new InvalidOperationException("Forwarder was stopped, can't restart it");
|
|
}
|
|
|
|
data_read_thread = new Thread(() => DoWorkerJob(data_socket, data_port));
|
|
data_read_thread.Name = "DataPort " + data_port;
|
|
data_read_thread.Start();
|
|
|
|
control_read_thread = new Thread(() => DoWorkerJob(control_socket, control_port));
|
|
control_read_thread.Name = "ControlPort " + control_port;
|
|
control_read_thread.Start();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Stops this instance.
|
|
/// </summary>
|
|
public void Stop()
|
|
{
|
|
if (is_multicast)
|
|
{
|
|
// leave the multicast groups
|
|
data_socket.DropMulticastGroup(data_mcast_addr);
|
|
control_socket.DropMulticastGroup(control_mcast_addr);
|
|
}
|
|
data_socket.Close();
|
|
control_socket.Close();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Occurs when message is received.
|
|
/// </summary>
|
|
public event EventHandler<RtspChunkEventArgs> DataReceived;
|
|
|
|
/// <summary>
|
|
/// Raises the <see cref="E:DataReceived"/> event.
|
|
/// </summary>
|
|
/// <param name="rtspChunkEventArgs">The <see cref="Rtsp.RtspChunkEventArgs"/> instance containing the event data.</param>
|
|
protected void OnDataReceived(RtspChunkEventArgs rtspChunkEventArgs)
|
|
{
|
|
EventHandler<RtspChunkEventArgs> handler = DataReceived;
|
|
|
|
if (handler != null)
|
|
handler(this, rtspChunkEventArgs);
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Does the video job.
|
|
/// </summary>
|
|
private void DoWorkerJob(System.Net.Sockets.UdpClient socket, int data_port)
|
|
{
|
|
|
|
IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Any, data_port);
|
|
try
|
|
{
|
|
// loop until we get an exception eg the socket closed
|
|
while (true)
|
|
{
|
|
byte[] frame = socket.Receive(ref ipEndPoint);
|
|
|
|
// We have an RTP frame.
|
|
// Fire the DataReceived event with 'frame'
|
|
Console.WriteLine("Received RTP data on port " + data_port);
|
|
|
|
RtspChunk currentMessage = new RtspData();
|
|
// aMessage.SourcePort = ??
|
|
currentMessage.Data = frame;
|
|
((RtspData)currentMessage).Channel = data_port;
|
|
|
|
|
|
OnDataReceived(new RtspChunkEventArgs(currentMessage));
|
|
|
|
}
|
|
}
|
|
catch (ObjectDisposedException)
|
|
{
|
|
}
|
|
catch (SocketException)
|
|
{
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Write to the RTP Data Port
|
|
/// </summary>
|
|
public void Write_To_Data_Port(byte[] data, String hostname, int port) {
|
|
data_socket.Send(data,data.Length, hostname, port);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Write to the RTP Control Port
|
|
/// </summary>
|
|
public void Write_To_Control_Port(byte[] data, String hostname, int port)
|
|
{
|
|
data_socket.Send(data, data.Length, hostname, port);
|
|
}
|
|
|
|
}
|
|
}
|