diff options
24 files changed, 1624 insertions, 53 deletions
diff --git a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs index 6bf414dfa..ce00acb52 100644 --- a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs @@ -481,6 +481,16 @@ namespace MediaBrowser.MediaEncoding.Encoder } } + if (state.IsVideoRequest) + { + var encodingOptions = GetEncodingOptions(); + var videoEncoder = EncodingJobFactory.GetVideoEncoder(MediaEncoder, state, encodingOptions); + if (videoEncoder.IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1) + { + arg = "-hwaccel vaapi -hwaccel_output_format vaapi -vaapi_device " + encodingOptions.VaapiDevice + " " + arg; + } + } + return arg.Trim(); } diff --git a/MediaBrowser.Model/ApiClient/ServerCredentials.cs b/MediaBrowser.Model/ApiClient/ServerCredentials.cs index 19f68445e..ddeb7e546 100644 --- a/MediaBrowser.Model/ApiClient/ServerCredentials.cs +++ b/MediaBrowser.Model/ApiClient/ServerCredentials.cs @@ -67,7 +67,7 @@ namespace MediaBrowser.Model.ApiClient } if (!string.IsNullOrEmpty(server.ManualAddress)) { - existing.LocalAddress = server.ManualAddress; + existing.ManualAddress = server.ManualAddress; } if (!string.IsNullOrEmpty(server.Name)) { diff --git a/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs b/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs index 28b7824c8..8e46f8f03 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs @@ -102,14 +102,14 @@ namespace MediaBrowser.Server.Implementations.HttpServer // new SessionAuthProvider(_containerAdapter.Resolve<ISessionContext>()), //})); - PreRequestFilters.Add((httpReq, httpRes) => - { - //Handles Request and closes Responses after emitting global HTTP Headers - if (string.Equals(httpReq.Verb, "OPTIONS", StringComparison.OrdinalIgnoreCase)) - { - httpRes.EndRequest(); //add a 'using ServiceStack;' - } - }); + //PreRequestFilters.Add((httpReq, httpRes) => + //{ + // //Handles Request and closes Responses after emitting global HTTP Headers + // if (string.Equals(httpReq.Verb, "OPTIONS", StringComparison.OrdinalIgnoreCase)) + // { + // httpRes.EndRequest(); //add a 'using ServiceStack;' + // } + //}); HostContext.GlobalResponseFilters.Add(new ResponseFilter(_logger).FilterResponse); } @@ -403,6 +403,17 @@ namespace MediaBrowser.Server.Implementations.HttpServer return; } + if (string.Equals(httpReq.Verb, "OPTIONS", StringComparison.OrdinalIgnoreCase)) + { + httpRes.StatusCode = 200; + httpRes.AddHeader("Access-Control-Allow-Origin", "*"); + httpRes.AddHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, PATCH, OPTIONS"); + httpRes.AddHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, Range, X-MediaBrowser-Token, X-Emby-Authorization"); + httpRes.ContentType = "text/html"; + + httpRes.Close(); + } + var operationName = httpReq.OperationName; var localPath = url.LocalPath; diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/Rtcp/ReportBlock.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/Rtcp/ReportBlock.cs new file mode 100644 index 000000000..dddd77179 --- /dev/null +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/Rtcp/ReportBlock.cs @@ -0,0 +1,79 @@ +/* + 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/>. +*/ + +namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp.Rtcp +{ + public class ReportBlock + { + /// <summary> + /// Get the length of the block. + /// </summary> + public int BlockLength { get { return (24); } } + /// <summary> + /// Get the synchronization source. + /// </summary> + public string SynchronizationSource { get; private set; } + /// <summary> + /// Get the fraction lost. + /// </summary> + public int FractionLost { get; private set; } + /// <summary> + /// Get the cumulative packets lost. + /// </summary> + public int CumulativePacketsLost { get; private set; } + /// <summary> + /// Get the highest number received. + /// </summary> + public int HighestNumberReceived { get; private set; } + /// <summary> + /// Get the inter arrival jitter. + /// </summary> + public int InterArrivalJitter { get; private set; } + /// <summary> + /// Get the timestamp of the last report. + /// </summary> + public int LastReportTimeStamp { get; private set; } + /// <summary> + /// Get the delay since the last report. + /// </summary> + public int DelaySinceLastReport { get; private set; } + + /// <summary> + /// Initialize a new instance of the ReportBlock class. + /// </summary> + public ReportBlock() { } + + /// <summary> + /// Unpack the data in a packet. + /// </summary> + /// <param name="buffer">The buffer containing the packet.</param> + /// <param name="offset">The offset to the first byte of the packet within the buffer.</param> + /// <returns>An ErrorSpec instance if an error occurs; null otherwise.</returns> + public void Process(byte[] buffer, int offset) + { + SynchronizationSource = Utils.ConvertBytesToString(buffer, offset, 4); + FractionLost = buffer[offset + 4]; + CumulativePacketsLost = Utils.Convert3BytesToInt(buffer, offset + 5); + HighestNumberReceived = Utils.Convert4BytesToInt(buffer, offset + 8); + InterArrivalJitter = Utils.Convert4BytesToInt(buffer, offset + 12); + LastReportTimeStamp = Utils.Convert4BytesToInt(buffer, offset + 16); + DelaySinceLastReport = Utils.Convert4BytesToInt(buffer, offset + 20); + + + } + } +} diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/Rtcp/RtcpAppPacket.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/Rtcp/RtcpAppPacket.cs new file mode 100644 index 000000000..990b6dd94 --- /dev/null +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/Rtcp/RtcpAppPacket.cs @@ -0,0 +1,68 @@ +/* + 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.Text; + +namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp.Rtcp +{ + class RtcpAppPacket : RtcpPacket + { + /// <summary> + /// Get the synchronization source. + /// </summary> + public int SynchronizationSource { get; private set; } + /// <summary> + /// Get the name. + /// </summary> + public string Name { get; private set; } + /// <summary> + /// Get the identity. + /// </summary> + public int Identity { get; private set; } + /// <summary> + /// Get the variable data portion. + /// </summary> + public string Data { get; private set; } + + public override void Parse(byte[] buffer, int offset) + { + base.Parse(buffer, offset); + SynchronizationSource = Utils.Convert4BytesToInt(buffer, offset + 4); + Name = Utils.ConvertBytesToString(buffer, offset + 8, 4); + Identity = Utils.Convert2BytesToInt(buffer, offset + 12); + + int dataLength = Utils.Convert2BytesToInt(buffer, offset + 14); + if (dataLength != 0) + Data = Utils.ConvertBytesToString(buffer, offset + 16, dataLength); + } + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + sb.AppendFormat("Application Specific.\n"); + sb.AppendFormat("Version : {0} .\n", Version); + sb.AppendFormat("Padding : {0} .\n", Padding); + sb.AppendFormat("Report Count : {0} .\n", ReportCount); + sb.AppendFormat("PacketType: {0} .\n", Type); + sb.AppendFormat("Length : {0} .\n", Length); + sb.AppendFormat("SynchronizationSource : {0} .\n", SynchronizationSource); + sb.AppendFormat("Name : {0} .\n", Name); + sb.AppendFormat("Identity : {0} .\n", Identity); + sb.AppendFormat("Data : {0} .\n", Data); + sb.AppendFormat(".\n"); + return sb.ToString(); + } + } +} diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/Rtcp/RtcpByePacket.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/Rtcp/RtcpByePacket.cs new file mode 100644 index 000000000..c79ea31a8 --- /dev/null +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/Rtcp/RtcpByePacket.cs @@ -0,0 +1,59 @@ +using System.Collections.ObjectModel; +/* + 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.Text; + +namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp.Rtcp +{ + public class RtcpByePacket :RtcpPacket + { + public Collection<string> SynchronizationSources { get; private set; } + public string ReasonForLeaving { get; private set; } + public override void Parse(byte[] buffer, int offset) + { + base.Parse(buffer, offset); + SynchronizationSources = new Collection<string>(); + int index = 4; + + while (SynchronizationSources.Count < ReportCount) + { + SynchronizationSources.Add(Utils.ConvertBytesToString(buffer, offset + index, 4)); + index += 4; + } + + if (index < Length) + { + int reasonLength = buffer[offset + index]; + ReasonForLeaving = Utils.ConvertBytesToString(buffer, offset + index + 1, reasonLength); + } + } + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + sb.AppendFormat("ByeBye .\n"); + sb.AppendFormat("Version : {0} .\n", Version); + sb.AppendFormat("Padding : {0} .\n", Padding); + sb.AppendFormat("Report Count : {0} .\n", ReportCount); + sb.AppendFormat("PacketType: {0} .\n", Type); + sb.AppendFormat("Length : {0} .\n", Length); + sb.AppendFormat("SynchronizationSources : {0} .\n", SynchronizationSources); + sb.AppendFormat("ReasonForLeaving : {0} .\n", ReasonForLeaving); + sb.AppendFormat(".\n"); + return sb.ToString(); + } + } +} diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/Rtcp/RtcpListener.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/Rtcp/RtcpListener.cs new file mode 100644 index 000000000..2c54f0665 --- /dev/null +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/Rtcp/RtcpListener.cs @@ -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); + } + } + } +} diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/Rtcp/RtcpPacket.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/Rtcp/RtcpPacket.cs new file mode 100644 index 000000000..0a949eb7e --- /dev/null +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/Rtcp/RtcpPacket.cs @@ -0,0 +1,37 @@ +/* + 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/>. +*/ + +namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp.Rtcp +{ + public abstract class RtcpPacket + { + public int Version { get; private set; } + public bool Padding { get; private set; } + public int ReportCount { get; private set; } + public int Type { get; private set; } + public int Length { get; private set; } + + public virtual void Parse(byte[] buffer, int offset) + { + Version = buffer[offset] >> 6; + Padding = (buffer[offset] & 0x20) != 0; + ReportCount = buffer[offset] & 0x1f; + Type = buffer[offset + 1]; + Length = (Utils.Convert2BytesToInt(buffer, offset + 2) * 4) + 4; + } + } +} diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/Rtcp/RtcpReceiverReportPacket.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/Rtcp/RtcpReceiverReportPacket.cs new file mode 100644 index 000000000..abb863652 --- /dev/null +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/Rtcp/RtcpReceiverReportPacket.cs @@ -0,0 +1,68 @@ +using System.Collections.ObjectModel; +/* + 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.Text; + +namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp.Rtcp +{ + public class RtcpReceiverReportPacket :RtcpPacket + { + public string SynchronizationSource { get; private set; } + public Collection<ReportBlock> ReportBlocks { get; private set; } + public byte[] ProfileExtension { get; private set; } + public override void Parse(byte[] buffer, int offset) + { + base.Parse(buffer, offset); + SynchronizationSource = Utils.ConvertBytesToString(buffer, offset + 4, 4); + + ReportBlocks = new Collection<ReportBlock>(); + int index = 8; + + while (ReportBlocks.Count < ReportCount) + { + ReportBlock reportBlock = new ReportBlock(); + reportBlock.Process(buffer, offset + index); + ReportBlocks.Add(reportBlock); + index += reportBlock.BlockLength; + } + + if (index < Length) + { + ProfileExtension = new byte[Length - index]; + + for (int extensionIndex = 0; index < Length; index++) + { + ProfileExtension[extensionIndex] = buffer[offset + index]; + extensionIndex++; + } + } + } + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + sb.AppendFormat("Receiver Report.\n"); + sb.AppendFormat("Version : {0} .\n", Version); + sb.AppendFormat("Padding : {0} .\n", Padding); + sb.AppendFormat("Report Count : {0} .\n", ReportCount); + sb.AppendFormat("PacketType: {0} .\n", Type); + sb.AppendFormat("Length : {0} .\n", Length); + sb.AppendFormat("SynchronizationSource : {0} .\n", SynchronizationSource); + sb.AppendFormat(".\n"); + return sb.ToString(); + } + } +} diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/Rtcp/RtcpSenderReportPacket.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/Rtcp/RtcpSenderReportPacket.cs new file mode 100644 index 000000000..dda5d6a03 --- /dev/null +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/Rtcp/RtcpSenderReportPacket.cs @@ -0,0 +1,105 @@ +using System.Collections.ObjectModel; +/* + 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.Text; + +namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp.Rtcp +{ + public class RtcpSenderReportPacket : RtcpPacket + { + #region Properties + /// <summary> + /// Get the synchronization source. + /// </summary> + public int SynchronizationSource { get; private set; } + /// <summary> + /// Get the NPT timestamp. + /// </summary> + public long NPTTimeStamp { get; private set; } + /// <summary> + /// Get the RTP timestamp. + /// </summary> + public int RTPTimeStamp { get; private set; } + /// <summary> + /// Get the packet count. + /// </summary> + public int SenderPacketCount { get; private set; } + /// <summary> + /// Get the octet count. + /// </summary> + public int SenderOctetCount { get; private set; } + /// <summary> + /// Get the list of report blocks. + /// </summary> + public Collection<ReportBlock> ReportBlocks { get; private set; } + /// <summary> + /// Get the profile extension data. + /// </summary> + public byte[] ProfileExtension { get; private set; } + #endregion + + public override void Parse(byte[] buffer, int offset) + { + base.Parse(buffer, offset); + SynchronizationSource = Utils.Convert4BytesToInt(buffer, offset + 4); + NPTTimeStamp = Utils.Convert8BytesToLong(buffer, offset + 8); + RTPTimeStamp = Utils.Convert4BytesToInt(buffer, offset + 16); + SenderPacketCount = Utils.Convert4BytesToInt(buffer, offset + 20); + SenderOctetCount = Utils.Convert4BytesToInt(buffer, offset + 24); + + ReportBlocks = new Collection<ReportBlock>(); + int index = 28; + + while (ReportBlocks.Count < ReportCount) + { + ReportBlock reportBlock = new ReportBlock(); + reportBlock.Process(buffer, offset + index); + ReportBlocks.Add(reportBlock); + index += reportBlock.BlockLength; + } + + if (index < Length) + { + ProfileExtension = new byte[Length - index]; + + for (int extensionIndex = 0; index < Length; index++) + { + ProfileExtension[extensionIndex] = buffer[offset + index]; + extensionIndex++; + } + } + } + + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + sb.AppendFormat("Sender Report.\n"); + sb.AppendFormat("Version : {0} .\n", Version); + sb.AppendFormat("Padding : {0} .\n", Padding); + sb.AppendFormat("Report Count : {0} .\n", ReportCount); + sb.AppendFormat("PacketType: {0} .\n", Type); + sb.AppendFormat("Length : {0} .\n", Length); + sb.AppendFormat("SynchronizationSource : {0} .\n", SynchronizationSource); + sb.AppendFormat("NTP Timestamp : {0} .\n", Utils.NptTimestampToDateTime(NPTTimeStamp)); + sb.AppendFormat("RTP Timestamp : {0} .\n", RTPTimeStamp); + sb.AppendFormat("Sender PacketCount : {0} .\n", SenderPacketCount); + sb.AppendFormat("Sender Octet Count : {0} .\n", SenderOctetCount); + sb.AppendFormat(".\n"); + return sb.ToString(); + } + } +} diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/Rtcp/RtcpSourceDescriptionPacket.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/Rtcp/RtcpSourceDescriptionPacket.cs new file mode 100644 index 000000000..0a95a4413 --- /dev/null +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/Rtcp/RtcpSourceDescriptionPacket.cs @@ -0,0 +1,57 @@ +using System.Collections.ObjectModel; +/* + 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.Text; + +namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp.Rtcp +{ + class RtcpSourceDescriptionPacket :RtcpPacket + { /// <summary> + /// Get the list of source descriptions. + /// </summary> + public Collection<SourceDescriptionBlock> Descriptions; + public override void Parse(byte[] buffer, int offset) + { + base.Parse(buffer, offset); + Descriptions = new Collection<SourceDescriptionBlock>(); + + int index = 4; + + while (Descriptions.Count < ReportCount) + { + SourceDescriptionBlock descriptionBlock = new SourceDescriptionBlock(); + descriptionBlock.Process(buffer, offset + index); + Descriptions.Add(descriptionBlock); + index += descriptionBlock.BlockLength; + } + } + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + sb.AppendFormat("Source Description.\n"); + sb.AppendFormat("Version : {0} .\n", Version); + sb.AppendFormat("Padding : {0} .\n", Padding); + sb.AppendFormat("Report Count : {0} .\n", ReportCount); + sb.AppendFormat("PacketType: {0} .\n", Type); + sb.AppendFormat("Length : {0} .\n", Length); + sb.AppendFormat("Descriptions : {0} .\n", Descriptions); + + sb.AppendFormat(".\n"); + return sb.ToString(); + } + } +} diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/Rtcp/SourceDescriptionBlock.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/Rtcp/SourceDescriptionBlock.cs new file mode 100644 index 000000000..bf56087cd --- /dev/null +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/Rtcp/SourceDescriptionBlock.cs @@ -0,0 +1,65 @@ +/* + 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.Collections.ObjectModel; + +namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp.Rtcp +{ + class SourceDescriptionBlock + { + /// <summary> + /// Get the length of the block. + /// </summary> + public int BlockLength { get { return (blockLength + (blockLength % 4)); } } + + /// <summary> + /// Get the synchronization source. + /// </summary> + public string SynchronizationSource { get; private set; } + /// <summary> + /// Get the list of source descriptioni items. + /// </summary> + public Collection<SourceDescriptionItem> Items; + + private int blockLength; + + public void Process(byte[] buffer, int offset) + { + SynchronizationSource = Utils.ConvertBytesToString(buffer, offset, 4); + Items = new Collection<SourceDescriptionItem>(); + int index = 4; + bool done = false; + do + { + SourceDescriptionItem item = new SourceDescriptionItem(); + item.Process(buffer, offset + index); + + if (item.Type != 0) + { + Items.Add(item); + index += item.ItemLength; + blockLength += item.ItemLength; + } + else + { + blockLength++; + done = true; + } + } + while (!done); + } + } +} diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/Rtcp/SourceDescriptionItem.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/Rtcp/SourceDescriptionItem.cs new file mode 100644 index 000000000..5dd033642 --- /dev/null +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/Rtcp/SourceDescriptionItem.cs @@ -0,0 +1,60 @@ +/* + 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/>. +*/ + +namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp.Rtcp +{ + /// <summary> + /// The class that describes a source description item. + /// </summary> + public class SourceDescriptionItem + { + /// <summary> + /// Get the type. + /// </summary> + public int Type { get; private set; } + /// <summary> + /// Get the text. + /// </summary> + public string Text { get; private set; } + + /// <summary> + /// Get the length of the item. + /// </summary> + public int ItemLength { get { return (Text.Length + 2); } } + + /// <summary> + /// Initialize a new instance of the SourceDescriptionItem class. + /// </summary> + public SourceDescriptionItem() { } + + /// <summary> + /// Unpack the data in a packet. + /// </summary> + /// <param name="buffer">The buffer containing the packet.</param> + /// <param name="offset">The offset to the first byte of the packet within the buffer.</param> + /// <returns>An ErrorSpec instance if an error occurs; null otherwise.</returns> + public void Process(byte[] buffer, int offset) + { + Type = buffer[offset]; + if (Type != 0) + { + int length = buffer[offset + 1]; + Text = Utils.ConvertBytesToString(buffer, offset + 2, length); + } + } + } +} diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/Rtp/RtpListener.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/Rtp/RtpListener.cs new file mode 100644 index 000000000..ea6a9ba6a --- /dev/null +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/Rtp/RtpListener.cs @@ -0,0 +1,160 @@ +/* + 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.Rtp +{ + public class RtpListener + { + private readonly ILogger _logger; + private AutoResetEvent _rtpListenerThreadStopEvent; + private Thread _rtpListenerThread; + private UdpClient _udpClient; + private IPEndPoint _multicastEndPoint; + private IPEndPoint _serverEndPoint; + private TransmissionMode _transmissionMode; + public RtpListener(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 = null; + _udpClient = new UdpClient(); + _udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, 1); + _udpClient.ExclusiveAddressUse = false; + _udpClient.Client.Bind(new IPEndPoint(IPAddress.Any, _multicastEndPoint.Port)); + _udpClient.JoinMulticastGroup(_multicastEndPoint.Address); + break; + } + //StartRtpListenerThread(); + } + public void StartRtpListenerThread() + { + // Kill the existing thread if it is in "zombie" state. + if (_rtpListenerThread != null && !_rtpListenerThread.IsAlive) + { + StopRtpListenerThread(); + } + + if (_rtpListenerThread == null) + { + _logger.Info("SAT>IP : starting new RTP listener thread"); + _rtpListenerThreadStopEvent = new AutoResetEvent(false); + _rtpListenerThread = new Thread(new ThreadStart(RtpListenerThread)); + _rtpListenerThread.Name = string.Format("SAT>IP tuner RTP listener"); + _rtpListenerThread.IsBackground = true; + _rtpListenerThread.Priority = ThreadPriority.Lowest; + _rtpListenerThread.Start(); + } + } + + public void StopRtpListenerThread() + { + if (_rtpListenerThread != null) + { + if (!_rtpListenerThread.IsAlive) + { + _logger.Info("SAT>IP : aborting old RTP listener thread"); + _rtpListenerThread.Abort(); + } + else + { + _rtpListenerThreadStopEvent.Set(); + if (!_rtpListenerThread.Join(400 * 2)) + { + _logger.Info("SAT>IP : failed to join RTP listener thread, aborting thread"); + _rtpListenerThread.Abort(); + } + } + _rtpListenerThread = null; + if (_rtpListenerThreadStopEvent != null) + { + _rtpListenerThreadStopEvent.Close(); + _rtpListenerThreadStopEvent = null; + } + } + } + + private void RtpListenerThread() + { + try + { + try + { + + while (!_rtpListenerThreadStopEvent.WaitOne(1)) + { + byte[] receivedbytes = _udpClient.Receive(ref _serverEndPoint); + RtpPacket packet = RtpPacket.Decode(receivedbytes); + OnPacketReceived(new RtpPacketReceivedArgs(packet)); + } + } + 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 : RTP listener thread exception"), ex); + return; + } + _logger.Info("SAT>IP : RTP listener thread stopping"); + } + public delegate void PacketReceivedHandler(object sender, RtpPacketReceivedArgs e); + public event PacketReceivedHandler PacketReceived; + public class RtpPacketReceivedArgs : EventArgs + { + public RtpPacket Packet { get; private set; } + + public RtpPacketReceivedArgs(RtpPacket packet) + { + Packet = packet; + } + } + protected void OnPacketReceived(RtpPacketReceivedArgs args) + { + if (PacketReceived != null) + { + PacketReceived(this, args); + } + } + } +} diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/Rtp/RtpPacket.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/Rtp/RtpPacket.cs new file mode 100644 index 000000000..489d7f087 --- /dev/null +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/Rtp/RtpPacket.cs @@ -0,0 +1,116 @@ +/* + 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.Collections.ObjectModel; +using System.Text; + +namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp.Rtp +{ + public class RtpPacket + { + private static int MinHeaderLength = 12; + public int HeaderSize = MinHeaderLength; + public int Version { get; set; } + public Boolean Padding { get; set; } + public Boolean Extension { get; set; } + public int ContributingSourceCount { get; set; } + public Boolean Marker { get; set; } + public int PayloadType { get; set; } + public int SequenceNumber { get; set; } + public long TimeStamp { get; set; } + public long SynchronizationSource { get; set; } + public Collection<string> ContributingSources { get; private set; } + public int ExtensionHeaderId = 0; + public int ExtensionHeaderLength = 0; + public bool HasPayload { get; set; } + public byte[] Payload { get; set; } + public RtpPacket() + { + + } + public static RtpPacket Decode(byte[] buffer) + { + var packet = new RtpPacket(); + packet.Version = buffer[0] >> 6; + packet.Padding = (buffer[0] & 0x20) != 0; + packet.Extension = (buffer[0] & 0x10) != 0; + packet.ContributingSourceCount = buffer[0] & 0x0f; + + packet.Marker = (buffer[1] & 0x80) != 0; + packet.PayloadType = buffer[1] & 0x7f; + + packet.SequenceNumber = Utils.Convert2BytesToInt(buffer, 2); + packet.TimeStamp = Utils.Convert4BytesToLong(buffer, 4); + packet.SynchronizationSource = Utils.Convert4BytesToLong(buffer, 8); + + int index = 12; + + if (packet.ContributingSourceCount != 0) + { + packet.ContributingSources = new Collection<string>(); + + while (packet.ContributingSources.Count < packet.ContributingSourceCount) + { + packet.ContributingSources.Add(Utils.ConvertBytesToString(buffer, index, 4)); + index += 4; + } + } + var dataoffset = 0; + if (!packet.Extension) + dataoffset = index; + else + { + packet.ExtensionHeaderId = Utils.Convert2BytesToInt(buffer, index); + packet.ExtensionHeaderLength = Utils.Convert2BytesToInt(buffer, index + 2); + dataoffset = index + packet.ExtensionHeaderLength + 4; + } + + var dataLength = buffer.Length - dataoffset; + if (dataLength > dataoffset) + { + packet.HasPayload = true; + packet.Payload = new byte[dataLength]; + Array.Copy(buffer, dataoffset, packet.Payload, 0, dataLength); + } + else + { + packet.HasPayload = false; + } + return packet; + } + + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + sb.AppendFormat("RTP Packet"); + sb.AppendFormat("Version: {0} \n", Version); + sb.AppendFormat("Padding: {0} \n", Padding); + sb.AppendFormat("Extension: {0} \n", Extension); + sb.AppendFormat("Contributing Source Identifiers Count: {0} \n", ContributingSourceCount); + sb.AppendFormat("Marker: {0} \n", Marker); + sb.AppendFormat("Payload Type: {0} \n", PayloadType); + sb.AppendFormat("Sequence Number: {0} \n", SequenceNumber); + sb.AppendFormat("Timestamp: {0} .\n", TimeStamp); + sb.AppendFormat("Synchronization Source Identifier: {0} \n", SynchronizationSource); + sb.AppendFormat("\n"); + return sb.ToString(); + } + + } + +} diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/SatIpDiscovery.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/SatIpDiscovery.cs index ba5c604ed..cb0e573da 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/SatIpDiscovery.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/SatIpDiscovery.cs @@ -237,7 +237,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp string modelurl = ""; string serialnumber = ""; string presentationurl = ""; - string capabilities = ""; + //string capabilities = ""; string m3u = ""; var document = XDocument.Load(locationUri.AbsoluteUri); var xnm = new XmlNamespaceManager(new NameTable()); @@ -284,22 +284,22 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp var capabilitiesElement = deviceElement.Element(n1 + "X_SATIPCAP"); if (capabilitiesElement != null) { - //_capabilities = capabilitiesElement.Value; - //if (capabilitiesElement.Value.Contains(',')) - //{ - // string[] capabilities = capabilitiesElement.Value.Split(','); - // foreach (var capability in capabilities) - // { - // ReadCapability(capability); - // } - //} - //else - //{ - // ReadCapability(capabilitiesElement.Value); - //} + //_capabilities = capabilitiesElement.Value; + if (capabilitiesElement.Value.Contains(',')) + { + string[] capabilities = capabilitiesElement.Value.Split(','); + foreach (var capability in capabilities) + { + ReadCapability(capability); + } } else { + ReadCapability(capabilitiesElement.Value); + } + } + else + { _supportsDVBS = true; _tunerCountDVBS =1; } @@ -314,8 +314,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp Id = uniquedevicename, IsEnabled = true, Type = SatIpHost.DeviceType, - Tuners = 1, - TunersAvailable = 1, + Tuners = _tunerCountDVBS, + TunersAvailable = _tunerCountDVBS, M3UUrl = m3u }; diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/TransmissionMode.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/TransmissionMode.cs new file mode 100644 index 000000000..71d7656d9 --- /dev/null +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/TransmissionMode.cs @@ -0,0 +1,25 @@ +/* + 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/>. +*/ + +namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp +{ + public enum TransmissionMode + { + Unicast, + Multicast + } +} diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/Utils.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/Utils.cs new file mode 100644 index 000000000..3595e4b0a --- /dev/null +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/Utils.cs @@ -0,0 +1,90 @@ +/* + 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.Text; + +namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp +{ + public class Utils + { + public static int Convert2BytesToInt(byte[] buffer, int offset) + { + int temp = (int)buffer[offset]; + temp = (temp * 256) + buffer[offset + 1]; + + return (temp); + } + public static int Convert3BytesToInt(byte[] buffer, int offset) + { + int temp = (int)buffer[offset]; + temp = (temp * 256) + buffer[offset + 1]; + temp = (temp * 256) + buffer[offset + 2]; + + return (temp); + } + public static int Convert4BytesToInt(byte[] buffer, int offset) + { + int temp =(int)buffer[offset]; + temp = (temp * 256) + buffer[offset + 1]; + temp = (temp * 256) + buffer[offset + 2]; + temp = (temp * 256) + buffer[offset + 3]; + + return (temp); + } + public static long Convert4BytesToLong(byte[] buffer, int offset) + { + long temp = 0; + + for (int index = 0; index < 4; index++) + temp = (temp * 256) + buffer[offset + index]; + + return (temp); + } + public static long Convert8BytesToLong(byte[] buffer, int offset) + { + long temp = 0; + + for (int index = 0; index < 8; index++) + temp = (temp * 256) + buffer[offset + index]; + + return (temp); + } + public static string ConvertBytesToString(byte[] buffer, int offset, int length) + { + StringBuilder reply = new StringBuilder(4); + for (int index = 0; index < length; index++) + reply.Append((char)buffer[offset + index]); + return (reply.ToString()); + } + public static DateTime NptTimestampToDateTime(long nptTimestamp) { return NptTimestampToDateTime((uint)((nptTimestamp >> 32) & 0xFFFFFFFF), (uint)(nptTimestamp & 0xFFFFFFFF),null); } + + public static DateTime NptTimestampToDateTime(uint seconds, uint fractions, DateTime? epoch ) + { + ulong ticks =(ulong)((seconds * TimeSpan.TicksPerSecond) + ((fractions * TimeSpan.TicksPerSecond) / 0x100000000L)); + if (epoch.HasValue) return epoch.Value + TimeSpan.FromTicks((Int64)ticks); + return (seconds & 0x80000000L) == 0 ? UtcEpoch2036 + TimeSpan.FromTicks((Int64)ticks) : UtcEpoch1900 + TimeSpan.FromTicks((Int64)ticks); + } + + //When the First Epoch will wrap (The real Y2k) + public static DateTime UtcEpoch2036 = new DateTime(2036, 2, 7, 6, 28, 16, DateTimeKind.Utc); + + public static DateTime UtcEpoch1900 = new DateTime(1900, 1, 1, 0, 0, 0, DateTimeKind.Utc); + + public static DateTime UtcEpoch1970 = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + + } +} diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj index 6879c3f40..9a92cf896 100644 --- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj +++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj @@ -251,6 +251,18 @@ <Compile Include="LiveTv\RecordingImageProvider.cs" /> <Compile Include="LiveTv\RefreshChannelsScheduledTask.cs" /> <Compile Include="LiveTv\TunerHosts\SatIp\ChannelScan.cs" /> + <Compile Include="LiveTv\TunerHosts\SatIp\Rtcp\ReportBlock.cs" /> + <Compile Include="LiveTv\TunerHosts\SatIp\Rtcp\RtcpAppPacket.cs" /> + <Compile Include="LiveTv\TunerHosts\SatIp\Rtcp\RtcpByePacket.cs" /> + <Compile Include="LiveTv\TunerHosts\SatIp\Rtcp\RtcpListener.cs" /> + <Compile Include="LiveTv\TunerHosts\SatIp\Rtcp\RtcpPacket.cs" /> + <Compile Include="LiveTv\TunerHosts\SatIp\Rtcp\RtcpReceiverReportPacket.cs" /> + <Compile Include="LiveTv\TunerHosts\SatIp\Rtcp\RtcpSenderReportPacket.cs" /> + <Compile Include="LiveTv\TunerHosts\SatIp\Rtcp\RtcpSourceDescriptionPacket.cs" /> + <Compile Include="LiveTv\TunerHosts\SatIp\Rtcp\SourceDescriptionBlock.cs" /> + <Compile Include="LiveTv\TunerHosts\SatIp\Rtcp\SourceDescriptionItem.cs" /> + <Compile Include="LiveTv\TunerHosts\SatIp\Rtp\RtpListener.cs" /> + <Compile Include="LiveTv\TunerHosts\SatIp\Rtp\RtpPacket.cs" /> <Compile Include="LiveTv\TunerHosts\SatIp\Rtsp\RtspMethod.cs" /> <Compile Include="LiveTv\TunerHosts\SatIp\Rtsp\RtspRequest.cs" /> <Compile Include="LiveTv\TunerHosts\SatIp\Rtsp\RtspResponse.cs" /> @@ -258,6 +270,8 @@ <Compile Include="LiveTv\TunerHosts\SatIp\Rtsp\RtspStatusCode.cs" /> <Compile Include="LiveTv\TunerHosts\SatIp\SatIpHost.cs" /> <Compile Include="LiveTv\TunerHosts\SatIp\SatIpDiscovery.cs" /> + <Compile Include="LiveTv\TunerHosts\SatIp\TransmissionMode.cs" /> + <Compile Include="LiveTv\TunerHosts\SatIp\Utils.cs" /> <Compile Include="Localization\LocalizationManager.cs" /> <Compile Include="Logging\PatternsLogger.cs" /> <Compile Include="MediaEncoder\EncodingManager.cs" /> diff --git a/MediaBrowser.Server.Implementations/Udp/UdpServer.cs b/MediaBrowser.Server.Implementations/Udp/UdpServer.cs index 32992b9b2..9d60dcd40 100644 --- a/MediaBrowser.Server.Implementations/Udp/UdpServer.cs +++ b/MediaBrowser.Server.Implementations/Udp/UdpServer.cs @@ -51,7 +51,6 @@ namespace MediaBrowser.Server.Implementations.Udp AddMessageResponder("who is EmbyServer?", RespondToV2Message); AddMessageResponder("who is MediaBrowserServer_v2?", RespondToV2Message); - AddMessageResponder("who is MediaBrowserServer?", RespondToV1Message); } private void AddMessageResponder(string message, Action<string, Encoding> responder) @@ -94,31 +93,6 @@ namespace MediaBrowser.Server.Implementations.Udp } } - private async void RespondToV1Message(string endpoint, Encoding encoding) - { - var localUrl = await _appHost.GetLocalApiUrl().ConfigureAwait(false); - - if (!string.IsNullOrEmpty(localUrl)) - { - // This is how we did the old v1 search, so need to strip off the protocol - var index = localUrl.IndexOf("://", StringComparison.OrdinalIgnoreCase); - - if (index != -1) - { - localUrl = localUrl.Substring(index + 3); - } - - // Send a response back with our ip address and port - var response = String.Format("MediaBrowserServer|{0}", localUrl); - - await SendAsync(Encoding.UTF8.GetBytes(response), endpoint); - } - else - { - _logger.Warn("Unable to respond to udp request because the local ip address could not be determined."); - } - } - private async void RespondToV2Message(string endpoint, Encoding encoding) { var localUrl = await _appHost.GetLocalApiUrl().ConfigureAwait(false); diff --git a/MediaBrowser.ServerApplication/MainStartup.cs b/MediaBrowser.ServerApplication/MainStartup.cs index 8f153f33f..67b2a3b47 100644 --- a/MediaBrowser.ServerApplication/MainStartup.cs +++ b/MediaBrowser.ServerApplication/MainStartup.cs @@ -292,6 +292,14 @@ namespace MediaBrowser.ServerApplication ErrorModes.SEM_NOGPFAULTERRORBOX | ErrorModes.SEM_NOOPENFILEERRORBOX); } + try + { + LoopUtil.Run(); + } + catch (Exception ex) + { + logManager.GetLogger("LoopUtil").ErrorException("Error in LoopUtil", ex); + } var task = _appHost.Init(initProgress); Task.WaitAll(task); diff --git a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj index 9c5470358..a32312493 100644 --- a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj +++ b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj @@ -119,6 +119,7 @@ <Compile Include="MainStartup.cs" /> <Compile Include="Native\LnkShortcutHandler.cs" /> <Compile Include="Native\DbConnector.cs" /> + <Compile Include="Native\LoopbackUtil.cs" /> <Compile Include="Native\Standby.cs" /> <Compile Include="Native\ServerAuthorization.cs" /> <Compile Include="Native\WindowsApp.cs" /> diff --git a/MediaBrowser.ServerApplication/Native/LoopbackUtil.cs b/MediaBrowser.ServerApplication/Native/LoopbackUtil.cs new file mode 100644 index 000000000..dea77d375 --- /dev/null +++ b/MediaBrowser.ServerApplication/Native/LoopbackUtil.cs @@ -0,0 +1,358 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; + +namespace MediaBrowser.ServerApplication.Native +{ + /// <summary> + /// http://blogs.msdn.com/b/fiddler/archive/2011/12/10/fiddler-windows-8-apps-enable-LoopUtil-network-isolation-exemption.aspx + /// </summary> + public class LoopUtil + { + //http://msdn.microsoft.com/en-us/library/windows/desktop/aa379595(v=vs.85).aspx + [StructLayout(LayoutKind.Sequential)] + internal struct SID_AND_ATTRIBUTES + { + public IntPtr Sid; + public uint Attributes; + } + + [StructLayoutAttribute(LayoutKind.Sequential)] + internal struct INET_FIREWALL_AC_CAPABILITIES + { + public uint count; + public IntPtr capabilities; //SID_AND_ATTRIBUTES + } + + [StructLayoutAttribute(LayoutKind.Sequential)] + internal struct INET_FIREWALL_AC_BINARIES + { + public uint count; + public IntPtr binaries; + } + + [StructLayoutAttribute(LayoutKind.Sequential)] + internal struct INET_FIREWALL_APP_CONTAINER + { + internal IntPtr appContainerSid; + internal IntPtr userSid; + [MarshalAs(UnmanagedType.LPWStr)] + public string appContainerName; + [MarshalAs(UnmanagedType.LPWStr)] + public string displayName; + [MarshalAs(UnmanagedType.LPWStr)] + public string description; + internal INET_FIREWALL_AC_CAPABILITIES capabilities; + internal INET_FIREWALL_AC_BINARIES binaries; + [MarshalAs(UnmanagedType.LPWStr)] + public string workingDirectory; + [MarshalAs(UnmanagedType.LPWStr)] + public string packageFullName; + } + + + // Call this API to free the memory returned by the Enumeration API + [DllImport("FirewallAPI.dll")] + internal static extern void NetworkIsolationFreeAppContainers(IntPtr pACs); + + // Call this API to load the current list of LoopUtil-enabled AppContainers + [DllImport("FirewallAPI.dll")] + internal static extern uint NetworkIsolationGetAppContainerConfig(out uint pdwCntACs, out IntPtr appContainerSids); + + // Call this API to set the LoopUtil-exemption list + [DllImport("FirewallAPI.dll")] + private static extern uint NetworkIsolationSetAppContainerConfig(uint pdwCntACs, SID_AND_ATTRIBUTES[] appContainerSids); + + + // Use this API to convert a string SID into an actual SID + [DllImport("advapi32.dll", SetLastError = true)] + internal static extern bool ConvertStringSidToSid(string strSid, out IntPtr pSid); + + [DllImport("advapi32", CharSet = CharSet.Auto, SetLastError = true)] + static extern bool ConvertSidToStringSid( + [MarshalAs(UnmanagedType.LPArray)] byte[] pSID, + out IntPtr ptrSid); + + [DllImport("advapi32", CharSet = CharSet.Auto, SetLastError = true)] + static extern bool ConvertSidToStringSid(IntPtr pSid, out string strSid); + + // Use this API to convert a string reference (e.g. "@{blah.pri?ms-resource://whatever}") into a plain string + [DllImport("shlwapi.dll", CharSet = CharSet.Unicode, ExactSpelling = true)] + internal static extern int SHLoadIndirectString(string pszSource, StringBuilder pszOutBuf); + + // Call this API to enumerate all of the AppContainers on the system + [DllImport("FirewallAPI.dll")] + internal static extern uint NetworkIsolationEnumAppContainers(uint Flags, out uint pdwCntPublicACs, out IntPtr ppACs); + // DWORD NetworkIsolationEnumAppContainers( + // _In_ DWORD Flags, + // _Out_ DWORD *pdwNumPublicAppCs, + // _Out_ PINET_FIREWALL_APP_CONTAINER *ppPublicAppCs + //); + + //http://msdn.microsoft.com/en-gb/library/windows/desktop/hh968116.aspx + enum NETISO_FLAG + { + NETISO_FLAG_FORCE_COMPUTE_BINARIES = 0x1, + NETISO_FLAG_MAX = 0x2 + } + + + public class AppContainer + { + public String appContainerName { get; set; } + public String displayName { get; set; } + public String workingDirectory { get; set; } + public String StringSid { get; set; } + public List<uint> capabilities { get; set; } + public bool LoopUtil { get; set; } + + public AppContainer(String _appContainerName, String _displayName, String _workingDirectory, IntPtr _sid) + { + this.appContainerName = _appContainerName; + this.displayName = _displayName; + this.workingDirectory = _workingDirectory; + String tempSid; + ConvertSidToStringSid(_sid, out tempSid); + this.StringSid = tempSid; + } + } + + internal List<LoopUtil.INET_FIREWALL_APP_CONTAINER> _AppList; + internal List<LoopUtil.SID_AND_ATTRIBUTES> _AppListConfig; + public List<AppContainer> Apps = new List<AppContainer>(); + internal IntPtr _pACs; + + public LoopUtil() + { + LoadApps(); + } + + public void LoadApps() + { + Apps.Clear(); + _pACs = IntPtr.Zero; + //Full List of Apps + _AppList = PI_NetworkIsolationEnumAppContainers(); + //List of Apps that have LoopUtil enabled. + _AppListConfig = PI_NetworkIsolationGetAppContainerConfig(); + foreach (var PI_app in _AppList) + { + AppContainer app = new AppContainer(PI_app.appContainerName, PI_app.displayName, PI_app.workingDirectory, PI_app.appContainerSid); + + var app_capabilities = LoopUtil.getCapabilites(PI_app.capabilities); + if (app_capabilities.Count > 0) + { + //var sid = new SecurityIdentifier(app_capabilities[0], 0); + + IntPtr arrayValue = IntPtr.Zero; + //var b = LoopUtil.ConvertStringSidToSid(app_capabilities[0].Sid, out arrayValue); + //string mysid; + //var b = LoopUtil.ConvertSidToStringSid(app_capabilities[0].Sid, out mysid); + } + app.LoopUtil = CheckLoopback(PI_app.appContainerSid); + Apps.Add(app); + } + } + private bool CheckLoopback(IntPtr intPtr) + { + foreach (SID_AND_ATTRIBUTES item in _AppListConfig) + { + string left, right; + ConvertSidToStringSid(item.Sid, out left); + ConvertSidToStringSid(intPtr, out right); + + if (left == right) + { + return true; + } + } + return false; + } + + private bool CreateExcemptions(string appName) + { + var hasChanges = false; + + foreach (var app in Apps) + { + if ((app.appContainerName ?? string.Empty).IndexOf(appName, StringComparison.OrdinalIgnoreCase) != -1 || + (app.displayName ?? string.Empty).IndexOf(appName, StringComparison.OrdinalIgnoreCase) != -1) + { + if (!app.LoopUtil) + { + app.LoopUtil = true; + hasChanges = true; + } + } + } + + return hasChanges; + } + + public static void Run() + { + var util = new LoopUtil(); + util.LoadApps(); + + var hasChanges = util.CreateExcemptions("Emby"); + + if (hasChanges) + { + util.SaveLoopbackState(); + } + util.SaveLoopbackState(); + } + + private static List<SID_AND_ATTRIBUTES> getCapabilites(INET_FIREWALL_AC_CAPABILITIES cap) + { + List<SID_AND_ATTRIBUTES> mycap = new List<SID_AND_ATTRIBUTES>(); + + IntPtr arrayValue = cap.capabilities; + + var structSize = Marshal.SizeOf(typeof(SID_AND_ATTRIBUTES)); + for (var i = 0; i < cap.count; i++) + { + var cur = (SID_AND_ATTRIBUTES)Marshal.PtrToStructure(arrayValue, typeof(SID_AND_ATTRIBUTES)); + mycap.Add(cur); + arrayValue = new IntPtr((long)(arrayValue) + (long)(structSize)); + } + + return mycap; + + } + + private static List<SID_AND_ATTRIBUTES> getContainerSID(INET_FIREWALL_AC_CAPABILITIES cap) + { + List<SID_AND_ATTRIBUTES> mycap = new List<SID_AND_ATTRIBUTES>(); + + IntPtr arrayValue = cap.capabilities; + + var structSize = Marshal.SizeOf(typeof(SID_AND_ATTRIBUTES)); + for (var i = 0; i < cap.count; i++) + { + var cur = (SID_AND_ATTRIBUTES)Marshal.PtrToStructure(arrayValue, typeof(SID_AND_ATTRIBUTES)); + mycap.Add(cur); + arrayValue = new IntPtr((long)(arrayValue) + (long)(structSize)); + } + + return mycap; + + } + + private static List<SID_AND_ATTRIBUTES> PI_NetworkIsolationGetAppContainerConfig() + { + + IntPtr arrayValue = IntPtr.Zero; + uint size = 0; + var list = new List<SID_AND_ATTRIBUTES>(); + + // Pin down variables + GCHandle handle_pdwCntPublicACs = GCHandle.Alloc(size, GCHandleType.Pinned); + GCHandle handle_ppACs = GCHandle.Alloc(arrayValue, GCHandleType.Pinned); + + uint retval = NetworkIsolationGetAppContainerConfig(out size, out arrayValue); + + var structSize = Marshal.SizeOf(typeof(SID_AND_ATTRIBUTES)); + for (var i = 0; i < size; i++) + { + var cur = (SID_AND_ATTRIBUTES)Marshal.PtrToStructure(arrayValue, typeof(SID_AND_ATTRIBUTES)); + list.Add(cur); + arrayValue = new IntPtr((long)(arrayValue) + (long)(structSize)); + } + + //release pinned variables. + handle_pdwCntPublicACs.Free(); + handle_ppACs.Free(); + + return list; + + + } + + private List<INET_FIREWALL_APP_CONTAINER> PI_NetworkIsolationEnumAppContainers() + { + + IntPtr arrayValue = IntPtr.Zero; + uint size = 0; + var list = new List<INET_FIREWALL_APP_CONTAINER>(); + + // Pin down variables + GCHandle handle_pdwCntPublicACs = GCHandle.Alloc(size, GCHandleType.Pinned); + GCHandle handle_ppACs = GCHandle.Alloc(arrayValue, GCHandleType.Pinned); + + //uint retval2 = NetworkIsolationGetAppContainerConfig( out size, out arrayValue); + + uint retval = NetworkIsolationEnumAppContainers((Int32)NETISO_FLAG.NETISO_FLAG_MAX, out size, out arrayValue); + _pACs = arrayValue; //store the pointer so it can be freed when we close the form + + var structSize = Marshal.SizeOf(typeof(INET_FIREWALL_APP_CONTAINER)); + for (var i = 0; i < size; i++) + { + var cur = (INET_FIREWALL_APP_CONTAINER)Marshal.PtrToStructure(arrayValue, typeof(INET_FIREWALL_APP_CONTAINER)); + list.Add(cur); + arrayValue = new IntPtr((long)(arrayValue) + (long)(structSize)); + } + + //release pinned variables. + handle_pdwCntPublicACs.Free(); + handle_ppACs.Free(); + + return list; + + + } + + public bool SaveLoopbackState() + { + var countEnabled = CountEnabledLoopUtil(); + SID_AND_ATTRIBUTES[] arr = new SID_AND_ATTRIBUTES[countEnabled]; + int count = 0; + + for (int i = 0; i < Apps.Count; i++) + { + if (Apps[i].LoopUtil) + { + arr[count].Attributes = 0; + //TO DO: + IntPtr ptr; + ConvertStringSidToSid(Apps[i].StringSid, out ptr); + arr[count].Sid = ptr; + count++; + } + + } + + + if (NetworkIsolationSetAppContainerConfig((uint)countEnabled, arr) == 0) + { + return true; + } + else + { return false; } + + } + + private int CountEnabledLoopUtil() + { + var count = 0; + for (int i = 0; i < Apps.Count; i++) + { + if (Apps[i].LoopUtil) + { + count++; + } + + } + return count; + } + + public void FreeResources() + { + NetworkIsolationFreeAppContainers(_pACs); + } + + } +} diff --git a/MediaBrowser.WebDashboard/Api/PackageCreator.cs b/MediaBrowser.WebDashboard/Api/PackageCreator.cs index 65e7fa5d3..e7247a11f 100644 --- a/MediaBrowser.WebDashboard/Api/PackageCreator.cs +++ b/MediaBrowser.WebDashboard/Api/PackageCreator.cs @@ -346,11 +346,14 @@ namespace MediaBrowser.WebDashboard.Api if (string.Equals(mode, "cordova", StringComparison.OrdinalIgnoreCase)) { - sb.Append("<meta http-equiv=\"Content-Security-Policy\" content=\"default-src * 'unsafe-inline' 'unsafe-eval' data: filesystem:;\">"); + sb.Append("<meta http-equiv=\"Content-Security-Policy\" content=\"default-src * 'self' 'unsafe-inline' 'unsafe-eval' data: gap: file: filesystem:; connect-src ws: *\">"); + } + else + { + sb.Append("<meta http-equiv=\"X-UA-Compatibility\" content=\"IE=Edge\">"); } sb.Append("<link rel=\"manifest\" href=\"manifest.json\">"); - sb.Append("<meta http-equiv=\"X-UA-Compatibility\" content=\"IE=Edge\">"); sb.Append("<meta name=\"format-detection\" content=\"telephone=no\">"); sb.Append("<meta name=\"msapplication-tap-highlight\" content=\"no\">"); sb.Append("<meta name=\"viewport\" content=\"user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width\">"); |
