diff options
| author | Luke Pulverenti <luke.pulverenti@gmail.com> | 2016-11-03 19:35:19 -0400 |
|---|---|---|
| committer | Luke Pulverenti <luke.pulverenti@gmail.com> | 2016-11-03 19:35:19 -0400 |
| commit | d5ea8ca3ad378fc7e0a18ad314e1dfce07003ab6 (patch) | |
| tree | 4742a665e3455389a9795ff8b6c292263b3876e8 /Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs | |
| parent | d0babf322dad6624ee15622d11db52e58db5197f (diff) | |
move classes to portable
Diffstat (limited to 'Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs')
| -rw-r--r-- | Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs | 219 |
1 files changed, 219 insertions, 0 deletions
diff --git a/Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs b/Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs new file mode 100644 index 000000000..e0a35686e --- /dev/null +++ b/Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs @@ -0,0 +1,219 @@ +using MediaBrowser.Controller; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.LiveTv; +using MediaBrowser.Controller.MediaEncoding; +using MediaBrowser.Model.Dto; +using MediaBrowser.Model.Logging; +using MediaBrowser.Model.MediaInfo; +using MediaBrowser.Model.Serialization; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using MediaBrowser.Model.Dlna; + +namespace Emby.Server.Implementations.LiveTv +{ + public class LiveTvMediaSourceProvider : IMediaSourceProvider + { + private readonly ILiveTvManager _liveTvManager; + private readonly IJsonSerializer _jsonSerializer; + private readonly ILogger _logger; + private readonly IMediaSourceManager _mediaSourceManager; + private readonly IMediaEncoder _mediaEncoder; + private readonly IServerApplicationHost _appHost; + + public LiveTvMediaSourceProvider(ILiveTvManager liveTvManager, IJsonSerializer jsonSerializer, ILogManager logManager, IMediaSourceManager mediaSourceManager, IMediaEncoder mediaEncoder, IServerApplicationHost appHost) + { + _liveTvManager = liveTvManager; + _jsonSerializer = jsonSerializer; + _mediaSourceManager = mediaSourceManager; + _mediaEncoder = mediaEncoder; + _appHost = appHost; + _logger = logManager.GetLogger(GetType().Name); + } + + public Task<IEnumerable<MediaSourceInfo>> GetMediaSources(IHasMediaSources item, CancellationToken cancellationToken) + { + var baseItem = (BaseItem)item; + + if (baseItem.SourceType == SourceType.LiveTV) + { + if (string.IsNullOrWhiteSpace(baseItem.Path)) + { + return GetMediaSourcesInternal(item, cancellationToken); + } + } + + return Task.FromResult<IEnumerable<MediaSourceInfo>>(new List<MediaSourceInfo>()); + } + + // Do not use a pipe here because Roku http requests to the server will fail, without any explicit error message. + private const char StreamIdDelimeter = '_'; + private const string StreamIdDelimeterString = "_"; + + private async Task<IEnumerable<MediaSourceInfo>> GetMediaSourcesInternal(IHasMediaSources item, CancellationToken cancellationToken) + { + IEnumerable<MediaSourceInfo> sources; + + var forceRequireOpening = false; + + try + { + if (item is ILiveTvRecording) + { + sources = await _liveTvManager.GetRecordingMediaSources(item, cancellationToken) + .ConfigureAwait(false); + } + else + { + sources = await _liveTvManager.GetChannelMediaSources(item, cancellationToken) + .ConfigureAwait(false); + } + } + catch (NotImplementedException) + { + var hasMediaSources = (IHasMediaSources)item; + + sources = _mediaSourceManager.GetStaticMediaSources(hasMediaSources, false) + .ToList(); + + forceRequireOpening = true; + } + + var list = sources.ToList(); + var serverUrl = await _appHost.GetLocalApiUrl().ConfigureAwait(false); + + foreach (var source in list) + { + source.Type = MediaSourceType.Default; + source.BufferMs = source.BufferMs ?? 1500; + + if (source.RequiresOpening || forceRequireOpening) + { + source.RequiresOpening = true; + } + + if (source.RequiresOpening) + { + var openKeys = new List<string>(); + openKeys.Add(item.GetType().Name); + openKeys.Add(item.Id.ToString("N")); + openKeys.Add(source.Id ?? string.Empty); + source.OpenToken = string.Join(StreamIdDelimeterString, openKeys.ToArray()); + } + + // Dummy this up so that direct play checks can still run + if (string.IsNullOrEmpty(source.Path) && source.Protocol == MediaProtocol.Http) + { + source.Path = serverUrl; + } + } + + _logger.Debug("MediaSources: {0}", _jsonSerializer.SerializeToString(list)); + + return list; + } + + public async Task<Tuple<MediaSourceInfo, IDirectStreamProvider>> OpenMediaSource(string openToken, CancellationToken cancellationToken) + { + MediaSourceInfo stream = null; + const bool isAudio = false; + + var keys = openToken.Split(new[] { StreamIdDelimeter }, 3); + var mediaSourceId = keys.Length >= 3 ? keys[2] : null; + IDirectStreamProvider directStreamProvider = null; + + if (string.Equals(keys[0], typeof(LiveTvChannel).Name, StringComparison.OrdinalIgnoreCase)) + { + var info = await _liveTvManager.GetChannelStream(keys[1], mediaSourceId, cancellationToken).ConfigureAwait(false); + stream = info.Item1; + directStreamProvider = info.Item2; + } + else + { + stream = await _liveTvManager.GetRecordingStream(keys[1], cancellationToken).ConfigureAwait(false); + } + + try + { + if (!stream.SupportsProbing || stream.MediaStreams.Any(i => i.Index != -1)) + { + await AddMediaInfo(stream, isAudio, cancellationToken).ConfigureAwait(false); + } + else + { + await new LiveStreamHelper(_mediaEncoder, _logger).AddMediaInfoWithProbe(stream, isAudio, cancellationToken).ConfigureAwait(false); + } + } + catch (Exception ex) + { + _logger.ErrorException("Error probing live tv stream", ex); + } + + return new Tuple<MediaSourceInfo, IDirectStreamProvider>(stream, directStreamProvider); + } + + private async Task AddMediaInfo(MediaSourceInfo mediaSource, bool isAudio, CancellationToken cancellationToken) + { + mediaSource.DefaultSubtitleStreamIndex = null; + + // Null this out so that it will be treated like a live stream + mediaSource.RunTimeTicks = null; + + var audioStream = mediaSource.MediaStreams.FirstOrDefault(i => i.Type == MediaBrowser.Model.Entities.MediaStreamType.Audio); + + if (audioStream == null || audioStream.Index == -1) + { + mediaSource.DefaultAudioStreamIndex = null; + } + else + { + mediaSource.DefaultAudioStreamIndex = audioStream.Index; + } + + var videoStream = mediaSource.MediaStreams.FirstOrDefault(i => i.Type == MediaBrowser.Model.Entities.MediaStreamType.Video); + if (videoStream != null) + { + if (!videoStream.BitRate.HasValue) + { + var width = videoStream.Width ?? 1920; + + if (width >= 1900) + { + videoStream.BitRate = 8000000; + } + + else if (width >= 1260) + { + videoStream.BitRate = 3000000; + } + + else if (width >= 700) + { + videoStream.BitRate = 1000000; + } + } + } + + // Try to estimate this + if (!mediaSource.Bitrate.HasValue) + { + var total = mediaSource.MediaStreams.Select(i => i.BitRate ?? 0).Sum(); + + if (total > 0) + { + mediaSource.Bitrate = total; + } + } + } + + public Task CloseMediaSource(string liveStreamId) + { + return _liveTvManager.CloseLiveStream(liveStreamId); + } + } +} |
