diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index b469966f5..9992c71ec 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -1052,10 +1052,27 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV { _liveStreamsSemaphore.Release(); } - } - private async Task> GetChannelStreamInternal(string channelId, string streamId, CancellationToken cancellationToken) + public async Task> GetLiveStreams(TunerHostInfo host, CancellationToken cancellationToken) + { + //await _liveStreamsSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); + + //try + //{ + var hostId = host.Id; + + return _liveStreams + .Where(i => string.Equals(i.TunerHostId, hostId, StringComparison.OrdinalIgnoreCase)) + .ToList(); + //} + //finally + //{ + // _liveStreamsSemaphore.Release(); + //} + } + + private async Task> GetChannelStreamInternal(string channelId, string streamId, CancellationToken cancellationToken) { _logger.Info("Streaming Channel " + channelId); @@ -1072,7 +1089,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV _logger.Info("Live stream {0} consumer count is now {1}", streamId, result.ConsumerCount); - return new Tuple(result, openedMediaSource, result.TunerHost); + return new Tuple(result, openedMediaSource); } foreach (var hostInstance in _liveTvManager.TunerHosts) @@ -1086,13 +1103,12 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV result.SharedStreamIds.Add(openedMediaSource.Id); _liveStreams.Add(result); - result.TunerHost = hostInstance; result.OriginalStreamId = streamId; _logger.Info("Returning mediasource streamId {0}, mediaSource.Id {1}, mediaSource.LiveStreamId {2}", streamId, openedMediaSource.Id, openedMediaSource.LiveStreamId); - return new Tuple(result, openedMediaSource, hostInstance); + return new Tuple(result, openedMediaSource); } catch (FileNotFoundException) { diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs index 08eab9a35..74758e906 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs @@ -598,7 +598,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun if (hdhomerunChannel != null && hdhomerunChannel.IsLegacyTuner) { - return new HdHomerunUdpStream(mediaSource, streamId, new LegacyHdHomerunChannelCommands(hdhomerunChannel.Path), modelInfo.TunerCount, FileSystem, _httpClient, Logger, Config.ApplicationPaths, _appHost, _socketFactory, _networkManager, _environment); + return new HdHomerunUdpStream(mediaSource, info, streamId, new LegacyHdHomerunChannelCommands(hdhomerunChannel.Path), modelInfo.TunerCount, FileSystem, _httpClient, Logger, Config.ApplicationPaths, _appHost, _socketFactory, _networkManager, _environment); } // The UDP method is not working reliably on OSX, and on BSD it hasn't been tested yet @@ -618,10 +618,10 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun } mediaSource.Path = httpUrl; - return new SharedHttpStream(mediaSource, streamId, FileSystem, _httpClient, Logger, Config.ApplicationPaths, _appHost, _environment); + return new SharedHttpStream(mediaSource, info, streamId, FileSystem, _httpClient, Logger, Config.ApplicationPaths, _appHost, _environment); } - return new HdHomerunUdpStream(mediaSource, streamId, new HdHomerunChannelCommands(hdhomerunChannel.Number, profile), modelInfo.TunerCount, FileSystem, _httpClient, Logger, Config.ApplicationPaths, _appHost, _socketFactory, _networkManager, _environment); + return new HdHomerunUdpStream(mediaSource, info, streamId, new HdHomerunChannelCommands(hdhomerunChannel.Number, profile), modelInfo.TunerCount, FileSystem, _httpClient, Logger, Config.ApplicationPaths, _appHost, _socketFactory, _networkManager, _environment); } public async Task Validate(TunerHostInfo info) diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs index a32930080..6e93055be 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs @@ -11,6 +11,7 @@ using MediaBrowser.Model.Logging; using MediaBrowser.Model.MediaInfo; using MediaBrowser.Model.Net; using MediaBrowser.Model.System; +using MediaBrowser.Model.LiveTv; namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun { @@ -23,8 +24,8 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun private readonly int _numTuners; private readonly 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, IEnvironmentInfo environment) - : base(mediaSource, environment, fileSystem, logger, appPaths) + public HdHomerunUdpStream(MediaSourceInfo mediaSource, TunerHostInfo tunerHostInfo, string originalStreamId, IHdHomerunChannelCommands channelCommands, int numTuners, IFileSystem fileSystem, IHttpClient httpClient, ILogger logger, IServerApplicationPaths appPaths, IServerApplicationHost appHost, ISocketFactory socketFactory, INetworkManager networkManager, IEnvironmentInfo environment) + : base(mediaSource, tunerHostInfo, environment, fileSystem, logger, appPaths) { _appHost = appHost; _socketFactory = socketFactory; diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs index bec92716b..f6758e94e 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs @@ -10,6 +10,7 @@ using MediaBrowser.Model.Dto; using MediaBrowser.Model.IO; using MediaBrowser.Model.Logging; using MediaBrowser.Model.System; +using MediaBrowser.Model.LiveTv; namespace Emby.Server.Implementations.LiveTv.TunerHosts { @@ -21,7 +22,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts { get { return SharedStreamIds.Count; } } - public ITunerHost TunerHost { get; set; } + public string OriginalStreamId { get; set; } public bool EnableStreamSharing { get; set; } public string UniqueId { get; private set; } @@ -35,7 +36,9 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts protected readonly ILogger Logger; protected readonly CancellationTokenSource LiveStreamCancellationTokenSource = new CancellationTokenSource(); - public LiveStream(MediaSourceInfo mediaSource, IEnvironmentInfo environment, IFileSystem fileSystem, ILogger logger, IServerApplicationPaths appPaths) + public string TunerHostId { get; private set; } + + public LiveStream(MediaSourceInfo mediaSource, TunerHostInfo tuner, IEnvironmentInfo environment, IFileSystem fileSystem, ILogger logger, IServerApplicationPaths appPaths) { OriginalMediaSource = mediaSource; Environment = environment; @@ -45,6 +48,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts EnableStreamSharing = true; SharedStreamIds = new List(); UniqueId = Guid.NewGuid().ToString("N"); + TunerHostId = tuner.Id; AppPaths = appPaths; diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs index e41fb7fbe..c96d1f359 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs @@ -77,16 +77,28 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts protected override async Task GetChannelStream(TunerHostInfo info, string channelId, string streamId, CancellationToken cancellationToken) { + var tunerCount = info.TunerCount; + + if (tunerCount > 0) + { + var liveStreams = await EmbyTV.EmbyTV.Current.GetLiveStreams(info, cancellationToken).ConfigureAwait(false); + + if (liveStreams.Count >= info.TunerCount) + { + throw new LiveTvConflictException(); + } + } + var sources = await GetChannelStreamMediaSources(info, channelId, cancellationToken).ConfigureAwait(false); var mediaSource = sources.First(); if (mediaSource.Protocol == MediaProtocol.Http && !mediaSource.RequiresLooping) { - return new SharedHttpStream(mediaSource, streamId, FileSystem, _httpClient, Logger, Config.ApplicationPaths, _appHost, _environment); + return new SharedHttpStream(mediaSource, info, streamId, FileSystem, _httpClient, Logger, Config.ApplicationPaths, _appHost, _environment); } - return new LiveStream(mediaSource, _environment, FileSystem, Logger, Config.ApplicationPaths); + return new LiveStream(mediaSource, info, _environment, FileSystem, Logger, Config.ApplicationPaths); } public async Task Validate(TunerHostInfo info) diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs index a33b0945b..a3bfff7c1 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs @@ -14,6 +14,7 @@ using MediaBrowser.Model.MediaInfo; using MediaBrowser.Model.System; using System.Globalization; using MediaBrowser.Controller.IO; +using MediaBrowser.Model.LiveTv; namespace Emby.Server.Implementations.LiveTv.TunerHosts { @@ -22,8 +23,8 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts private readonly IHttpClient _httpClient; private readonly IServerApplicationHost _appHost; - public SharedHttpStream(MediaSourceInfo mediaSource, string originalStreamId, IFileSystem fileSystem, IHttpClient httpClient, ILogger logger, IServerApplicationPaths appPaths, IServerApplicationHost appHost, IEnvironmentInfo environment) - : base(mediaSource, environment, fileSystem, logger, appPaths) + public SharedHttpStream(MediaSourceInfo mediaSource, TunerHostInfo tunerHostInfo, string originalStreamId, IFileSystem fileSystem, IHttpClient httpClient, ILogger logger, IServerApplicationPaths appPaths, IServerApplicationHost appHost, IEnvironmentInfo environment) + : base(mediaSource, tunerHostInfo, environment, fileSystem, logger, appPaths) { _httpClient = httpClient; _appHost = appHost; diff --git a/MediaBrowser.Api/VideosService.cs b/MediaBrowser.Api/VideosService.cs index 3f840dbfa..3f4bb46f4 100644 --- a/MediaBrowser.Api/VideosService.cs +++ b/MediaBrowser.Api/VideosService.cs @@ -114,12 +114,14 @@ namespace MediaBrowser.Api foreach (var link in video.GetLinkedAlternateVersions()) { - link.PrimaryVersionId = null; + link.SetPrimaryVersionId(null); + link.LinkedAlternateVersions = Video.EmptyLinkedChildArray; link.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None); } video.LinkedAlternateVersions = Video.EmptyLinkedChildArray; + video.SetPrimaryVersionId(null); video.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None); } @@ -174,7 +176,7 @@ namespace MediaBrowser.Api foreach (var item in items.Where(i => i.Id != primaryVersion.Id)) { - item.PrimaryVersionId = primaryVersion.Id.ToString("N"); + item.SetPrimaryVersionId(primaryVersion.Id.ToString("N")); item.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None); diff --git a/MediaBrowser.Controller/Entities/Video.cs b/MediaBrowser.Controller/Entities/Video.cs index 52f1dd051..dca1cfd01 100644 --- a/MediaBrowser.Controller/Entities/Video.cs +++ b/MediaBrowser.Controller/Entities/Video.cs @@ -84,6 +84,20 @@ namespace MediaBrowser.Controller.Entities } } + public void SetPrimaryVersionId(string id) + { + if (string.IsNullOrWhiteSpace(id)) + { + PrimaryVersionId = null; + } + else + { + PrimaryVersionId = id; + } + + PresentationUniqueKey = CreatePresentationUniqueKey(); + } + public override string CreatePresentationUniqueKey() { if (!string.IsNullOrWhiteSpace(PrimaryVersionId)) @@ -667,8 +681,6 @@ namespace MediaBrowser.Controller.Entities throw new ArgumentNullException("media"); } - var mediaStreams = MediaSourceManager.GetMediaStreams(media.Id); - var locationType = media.LocationType; var info = new MediaSourceInfo @@ -676,8 +688,8 @@ namespace MediaBrowser.Controller.Entities Id = media.Id.ToString("N"), IsoType = media.IsoType, Protocol = locationType == LocationType.Remote ? MediaProtocol.Http : MediaProtocol.File, - MediaStreams = mediaStreams, - Name = GetMediaSourceName(media, mediaStreams), + MediaStreams = MediaSourceManager.GetMediaStreams(media.Id), + Name = GetMediaSourceName(media), Path = enablePathSubstitution ? GetMappedPath(media, media.Path, locationType) : media.Path, RunTimeTicks = media.RunTimeTicks, Video3DFormat = media.Video3DFormat, @@ -740,12 +752,20 @@ namespace MediaBrowser.Controller.Entities return info; } - private static string GetMediaSourceName(Video video, List mediaStreams) + private static string GetMediaSourceName(Video video) { var terms = new List(); - var videoStream = mediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Video); - var audioStream = mediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Audio); + var locationType = video.LocationType; + var path = video.Path; + if ((locationType == LocationType.FileSystem || locationType == LocationType.Offline) && !string.IsNullOrWhiteSpace(path)) + { + terms.Add(System.IO.Path.GetFileName(path)); + } + else + { + terms.Add(video.Name); + } if (video.Video3DFormat.HasValue) { @@ -779,50 +799,6 @@ namespace MediaBrowser.Controller.Entities } } - if (videoStream != null) - { - if (videoStream.Width.HasValue) - { - if (videoStream.Width.Value >= 3800) - { - terms.Add("4K"); - } - else if (videoStream.Width.Value >= 1900) - { - terms.Add("1080P"); - } - else if (videoStream.Width.Value >= 1270) - { - terms.Add("720P"); - } - else if (videoStream.Width.Value >= 700) - { - terms.Add("480P"); - } - else - { - terms.Add("SD"); - } - } - } - - if (videoStream != null && !string.IsNullOrWhiteSpace(videoStream.Codec)) - { - terms.Add(videoStream.Codec.ToUpper()); - } - - if (audioStream != null) - { - var audioCodec = string.Equals(audioStream.Codec, "dca", StringComparison.OrdinalIgnoreCase) - ? audioStream.Profile - : audioStream.Codec; - - if (!string.IsNullOrEmpty(audioCodec)) - { - terms.Add(audioCodec.ToUpper()); - } - } - return string.Join("/", terms.ToArray(terms.Count)); } diff --git a/MediaBrowser.Controller/LiveTv/ITunerHost.cs b/MediaBrowser.Controller/LiveTv/ITunerHost.cs index 523eec24a..242011db0 100644 --- a/MediaBrowser.Controller/LiveTv/ITunerHost.cs +++ b/MediaBrowser.Controller/LiveTv/ITunerHost.cs @@ -63,8 +63,8 @@ namespace MediaBrowser.Controller.LiveTv void Close(); int ConsumerCount { get; } string OriginalStreamId { get; set; } + string TunerHostId { get; } bool EnableStreamSharing { get; set; } - ITunerHost TunerHost { get; set; } MediaSourceInfo OpenedMediaSource { get; set; } string UniqueId { get; } List SharedStreamIds { get; } diff --git a/MediaBrowser.Model/Dlna/StreamBuilder.cs b/MediaBrowser.Model/Dlna/StreamBuilder.cs index cf4cd9925..b80a2baa9 100644 --- a/MediaBrowser.Model/Dlna/StreamBuilder.cs +++ b/MediaBrowser.Model/Dlna/StreamBuilder.cs @@ -1341,13 +1341,11 @@ namespace MediaBrowser.Model.Dlna return false; } - if (!item.Bitrate.HasValue) - { - _logger.Info("Cannot " + playMethod + " due to unknown content bitrate"); - return false; - } + // If we don't know the bitrate, then force a transcode if requested max bitrate is under 40 mbps + var itemBitrate = item.Bitrate ?? + 40000000; - if (item.Bitrate.Value > maxBitrate.Value) + if (itemBitrate > maxBitrate.Value) { _logger.Info("Bitrate exceeds " + playMethod + " limit: media bitrate: {0}, max bitrate: {1}", item.Bitrate.Value.ToString(CultureInfo.InvariantCulture), maxBitrate.Value.ToString(CultureInfo.InvariantCulture)); return false; diff --git a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs index f177233f9..75edf05aa 100644 --- a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs +++ b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs @@ -47,6 +47,7 @@ namespace MediaBrowser.Model.LiveTv public bool EnableStreamLooping { get; set; } public bool EnableNewHdhrChannelIds { get; set; } public string Source { get; set; } + public int TunerCount { get; set; } public TunerHostInfo() { diff --git a/SharedVersion.cs b/SharedVersion.cs index 6e59ea964..070f8b175 100644 --- a/SharedVersion.cs +++ b/SharedVersion.cs @@ -1,3 +1,3 @@ using System.Reflection; -[assembly: AssemblyVersion("3.2.36.11")] +[assembly: AssemblyVersion("3.2.36.12")]