diff --git a/MediaBrowser.Controller/LiveTv/ITunerHost.cs b/MediaBrowser.Controller/LiveTv/ITunerHost.cs
index 0d1852fe2e..bedbcffe32 100644
--- a/MediaBrowser.Controller/LiveTv/ITunerHost.cs
+++ b/MediaBrowser.Controller/LiveTv/ITunerHost.cs
@@ -33,20 +33,18 @@ namespace MediaBrowser.Controller.LiveTv
///
/// Gets the channel stream.
///
- /// The information.
/// The channel identifier.
/// The stream identifier.
/// The cancellation token.
/// Task<MediaSourceInfo>.
- Task GetChannelStream(TunerHostInfo info, string channelId, string streamId, CancellationToken cancellationToken);
+ Task GetChannelStream(string channelId, string streamId, CancellationToken cancellationToken);
///
/// Gets the channel stream media sources.
///
- /// The information.
/// The channel identifier.
/// The cancellation token.
/// Task<List<MediaSourceInfo>>.
- Task> GetChannelStreamMediaSources(TunerHostInfo info, string channelId, CancellationToken cancellationToken);
+ Task> GetChannelStreamMediaSources(string channelId, CancellationToken cancellationToken);
///
/// Validates the specified information.
///
diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
index eb23fab80e..7fbff31b23 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
@@ -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> 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(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> 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)
{
diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs
index b3c8bce262..fb6fa9084b 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs
@@ -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> GetChannelStreamMediaSources(TunerHostInfo tuner, string channelId, CancellationToken cancellationToken);
+
+ public async Task> GetChannelStreamMediaSources(string channelId, CancellationToken cancellationToken)
+ {
+ if (IsValidChannelId(channelId))
+ {
+ var hosts = GetTunerHosts();
+
+ var hostsWithChannel = new List();
+
+ 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();
+ }
+
+ protected abstract Task GetChannelStream(TunerHostInfo tuner, string channelId, string streamId, CancellationToken cancellationToken);
+
+ public async Task GetChannelStream(string channelId, string streamId, CancellationToken cancellationToken)
+ {
+ if (IsValidChannelId(channelId))
+ {
+ var hosts = GetTunerHosts();
+
+ var hostsWithChannel = new List();
+
+ 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 { 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 IsAvailable(TunerHostInfo tuner, string channelId, CancellationToken cancellationToken);
+
+ protected abstract bool IsValidChannelId(string channelId);
+
protected LiveTvOptions GetConfiguration()
{
return Config.GetConfiguration("livetv");
}
-
+
private class ChannelCache
{
public DateTime Date;
diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
index a07ccd3a48..307a61588b 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
@@ -329,7 +329,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun
return mediaSource;
}
- public async Task> GetChannelStreamMediaSources(TunerHostInfo info, string channelId, CancellationToken cancellationToken)
+ protected override async Task> GetChannelStreamMediaSources(TunerHostInfo info, string channelId, CancellationToken cancellationToken)
{
var list = new List();
@@ -364,7 +364,12 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun
return list;
}
- public async Task 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 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 IsAvailable(TunerHostInfo tuner, string channelId, CancellationToken cancellationToken)
+ {
+ // TODO
+ return true;
+ }
}
}
diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs
index 0dc170cfdd..bd0feb5737 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs
@@ -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> 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 GetChannelStream(TunerHostInfo info, string channelId, string streamId, CancellationToken cancellationToken)
+ protected override async Task 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();
@@ -196,9 +200,19 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
}
}
- public Task> GetChannelStreamMediaSources(TunerHostInfo info, string channelId, CancellationToken cancellationToken)
+ protected override bool IsValidChannelId(string channelId)
+ {
+ return channelId.StartsWith(ChannelIdPrefix, StringComparison.OrdinalIgnoreCase);
+ }
+
+ protected override Task> GetChannelStreamMediaSources(TunerHostInfo info, string channelId, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
+
+ protected override Task IsAvailable(TunerHostInfo tuner, string channelId, CancellationToken cancellationToken)
+ {
+ return Task.FromResult(true);
+ }
}
}