commit
80c5ef35a1
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user