update legacy hdhomerun support

This commit is contained in:
Luke Pulverenti 2017-03-05 21:32:56 -05:00
parent 00fb471162
commit 9e74d834a7
10 changed files with 90 additions and 82 deletions

View File

@ -39,7 +39,15 @@ namespace Emby.Server.Core.Localization
} }
} }
return text.Normalize(form); try
{
return text.Normalize(form);
}
catch (ArgumentException)
{
// if it still fails, return the original text
return text;
}
} }
private static string StripInvalidUnicodeCharacters(string str) private static string StripInvalidUnicodeCharacters(string str)

View File

@ -579,7 +579,7 @@ namespace Emby.Server.Implementations.HttpServer
} }
else else
{ {
ErrorHandler(new FileNotFoundException(), httpReq); ErrorHandler(new FileNotFoundException(), httpReq, false);
} }
} }
catch (OperationCanceledException ex) catch (OperationCanceledException ex)
@ -633,7 +633,6 @@ namespace Emby.Server.Implementations.HttpServer
return null; return null;
} }
private void Write(IResponse response, string text) private void Write(IResponse response, string text)
{ {
var bOutput = Encoding.UTF8.GetBytes(text); var bOutput = Encoding.UTF8.GetBytes(text);

View File

@ -69,9 +69,11 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
private async Task<List<Channels>> GetLineup(TunerHostInfo info, CancellationToken cancellationToken) private async Task<List<Channels>> GetLineup(TunerHostInfo info, CancellationToken cancellationToken)
{ {
var model = await GetModelInfo(info, false, cancellationToken).ConfigureAwait(false);
var options = new HttpRequestOptions var options = new HttpRequestOptions
{ {
Url = string.Format("{0}/lineup.json", GetApiUrl(info, false)), Url = model.LineupURL,
CancellationToken = cancellationToken, CancellationToken = cancellationToken,
BufferContent = false BufferContent = false
}; };
@ -451,7 +453,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
string nal = null; string nal = null;
var url = info.Url; var url = GetApiUrl(info, false);
var id = channelId; var id = channelId;
id += "_" + url.GetMD5().ToString("N"); id += "_" + url.GetMD5().ToString("N");
@ -586,18 +588,17 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
if (hdhomerunChannel != null && hdhomerunChannel.IsLegacyTuner) if (hdhomerunChannel != null && hdhomerunChannel.IsLegacyTuner)
{ {
var modelInfo = await GetModelInfo(info, false, cancellationToken).ConfigureAwait(false);
var mediaSource = GetLegacyMediaSource(info, hdhrId, channelInfo); var mediaSource = GetLegacyMediaSource(info, hdhrId, channelInfo);
var modelInfo = await GetModelInfo(info, false, cancellationToken).ConfigureAwait(false);
var liveStream = new HdHomerunUdpStream(mediaSource, streamId, hdhomerunChannel.Url, modelInfo.TunerCount, _fileSystem, _httpClient, Logger, Config.ApplicationPaths, _appHost, _socketFactory, _networkManager); return new HdHomerunUdpStream(mediaSource, streamId, new LegacyHdHomerunChannelCommands(hdhomerunChannel.Url), modelInfo.TunerCount, _fileSystem, _httpClient, Logger, Config.ApplicationPaths, _appHost, _socketFactory, _networkManager);
return liveStream;
} }
else else
{ {
var mediaSource = GetMediaSource(info, hdhrId, channelInfo, profile); var mediaSource = GetMediaSource(info, hdhrId, channelInfo, profile);
var liveStream = new HdHomerunHttpStream(mediaSource, streamId, _fileSystem, _httpClient, Logger, Config.ApplicationPaths, _appHost); return new HdHomerunHttpStream(mediaSource, streamId, _fileSystem, _httpClient, Logger, Config.ApplicationPaths, _appHost);
return liveStream; //return new HdHomerunUdpStream(mediaSource, streamId, new HdHomerunChannelCommands(hdhomerunChannel.Number), modelInfo.TunerCount, _fileSystem, _httpClient, Logger, Config.ApplicationPaths, _appHost, _socketFactory, _networkManager);
} }
} }

View File

@ -9,6 +9,60 @@ using MediaBrowser.Model.Net;
namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
{ {
public interface IHdHomerunChannelCommands
{
IEnumerable<Tuple<string, string>> GetCommands();
}
public class LegacyHdHomerunChannelCommands : IHdHomerunChannelCommands
{
private string _channel;
private string _program;
public LegacyHdHomerunChannelCommands(string url)
{
// parse url for channel and program
var regExp = new Regex(@"\/ch(\d+)-?(\d*)");
var match = regExp.Match(url);
if (match.Success)
{
_channel = match.Groups[1].Value;
_program = match.Groups[2].Value;
}
}
public IEnumerable<Tuple<string, string>> GetCommands()
{
var commands = new List<Tuple<string, string>>();
if (!String.IsNullOrEmpty(_channel))
commands.Add(Tuple.Create("channel", _channel));
if (!String.IsNullOrEmpty(_program))
commands.Add(Tuple.Create("program", _program));
return commands;
}
}
public class HdHomerunChannelCommands : IHdHomerunChannelCommands
{
private string _channel;
public HdHomerunChannelCommands(string channel)
{
_channel = channel;
}
public IEnumerable<Tuple<string, string>> GetCommands()
{
var commands = new List<Tuple<string, string>>();
if (!String.IsNullOrEmpty(_channel))
commands.Add(Tuple.Create("vchannel", _channel));
return commands;
}
}
public class HdHomerunManager : IDisposable public class HdHomerunManager : IDisposable
{ {
public static int HdHomeRunPort = 65001; public static int HdHomeRunPort = 65001;
@ -57,15 +111,9 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
return string.Equals(returnVal, "none", StringComparison.OrdinalIgnoreCase); return string.Equals(returnVal, "none", StringComparison.OrdinalIgnoreCase);
} }
public async Task StartStreaming(IpAddressInfo remoteIp, IpAddressInfo localIp, int localPort, string url, int numTuners, CancellationToken cancellationToken) public async Task StartStreaming(IpAddressInfo remoteIp, IpAddressInfo localIp, int localPort, IHdHomerunChannelCommands commands, int numTuners, CancellationToken cancellationToken)
{ {
_remoteIp = remoteIp; _remoteIp = remoteIp;
// parse url for channel and program
string frequency, program;
if (!ParseUrl(url, out frequency, out program))
{
return;
}
using (var tcpClient = _socketFactory.CreateTcpSocket(_remoteIp, HdHomeRunPort)) using (var tcpClient = _socketFactory.CreateTcpSocket(_remoteIp, HdHomeRunPort))
{ {
@ -92,20 +140,11 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
if (!ParseReturnMessage(response.Buffer, response.ReceivedBytes, out returnVal)) if (!ParseReturnMessage(response.Buffer, response.ReceivedBytes, out returnVal))
continue; continue;
var channelMsg = CreateSetMessage(i, "channel", frequency, _lockkey.Value); var commandList = commands.GetCommands();
await tcpClient.SendAsync(channelMsg, channelMsg.Length, ipEndPoint, cancellationToken).ConfigureAwait(false); foreach(Tuple<string,string> command in commandList)
await tcpClient.ReceiveAsync(cancellationToken).ConfigureAwait(false);
// parse response to make sure it worked
if (!ParseReturnMessage(response.Buffer, response.ReceivedBytes, out returnVal))
{ {
await ReleaseLockkey(tcpClient).ConfigureAwait(false); var channelMsg = CreateSetMessage(i, command.Item1, command.Item2, _lockkey.Value);
continue; await tcpClient.SendAsync(channelMsg, channelMsg.Length, ipEndPoint, cancellationToken).ConfigureAwait(false);
}
if (program != String.Empty)
{
var programMsg = CreateSetMessage(i, "program", program, _lockkey.Value);
await tcpClient.SendAsync(programMsg, programMsg.Length, ipEndPoint, cancellationToken).ConfigureAwait(false);
await tcpClient.ReceiveAsync(cancellationToken).ConfigureAwait(false); await tcpClient.ReceiveAsync(cancellationToken).ConfigureAwait(false);
// parse response to make sure it worked // parse response to make sure it worked
if (!ParseReturnMessage(response.Buffer, response.ReceivedBytes, out returnVal)) if (!ParseReturnMessage(response.Buffer, response.ReceivedBytes, out returnVal))
@ -113,6 +152,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
await ReleaseLockkey(tcpClient).ConfigureAwait(false); await ReleaseLockkey(tcpClient).ConfigureAwait(false);
continue; continue;
} }
} }
var targetValue = String.Format("rtp://{0}:{1}", localIp, localPort); var targetValue = String.Format("rtp://{0}:{1}", localIp, localPort);
@ -154,22 +194,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
await tcpClient.ReceiveAsync(CancellationToken.None).ConfigureAwait(false); await tcpClient.ReceiveAsync(CancellationToken.None).ConfigureAwait(false);
} }
private static bool ParseUrl(string url, out string frequency, out string program)
{
frequency = String.Empty;
program = String.Empty;
var regExp = new Regex(@"\/ch(\d+)-?(\d*)");
var match = regExp.Match(url);
if (match.Success)
{
frequency = match.Groups[1].Value;
program = match.Groups[2].Value;
return true;
}
return false;
}
private static byte[] CreateGetMessage(int tuner, string name) private static byte[] CreateGetMessage(int tuner, string name)
{ {
var byteName = Encoding.UTF8.GetBytes(String.Format("/tuner{0}/{1}\0", tuner, name)); var byteName = Encoding.UTF8.GetBytes(String.Format("/tuner{0}/{1}\0", tuner, name));

View File

@ -29,11 +29,11 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
private readonly CancellationTokenSource _liveStreamCancellationTokenSource = new CancellationTokenSource(); private readonly CancellationTokenSource _liveStreamCancellationTokenSource = new CancellationTokenSource();
private readonly TaskCompletionSource<bool> _liveStreamTaskCompletionSource = new TaskCompletionSource<bool>(); private readonly TaskCompletionSource<bool> _liveStreamTaskCompletionSource = new TaskCompletionSource<bool>();
private readonly MulticastStream _multicastStream; private readonly MulticastStream _multicastStream;
private readonly string _channelUrl; private readonly IHdHomerunChannelCommands _channelCommands;
private readonly int _numTuners; private readonly int _numTuners;
private readonly INetworkManager _networkManager; private readonly INetworkManager _networkManager;
public HdHomerunUdpStream(MediaSourceInfo mediaSource, string originalStreamId, string channelUrl, int numTuners, IFileSystem fileSystem, IHttpClient httpClient, ILogger logger, IServerApplicationPaths appPaths, IServerApplicationHost appHost, ISocketFactory socketFactory, INetworkManager networkManager) public HdHomerunUdpStream(MediaSourceInfo mediaSource, string originalStreamId, IHdHomerunChannelCommands channelCommands, int numTuners, IFileSystem fileSystem, IHttpClient httpClient, ILogger logger, IServerApplicationPaths appPaths, IServerApplicationHost appHost, ISocketFactory socketFactory, INetworkManager networkManager)
: base(mediaSource) : base(mediaSource)
{ {
_fileSystem = fileSystem; _fileSystem = fileSystem;
@ -45,7 +45,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
_networkManager = networkManager; _networkManager = networkManager;
OriginalStreamId = originalStreamId; OriginalStreamId = originalStreamId;
_multicastStream = new MulticastStream(_logger); _multicastStream = new MulticastStream(_logger);
_channelUrl = channelUrl; _channelCommands = channelCommands;
_numTuners = numTuners; _numTuners = numTuners;
} }
@ -118,10 +118,10 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
try try
{ {
// send url to start streaming // send url to start streaming
await hdHomerunManager.StartStreaming(remoteAddress, localAddress, localPort, _channelUrl, _numTuners, cancellationToken).ConfigureAwait(false); await hdHomerunManager.StartStreaming(remoteAddress, localAddress, localPort, _channelCommands, _numTuners, cancellationToken).ConfigureAwait(false);
var response = await udpClient.ReceiveAsync(cancellationToken).ConfigureAwait(false); var response = await udpClient.ReceiveAsync(cancellationToken).ConfigureAwait(false);
_logger.Info("Opened HDHR UDP stream from {0}", _channelUrl); _logger.Info("Opened HDHR UDP stream from {0}", remoteAddress);
if (!cancellationToken.IsCancellationRequested) if (!cancellationToken.IsCancellationRequested)
{ {

View File

@ -16,7 +16,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
private const int BufferSize = 81920; private const int BufferSize = 81920;
private CancellationToken _cancellationToken; private CancellationToken _cancellationToken;
private readonly ILogger _logger; private readonly ILogger _logger;
private readonly ConcurrentQueue<byte[]> _sharedBuffer = new ConcurrentQueue<byte[]>();
public MulticastStream(ILogger logger) public MulticastStream(ILogger logger)
{ {
@ -38,14 +37,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
byte[] copy = new byte[bytesRead]; byte[] copy = new byte[bytesRead];
Buffer.BlockCopy(buffer, 0, copy, 0, bytesRead); Buffer.BlockCopy(buffer, 0, copy, 0, bytesRead);
_sharedBuffer.Enqueue(copy);
while (_sharedBuffer.Count > 10000)
{
byte[] bytes;
_sharedBuffer.TryDequeue(out bytes);
}
var allStreams = _outputStreams.ToList(); var allStreams = _outputStreams.ToList();
foreach (var stream in allStreams) foreach (var stream in allStreams)
{ {
@ -74,16 +65,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
OnFinished = OnFinished OnFinished = OnFinished
}; };
var list = new List<byte>();
foreach (var bytes in _sharedBuffer)
{
list.AddRange(bytes);
}
_logger.Info("QueueStream started with {0} initial bytes", list.Count);
result.Queue(list.ToArray());
_outputStreams.TryAdd(result.Id, result); _outputStreams.TryAdd(result.Id, result);
result.Start(_cancellationToken); result.Start(_cancellationToken);

View File

@ -170,11 +170,6 @@ namespace MediaBrowser.Providers.TV
/// <exception cref="System.ArgumentNullException">seriesId</exception> /// <exception cref="System.ArgumentNullException">seriesId</exception>
internal async Task DownloadSeriesZip(string seriesId, string idType, string seriesDataPath, long? lastTvDbUpdateTime, string preferredMetadataLanguage, CancellationToken cancellationToken) internal async Task DownloadSeriesZip(string seriesId, string idType, string seriesDataPath, long? lastTvDbUpdateTime, string preferredMetadataLanguage, CancellationToken cancellationToken)
{ {
if (string.IsNullOrWhiteSpace(seriesId))
{
throw new ArgumentNullException("seriesId");
}
try try
{ {
await DownloadSeriesZip(seriesId, idType, seriesDataPath, lastTvDbUpdateTime, preferredMetadataLanguage, preferredMetadataLanguage, cancellationToken).ConfigureAwait(false); await DownloadSeriesZip(seriesId, idType, seriesDataPath, lastTvDbUpdateTime, preferredMetadataLanguage, preferredMetadataLanguage, cancellationToken).ConfigureAwait(false);

View File

@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd"> <package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
<metadata> <metadata>
<id>MediaBrowser.Common</id> <id>MediaBrowser.Common</id>
<version>3.0.695</version> <version>3.0.696</version>
<title>Emby.Common</title> <title>Emby.Common</title>
<authors>Emby Team</authors> <authors>Emby Team</authors>
<owners>ebr,Luke,scottisafool</owners> <owners>ebr,Luke,scottisafool</owners>

View File

@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd"> <package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata> <metadata>
<id>MediaBrowser.Server.Core</id> <id>MediaBrowser.Server.Core</id>
<version>3.0.695</version> <version>3.0.696</version>
<title>Emby.Server.Core</title> <title>Emby.Server.Core</title>
<authors>Emby Team</authors> <authors>Emby Team</authors>
<owners>ebr,Luke,scottisafool</owners> <owners>ebr,Luke,scottisafool</owners>
@ -12,7 +12,7 @@
<description>Contains core components required to build plugins for Emby Server.</description> <description>Contains core components required to build plugins for Emby Server.</description>
<copyright>Copyright © Emby 2013</copyright> <copyright>Copyright © Emby 2013</copyright>
<dependencies> <dependencies>
<dependency id="MediaBrowser.Common" version="3.0.695" /> <dependency id="MediaBrowser.Common" version="3.0.696" />
</dependencies> </dependencies>
</metadata> </metadata>
<files> <files>

View File

@ -1,3 +1,3 @@
using System.Reflection; using System.Reflection;
[assembly: AssemblyVersion("3.2.5.6")] [assembly: AssemblyVersion("3.2.5.7")]