Merge pull request #1240 from MediaBrowser/master

update tuner pooling
This commit is contained in:
Luke 2015-10-30 12:43:17 -04:00
commit 80c5ef35a1
3 changed files with 81 additions and 27 deletions

View File

@ -117,8 +117,23 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
foreach (var host in hostsWithChannel) foreach (var host in hostsWithChannel)
{ {
var resourcePool = GetLock(host.Url);
Logger.Debug("GetChannelStreamMediaSources - Waiting on tuner resource pool");
await resourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
Logger.Debug("GetChannelStreamMediaSources - Unlocked resource pool");
try try
{ {
// 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); var mediaSources = await GetChannelStreamMediaSources(host, channelId, cancellationToken).ConfigureAwait(false);
// Prefix the id with the host Id so that we can easily find it // Prefix the id with the host Id so that we can easily find it
@ -133,6 +148,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
{ {
Logger.Error("Error opening tuner", ex); Logger.Error("Error opening tuner", ex);
} }
finally
{
resourcePool.Release();
}
} }
} }
@ -170,17 +189,35 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
foreach (var host in hostsWithChannel) foreach (var host in hostsWithChannel)
{ {
var resourcePool = GetLock(host.Url);
Logger.Debug("GetChannelStream - Waiting on tuner resource pool");
await resourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
Logger.Debug("GetChannelStream - Unlocked resource pool");
try try
{ {
var stream = await GetChannelStream(host, channelId, streamId, cancellationToken).ConfigureAwait(false); // Check to make sure the tuner is available
var resourcePool = GetLock(host.Url); // 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");
resourcePool.Release();
continue;
}
}
await AddMediaInfo(stream, false, resourcePool, cancellationToken).ConfigureAwait(false); var stream = await GetChannelStream(host, channelId, streamId, cancellationToken).ConfigureAwait(false);
//await AddMediaInfo(stream, false, resourcePool, cancellationToken).ConfigureAwait(false);
return new Tuple<MediaSourceInfo, SemaphoreSlim>(stream, resourcePool); return new Tuple<MediaSourceInfo, SemaphoreSlim>(stream, resourcePool);
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.Error("Error opening tuner", ex); Logger.Error("Error opening tuner", ex);
resourcePool.Release();
} }
} }
} }
@ -188,6 +225,21 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
throw new LiveTvConflictException(); throw new LiveTvConflictException();
} }
protected async Task<bool> IsAvailable(TunerHostInfo tuner, string channelId, CancellationToken cancellationToken)
{
try
{
return await IsAvailableInternal(tuner, channelId, cancellationToken).ConfigureAwait(false);
}
catch (Exception ex)
{
Logger.ErrorException("Error checking tuner availability", ex);
return false;
}
}
protected abstract Task<bool> IsAvailableInternal(TunerHostInfo tuner, string channelId, CancellationToken cancellationToken);
/// <summary> /// <summary>
/// The _semaphoreLocks /// The _semaphoreLocks
/// </summary> /// </summary>
@ -202,25 +254,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
return _semaphoreLocks.GetOrAdd(url, key => new SemaphoreSlim(1, 1)); return _semaphoreLocks.GetOrAdd(url, key => new SemaphoreSlim(1, 1));
} }
private async Task AddMediaInfo(MediaSourceInfo mediaSource, bool isAudio, SemaphoreSlim resourcePool, CancellationToken cancellationToken)
{
await resourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
try
{
await AddMediaInfoInternal(mediaSource, isAudio, cancellationToken).ConfigureAwait(false);
// Leave the resource locked. it will be released upstream
}
catch (Exception)
{
// Release the resource if there's some kind of failure.
resourcePool.Release();
throw;
}
}
private async Task AddMediaInfoInternal(MediaSourceInfo mediaSource, bool isAudio, CancellationToken cancellationToken) private async Task AddMediaInfoInternal(MediaSourceInfo mediaSource, bool isAudio, CancellationToken cancellationToken)
{ {
var originalRuntime = mediaSource.RunTimeTicks; var originalRuntime = mediaSource.RunTimeTicks;

View File

@ -15,6 +15,7 @@ using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Dlna;
namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun
@ -23,7 +24,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun
{ {
private readonly IHttpClient _httpClient; private readonly IHttpClient _httpClient;
public HdHomerunHost(IConfigurationManager config, ILogger logger, IJsonSerializer jsonSerializer, IMediaEncoder mediaEncoder, IHttpClient httpClient) : base(config, logger, jsonSerializer, mediaEncoder) public HdHomerunHost(IConfigurationManager config, ILogger logger, IJsonSerializer jsonSerializer, IMediaEncoder mediaEncoder, IHttpClient httpClient)
: base(config, logger, jsonSerializer, mediaEncoder)
{ {
_httpClient = httpClient; _httpClient = httpClient;
} }
@ -232,7 +234,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun
int? width = null; int? width = null;
int? height = null; int? height = null;
bool isInterlaced = true; bool isInterlaced = true;
var videoCodec = "mpeg2video"; var videoCodec = !string.IsNullOrWhiteSpace(GetEncodingOptions().HardwareVideoDecoder) ? null : "mpeg2video";
int? videoBitrate = null; int? videoBitrate = null;
if (string.Equals(profile, "mobile", StringComparison.OrdinalIgnoreCase)) if (string.Equals(profile, "mobile", StringComparison.OrdinalIgnoreCase))
@ -326,8 +329,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun
BitRate = 128000 BitRate = 128000
} }
}, },
RequiresOpening = true, RequiresOpening = false,
RequiresClosing = true, RequiresClosing = false,
BufferMs = 1000, BufferMs = 1000,
Container = "ts", Container = "ts",
Id = profile, Id = profile,
@ -339,6 +342,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun
return mediaSource; return mediaSource;
} }
protected EncodingOptions GetEncodingOptions()
{
return Config.GetConfiguration<EncodingOptions>("encoding");
}
protected override 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>(); var list = new List<MediaSourceInfo>();
@ -404,5 +412,12 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun
await GetChannels(info, false, CancellationToken.None).ConfigureAwait(false); await GetChannels(info, false, CancellationToken.None).ConfigureAwait(false);
} }
} }
protected override async Task<bool> IsAvailableInternal(TunerHostInfo tuner, string channelId, CancellationToken cancellationToken)
{
var info = await GetTunerInfos(tuner, cancellationToken).ConfigureAwait(false);
return info.Any(i => i.Status == LiveTvTunerStatus.Available);
}
} }
} }

View File

@ -25,7 +25,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
private readonly IFileSystem _fileSystem; private readonly IFileSystem _fileSystem;
private readonly IHttpClient _httpClient; private readonly IHttpClient _httpClient;
public M3UTunerHost(IConfigurationManager config, ILogger logger, IJsonSerializer jsonSerializer, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IHttpClient httpClient) : base(config, logger, jsonSerializer, mediaEncoder) public M3UTunerHost(IConfigurationManager config, ILogger logger, IJsonSerializer jsonSerializer, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IHttpClient httpClient)
: base(config, logger, jsonSerializer, mediaEncoder)
{ {
_fileSystem = fileSystem; _fileSystem = fileSystem;
_httpClient = httpClient; _httpClient = httpClient;
@ -209,5 +210,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
} }
return new List<MediaSourceInfo> { }; return new List<MediaSourceInfo> { };
} }
protected override Task<bool> IsAvailableInternal(TunerHostInfo tuner, string channelId, CancellationToken cancellationToken)
{
return Task.FromResult(true);
}
} }
} }