update tuner pooling

This commit is contained in:
Luke Pulverenti 2015-08-19 15:25:18 -04:00
parent 2c050d05f8
commit 8c32aefb53
5 changed files with 146 additions and 49 deletions

View file

@ -33,20 +33,18 @@ namespace MediaBrowser.Controller.LiveTv
/// <summary>
/// Gets the channel stream.
/// </summary>
/// <param name="info">The information.</param>
/// <param name="channelId">The channel identifier.</param>
/// <param name="streamId">The stream identifier.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task&lt;MediaSourceInfo&gt;.</returns>
Task<MediaSourceInfo> GetChannelStream(TunerHostInfo info, string channelId, string streamId, CancellationToken cancellationToken);
Task<MediaSourceInfo> GetChannelStream(string channelId, string streamId, CancellationToken cancellationToken);
/// <summary>
/// Gets the channel stream media sources.
/// </summary>
/// <param name="info">The information.</param>
/// <param name="channelId">The channel identifier.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task&lt;List&lt;MediaSourceInfo&gt;&gt;.</returns>
Task<List<MediaSourceInfo>> GetChannelStreamMediaSources(TunerHostInfo info, string channelId, CancellationToken cancellationToken);
Task<List<MediaSourceInfo>> GetChannelStreamMediaSources(string channelId, CancellationToken cancellationToken);
/// <summary>
/// Validates the specified information.
/// </summary>

View file

@ -1,6 +1,5 @@
using MediaBrowser.Common;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.IO;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Drawing;
@ -13,7 +12,6 @@ using MediaBrowser.Model.Serialization;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading;
@ -161,20 +159,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
return GetChannelsAsync(false, cancellationToken);
}
private List<Tuple<ITunerHost, TunerHostInfo>> GetTunerHosts()
{
return GetConfiguration().TunerHosts
.Where(i => i.IsEnabled)
.Select(i =>
{
var provider = _liveTvManager.TunerHosts.FirstOrDefault(l => string.Equals(l.Type, i.Type, StringComparison.OrdinalIgnoreCase));
return provider == null ? null : new Tuple<ITunerHost, TunerHostInfo>(provider, i);
})
.Where(i => i != null)
.ToList();
}
public Task CancelSeriesTimerAsync(string timerId, CancellationToken cancellationToken)
{
var timers = _timerProvider.GetAll().Where(i => string.Equals(i.SeriesTimerId, timerId, StringComparison.OrdinalIgnoreCase));
@ -409,22 +393,12 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
{
_logger.Info("Streaming Channel " + channelId);
foreach (var hostInstance in GetTunerHosts())
foreach (var hostInstance in _liveTvManager.TunerHosts)
{
if (!string.IsNullOrWhiteSpace(streamId))
{
var originalStreamId = string.Join("-", streamId.Split('-').Skip(1).ToArray());
if (!string.Equals(hostInstance.Item2.Id, originalStreamId, StringComparison.OrdinalIgnoreCase))
{
continue;
}
}
MediaSourceInfo mediaSourceInfo = null;
try
{
mediaSourceInfo = await hostInstance.Item1.GetChannelStream(hostInstance.Item2, channelId, streamId, cancellationToken).ConfigureAwait(false);
mediaSourceInfo = await hostInstance.GetChannelStream(channelId, streamId, cancellationToken).ConfigureAwait(false);
}
catch (Exception e)
{
@ -443,16 +417,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
public async Task<List<MediaSourceInfo>> GetChannelStreamMediaSources(string channelId, CancellationToken cancellationToken)
{
foreach (var hostInstance in GetTunerHosts())
foreach (var hostInstance in _liveTvManager.TunerHosts)
{
try
{
var sources = await hostInstance.Item1.GetChannelStreamMediaSources(hostInstance.Item2, channelId, cancellationToken).ConfigureAwait(false);
foreach (var source in sources)
{
source.Id = hostInstance.Item2.Id + "-" + source.Id;
}
var sources = await hostInstance.GetChannelStreamMediaSources(channelId, cancellationToken).ConfigureAwait(false);
if (sources.Count > 0)
{

View file

@ -1,5 +1,6 @@
using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.LiveTv;
using MediaBrowser.Model.Logging;
using System;
@ -83,11 +84,115 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
return list;
}
protected abstract Task<List<MediaSourceInfo>> GetChannelStreamMediaSources(TunerHostInfo tuner, string channelId, CancellationToken cancellationToken);
public async Task<List<MediaSourceInfo>> GetChannelStreamMediaSources(string channelId, CancellationToken cancellationToken)
{
if (IsValidChannelId(channelId))
{
var hosts = GetTunerHosts();
var hostsWithChannel = new List<TunerHostInfo>();
foreach (var host in hosts)
{
var channels = await GetChannels(host, true, cancellationToken).ConfigureAwait(false);
if (channels.Any(i => string.Equals(i.Id, channelId, StringComparison.OrdinalIgnoreCase)))
{
hostsWithChannel.Add(host);
}
}
foreach (var host in hostsWithChannel)
{
// Check to make sure the tuner is available
// If there's only one tuner, don't bother with the check and just let the tuner be the one to throw an error
if (hostsWithChannel.Count > 1 && !await IsAvailable(host, channelId, cancellationToken).ConfigureAwait(false))
{
Logger.Error("Tuner is not currently available");
continue;
}
var mediaSources = await GetChannelStreamMediaSources(host, channelId, cancellationToken).ConfigureAwait(false);
// Prefix the id with the host Id so that we can easily find it
foreach (var mediaSource in mediaSources)
{
mediaSource.Id = host.Id + mediaSource.Id;
}
return mediaSources;
}
}
return new List<MediaSourceInfo>();
}
protected abstract Task<MediaSourceInfo> GetChannelStream(TunerHostInfo tuner, string channelId, string streamId, CancellationToken cancellationToken);
public async Task<MediaSourceInfo> GetChannelStream(string channelId, string streamId, CancellationToken cancellationToken)
{
if (IsValidChannelId(channelId))
{
var hosts = GetTunerHosts();
var hostsWithChannel = new List<TunerHostInfo>();
foreach (var host in hosts)
{
if (string.IsNullOrWhiteSpace(streamId))
{
var channels = await GetChannels(host, true, cancellationToken).ConfigureAwait(false);
if (channels.Any(i => string.Equals(i.Id, channelId, StringComparison.OrdinalIgnoreCase)))
{
hostsWithChannel.Add(host);
}
}
else if (streamId.StartsWith(host.Id, StringComparison.OrdinalIgnoreCase))
{
hostsWithChannel = new List<TunerHostInfo> { host };
streamId = streamId.Substring(host.Id.Length);
break;
}
}
foreach (var host in hostsWithChannel)
{
// Check to make sure the tuner is available
// If there's only one tuner, don't bother with the check and just let the tuner be the one to throw an error
// If a streamId is specified then availibility has already been checked in GetChannelStreamMediaSources
if (string.IsNullOrWhiteSpace(streamId) && hostsWithChannel.Count > 1)
{
if (!await IsAvailable(host, channelId, cancellationToken).ConfigureAwait(false))
{
Logger.Error("Tuner is not currently available");
continue;
}
}
var stream = await GetChannelStream(host, channelId, streamId, cancellationToken).ConfigureAwait(false);
if (stream != null)
{
return null;
}
}
}
throw new LiveTvConflictException();
}
protected abstract Task<bool> IsAvailable(TunerHostInfo tuner, string channelId, CancellationToken cancellationToken);
protected abstract bool IsValidChannelId(string channelId);
protected LiveTvOptions GetConfiguration()
{
return Config.GetConfiguration<LiveTvOptions>("livetv");
}
private class ChannelCache
{
public DateTime Date;

View file

@ -329,7 +329,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun
return mediaSource;
}
public async Task<List<MediaSourceInfo>> GetChannelStreamMediaSources(TunerHostInfo info, string channelId, CancellationToken cancellationToken)
protected override async Task<List<MediaSourceInfo>> GetChannelStreamMediaSources(TunerHostInfo info, string channelId, CancellationToken cancellationToken)
{
var list = new List<MediaSourceInfo>();
@ -364,7 +364,12 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun
return list;
}
public async Task<MediaSourceInfo> GetChannelStream(TunerHostInfo info, string channelId, string streamId, CancellationToken cancellationToken)
protected override bool IsValidChannelId(string channelId)
{
return channelId.StartsWith(ChannelIdPrefix, StringComparison.OrdinalIgnoreCase);
}
protected override async Task<MediaSourceInfo> GetChannelStream(TunerHostInfo info, string channelId, string streamId, CancellationToken cancellationToken)
{
if (!channelId.StartsWith(ChannelIdPrefix, StringComparison.OrdinalIgnoreCase))
{
@ -379,5 +384,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun
{
await GetChannels(info, false, CancellationToken.None).ConfigureAwait(false);
}
protected override async Task<bool> IsAvailable(TunerHostInfo tuner, string channelId, CancellationToken cancellationToken)
{
// TODO
return true;
}
}
}

View file

@ -17,7 +17,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
{
public class M3UTunerHost : BaseTunerHost, ITunerHost
{
public M3UTunerHost(IConfigurationManager config, ILogger logger) : base(config, logger)
public M3UTunerHost(IConfigurationManager config, ILogger logger)
: base(config, logger)
{
}
@ -31,6 +32,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
get { return "M3U Tuner"; }
}
private const string ChannelIdPrefix = "m3u_";
protected override async Task<IEnumerable<ChannelInfo>> GetChannelsInternal(TunerHostInfo info, CancellationToken cancellationToken)
{
var url = info.Url;
@ -88,7 +91,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
switch (list[0])
{
case "tvg-id":
channels.Last().Id = urlHash + list[1];
channels.Last().Id = ChannelIdPrefix + urlHash + list[1];
channels.Last().Number = list[1];
break;
case "tvg-name":
@ -117,19 +120,20 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
Url = i.Url
})
.ToList();
return Task.FromResult(list);
}
public async Task<MediaSourceInfo> GetChannelStream(TunerHostInfo info, string channelId, string streamId, CancellationToken cancellationToken)
protected override async Task<MediaSourceInfo> GetChannelStream(TunerHostInfo info, string channelId, string streamId, CancellationToken cancellationToken)
{
var urlHash = info.Url.GetMD5().ToString("N");
if (!channelId.StartsWith(urlHash, StringComparison.OrdinalIgnoreCase))
var prefix = ChannelIdPrefix + urlHash;
if (!channelId.StartsWith(prefix, StringComparison.OrdinalIgnoreCase))
{
return null;
}
channelId = channelId.Substring(urlHash.Length);
channelId = channelId.Substring(prefix.Length);
var channels = await GetChannels(info, true, cancellationToken).ConfigureAwait(false);
var m3uchannels = channels.Cast<M3UChannel>();
@ -196,9 +200,19 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
}
}
public Task<List<MediaSourceInfo>> GetChannelStreamMediaSources(TunerHostInfo info, string channelId, CancellationToken cancellationToken)
protected override bool IsValidChannelId(string channelId)
{
return channelId.StartsWith(ChannelIdPrefix, StringComparison.OrdinalIgnoreCase);
}
protected override Task<List<MediaSourceInfo>> GetChannelStreamMediaSources(TunerHostInfo info, string channelId, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
protected override Task<bool> IsAvailable(TunerHostInfo tuner, string channelId, CancellationToken cancellationToken)
{
return Task.FromResult(true);
}
}
}