|
|
|
@ -0,0 +1,203 @@
|
|
|
|
|
/*
|
|
|
|
|
Copyright (C) <2007-2016> <Kay Diefenthal>
|
|
|
|
|
|
|
|
|
|
SatIp.RtspSample is free software: you can redistribute it and/or modify
|
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
|
|
SatIp.RtspSample is distributed in the hope that it will be useful,
|
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
|
along with SatIp.RtspSample. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
*/
|
|
|
|
|
using System;
|
|
|
|
|
using System.Net;
|
|
|
|
|
using System.Net.Sockets;
|
|
|
|
|
using System.Threading;
|
|
|
|
|
using MediaBrowser.Model.Logging;
|
|
|
|
|
|
|
|
|
|
namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp.Rtcp
|
|
|
|
|
{
|
|
|
|
|
public class RtcpListener
|
|
|
|
|
{
|
|
|
|
|
private readonly ILogger _logger;
|
|
|
|
|
private Thread _rtcpListenerThread;
|
|
|
|
|
private AutoResetEvent _rtcpListenerThreadStopEvent = null;
|
|
|
|
|
private UdpClient _udpClient;
|
|
|
|
|
private IPEndPoint _multicastEndPoint;
|
|
|
|
|
private IPEndPoint _serverEndPoint;
|
|
|
|
|
private TransmissionMode _transmissionMode;
|
|
|
|
|
|
|
|
|
|
public RtcpListener(String address, int port, TransmissionMode mode,ILogger logger)
|
|
|
|
|
{
|
|
|
|
|
_logger = logger;
|
|
|
|
|
_transmissionMode = mode;
|
|
|
|
|
switch (mode)
|
|
|
|
|
{
|
|
|
|
|
case TransmissionMode.Unicast:
|
|
|
|
|
_udpClient = new UdpClient(new IPEndPoint(IPAddress.Parse(address), port));
|
|
|
|
|
_serverEndPoint = new IPEndPoint(IPAddress.Any, 0);
|
|
|
|
|
break;
|
|
|
|
|
case TransmissionMode.Multicast:
|
|
|
|
|
_multicastEndPoint = new IPEndPoint(IPAddress.Parse(address), port);
|
|
|
|
|
_serverEndPoint = new IPEndPoint(IPAddress.Any, 0);
|
|
|
|
|
_udpClient = new UdpClient();
|
|
|
|
|
_udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, 1);
|
|
|
|
|
_udpClient.ExclusiveAddressUse = false;
|
|
|
|
|
_udpClient.Client.Bind(new IPEndPoint(IPAddress.Any, port));
|
|
|
|
|
_udpClient.JoinMulticastGroup(_multicastEndPoint.Address);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
//StartRtcpListenerThread();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void StartRtcpListenerThread()
|
|
|
|
|
{
|
|
|
|
|
// Kill the existing thread if it is in "zombie" state.
|
|
|
|
|
if (_rtcpListenerThread != null && !_rtcpListenerThread.IsAlive)
|
|
|
|
|
{
|
|
|
|
|
StopRtcpListenerThread();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (_rtcpListenerThread == null)
|
|
|
|
|
{
|
|
|
|
|
_logger.Info("SAT>IP : starting new RTCP listener thread");
|
|
|
|
|
_rtcpListenerThreadStopEvent = new AutoResetEvent(false);
|
|
|
|
|
_rtcpListenerThread = new Thread(new ThreadStart(RtcpListenerThread));
|
|
|
|
|
_rtcpListenerThread.Name = string.Format("SAT>IP tuner RTCP listener");
|
|
|
|
|
_rtcpListenerThread.IsBackground = true;
|
|
|
|
|
_rtcpListenerThread.Priority = ThreadPriority.Lowest;
|
|
|
|
|
_rtcpListenerThread.Start();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void StopRtcpListenerThread()
|
|
|
|
|
{
|
|
|
|
|
if (_rtcpListenerThread != null)
|
|
|
|
|
{
|
|
|
|
|
if (!_rtcpListenerThread.IsAlive)
|
|
|
|
|
{
|
|
|
|
|
_logger.Info("SAT>IP : aborting old RTCP listener thread");
|
|
|
|
|
_rtcpListenerThread.Abort();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
_rtcpListenerThreadStopEvent.Set();
|
|
|
|
|
if (!_rtcpListenerThread.Join(400 * 2))
|
|
|
|
|
{
|
|
|
|
|
_logger.Info("SAT>IP : failed to join RTCP listener thread, aborting thread");
|
|
|
|
|
_rtcpListenerThread.Abort();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
_rtcpListenerThread = null;
|
|
|
|
|
if (_rtcpListenerThreadStopEvent != null)
|
|
|
|
|
{
|
|
|
|
|
_rtcpListenerThreadStopEvent.Close();
|
|
|
|
|
_rtcpListenerThreadStopEvent = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void RtcpListenerThread()
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
bool receivedGoodBye = false;
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
_udpClient.Client.ReceiveTimeout = 400;
|
|
|
|
|
IPEndPoint serverEndPoint = new IPEndPoint(IPAddress.Any, 0);
|
|
|
|
|
while (!receivedGoodBye && !_rtcpListenerThreadStopEvent.WaitOne(1))
|
|
|
|
|
{
|
|
|
|
|
byte[] packets = _udpClient.Receive(ref serverEndPoint);
|
|
|
|
|
if (packets == null)
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int offset = 0;
|
|
|
|
|
while (offset < packets.Length)
|
|
|
|
|
{
|
|
|
|
|
switch (packets[offset + 1])
|
|
|
|
|
{
|
|
|
|
|
case 200: //sr
|
|
|
|
|
var sr = new RtcpSenderReportPacket();
|
|
|
|
|
sr.Parse(packets, offset);
|
|
|
|
|
offset += sr.Length;
|
|
|
|
|
break;
|
|
|
|
|
case 201: //rr
|
|
|
|
|
var rr = new RtcpReceiverReportPacket();
|
|
|
|
|
rr.Parse(packets, offset);
|
|
|
|
|
offset += rr.Length;
|
|
|
|
|
break;
|
|
|
|
|
case 202: //sd
|
|
|
|
|
var sd = new RtcpSourceDescriptionPacket();
|
|
|
|
|
sd.Parse(packets, offset);
|
|
|
|
|
offset += sd.Length;
|
|
|
|
|
break;
|
|
|
|
|
case 203: // bye
|
|
|
|
|
var bye = new RtcpByePacket();
|
|
|
|
|
bye.Parse(packets, offset);
|
|
|
|
|
receivedGoodBye = true;
|
|
|
|
|
OnPacketReceived(new RtcpPacketReceivedArgs(bye));
|
|
|
|
|
offset += bye.Length;
|
|
|
|
|
break;
|
|
|
|
|
case 204: // app
|
|
|
|
|
var app = new RtcpAppPacket();
|
|
|
|
|
app.Parse(packets, offset);
|
|
|
|
|
OnPacketReceived(new RtcpPacketReceivedArgs(app));
|
|
|
|
|
offset += app.Length;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
switch (_transmissionMode)
|
|
|
|
|
{
|
|
|
|
|
case TransmissionMode.Multicast:
|
|
|
|
|
_udpClient.DropMulticastGroup(_multicastEndPoint.Address);
|
|
|
|
|
_udpClient.Close();
|
|
|
|
|
break;
|
|
|
|
|
case TransmissionMode.Unicast:
|
|
|
|
|
_udpClient.Close();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (ThreadAbortException)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
_logger.Info(string.Format("SAT>IP : RTCP listener thread exception"), ex);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
_logger.Info("SAT>IP : RTCP listener thread stopping");
|
|
|
|
|
}
|
|
|
|
|
public delegate void PacketReceivedHandler(object sender, RtcpPacketReceivedArgs e);
|
|
|
|
|
public event PacketReceivedHandler PacketReceived;
|
|
|
|
|
public class RtcpPacketReceivedArgs : EventArgs
|
|
|
|
|
{
|
|
|
|
|
public Object Packet { get; private set; }
|
|
|
|
|
|
|
|
|
|
public RtcpPacketReceivedArgs(Object packet)
|
|
|
|
|
{
|
|
|
|
|
Packet = packet;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
protected void OnPacketReceived(RtcpPacketReceivedArgs args)
|
|
|
|
|
{
|
|
|
|
|
if (PacketReceived != null)
|
|
|
|
|
{
|
|
|
|
|
PacketReceived(this, args);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|