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; /// /// Initializes a new instance of the class. /// Creates two new UDP sockets using the start and end Port range /// 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; } } } /// /// Initializes a new instance of the class. /// Used with Multicast mode with the Multicast Address and Port /// 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; } } /// /// Starts this instance. /// 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(); } /// /// Stops this instance. /// 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(); } /// /// Occurs when message is received. /// public event EventHandler DataReceived; /// /// Raises the event. /// /// The instance containing the event data. protected void OnDataReceived(RtspChunkEventArgs rtspChunkEventArgs) { EventHandler handler = DataReceived; if (handler != null) handler(this, rtspChunkEventArgs); } /// /// Does the video job. /// 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) { } } /// /// Write to the RTP Data Port /// public void Write_To_Data_Port(byte[] data, String hostname, int port) { data_socket.Send(data,data.Length, hostname, port); } /// /// Write to the RTP Control Port /// public void Write_To_Control_Port(byte[] data, String hostname, int port) { data_socket.Send(data, data.Length, hostname, port); } } }