Luke Pulverenti пре 11 година
родитељ
комит
3ccecd3ca3
39 измењених фајлова са 285 додато и 1119 уклоњено
  1. 41 10
      MediaBrowser.Api/Playback/BaseStreamingService.cs
  2. 2 2
      MediaBrowser.Api/Playback/Hls/BaseHlsService.cs
  3. 2 1
      MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
  4. 2 1
      MediaBrowser.Api/Playback/Hls/VideoHlsService.cs
  5. 2 2
      MediaBrowser.Api/Playback/Progressive/AudioService.cs
  6. 3 3
      MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs
  7. 3 2
      MediaBrowser.Api/Playback/Progressive/VideoService.cs
  8. 5 2
      MediaBrowser.Api/Playback/StreamState.cs
  9. 6 1
      MediaBrowser.Api/SessionsService.cs
  10. 24 2
      MediaBrowser.Controller/Channels/ChannelAudioItem.cs
  11. 8 1
      MediaBrowser.Controller/Channels/ChannelCategoryItem.cs
  12. 2 0
      MediaBrowser.Controller/Channels/ChannelItemInfo.cs
  13. 3 0
      MediaBrowser.Controller/Channels/ChannelMediaInfo.cs
  14. 21 0
      MediaBrowser.Controller/Channels/ChannelVideoItem.cs
  15. 11 0
      MediaBrowser.Controller/Channels/IChannel.cs
  16. 1 1
      MediaBrowser.Controller/Channels/IChannelItem.cs
  17. 8 0
      MediaBrowser.Controller/Channels/IChannelManager.cs
  18. 5 1
      MediaBrowser.Controller/Channels/IChannelMediaItem.cs
  19. 3 1
      MediaBrowser.Controller/Entities/Audio/Audio.cs
  20. 3 1
      MediaBrowser.Controller/Session/ISessionController.cs
  21. 2 1
      MediaBrowser.Dlna/PlayTo/PlayToController.cs
  22. 0 91
      MediaBrowser.MediaEncoding/Encoder/AudioEncoder.cs
  23. 0 114
      MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs
  24. 0 168
      MediaBrowser.MediaEncoding/Encoder/FFMpegProcess.cs
  25. 0 235
      MediaBrowser.MediaEncoding/Encoder/ImageEncoder.cs
  26. 0 95
      MediaBrowser.MediaEncoding/Encoder/InternalEncodingTask.cs
  27. 0 311
      MediaBrowser.MediaEncoding/Encoder/InternalEncodingTaskFactory.cs
  28. 1 1
      MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
  29. 0 5
      MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj
  30. 2 0
      MediaBrowser.Model/Session/SessionCapabilities.cs
  31. 37 8
      MediaBrowser.Server.Implementations/Channels/ChannelManager.cs
  32. 47 38
      MediaBrowser.Server.Implementations/Session/HttpSessionController.cs
  33. 28 4
      MediaBrowser.Server.Implementations/Session/SessionManager.cs
  34. 3 5
      MediaBrowser.Server.Implementations/Session/SessionWebSocketListener.cs
  35. 4 6
      MediaBrowser.Server.Implementations/Session/WebSocketController.cs
  36. 1 1
      MediaBrowser.ServerApplication/ApplicationHost.cs
  37. 2 2
      Nuget/MediaBrowser.Common.Internal.nuspec
  38. 1 1
      Nuget/MediaBrowser.Common.nuspec
  39. 2 2
      Nuget/MediaBrowser.Server.Core.nuspec

+ 41 - 10
MediaBrowser.Api/Playback/BaseStreamingService.cs

@@ -1,5 +1,6 @@
 using MediaBrowser.Common.Extensions;
 using MediaBrowser.Common.Extensions;
 using MediaBrowser.Common.IO;
 using MediaBrowser.Common.IO;
+using MediaBrowser.Controller.Channels;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Dlna;
 using MediaBrowser.Controller.Dlna;
 using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Dto;
@@ -25,7 +26,6 @@ using System.Linq;
 using System.Text;
 using System.Text;
 using System.Threading;
 using System.Threading;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
-using MediaBrowser.Model.MediaInfo;
 
 
 namespace MediaBrowser.Api.Playback
 namespace MediaBrowser.Api.Playback
 {
 {
@@ -71,6 +71,7 @@ namespace MediaBrowser.Api.Playback
         protected IItemRepository ItemRepository { get; private set; }
         protected IItemRepository ItemRepository { get; private set; }
         protected ILiveTvManager LiveTvManager { get; private set; }
         protected ILiveTvManager LiveTvManager { get; private set; }
         protected IDlnaManager DlnaManager { get; private set; }
         protected IDlnaManager DlnaManager { get; private set; }
+        protected IChannelManager ChannelManager { get; private set; }
 
 
         /// <summary>
         /// <summary>
         /// Initializes a new instance of the <see cref="BaseStreamingService" /> class.
         /// Initializes a new instance of the <see cref="BaseStreamingService" /> class.
@@ -83,8 +84,9 @@ namespace MediaBrowser.Api.Playback
         /// <param name="dtoService">The dto service.</param>
         /// <param name="dtoService">The dto service.</param>
         /// <param name="fileSystem">The file system.</param>
         /// <param name="fileSystem">The file system.</param>
         /// <param name="itemRepository">The item repository.</param>
         /// <param name="itemRepository">The item repository.</param>
-        protected BaseStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager, IDlnaManager dlnaManager)
+        protected BaseStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager, IDlnaManager dlnaManager, IChannelManager channelManager)
         {
         {
+            ChannelManager = channelManager;
             DlnaManager = dlnaManager;
             DlnaManager = dlnaManager;
             EncodingManager = encodingManager;
             EncodingManager = encodingManager;
             LiveTvManager = liveTvManager;
             LiveTvManager = liveTvManager;
@@ -169,13 +171,28 @@ namespace MediaBrowser.Api.Playback
         /// <returns>System.String.</returns>
         /// <returns>System.String.</returns>
         protected virtual string GetMapArgs(StreamState state)
         protected virtual string GetMapArgs(StreamState state)
         {
         {
-            var args = string.Empty;
+            // If we don't have known media info
+            // If input is video, use -sn to drop subtitles
+            // Otherwise just return empty
+            if (state.VideoStream == null && state.AudioStream == null)
+            {
+                return state.IsInputVideo ? "-sn" : string.Empty;
+            }
 
 
-            if (!state.HasMediaStreams)
+            // We have media info, but we don't know the stream indexes
+            if (state.VideoStream != null && state.VideoStream.Index == -1)
+            {
+                return "-sn";
+            }
+
+            // We have media info, but we don't know the stream indexes
+            if (state.AudioStream != null && state.AudioStream.Index == -1)
             {
             {
                 return state.IsInputVideo ? "-sn" : string.Empty;
                 return state.IsInputVideo ? "-sn" : string.Empty;
             }
             }
 
 
+            var args = string.Empty;
+
             if (state.VideoStream != null)
             if (state.VideoStream != null)
             {
             {
                 args += string.Format("-map 0:{0}", state.VideoStream.Index);
                 args += string.Format("-map 0:{0}", state.VideoStream.Index);
@@ -1329,13 +1346,14 @@ namespace MediaBrowser.Api.Playback
                 throw new ArgumentException(string.Format("{0} is not allowed to play media.", user.Name));
                 throw new ArgumentException(string.Format("{0} is not allowed to play media.", user.Name));
             }
             }
 
 
+            List<MediaStream> mediaStreams = null;
+
             if (item is ILiveTvRecording)
             if (item is ILiveTvRecording)
             {
             {
                 var recording = await LiveTvManager.GetInternalRecording(request.Id, cancellationToken).ConfigureAwait(false);
                 var recording = await LiveTvManager.GetInternalRecording(request.Id, cancellationToken).ConfigureAwait(false);
 
 
                 state.VideoType = VideoType.VideoFile;
                 state.VideoType = VideoType.VideoFile;
                 state.IsInputVideo = string.Equals(recording.MediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase);
                 state.IsInputVideo = string.Equals(recording.MediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase);
-                state.PlayableStreamFileNames = new List<string>();
 
 
                 var path = recording.RecordingInfo.Path;
                 var path = recording.RecordingInfo.Path;
                 var mediaUrl = recording.RecordingInfo.Url;
                 var mediaUrl = recording.RecordingInfo.Url;
@@ -1345,6 +1363,7 @@ namespace MediaBrowser.Api.Playback
                     var streamInfo = await LiveTvManager.GetRecordingStream(request.Id, cancellationToken).ConfigureAwait(false);
                     var streamInfo = await LiveTvManager.GetRecordingStream(request.Id, cancellationToken).ConfigureAwait(false);
 
 
                     state.LiveTvStreamId = streamInfo.Id;
                     state.LiveTvStreamId = streamInfo.Id;
+                    mediaStreams = streamInfo.MediaStreams;
 
 
                     path = streamInfo.Path;
                     path = streamInfo.Path;
                     mediaUrl = streamInfo.Url;
                     mediaUrl = streamInfo.Url;
@@ -1381,11 +1400,11 @@ namespace MediaBrowser.Api.Playback
 
 
                 state.VideoType = VideoType.VideoFile;
                 state.VideoType = VideoType.VideoFile;
                 state.IsInputVideo = string.Equals(channel.MediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase);
                 state.IsInputVideo = string.Equals(channel.MediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase);
-                state.PlayableStreamFileNames = new List<string>();
 
 
                 var streamInfo = await LiveTvManager.GetChannelStream(request.Id, cancellationToken).ConfigureAwait(false);
                 var streamInfo = await LiveTvManager.GetChannelStream(request.Id, cancellationToken).ConfigureAwait(false);
 
 
                 state.LiveTvStreamId = streamInfo.Id;
                 state.LiveTvStreamId = streamInfo.Id;
+                mediaStreams = streamInfo.MediaStreams;
 
 
                 if (!string.IsNullOrEmpty(streamInfo.Path))
                 if (!string.IsNullOrEmpty(streamInfo.Path))
                 {
                 {
@@ -1406,6 +1425,16 @@ namespace MediaBrowser.Api.Playback
                 state.InputVideoSync = "-1";
                 state.InputVideoSync = "-1";
                 state.InputAudioSync = "1";
                 state.InputAudioSync = "1";
             }
             }
+            else if (item is IChannelMediaItem)
+            {
+                var channelMediaSources = await ChannelManager.GetChannelItemMediaSources(request.Id, CancellationToken.None).ConfigureAwait(false);
+
+                var source = channelMediaSources.First();
+                state.IsInputVideo = string.Equals(item.MediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase);
+                state.IsRemote = source.IsRemote;
+                state.MediaPath = source.Path;
+                state.RunTimeTicks = item.RunTimeTicks;
+            }
             else
             else
             {
             {
                 state.MediaPath = item.Path;
                 state.MediaPath = item.Path;
@@ -1424,7 +1453,11 @@ namespace MediaBrowser.Api.Playback
                         : video.PlayableStreamFileNames.ToList();
                         : video.PlayableStreamFileNames.ToList();
 
 
                     state.DeInterlace = string.Equals(video.Container, "wtv", StringComparison.OrdinalIgnoreCase);
                     state.DeInterlace = string.Equals(video.Container, "wtv", StringComparison.OrdinalIgnoreCase);
-                    state.InputTimestamp = video.Timestamp ?? TransportStreamTimestamp.None;
+
+                    if (video.Timestamp.HasValue)
+                    {
+                        state.InputTimestamp = video.Timestamp.Value;
+                    }
 
 
                     state.InputContainer = video.Container;
                     state.InputContainer = video.Container;
                 }
                 }
@@ -1440,7 +1473,7 @@ namespace MediaBrowser.Api.Playback
 
 
             var videoRequest = request as VideoStreamRequest;
             var videoRequest = request as VideoStreamRequest;
 
 
-            var mediaStreams = ItemRepository.GetMediaStreams(new MediaStreamQuery
+            mediaStreams = mediaStreams ?? ItemRepository.GetMediaStreams(new MediaStreamQuery
             {
             {
                 ItemId = item.Id
                 ItemId = item.Id
 
 
@@ -1469,8 +1502,6 @@ namespace MediaBrowser.Api.Playback
                 state.AudioStream = GetMediaStream(mediaStreams, null, MediaStreamType.Audio, true);
                 state.AudioStream = GetMediaStream(mediaStreams, null, MediaStreamType.Audio, true);
             }
             }
 
 
-            state.HasMediaStreams = mediaStreams.Count > 0;
-
             state.SegmentLength = state.ReadInputAtNativeFramerate ? 5 : 10;
             state.SegmentLength = state.ReadInputAtNativeFramerate ? 5 : 10;
             state.HlsListSize = state.ReadInputAtNativeFramerate ? 100 : 1440;
             state.HlsListSize = state.ReadInputAtNativeFramerate ? 100 : 1440;
 
 

+ 2 - 2
MediaBrowser.Api/Playback/Hls/BaseHlsService.cs

@@ -1,6 +1,7 @@
 using MediaBrowser.Common.Extensions;
 using MediaBrowser.Common.Extensions;
 using MediaBrowser.Common.IO;
 using MediaBrowser.Common.IO;
 using MediaBrowser.Common.Net;
 using MediaBrowser.Common.Net;
+using MediaBrowser.Controller.Channels;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Dlna;
 using MediaBrowser.Controller.Dlna;
 using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Dto;
@@ -24,8 +25,7 @@ namespace MediaBrowser.Api.Playback.Hls
     /// </summary>
     /// </summary>
     public abstract class BaseHlsService : BaseStreamingService
     public abstract class BaseHlsService : BaseStreamingService
     {
     {
-        protected BaseHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager, IDlnaManager dlnaManager)
-            : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository, liveTvManager, encodingManager, dlnaManager)
+        protected BaseHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager, IDlnaManager dlnaManager, IChannelManager channelManager) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository, liveTvManager, encodingManager, dlnaManager, channelManager)
         {
         {
         }
         }
 
 

+ 2 - 1
MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs

@@ -1,4 +1,5 @@
 using MediaBrowser.Common.IO;
 using MediaBrowser.Common.IO;
+using MediaBrowser.Controller.Channels;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Dlna;
 using MediaBrowser.Controller.Dlna;
 using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Dto;
@@ -59,7 +60,7 @@ namespace MediaBrowser.Api.Playback.Hls
 
 
     public class DynamicHlsService : BaseHlsService
     public class DynamicHlsService : BaseHlsService
     {
     {
-        public DynamicHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager, IDlnaManager dlnaManager) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository, liveTvManager, encodingManager, dlnaManager)
+        public DynamicHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager, IDlnaManager dlnaManager, IChannelManager channelManager) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository, liveTvManager, encodingManager, dlnaManager, channelManager)
         {
         {
         }
         }
 
 

+ 2 - 1
MediaBrowser.Api/Playback/Hls/VideoHlsService.cs

@@ -1,4 +1,5 @@
 using MediaBrowser.Common.IO;
 using MediaBrowser.Common.IO;
+using MediaBrowser.Controller.Channels;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Dlna;
 using MediaBrowser.Controller.Dlna;
 using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Dto;
@@ -53,7 +54,7 @@ namespace MediaBrowser.Api.Playback.Hls
     /// </summary>
     /// </summary>
     public class VideoHlsService : BaseHlsService
     public class VideoHlsService : BaseHlsService
     {
     {
-        public VideoHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager, IDlnaManager dlnaManager) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository, liveTvManager, encodingManager, dlnaManager)
+        public VideoHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager, IDlnaManager dlnaManager, IChannelManager channelManager) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository, liveTvManager, encodingManager, dlnaManager, channelManager)
         {
         {
         }
         }
 
 

+ 2 - 2
MediaBrowser.Api/Playback/Progressive/AudioService.cs

@@ -1,5 +1,6 @@
 using MediaBrowser.Common.IO;
 using MediaBrowser.Common.IO;
 using MediaBrowser.Common.Net;
 using MediaBrowser.Common.Net;
+using MediaBrowser.Controller.Channels;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Dlna;
 using MediaBrowser.Controller.Dlna;
 using MediaBrowser.Controller.Drawing;
 using MediaBrowser.Controller.Drawing;
@@ -43,8 +44,7 @@ namespace MediaBrowser.Api.Playback.Progressive
     /// </summary>
     /// </summary>
     public class AudioService : BaseProgressiveStreamingService
     public class AudioService : BaseProgressiveStreamingService
     {
     {
-        public AudioService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager, IDlnaManager dlnaManager, IHttpClient httpClient, IImageProcessor imageProcessor)
-            : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository, liveTvManager, encodingManager, dlnaManager, httpClient, imageProcessor)
+        public AudioService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager, IDlnaManager dlnaManager, IChannelManager channelManager, IImageProcessor imageProcessor, IHttpClient httpClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository, liveTvManager, encodingManager, dlnaManager, channelManager, imageProcessor, httpClient)
         {
         {
         }
         }
 
 

+ 3 - 3
MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs

@@ -1,5 +1,6 @@
 using MediaBrowser.Common.IO;
 using MediaBrowser.Common.IO;
 using MediaBrowser.Common.Net;
 using MediaBrowser.Common.Net;
+using MediaBrowser.Controller.Channels;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Dlna;
 using MediaBrowser.Controller.Dlna;
 using MediaBrowser.Controller.Drawing;
 using MediaBrowser.Controller.Drawing;
@@ -26,11 +27,10 @@ namespace MediaBrowser.Api.Playback.Progressive
         protected readonly IImageProcessor ImageProcessor;
         protected readonly IImageProcessor ImageProcessor;
         protected readonly IHttpClient HttpClient;
         protected readonly IHttpClient HttpClient;
 
 
-        protected BaseProgressiveStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager, IDlnaManager dlnaManager, IHttpClient httpClient, IImageProcessor imageProcessor)
-            : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository, liveTvManager, encodingManager, dlnaManager)
+        protected BaseProgressiveStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager, IDlnaManager dlnaManager, IChannelManager channelManager, IImageProcessor imageProcessor, IHttpClient httpClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository, liveTvManager, encodingManager, dlnaManager, channelManager)
         {
         {
-            HttpClient = httpClient;
             ImageProcessor = imageProcessor;
             ImageProcessor = imageProcessor;
+            HttpClient = httpClient;
         }
         }
 
 
         /// <summary>
         /// <summary>

+ 3 - 2
MediaBrowser.Api/Playback/Progressive/VideoService.cs

@@ -1,5 +1,6 @@
 using MediaBrowser.Common.IO;
 using MediaBrowser.Common.IO;
 using MediaBrowser.Common.Net;
 using MediaBrowser.Common.Net;
+using MediaBrowser.Controller.Channels;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Dlna;
 using MediaBrowser.Controller.Dlna;
 using MediaBrowser.Controller.Drawing;
 using MediaBrowser.Controller.Drawing;
@@ -59,7 +60,7 @@ namespace MediaBrowser.Api.Playback.Progressive
     /// </summary>
     /// </summary>
     public class VideoService : BaseProgressiveStreamingService
     public class VideoService : BaseProgressiveStreamingService
     {
     {
-        public VideoService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager, IDlnaManager dlnaManager, IHttpClient httpClient, IImageProcessor imageProcessor) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository, liveTvManager, encodingManager, dlnaManager, httpClient, imageProcessor)
+        public VideoService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, ILiveTvManager liveTvManager, IEncodingManager encodingManager, IDlnaManager dlnaManager, IChannelManager channelManager, IImageProcessor imageProcessor, IHttpClient httpClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository, liveTvManager, encodingManager, dlnaManager, channelManager, imageProcessor, httpClient)
         {
         {
         }
         }
 
 
@@ -183,7 +184,7 @@ namespace MediaBrowser.Api.Playback.Progressive
         private string GetAudioArguments(StreamState state)
         private string GetAudioArguments(StreamState state)
         {
         {
             // If the video doesn't have an audio stream, return a default.
             // If the video doesn't have an audio stream, return a default.
-            if (state.AudioStream == null && state.HasMediaStreams)
+            if (state.AudioStream == null && state.VideoStream != null)
             {
             {
                 return string.Empty;
                 return string.Empty;
             }
             }

+ 5 - 2
MediaBrowser.Api/Playback/StreamState.cs

@@ -28,6 +28,11 @@ namespace MediaBrowser.Api.Playback
             get { return Request as VideoStreamRequest; }
             get { return Request as VideoStreamRequest; }
         }
         }
 
 
+        public StreamState()
+        {
+            PlayableStreamFileNames = new List<string>();
+        }
+
         /// <summary>
         /// <summary>
         /// Gets or sets the log file stream.
         /// Gets or sets the log file stream.
         /// </summary>
         /// </summary>
@@ -57,8 +62,6 @@ namespace MediaBrowser.Api.Playback
 
 
         public List<string> PlayableStreamFileNames { get; set; }
         public List<string> PlayableStreamFileNames { get; set; }
 
 
-        public bool HasMediaStreams { get; set; }
-
         public string LiveTvStreamId { get; set; }
         public string LiveTvStreamId { get; set; }
 
 
         public int SegmentLength = 10;
         public int SegmentLength = 10;

+ 6 - 1
MediaBrowser.Api/SessionsService.cs

@@ -218,6 +218,9 @@ namespace MediaBrowser.Api
         [ApiMember(Name = "SupportedCommands", Description = "A list of supported remote control commands, comma delimited", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
         [ApiMember(Name = "SupportedCommands", Description = "A list of supported remote control commands, comma delimited", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
         public string SupportedCommands { get; set; }
         public string SupportedCommands { get; set; }
 
 
+        [ApiMember(Name = "MessageCallbackUrl", Description = "A url to post messages to, including remote control commands.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
+        public string MessageCallbackUrl { get; set; }
+
         [ApiMember(Name = "SupportsMediaControl", Description = "Determines whether media can be played remotely.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "POST")]
         [ApiMember(Name = "SupportsMediaControl", Description = "Determines whether media can be played remotely.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "POST")]
         public bool SupportsMediaControl { get; set; }
         public bool SupportsMediaControl { get; set; }
     }
     }
@@ -414,7 +417,9 @@ namespace MediaBrowser.Api
 
 
                 SupportedCommands = request.SupportedCommands.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList(),
                 SupportedCommands = request.SupportedCommands.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList(),
 
 
-                SupportsMediaControl = request.SupportsMediaControl
+                SupportsMediaControl = request.SupportsMediaControl,
+
+                MessageCallbackUrl = request.MessageCallbackUrl
             });
             });
         }
         }
 
 

+ 24 - 2
MediaBrowser.Controller/Channels/ChannelAudioItem.cs

@@ -1,6 +1,8 @@
-using System.Linq;
-using MediaBrowser.Controller.Entities.Audio;
+using MediaBrowser.Controller.Entities.Audio;
 using MediaBrowser.Model.Configuration;
 using MediaBrowser.Model.Configuration;
+using MediaBrowser.Model.Entities;
+using System.Collections.Generic;
+using System.Linq;
 
 
 namespace MediaBrowser.Controller.Channels
 namespace MediaBrowser.Controller.Channels
 {
 {
@@ -18,6 +20,8 @@ namespace MediaBrowser.Controller.Channels
 
 
         public string OriginalImageUrl { get; set; }
         public string OriginalImageUrl { get; set; }
 
 
+        public List<ChannelMediaInfo> ChannelMediaSources { get; set; }
+        
         protected override bool GetBlockUnratedValue(UserConfiguration config)
         protected override bool GetBlockUnratedValue(UserConfiguration config)
         {
         {
             return config.BlockUnratedItems.Contains(UnratedItem.ChannelContent);
             return config.BlockUnratedItems.Contains(UnratedItem.ChannelContent);
@@ -30,5 +34,23 @@ namespace MediaBrowser.Controller.Channels
                 return false;
                 return false;
             }
             }
         }
         }
+
+        public ChannelAudioItem()
+        {
+            ChannelMediaSources = new List<ChannelMediaInfo>();
+        }
+
+        public override LocationType LocationType
+        {
+            get
+            {
+                if (string.IsNullOrEmpty(Path))
+                {
+                    return LocationType.Remote;
+                }
+                
+                return base.LocationType;
+            }
+        }
     }
     }
 }
 }

+ 8 - 1
MediaBrowser.Controller/Channels/ChannelCategoryItem.cs

@@ -1,5 +1,6 @@
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Model.Configuration;
 using MediaBrowser.Model.Configuration;
+using System.Collections.Generic;
 
 
 namespace MediaBrowser.Controller.Channels
 namespace MediaBrowser.Controller.Channels
 {
 {
@@ -8,10 +9,11 @@ namespace MediaBrowser.Controller.Channels
         public string ExternalId { get; set; }
         public string ExternalId { get; set; }
 
 
         public string ChannelId { get; set; }
         public string ChannelId { get; set; }
-        
+
         public ChannelItemType ChannelItemType { get; set; }
         public ChannelItemType ChannelItemType { get; set; }
 
 
         public string OriginalImageUrl { get; set; }
         public string OriginalImageUrl { get; set; }
+        public List<string> Tags { get; set; }
 
 
         protected override bool GetBlockUnratedValue(UserConfiguration config)
         protected override bool GetBlockUnratedValue(UserConfiguration config)
         {
         {
@@ -26,5 +28,10 @@ namespace MediaBrowser.Controller.Channels
                 return false;
                 return false;
             }
             }
         }
         }
+
+        public ChannelCategoryItem()
+        {
+            Tags = new List<string>();
+        }
     }
     }
 }
 }

+ 2 - 0
MediaBrowser.Controller/Channels/ChannelItemInfo.cs

@@ -19,6 +19,7 @@ namespace MediaBrowser.Controller.Channels
 
 
         public List<string> Genres { get; set; }
         public List<string> Genres { get; set; }
         public List<string> Studios { get; set; }
         public List<string> Studios { get; set; }
+        public List<string> Tags { get; set; }
 
 
         public List<PersonInfo> People { get; set; }
         public List<PersonInfo> People { get; set; }
         
         
@@ -49,6 +50,7 @@ namespace MediaBrowser.Controller.Channels
             Genres = new List<string>();
             Genres = new List<string>();
             Studios = new List<string>();
             Studios = new List<string>();
             People = new List<PersonInfo>();
             People = new List<PersonInfo>();
+            Tags = new List<string>();
             ProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
             ProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
         }
         }
     }
     }

+ 3 - 0
MediaBrowser.Controller/Channels/ChannelMediaInfo.cs

@@ -18,9 +18,12 @@ namespace MediaBrowser.Controller.Channels
         public int? Height { get; set; }
         public int? Height { get; set; }
         public int? AudioChannels { get; set; }
         public int? AudioChannels { get; set; }
 
 
+        public bool IsRemote { get; set; }
+
         public ChannelMediaInfo()
         public ChannelMediaInfo()
         {
         {
             RequiredHttpHeaders = new Dictionary<string, string>();
             RequiredHttpHeaders = new Dictionary<string, string>();
+            IsRemote = true;
         }
         }
     }
     }
 }
 }

+ 21 - 0
MediaBrowser.Controller/Channels/ChannelVideoItem.cs

@@ -1,6 +1,7 @@
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Model.Configuration;
 using MediaBrowser.Model.Configuration;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Entities;
+using System.Collections.Generic;
 using System.Globalization;
 using System.Globalization;
 using System.Linq;
 using System.Linq;
 
 
@@ -20,6 +21,8 @@ namespace MediaBrowser.Controller.Channels
 
 
         public string OriginalImageUrl { get; set; }
         public string OriginalImageUrl { get; set; }
 
 
+        public List<ChannelMediaInfo> ChannelMediaSources { get; set; }
+        
         public override string GetUserDataKey()
         public override string GetUserDataKey()
         {
         {
             if (ContentType == ChannelMediaContentType.Trailer)
             if (ContentType == ChannelMediaContentType.Trailer)
@@ -55,5 +58,23 @@ namespace MediaBrowser.Controller.Channels
                 return false;
                 return false;
             }
             }
         }
         }
+
+        public ChannelVideoItem()
+        {
+            ChannelMediaSources = new List<ChannelMediaInfo>();
+        }
+
+        public override LocationType LocationType
+        {
+            get
+            {
+                if (string.IsNullOrEmpty(Path))
+                {
+                    return LocationType.Remote;
+                }
+
+                return base.LocationType;
+            }
+        }
     }
     }
 }
 }

+ 11 - 0
MediaBrowser.Controller/Channels/IChannel.cs

@@ -59,4 +59,15 @@ namespace MediaBrowser.Controller.Channels
         /// <returns>IEnumerable{ImageType}.</returns>
         /// <returns>IEnumerable{ImageType}.</returns>
         IEnumerable<ImageType> GetSupportedChannelImages();
         IEnumerable<ImageType> GetSupportedChannelImages();
     }
     }
+
+    public interface IRequiresMediaInfoCallback
+    {
+        /// <summary>
+        /// Gets the channel item media information.
+        /// </summary>
+        /// <param name="id">The identifier.</param>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <returns>Task{IEnumerable{ChannelMediaInfo}}.</returns>
+        Task<IEnumerable<ChannelMediaInfo>> GetChannelItemMediaInfo(string id, CancellationToken cancellationToken);
+    }
 }
 }

+ 1 - 1
MediaBrowser.Controller/Channels/IChannelItem.cs

@@ -2,7 +2,7 @@
 
 
 namespace MediaBrowser.Controller.Channels
 namespace MediaBrowser.Controller.Channels
 {
 {
-    public interface IChannelItem : IHasImages
+    public interface IChannelItem : IHasImages, IHasTags
     {
     {
         string ChannelId { get; set; }
         string ChannelId { get; set; }
 
 

+ 8 - 0
MediaBrowser.Controller/Channels/IChannelManager.cs

@@ -31,5 +31,13 @@ namespace MediaBrowser.Controller.Channels
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>Task{QueryResult{BaseItemDto}}.</returns>
         /// <returns>Task{QueryResult{BaseItemDto}}.</returns>
         Task<QueryResult<BaseItemDto>> GetChannelItems(ChannelItemQuery query, CancellationToken cancellationToken);
         Task<QueryResult<BaseItemDto>> GetChannelItems(ChannelItemQuery query, CancellationToken cancellationToken);
+
+        /// <summary>
+        /// Gets the channel item media sources.
+        /// </summary>
+        /// <param name="id">The identifier.</param>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <returns>Task{IEnumerable{ChannelMediaInfo}}.</returns>
+        Task<IEnumerable<ChannelMediaInfo>> GetChannelItemMediaSources(string id, CancellationToken cancellationToken);
     }
     }
 }
 }

+ 5 - 1
MediaBrowser.Controller/Channels/IChannelMediaItem.cs

@@ -1,9 +1,13 @@
-namespace MediaBrowser.Controller.Channels
+using System.Collections.Generic;
+
+namespace MediaBrowser.Controller.Channels
 {
 {
     public interface IChannelMediaItem : IChannelItem
     public interface IChannelMediaItem : IChannelItem
     {
     {
         bool IsInfiniteStream { get; set; }
         bool IsInfiniteStream { get; set; }
 
 
         ChannelMediaContentType ContentType { get; set; }
         ChannelMediaContentType ContentType { get; set; }
+
+        List<ChannelMediaInfo> ChannelMediaSources { get; set; }
     }
     }
 }
 }

+ 3 - 1
MediaBrowser.Controller/Entities/Audio/Audio.cs

@@ -10,16 +10,18 @@ namespace MediaBrowser.Controller.Entities.Audio
     /// <summary>
     /// <summary>
     /// Class Audio
     /// Class Audio
     /// </summary>
     /// </summary>
-    public class Audio : BaseItem, IHasMediaStreams, IHasAlbumArtist, IHasArtist, IHasMusicGenres, IHasLookupInfo<SongInfo>
+    public class Audio : BaseItem, IHasMediaStreams, IHasAlbumArtist, IHasArtist, IHasMusicGenres, IHasLookupInfo<SongInfo>, IHasTags
     {
     {
         public string FormatName { get; set; }
         public string FormatName { get; set; }
         public long? Size { get; set; }
         public long? Size { get; set; }
         public string Container { get; set; }
         public string Container { get; set; }
         public int? TotalBitrate { get; set; }
         public int? TotalBitrate { get; set; }
+        public List<string> Tags { get; set; }
 
 
         public Audio()
         public Audio()
         {
         {
             Artists = new List<string>();
             Artists = new List<string>();
+            Tags = new List<string>();
         }
         }
 
 
         /// <summary>
         /// <summary>

+ 3 - 1
MediaBrowser.Controller/Session/ISessionController.cs

@@ -1,5 +1,6 @@
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Session;
 using MediaBrowser.Model.Session;
+using MediaBrowser.Model.System;
 using System.Threading;
 using System.Threading;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 
 
@@ -54,9 +55,10 @@ namespace MediaBrowser.Controller.Session
         /// <summary>
         /// <summary>
         /// Sends the restart required message.
         /// Sends the restart required message.
         /// </summary>
         /// </summary>
+        /// <param name="info">The information.</param>
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>Task.</returns>
         /// <returns>Task.</returns>
-        Task SendRestartRequiredNotification(CancellationToken cancellationToken);
+        Task SendRestartRequiredNotification(SystemInfo info, CancellationToken cancellationToken);
 
 
         /// <summary>
         /// <summary>
         /// Sends the user data change info.
         /// Sends the user data change info.

+ 2 - 1
MediaBrowser.Dlna/PlayTo/PlayToController.cs

@@ -19,6 +19,7 @@ using System.Globalization;
 using System.Linq;
 using System.Linq;
 using System.Threading;
 using System.Threading;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
+using MediaBrowser.Model.System;
 
 
 namespace MediaBrowser.Dlna.PlayTo
 namespace MediaBrowser.Dlna.PlayTo
 {
 {
@@ -320,7 +321,7 @@ namespace MediaBrowser.Dlna.PlayTo
             return Task.FromResult(true);
             return Task.FromResult(true);
         }
         }
 
 
-        public Task SendRestartRequiredNotification(CancellationToken cancellationToken)
+        public Task SendRestartRequiredNotification(SystemInfo info, CancellationToken cancellationToken)
         {
         {
             return Task.FromResult(true);
             return Task.FromResult(true);
         }
         }

+ 0 - 91
MediaBrowser.MediaEncoding/Encoder/AudioEncoder.cs

@@ -1,91 +0,0 @@
-using MediaBrowser.Common.Configuration;
-using MediaBrowser.Common.IO;
-using MediaBrowser.Controller.LiveTv;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Logging;
-using System.Collections.Generic;
-using System.Globalization;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.MediaEncoding.Encoder
-{
-    public class AudioEncoder
-    {
-        private readonly string _ffmpegPath;
-        private readonly ILogger _logger;
-        private readonly IFileSystem _fileSystem;
-        private readonly IApplicationPaths _appPaths;
-        private readonly IIsoManager _isoManager;
-        private readonly ILiveTvManager _liveTvManager;
-
-        private readonly CultureInfo _usCulture = new CultureInfo("en-US");
-
-        public AudioEncoder(string ffmpegPath, ILogger logger, IFileSystem fileSystem, IApplicationPaths appPaths, IIsoManager isoManager, ILiveTvManager liveTvManager)
-        {
-            _ffmpegPath = ffmpegPath;
-            _logger = logger;
-            _fileSystem = fileSystem;
-            _appPaths = appPaths;
-            _isoManager = isoManager;
-            _liveTvManager = liveTvManager;
-        }
-
-        public Task BeginEncoding(InternalEncodingTask task)
-        {
-            return new FFMpegProcess(_ffmpegPath, _logger, _fileSystem, _appPaths, _isoManager, _liveTvManager).Start(task, GetArguments);
-        }
-
-        private string GetArguments(InternalEncodingTask task, string mountedPath)
-        {
-            var options = task.Request;
-
-            return string.Format("{0} -i {1} {2} -id3v2_version 3 -write_id3v1 1 \"{3}\"",
-                GetInputModifier(task),
-                GetInputArgument(task),
-                GetOutputModifier(task),
-                options.OutputPath).Trim();
-        }
-
-        private string GetInputModifier(InternalEncodingTask task)
-        {
-            return EncodingUtils.GetInputModifier(task);
-        }
-
-        private string GetInputArgument(InternalEncodingTask task)
-        {
-            return EncodingUtils.GetInputArgument(new List<string> { task.MediaPath }, task.IsInputRemote);
-        }
-
-        private string GetOutputModifier(InternalEncodingTask task)
-        {
-            var options = task.Request;
-
-            var audioTranscodeParams = new List<string>
-            {
-                "-threads " + EncodingUtils.GetNumberOfThreads(task, false).ToString(_usCulture),
-                "-vn"
-            };
-
-            var bitrate = EncodingUtils.GetAudioBitrateParam(task);
-
-            if (bitrate.HasValue)
-            {
-                audioTranscodeParams.Add("-ab " + bitrate.Value.ToString(_usCulture));
-            }
-
-            var channels = EncodingUtils.GetNumAudioChannelsParam(options, task.AudioStream);
-
-            if (channels.HasValue)
-            {
-                audioTranscodeParams.Add("-ac " + channels.Value);
-            }
-
-            if (options.AudioSampleRate.HasValue)
-            {
-                audioTranscodeParams.Add("-ar " + options.AudioSampleRate.Value);
-            }
-
-            return string.Join(" ", audioTranscodeParams.ToArray());
-        }
-    }
-}

+ 0 - 114
MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs

@@ -64,77 +64,6 @@ namespace MediaBrowser.MediaEncoding.Encoder
             return string.Format("\"{0}\"", url);
             return string.Format("\"{0}\"", url);
         }
         }
 
 
-        public static string GetAudioInputModifier(InternalEncodingTask options)
-        {
-            return GetCommonInputModifier(options);
-        }
-
-        public static string GetInputModifier(InternalEncodingTask options)
-        {
-            var inputModifier = GetCommonInputModifier(options);
-
-            //if (state.VideoRequest != null)
-            //{
-            //    inputModifier += " -fflags genpts";
-            //}
-
-            //if (!string.IsNullOrEmpty(state.InputVideoCodec))
-            //{
-            //    inputModifier += " -vcodec " + state.InputVideoCodec;
-            //}
-
-            //if (!string.IsNullOrEmpty(state.InputVideoSync))
-            //{
-            //    inputModifier += " -vsync " + state.InputVideoSync;
-            //}
-
-            return inputModifier;
-        }
-
-        private static string GetCommonInputModifier(InternalEncodingTask options)
-        {
-            var inputModifier = string.Empty;
-
-            if (options.EnableDebugLogging)
-            {
-                inputModifier += "-loglevel debug";
-            }
-
-            var probeSize = GetProbeSizeArgument(options.InputVideoType.HasValue && options.InputVideoType.Value == VideoType.Dvd);
-            inputModifier += " " + probeSize;
-            inputModifier = inputModifier.Trim();
-
-            if (!string.IsNullOrWhiteSpace(options.UserAgent))
-            {
-                inputModifier += " -user-agent \"" + options.UserAgent + "\"";
-            }
-
-            inputModifier += " " + GetFastSeekValue(options.Request);
-            inputModifier = inputModifier.Trim();
-
-            if (!string.IsNullOrEmpty(options.InputFormat))
-            {
-                inputModifier += " -f " + options.InputFormat;
-            }
-
-            if (!string.IsNullOrEmpty(options.InputAudioCodec))
-            {
-                inputModifier += " -acodec " + options.InputAudioCodec;
-            }
-
-            if (!string.IsNullOrEmpty(options.InputAudioSync))
-            {
-                inputModifier += " -async " + options.InputAudioSync;
-            }
-
-            if (options.ReadInputAtNativeFramerate)
-            {
-                inputModifier += " -re";
-            }
-
-            return inputModifier;
-        }
-
         private static string GetFastSeekValue(EncodingOptions options)
         private static string GetFastSeekValue(EncodingOptions options)
         {
         {
             var time = options.StartTimeTicks;
             var time = options.StartTimeTicks;
@@ -157,19 +86,6 @@ namespace MediaBrowser.MediaEncoding.Encoder
             return isDvd ? "-probesize 1G -analyzeduration 200M" : string.Empty;
             return isDvd ? "-probesize 1G -analyzeduration 200M" : string.Empty;
         }
         }
 
 
-        public static int? GetAudioBitrateParam(InternalEncodingTask task)
-        {
-            if (task.Request.AudioBitRate.HasValue)
-            {
-                // Make sure we don't request a bitrate higher than the source
-                var currentBitrate = task.AudioStream == null ? task.Request.AudioBitRate.Value : task.AudioStream.BitRate ?? task.Request.AudioBitRate.Value;
-
-                return Math.Min(currentBitrate, task.Request.AudioBitRate.Value);
-            }
-
-            return null;
-        }
-
         /// <summary>
         /// <summary>
         /// Gets the number of audio channels to specify on the command line
         /// Gets the number of audio channels to specify on the command line
         /// </summary>
         /// </summary>
@@ -201,35 +117,5 @@ namespace MediaBrowser.MediaEncoding.Encoder
 
 
             return request.AudioChannels;
             return request.AudioChannels;
         }
         }
-
-        public static int GetNumberOfThreads(InternalEncodingTask state, bool isWebm)
-        {
-            // Use more when this is true. -re will keep cpu usage under control
-            if (state.ReadInputAtNativeFramerate)
-            {
-                if (isWebm)
-                {
-                    return Math.Max(Environment.ProcessorCount - 1, 2);
-                }
-
-                return 0;
-            }
-
-            // Webm: http://www.webmproject.org/docs/encoder-parameters/
-            // The decoder will usually automatically use an appropriate number of threads according to how many cores are available but it can only use multiple threads 
-            // for the coefficient data if the encoder selected --token-parts > 0 at encode time.
-
-            switch (state.QualitySetting)
-            {
-                case EncodingQuality.HighSpeed:
-                    return 2;
-                case EncodingQuality.HighQuality:
-                    return 2;
-                case EncodingQuality.MaxQuality:
-                    return isWebm ? Math.Max(Environment.ProcessorCount - 1, 2) : 0;
-                default:
-                    throw new Exception("Unrecognized MediaEncodingQuality value.");
-            }
-        }
     }
     }
 }
 }

+ 0 - 168
MediaBrowser.MediaEncoding/Encoder/FFMpegProcess.cs

@@ -1,168 +0,0 @@
-using MediaBrowser.Common.Configuration;
-using MediaBrowser.Common.IO;
-using MediaBrowser.Controller.LiveTv;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Logging;
-using System;
-using System.Diagnostics;
-using System.IO;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.MediaEncoding.Encoder
-{
-    public class FFMpegProcess : IDisposable
-    {
-        private readonly string _ffmpegPath;
-        private readonly ILogger _logger;
-        private readonly IFileSystem _fileSystem;
-        private readonly IApplicationPaths _appPaths;
-        private readonly IIsoManager _isoManager;
-        private readonly ILiveTvManager _liveTvManager;
-
-        private Stream _logFileStream;
-        private InternalEncodingTask _task;
-        private IIsoMount _isoMount;
-
-        public FFMpegProcess(string ffmpegPath, ILogger logger, IFileSystem fileSystem, IApplicationPaths appPaths, IIsoManager isoManager, ILiveTvManager liveTvManager)
-        {
-            _ffmpegPath = ffmpegPath;
-            _logger = logger;
-            _fileSystem = fileSystem;
-            _appPaths = appPaths;
-            _isoManager = isoManager;
-            _liveTvManager = liveTvManager;
-        }
-
-        public async Task Start(InternalEncodingTask task, Func<InternalEncodingTask,string,string> argumentsFactory)
-        {
-            _task = task;
-            if (!File.Exists(_ffmpegPath))
-            {
-                throw new InvalidOperationException("ffmpeg was not found at " + _ffmpegPath);
-            }
-
-            Directory.CreateDirectory(Path.GetDirectoryName(task.Request.OutputPath));
-
-            string mountedPath = null;
-            if (task.InputVideoType.HasValue && task.InputVideoType == VideoType.Iso && task.IsoType.HasValue)
-            {
-                if (_isoManager.CanMount(task.MediaPath))
-                {
-                    _isoMount = await _isoManager.Mount(task.MediaPath, CancellationToken.None).ConfigureAwait(false);
-                    mountedPath = _isoMount.MountedPath;
-                }
-            }
-            
-            var process = new Process
-            {
-                StartInfo = new ProcessStartInfo
-                {
-                    CreateNoWindow = true,
-                    UseShellExecute = false,
-
-                    // Must consume both stdout and stderr or deadlocks may occur
-                    RedirectStandardOutput = true,
-                    RedirectStandardError = true,
-
-                    FileName = _ffmpegPath,
-                    WorkingDirectory = Path.GetDirectoryName(_ffmpegPath),
-                    Arguments = argumentsFactory(task, mountedPath),
-
-                    WindowStyle = ProcessWindowStyle.Hidden,
-                    ErrorDialog = false
-                },
-
-                EnableRaisingEvents = true
-            };
-
-            _logger.Info(process.StartInfo.FileName + " " + process.StartInfo.Arguments);
-
-            var logFilePath = Path.Combine(_appPaths.LogDirectoryPath, "ffmpeg-" + task.Id + ".txt");
-            Directory.CreateDirectory(Path.GetDirectoryName(logFilePath));
-
-            // FFMpeg writes debug/error info to stderr. This is useful when debugging so let's put it in the log directory.
-            _logFileStream = _fileSystem.GetFileStream(logFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, true);
-
-            process.Exited += process_Exited;
-
-            try
-            {
-                process.Start();
-            }
-            catch (Exception ex)
-            {
-                _logger.ErrorException("Error starting ffmpeg", ex);
-
-                task.OnError();
-
-                DisposeLogFileStream();
-
-                process.Dispose();
-
-                throw;
-            }
-
-            task.OnBegin();
-
-            // MUST read both stdout and stderr asynchronously or a deadlock may occurr
-            process.BeginOutputReadLine();
-
-#pragma warning disable 4014
-            // Important - don't await the log task or we won't be able to kill ffmpeg when the user stops playback
-            process.StandardError.BaseStream.CopyToAsync(_logFileStream);
-#pragma warning restore 4014
-        }
-
-        async void process_Exited(object sender, EventArgs e)
-        {
-            var process = (Process)sender;
-
-            if (_isoMount != null)
-            {
-                _isoMount.Dispose();
-                _isoMount = null;
-            }
-
-            DisposeLogFileStream();
-
-            try
-            {
-                _logger.Info("FFMpeg exited with code {0} for {1}", process.ExitCode, _task.Request.OutputPath);
-            }
-            catch
-            {
-                _logger.Info("FFMpeg exited with an error for {0}", _task.Request.OutputPath);
-            }
-
-            _task.OnCompleted();
-            
-            if (!string.IsNullOrEmpty(_task.LiveTvStreamId))
-            {
-                try
-                {
-                    await _liveTvManager.CloseLiveStream(_task.LiveTvStreamId, CancellationToken.None).ConfigureAwait(false);
-                }
-                catch (Exception ex)
-                {
-                    _logger.ErrorException("Error closing live tv stream", ex);
-                }
-            }
-        }
-
-        public void Dispose()
-        {
-            DisposeLogFileStream();
-        }
-
-        private void DisposeLogFileStream()
-        {
-            if (_logFileStream != null)
-            {
-                _logFileStream.Dispose();
-                _logFileStream = null;
-            }
-        }
-    }
-}

+ 0 - 235
MediaBrowser.MediaEncoding/Encoder/ImageEncoder.cs

@@ -1,235 +0,0 @@
-using MediaBrowser.Common.Configuration;
-using MediaBrowser.Common.IO;
-using MediaBrowser.Controller.MediaEncoding;
-using MediaBrowser.Model.Logging;
-using System;
-using System.Diagnostics;
-using System.Globalization;
-using System.IO;
-using System.Linq;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.MediaEncoding.Encoder
-{
-    public class ImageEncoder
-    {
-        private readonly string _ffmpegPath;
-        private readonly ILogger _logger;
-        private readonly IFileSystem _fileSystem;
-        private readonly IApplicationPaths _appPaths;
-
-        private readonly CultureInfo _usCulture = new CultureInfo("en-US");
-
-        private static readonly SemaphoreSlim ResourcePool = new SemaphoreSlim(10, 10);
-
-        public ImageEncoder(string ffmpegPath, ILogger logger, IFileSystem fileSystem, IApplicationPaths appPaths)
-        {
-            _ffmpegPath = ffmpegPath;
-            _logger = logger;
-            _fileSystem = fileSystem;
-            _appPaths = appPaths;
-        }
-
-        public async Task<Stream> EncodeImage(ImageEncodingOptions options, CancellationToken cancellationToken)
-        {
-            ValidateInput(options);
-
-            await ResourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
-
-            try
-            {
-                return await EncodeImageInternal(options, cancellationToken).ConfigureAwait(false);
-            }
-            finally
-            {
-                ResourcePool.Release();
-            }
-        }
-
-        private async Task<Stream> EncodeImageInternal(ImageEncodingOptions options, CancellationToken cancellationToken)
-        {
-            ValidateInput(options);
-
-            var inputPath = options.InputPath;
-            var filename = Path.GetFileName(inputPath);
-
-            if (HasDiacritics(filename))
-            {
-                inputPath = GetTempFile(inputPath);
-                filename = Path.GetFileName(inputPath);
-            }
-
-            var process = new Process
-            {
-                StartInfo = new ProcessStartInfo
-                {
-                    CreateNoWindow = true,
-                    UseShellExecute = false,
-                    FileName = _ffmpegPath,
-                    Arguments = GetArguments(options, filename),
-                    WindowStyle = ProcessWindowStyle.Hidden,
-                    ErrorDialog = false,
-                    RedirectStandardOutput = true,
-                    RedirectStandardError = true,
-                    WorkingDirectory = Path.GetDirectoryName(inputPath)
-                }
-            };
-
-            _logger.Debug("ffmpeg " + process.StartInfo.Arguments);
-
-            process.Start();
-
-            var memoryStream = new MemoryStream();
-
-#pragma warning disable 4014
-            // Important - don't await the log task or we won't be able to kill ffmpeg when the user stops playback
-            process.StandardOutput.BaseStream.CopyToAsync(memoryStream);
-#pragma warning restore 4014
-
-            // MUST read both stdout and stderr asynchronously or a deadlock may occurr
-            process.BeginErrorReadLine();
-
-            var ranToCompletion = process.WaitForExit(5000);
-
-            if (!ranToCompletion)
-            {
-                try
-                {
-                    _logger.Info("Killing ffmpeg process");
-
-                    process.Kill();
-
-                    process.WaitForExit(1000);
-                }
-                catch (Exception ex)
-                {
-                    _logger.ErrorException("Error killing process", ex);
-                }
-            }
-
-            var exitCode = ranToCompletion ? process.ExitCode : -1;
-
-            process.Dispose();
-
-            if (exitCode == -1 || memoryStream.Length == 0)
-            {
-                memoryStream.Dispose();
-
-                var msg = string.Format("ffmpeg image encoding failed for {0}", options.InputPath);
-
-                _logger.Error(msg);
-
-                throw new ApplicationException(msg);
-            }
-
-            memoryStream.Position = 0;
-            return memoryStream;
-        }
-
-        private string GetTempFile(string path)
-        {
-            var extension = Path.GetExtension(path) ?? string.Empty;
-
-            var tempPath = Path.Combine(_appPaths.TempDirectory, Guid.NewGuid().ToString("N") + extension);
-
-            File.Copy(path, tempPath);
-
-            return tempPath;
-        }
-        
-        private string GetArguments(ImageEncodingOptions options, string inputFilename)
-        {
-            var vfScale = GetFilterGraph(options);
-            var outputFormat = GetOutputFormat(options.Format);
-
-            var quality = (options.Quality ?? 100) * .3;
-            quality = 31 - quality;
-            var qualityValue = Convert.ToInt32(Math.Max(quality, 1));
-
-            return string.Format("-f image2 -i file:\"{3}\" -q:v {0} {1} -f image2pipe -vcodec {2} -",
-                qualityValue.ToString(_usCulture),
-                vfScale,
-                outputFormat,
-                inputFilename);
-        }
-
-        private string GetFilterGraph(ImageEncodingOptions options)
-        {
-            if (!options.Width.HasValue &&
-                !options.Height.HasValue &&
-                !options.MaxHeight.HasValue &&
-                !options.MaxWidth.HasValue)
-            {
-                return string.Empty;
-            }
-
-            var widthScale = "-1";
-            var heightScale = "-1";
-
-            if (options.MaxWidth.HasValue)
-            {
-                widthScale = "min(iw\\," + options.MaxWidth.Value.ToString(_usCulture) + ")";
-            }
-            else if (options.Width.HasValue)
-            {
-                widthScale = options.Width.Value.ToString(_usCulture);
-            }
-
-            if (options.MaxHeight.HasValue)
-            {
-                heightScale = "min(ih\\," + options.MaxHeight.Value.ToString(_usCulture) + ")";
-            }
-            else if (options.Height.HasValue)
-            {
-                heightScale = options.Height.Value.ToString(_usCulture);
-            }
-
-            var scaleMethod = "lanczos";
-
-            return string.Format("-vf scale=\"{0}:{1}\"",
-                widthScale,
-                heightScale);
-        }
-
-        private string GetOutputFormat(string format)
-        {
-            if (string.Equals(format, "jpeg", StringComparison.OrdinalIgnoreCase) ||
-                string.Equals(format, "jpg", StringComparison.OrdinalIgnoreCase))
-            {
-                return "mjpeg";
-            }
-            return format;
-        }
-
-        private void ValidateInput(ImageEncodingOptions options)
-        {
-
-        }
-
-        /// <summary>
-        /// Determines whether the specified text has diacritics.
-        /// </summary>
-        /// <param name="text">The text.</param>
-        /// <returns><c>true</c> if the specified text has diacritics; otherwise, <c>false</c>.</returns>
-        private bool HasDiacritics(string text)
-        {
-            return !String.Equals(text, RemoveDiacritics(text), StringComparison.Ordinal);
-        }
-
-        /// <summary>
-        /// Removes the diacritics.
-        /// </summary>
-        /// <param name="text">The text.</param>
-        /// <returns>System.String.</returns>
-        private string RemoveDiacritics(string text)
-        {
-            return String.Concat(
-                text.Normalize(NormalizationForm.FormD)
-                .Where(ch => CharUnicodeInfo.GetUnicodeCategory(ch) !=
-                                              UnicodeCategory.NonSpacingMark)
-              ).Normalize(NormalizationForm.FormC);
-        }
-    }
-}

+ 0 - 95
MediaBrowser.MediaEncoding/Encoder/InternalEncodingTask.cs

@@ -1,95 +0,0 @@
-using MediaBrowser.Controller.MediaEncoding;
-using MediaBrowser.Model.Configuration;
-using MediaBrowser.Model.Entities;
-using System;
-using System.Collections.Generic;
-using System.Threading;
-
-namespace MediaBrowser.MediaEncoding.Encoder
-{
-    public class InternalEncodingTask
-    {
-        public string Id { get; set; }
-
-        public CancellationTokenSource CancellationTokenSource { get; set; }
-
-        public double ProgressPercentage { get; set; }
-
-        public EncodingOptions Request { get; set; }
-
-        public VideoEncodingOptions VideoRequest
-        {
-            get { return Request as VideoEncodingOptions; }
-        }
-
-        public string MediaPath { get; set; }
-        public List<string> StreamFileNames { get; set; }
-        public bool IsInputRemote { get; set; }
-
-        public VideoType? InputVideoType { get; set; }
-        public IsoType? IsoType { get; set; }
-        public long? InputRunTimeTicks;
-
-        public string AudioSync = "1";
-        public string VideoSync = "vfr";
-
-        public string InputAudioSync { get; set; }
-        public string InputVideoSync { get; set; }
-
-        public bool DeInterlace { get; set; }
-
-        public bool ReadInputAtNativeFramerate { get; set; }
-
-        public string InputFormat { get; set; }
-
-        public string InputVideoCodec { get; set; }
-
-        public string InputAudioCodec { get; set; }
-
-        public string LiveTvStreamId { get; set; }
-
-        public MediaStream AudioStream { get; set; }
-        public MediaStream VideoStream { get; set; }
-        public MediaStream SubtitleStream { get; set; }
-        public bool HasMediaStreams { get; set; }
-
-        public int SegmentLength = 10;
-        public int HlsListSize;
-
-        public string MimeType { get; set; }
-        public string OrgPn { get; set; }
-        public bool EnableMpegtsM2TsMode { get; set; }
-
-        /// <summary>
-        /// Gets or sets the user agent.
-        /// </summary>
-        /// <value>The user agent.</value>
-        public string UserAgent { get; set; }
-
-        public EncodingQuality QualitySetting { get; set; }
-
-        public InternalEncodingTask()
-        {
-            Id = Guid.NewGuid().ToString("N");
-            CancellationTokenSource = new CancellationTokenSource();
-            StreamFileNames = new List<string>();
-        }
-
-        public bool EnableDebugLogging { get; set; }
-
-        internal void OnBegin()
-        {
-            
-        }
-
-        internal void OnCompleted()
-        {
-            
-        }
-
-        internal void OnError()
-        {
-            
-        }
-    }
-}

+ 0 - 311
MediaBrowser.MediaEncoding/Encoder/InternalEncodingTaskFactory.cs

@@ -1,311 +0,0 @@
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Dlna;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.LiveTv;
-using MediaBrowser.Controller.MediaEncoding;
-using MediaBrowser.Controller.Persistence;
-using MediaBrowser.Model.Configuration;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.LiveTv;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.MediaEncoding.Encoder
-{
-    public class InternalEncodingTaskFactory
-    {
-        private readonly ILibraryManager _libraryManager;
-        private readonly ILiveTvManager _liveTvManager;
-        private readonly IItemRepository _itemRepo;
-        private readonly IServerConfigurationManager _config;
-
-        public InternalEncodingTaskFactory(ILibraryManager libraryManager, ILiveTvManager liveTvManager, IItemRepository itemRepo, IServerConfigurationManager config)
-        {
-            _libraryManager = libraryManager;
-            _liveTvManager = liveTvManager;
-            _itemRepo = itemRepo;
-            _config = config;
-        }
-
-        public async Task<InternalEncodingTask> Create(EncodingOptions request, CancellationToken cancellationToken)
-        {
-            ValidateInput(request);
-
-            var state = new InternalEncodingTask
-            {
-                Request = request
-            };
-
-            var item = string.IsNullOrEmpty(request.MediaSourceId) ?
-                _libraryManager.GetItemById(new Guid(request.ItemId)) :
-                _libraryManager.GetItemById(new Guid(request.MediaSourceId));
-
-            if (item is ILiveTvRecording)
-            {
-                var recording = await _liveTvManager.GetInternalRecording(request.ItemId, cancellationToken).ConfigureAwait(false);
-
-                if (string.Equals(recording.MediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase))
-                {
-                    state.InputVideoType = VideoType.VideoFile;
-                }
-
-                var path = recording.RecordingInfo.Path;
-                var mediaUrl = recording.RecordingInfo.Url;
-
-                if (string.IsNullOrWhiteSpace(path) && string.IsNullOrWhiteSpace(mediaUrl))
-                {
-                    var streamInfo = await _liveTvManager.GetRecordingStream(request.ItemId, cancellationToken).ConfigureAwait(false);
-
-                    state.LiveTvStreamId = streamInfo.Id;
-
-                    path = streamInfo.Path;
-                    mediaUrl = streamInfo.Url;
-                }
-
-                if (!string.IsNullOrEmpty(path) && File.Exists(path))
-                {
-                    state.MediaPath = path;
-                    state.IsInputRemote = false;
-                }
-                else if (!string.IsNullOrEmpty(mediaUrl))
-                {
-                    state.MediaPath = mediaUrl;
-                    state.IsInputRemote = true;
-                }
-
-                state.InputRunTimeTicks = recording.RunTimeTicks;
-                if (recording.RecordingInfo.Status == RecordingStatus.InProgress && !state.IsInputRemote)
-                {
-                    await Task.Delay(1000, cancellationToken).ConfigureAwait(false);
-                }
-
-                state.ReadInputAtNativeFramerate = recording.RecordingInfo.Status == RecordingStatus.InProgress;
-                state.AudioSync = "1000";
-                state.DeInterlace = true;
-                state.InputVideoSync = "-1";
-                state.InputAudioSync = "1";
-            }
-            else if (item is LiveTvChannel)
-            {
-                var channel = _liveTvManager.GetInternalChannel(request.ItemId);
-
-                if (string.Equals(channel.MediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase))
-                {
-                    state.InputVideoType = VideoType.VideoFile;
-                }
-
-                var streamInfo = await _liveTvManager.GetChannelStream(request.ItemId, cancellationToken).ConfigureAwait(false);
-
-                state.LiveTvStreamId = streamInfo.Id;
-
-                if (!string.IsNullOrEmpty(streamInfo.Path) && File.Exists(streamInfo.Path))
-                {
-                    state.MediaPath = streamInfo.Path;
-                    state.IsInputRemote = false;
-
-                    await Task.Delay(1000, cancellationToken).ConfigureAwait(false);
-                }
-                else if (!string.IsNullOrEmpty(streamInfo.Url))
-                {
-                    state.MediaPath = streamInfo.Url;
-                    state.IsInputRemote = true;
-                }
-
-                state.ReadInputAtNativeFramerate = true;
-                state.AudioSync = "1000";
-                state.DeInterlace = true;
-                state.InputVideoSync = "-1";
-                state.InputAudioSync = "1";
-            }
-            else
-            {
-                state.MediaPath = item.Path;
-                state.IsInputRemote = item.LocationType == LocationType.Remote;
-
-                var video = item as Video;
-
-                if (video != null)
-                {
-                    state.InputVideoType = video.VideoType;
-                    state.IsoType = video.IsoType;
-
-                    state.StreamFileNames = video.PlayableStreamFileNames.ToList();
-                }
-
-                state.InputRunTimeTicks = item.RunTimeTicks;
-            }
-
-            var videoRequest = request as VideoEncodingOptions;
-
-            var mediaStreams = _itemRepo.GetMediaStreams(new MediaStreamQuery
-            {
-                ItemId = item.Id
-
-            }).ToList();
-
-            if (videoRequest != null)
-            {
-                state.VideoStream = GetMediaStream(mediaStreams, videoRequest.VideoStreamIndex, MediaStreamType.Video);
-                state.SubtitleStream = GetMediaStream(mediaStreams, videoRequest.SubtitleStreamIndex, MediaStreamType.Subtitle, false);
-                state.AudioStream = GetMediaStream(mediaStreams, videoRequest.AudioStreamIndex, MediaStreamType.Audio);
-
-                if (state.VideoStream != null && state.VideoStream.IsInterlaced)
-                {
-                    state.DeInterlace = true;
-                }
-            }
-            else
-            {
-                state.AudioStream = GetMediaStream(mediaStreams, null, MediaStreamType.Audio, true);
-            }
-
-            state.HasMediaStreams = mediaStreams.Count > 0;
-
-            state.SegmentLength = state.ReadInputAtNativeFramerate ? 5 : 10;
-            state.HlsListSize = state.ReadInputAtNativeFramerate ? 100 : 1440;
-
-            state.QualitySetting = GetQualitySetting();
-
-            ApplyDeviceProfileSettings(state);
-
-            return state;
-        }
-
-        private void ValidateInput(EncodingOptions request)
-        {
-            if (string.IsNullOrWhiteSpace(request.ItemId))
-            {
-                throw new ArgumentException("ItemId is required.");
-            }
-            if (string.IsNullOrWhiteSpace(request.OutputPath))
-            {
-                throw new ArgumentException("OutputPath is required.");
-            }
-            if (string.IsNullOrWhiteSpace(request.Container))
-            {
-                throw new ArgumentException("Container is required.");
-            }
-            if (string.IsNullOrWhiteSpace(request.AudioCodec))
-            {
-                throw new ArgumentException("AudioCodec is required.");
-            }
-
-            var videoRequest = request as VideoEncodingOptions;
-
-            if (videoRequest == null)
-            {
-                return;
-            }
-        }
-
-        /// <summary>
-        /// Determines which stream will be used for playback
-        /// </summary>
-        /// <param name="allStream">All stream.</param>
-        /// <param name="desiredIndex">Index of the desired.</param>
-        /// <param name="type">The type.</param>
-        /// <param name="returnFirstIfNoIndex">if set to <c>true</c> [return first if no index].</param>
-        /// <returns>MediaStream.</returns>
-        private MediaStream GetMediaStream(IEnumerable<MediaStream> allStream, int? desiredIndex, MediaStreamType type, bool returnFirstIfNoIndex = true)
-        {
-            var streams = allStream.Where(s => s.Type == type).OrderBy(i => i.Index).ToList();
-
-            if (desiredIndex.HasValue)
-            {
-                var stream = streams.FirstOrDefault(s => s.Index == desiredIndex.Value);
-
-                if (stream != null)
-                {
-                    return stream;
-                }
-            }
-
-            if (returnFirstIfNoIndex && type == MediaStreamType.Audio)
-            {
-                return streams.FirstOrDefault(i => i.Channels.HasValue && i.Channels.Value > 0) ??
-                       streams.FirstOrDefault();
-            }
-
-            // Just return the first one
-            return returnFirstIfNoIndex ? streams.FirstOrDefault() : null;
-        }
-
-        private void ApplyDeviceProfileSettings(InternalEncodingTask state)
-        {
-            var profile = state.Request.DeviceProfile;
-
-            if (profile == null)
-            {
-                // Don't use settings from the default profile. 
-                // Only use a specific profile if it was requested.
-                return;
-            }
-
-            var container = state.Request.Container;
-
-            var audioCodec = state.Request.AudioCodec;
-
-            if (string.Equals(audioCodec, "copy", StringComparison.OrdinalIgnoreCase) && state.AudioStream != null)
-            {
-                audioCodec = state.AudioStream.Codec;
-            }
-
-            var videoCodec = state.VideoRequest == null ? null : state.VideoRequest.VideoCodec;
-
-            if (string.Equals(videoCodec, "copy", StringComparison.OrdinalIgnoreCase) && state.VideoStream != null)
-            {
-                videoCodec = state.VideoStream.Codec;
-            }
-
-            //var mediaProfile = state.VideoRequest == null ?
-            //    profile.GetAudioMediaProfile(container, audioCodec) :
-            //    profile.GetVideoMediaProfile(container, audioCodec, videoCodec, state.AudioStream, state.VideoStream);
-
-            //if (mediaProfile != null)
-            //{
-            //    state.MimeType = mediaProfile.MimeType;
-            //    state.OrgPn = mediaProfile.OrgPn;
-            //}
-
-            //var transcodingProfile = state.VideoRequest == null ?
-            //    profile.GetAudioTranscodingProfile(container, audioCodec) :
-            //    profile.GetVideoTranscodingProfile(container, audioCodec, videoCodec);
-
-            //if (transcodingProfile != null)
-            //{
-            //    //state.EstimateContentLength = transcodingProfile.EstimateContentLength;
-            //    state.EnableMpegtsM2TsMode = transcodingProfile.EnableMpegtsM2TsMode;
-            //    //state.TranscodeSeekInfo = transcodingProfile.TranscodeSeekInfo;
-
-            //    if (state.VideoRequest != null && string.IsNullOrWhiteSpace(state.VideoRequest.VideoProfile))
-            //    {
-            //        state.VideoRequest.VideoProfile = transcodingProfile.VideoProfile;
-            //    }
-            //}
-        }
-
-        private EncodingQuality GetQualitySetting()
-        {
-            var quality = _config.Configuration.MediaEncodingQuality;
-
-            if (quality == EncodingQuality.Auto)
-            {
-                var cpuCount = Environment.ProcessorCount;
-
-                if (cpuCount >= 4)
-                {
-                    //return EncodingQuality.HighQuality;
-                }
-
-                return EncodingQuality.HighSpeed;
-            }
-
-            return quality;
-        }
-    }
-}

+ 1 - 1
MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs

@@ -853,7 +853,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
 
 
         public Task<Stream> EncodeImage(ImageEncodingOptions options, CancellationToken cancellationToken)
         public Task<Stream> EncodeImage(ImageEncodingOptions options, CancellationToken cancellationToken)
         {
         {
-            return new ImageEncoder(FFMpegPath, _logger, _fileSystem, _appPaths).EncodeImage(options, cancellationToken);
+            throw new NotImplementedException();
         }
         }
 
 
         /// <summary>
         /// <summary>

+ 0 - 5
MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj

@@ -53,12 +53,7 @@
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <Compile Include="BdInfo\BdInfoExaminer.cs" />
     <Compile Include="BdInfo\BdInfoExaminer.cs" />
-    <Compile Include="Encoder\AudioEncoder.cs" />
     <Compile Include="Encoder\EncodingUtils.cs" />
     <Compile Include="Encoder\EncodingUtils.cs" />
-    <Compile Include="Encoder\FFMpegProcess.cs" />
-    <Compile Include="Encoder\ImageEncoder.cs" />
-    <Compile Include="Encoder\InternalEncodingTask.cs" />
-    <Compile Include="Encoder\InternalEncodingTaskFactory.cs" />
     <Compile Include="Encoder\MediaEncoder.cs" />
     <Compile Include="Encoder\MediaEncoder.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="Subtitles\ISubtitleParser.cs" />
     <Compile Include="Subtitles\ISubtitleParser.cs" />

+ 2 - 0
MediaBrowser.Model/Session/SessionCapabilities.cs

@@ -10,6 +10,8 @@ namespace MediaBrowser.Model.Session
 
 
         public bool SupportsMediaControl { get; set; }
         public bool SupportsMediaControl { get; set; }
 
 
+        public string MessageCallbackUrl { get; set; }
+
         public SessionCapabilities()
         public SessionCapabilities()
         {
         {
             PlayableMediaTypes = new List<string>();
             PlayableMediaTypes = new List<string>();

+ 37 - 8
MediaBrowser.Server.Implementations/Channels/ChannelManager.cs

@@ -98,7 +98,7 @@ namespace MediaBrowser.Server.Implementations.Channels
             {
             {
                 all = all.Take(query.Limit.Value).ToList();
                 all = all.Take(query.Limit.Value).ToList();
             }
             }
-            
+
             // Get everything
             // Get everything
             var fields = Enum.GetNames(typeof(ItemFields))
             var fields = Enum.GetNames(typeof(ItemFields))
                     .Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true))
                     .Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true))
@@ -156,6 +156,23 @@ namespace MediaBrowser.Server.Implementations.Channels
             progress.Report(100);
             progress.Report(100);
         }
         }
 
 
+        public Task<IEnumerable<ChannelMediaInfo>> GetChannelItemMediaSources(string id, CancellationToken cancellationToken)
+        {
+            var item = (IChannelMediaItem)_libraryManager.GetItemById(id);
+
+            var channelGuid = new Guid(item.ChannelId);
+            var channel = _channelEntities.First(i => i.Id == channelGuid);
+
+            var requiresCallback = channel as IRequiresMediaInfoCallback;
+
+            if (requiresCallback != null)
+            {
+                return requiresCallback.GetChannelItemMediaInfo(item.ExternalId, cancellationToken);
+            }
+
+            return Task.FromResult<IEnumerable<ChannelMediaInfo>>(item.ChannelMediaSources);
+        }
+
         private async Task<Channel> GetChannel(IChannel channelInfo, CancellationToken cancellationToken)
         private async Task<Channel> GetChannel(IChannel channelInfo, CancellationToken cancellationToken)
         {
         {
             var path = Path.Combine(_config.ApplicationPaths.ItemsByNamePath, "channels", _fileSystem.GetValidFilename(channelInfo.Name));
             var path = Path.Combine(_config.ApplicationPaths.ItemsByNamePath, "channels", _fileSystem.GetValidFilename(channelInfo.Name));
@@ -303,10 +320,16 @@ namespace MediaBrowser.Server.Implementations.Channels
 
 
                 var query = new InternalChannelItemQuery
                 var query = new InternalChannelItemQuery
                 {
                 {
-                    User = user,
-                    CategoryId = categoryId
+                    User = user
                 };
                 };
 
 
+                if (!string.IsNullOrWhiteSpace(categoryId))
+                {
+                    var categoryItem = (IChannelItem)_libraryManager.GetItemById(new Guid(categoryId));
+
+                    query.CategoryId = categoryItem.ExternalId;
+                }
+
                 var result = await channel.GetChannelItems(query, cancellationToken).ConfigureAwait(false);
                 var result = await channel.GetChannelItems(query, cancellationToken).ConfigureAwait(false);
 
 
                 CacheResponse(result, cachePath);
                 CacheResponse(result, cachePath);
@@ -380,7 +403,7 @@ namespace MediaBrowser.Server.Implementations.Channels
         private string GetIdToHash(string externalId)
         private string GetIdToHash(string externalId)
         {
         {
             // Increment this as needed to force new downloads
             // Increment this as needed to force new downloads
-            return externalId + "4";
+            return externalId + "7";
         }
         }
 
 
         private async Task<BaseItem> GetChannelItemEntity(ChannelItemInfo info, string internalChannnelId, CancellationToken cancellationToken)
         private async Task<BaseItem> GetChannelItemEntity(ChannelItemInfo info, string internalChannnelId, CancellationToken cancellationToken)
@@ -434,10 +457,6 @@ namespace MediaBrowser.Server.Implementations.Channels
             item.Id = id;
             item.Id = id;
             item.RunTimeTicks = info.RunTimeTicks;
             item.RunTimeTicks = info.RunTimeTicks;
 
 
-            var mediaSource = info.MediaSources.FirstOrDefault();
-
-            item.Path = mediaSource == null ? null : mediaSource.Path;
-
             if (isNew)
             if (isNew)
             {
             {
                 item.Name = info.Name;
                 item.Name = info.Name;
@@ -464,12 +483,22 @@ namespace MediaBrowser.Server.Implementations.Channels
             channelItem.ChannelId = internalChannnelId;
             channelItem.ChannelId = internalChannnelId;
             channelItem.ChannelItemType = info.Type;
             channelItem.ChannelItemType = info.Type;
 
 
+            if (isNew)
+            {
+                channelItem.Tags = info.Tags;
+            }
+
             var channelMediaItem = item as IChannelMediaItem;
             var channelMediaItem = item as IChannelMediaItem;
 
 
             if (channelMediaItem != null)
             if (channelMediaItem != null)
             {
             {
                 channelMediaItem.IsInfiniteStream = info.IsInfiniteStream;
                 channelMediaItem.IsInfiniteStream = info.IsInfiniteStream;
                 channelMediaItem.ContentType = info.ContentType;
                 channelMediaItem.ContentType = info.ContentType;
+                channelMediaItem.ChannelMediaSources = info.MediaSources;
+
+                var mediaSource = info.MediaSources.FirstOrDefault();
+
+                item.Path = mediaSource == null ? null : mediaSource.Path;
             }
             }
 
 
             if (isNew)
             if (isNew)

+ 47 - 38
MediaBrowser.Server.Implementations/Session/HttpSessionController.cs

@@ -1,5 +1,8 @@
-using MediaBrowser.Common.Net;
-using MediaBrowser.Controller;
+using System.Collections.Generic;
+using System.Collections.Specialized;
+using System.Linq;
+using System.Net;
+using MediaBrowser.Common.Net;
 using MediaBrowser.Controller.Session;
 using MediaBrowser.Controller.Session;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Net;
 using MediaBrowser.Model.Net;
@@ -16,23 +19,18 @@ namespace MediaBrowser.Server.Implementations.Session
     {
     {
         private readonly IHttpClient _httpClient;
         private readonly IHttpClient _httpClient;
         private readonly IJsonSerializer _json;
         private readonly IJsonSerializer _json;
-        private readonly IServerApplicationHost _appHost;
 
 
         public SessionInfo Session { get; private set; }
         public SessionInfo Session { get; private set; }
 
 
-        //var postUrl = string.Format("http://{0}/mediabrowser/message", session.RemoteEndPoint);
-        
         private readonly string _postUrl;
         private readonly string _postUrl;
 
 
-        public HttpSessionController(IHttpClient httpClient, 
-            IJsonSerializer json, 
-            IServerApplicationHost appHost, 
-            SessionInfo session, 
+        public HttpSessionController(IHttpClient httpClient,
+            IJsonSerializer json,
+            SessionInfo session,
             string postUrl)
             string postUrl)
         {
         {
             _httpClient = httpClient;
             _httpClient = httpClient;
             _json = json;
             _json = json;
-            _appHost = appHost;
             Session = session;
             Session = session;
             _postUrl = postUrl;
             _postUrl = postUrl;
         }
         }
@@ -63,6 +61,21 @@ namespace MediaBrowser.Server.Implementations.Session
             });
             });
         }
         }
 
 
+        private Task SendMessage(string name, CancellationToken cancellationToken)
+        {
+            return SendMessage(name, new NameValueCollection(), cancellationToken);
+        }
+
+        private Task SendMessage(string name, NameValueCollection args, CancellationToken cancellationToken)
+        {
+            return SendMessage(new WebSocketMessage<string>
+            {
+                MessageType = name,
+                Data = string.Empty
+
+            }, cancellationToken);
+        }
+
         public Task SendSessionEndedNotification(SessionInfoDto sessionInfo, CancellationToken cancellationToken)
         public Task SendSessionEndedNotification(SessionInfoDto sessionInfo, CancellationToken cancellationToken)
         {
         {
             return Task.FromResult(true);
             return Task.FromResult(true);
@@ -80,22 +93,25 @@ namespace MediaBrowser.Server.Implementations.Session
 
 
         public Task SendPlayCommand(PlayRequest command, CancellationToken cancellationToken)
         public Task SendPlayCommand(PlayRequest command, CancellationToken cancellationToken)
         {
         {
-            return SendMessage(new WebSocketMessage<PlayRequest>
-            {
-                MessageType = "Play",
-                Data = command
+            return Task.FromResult(true);
+            //return SendMessage(new WebSocketMessage<PlayRequest>
+            //{
+            //    MessageType = "Play",
+            //    Data = command
 
 
-            }, cancellationToken);
+            //}, cancellationToken);
         }
         }
 
 
         public Task SendPlaystateCommand(PlaystateRequest command, CancellationToken cancellationToken)
         public Task SendPlaystateCommand(PlaystateRequest command, CancellationToken cancellationToken)
         {
         {
-            return SendMessage(new WebSocketMessage<PlaystateRequest>
+            var args = new Dictionary<string, string>();
+
+            if (command.Command == PlaystateCommand.Seek)
             {
             {
-                MessageType = "Playstate",
-                Data = command
 
 
-            }, cancellationToken);
+            }
+
+            return SendMessage(command.Command.ToString(), cancellationToken);
         }
         }
 
 
         public Task SendLibraryUpdateInfo(LibraryUpdateInfo info, CancellationToken cancellationToken)
         public Task SendLibraryUpdateInfo(LibraryUpdateInfo info, CancellationToken cancellationToken)
@@ -103,14 +119,9 @@ namespace MediaBrowser.Server.Implementations.Session
             return Task.FromResult(true);
             return Task.FromResult(true);
         }
         }
 
 
-        public Task SendRestartRequiredNotification(CancellationToken cancellationToken)
+        public Task SendRestartRequiredNotification(SystemInfo info, CancellationToken cancellationToken)
         {
         {
-            return SendMessage(new WebSocketMessage<SystemInfo>
-            {
-                MessageType = "RestartRequired",
-                Data = _appHost.GetSystemInfo()
-
-            }, cancellationToken);
+            return SendMessage("RestartRequired", cancellationToken);
         }
         }
 
 
         public Task SendUserDataChangeInfo(UserDataChangeInfo info, CancellationToken cancellationToken)
         public Task SendUserDataChangeInfo(UserDataChangeInfo info, CancellationToken cancellationToken)
@@ -120,22 +131,12 @@ namespace MediaBrowser.Server.Implementations.Session
 
 
         public Task SendServerShutdownNotification(CancellationToken cancellationToken)
         public Task SendServerShutdownNotification(CancellationToken cancellationToken)
         {
         {
-            return SendMessage(new WebSocketMessage<string>
-            {
-                MessageType = "ServerShuttingDown",
-                Data = string.Empty
-
-            }, cancellationToken);
+            return SendMessage("ServerShuttingDown", cancellationToken);
         }
         }
 
 
         public Task SendServerRestartNotification(CancellationToken cancellationToken)
         public Task SendServerRestartNotification(CancellationToken cancellationToken)
         {
         {
-            return SendMessage(new WebSocketMessage<string>
-            {
-                MessageType = "ServerRestarting",
-                Data = string.Empty
-
-            }, cancellationToken);
+            return SendMessage("ServerRestarting", cancellationToken);
         }
         }
 
 
         public Task SendGeneralCommand(GeneralCommand command, CancellationToken cancellationToken)
         public Task SendGeneralCommand(GeneralCommand command, CancellationToken cancellationToken)
@@ -147,5 +148,13 @@ namespace MediaBrowser.Server.Implementations.Session
 
 
             }, cancellationToken);
             }, cancellationToken);
         }
         }
+
+        private string ToQueryString(Dictionary<string, string> nvc)
+        {
+            var array = (from item in nvc
+                         select string.Format("{0}={1}", WebUtility.UrlEncode(item.Key), WebUtility.UrlEncode(item.Value)))
+                .ToArray();
+            return "?" + string.Join("&", array);
+        }
     }
     }
 }
 }

+ 28 - 4
MediaBrowser.Server.Implementations/Session/SessionManager.cs

@@ -1,6 +1,7 @@
-using System.Globalization;
-using MediaBrowser.Common.Events;
+using MediaBrowser.Common.Events;
 using MediaBrowser.Common.Extensions;
 using MediaBrowser.Common.Extensions;
+using MediaBrowser.Common.Net;
+using MediaBrowser.Controller;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Drawing;
 using MediaBrowser.Controller.Drawing;
 using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Dto;
@@ -14,10 +15,12 @@ using MediaBrowser.Controller.Session;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Library;
 using MediaBrowser.Model.Library;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Serialization;
 using MediaBrowser.Model.Session;
 using MediaBrowser.Model.Session;
 using System;
 using System;
 using System.Collections.Concurrent;
 using System.Collections.Concurrent;
 using System.Collections.Generic;
 using System.Collections.Generic;
+using System.Globalization;
 using System.Linq;
 using System.Linq;
 using System.Threading;
 using System.Threading;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
@@ -51,6 +54,10 @@ namespace MediaBrowser.Server.Implementations.Session
         private readonly IImageProcessor _imageProcessor;
         private readonly IImageProcessor _imageProcessor;
         private readonly IItemRepository _itemRepo;
         private readonly IItemRepository _itemRepo;
 
 
+        private readonly IHttpClient _httpClient;
+        private readonly IJsonSerializer _jsonSerializer;
+        private readonly IServerApplicationHost _appHost;
+
         /// <summary>
         /// <summary>
         /// Gets or sets the configuration manager.
         /// Gets or sets the configuration manager.
         /// </summary>
         /// </summary>
@@ -93,7 +100,7 @@ namespace MediaBrowser.Server.Implementations.Session
         /// <param name="logger">The logger.</param>
         /// <param name="logger">The logger.</param>
         /// <param name="userRepository">The user repository.</param>
         /// <param name="userRepository">The user repository.</param>
         /// <param name="libraryManager">The library manager.</param>
         /// <param name="libraryManager">The library manager.</param>
-        public SessionManager(IUserDataManager userDataRepository, IServerConfigurationManager configurationManager, ILogger logger, IUserRepository userRepository, ILibraryManager libraryManager, IUserManager userManager, IMusicManager musicManager, IDtoService dtoService, IImageProcessor imageProcessor, IItemRepository itemRepo)
+        public SessionManager(IUserDataManager userDataRepository, IServerConfigurationManager configurationManager, ILogger logger, IUserRepository userRepository, ILibraryManager libraryManager, IUserManager userManager, IMusicManager musicManager, IDtoService dtoService, IImageProcessor imageProcessor, IItemRepository itemRepo, IJsonSerializer jsonSerializer, IServerApplicationHost appHost, IHttpClient httpClient)
         {
         {
             _userDataRepository = userDataRepository;
             _userDataRepository = userDataRepository;
             _configurationManager = configurationManager;
             _configurationManager = configurationManager;
@@ -105,6 +112,9 @@ namespace MediaBrowser.Server.Implementations.Session
             _dtoService = dtoService;
             _dtoService = dtoService;
             _imageProcessor = imageProcessor;
             _imageProcessor = imageProcessor;
             _itemRepo = itemRepo;
             _itemRepo = itemRepo;
+            _jsonSerializer = jsonSerializer;
+            _appHost = appHost;
+            _httpClient = httpClient;
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -908,11 +918,13 @@ namespace MediaBrowser.Server.Implementations.Session
         {
         {
             var sessions = Sessions.Where(i => i.IsActive && i.SessionController != null).ToList();
             var sessions = Sessions.Where(i => i.IsActive && i.SessionController != null).ToList();
 
 
+            var info = _appHost.GetSystemInfo();
+
             var tasks = sessions.Select(session => Task.Run(async () =>
             var tasks = sessions.Select(session => Task.Run(async () =>
             {
             {
                 try
                 try
                 {
                 {
-                    await session.SessionController.SendRestartRequiredNotification(cancellationToken).ConfigureAwait(false);
+                    await session.SessionController.SendRestartRequiredNotification(info, cancellationToken).ConfigureAwait(false);
                 }
                 }
                 catch (Exception ex)
                 catch (Exception ex)
                 {
                 {
@@ -1135,6 +1147,18 @@ namespace MediaBrowser.Server.Implementations.Session
             session.PlayableMediaTypes = capabilities.PlayableMediaTypes;
             session.PlayableMediaTypes = capabilities.PlayableMediaTypes;
             session.SupportedCommands = capabilities.SupportedCommands;
             session.SupportedCommands = capabilities.SupportedCommands;
 
 
+            if (!string.IsNullOrWhiteSpace(capabilities.MessageCallbackUrl))
+            {
+                var postUrl = string.Format("http://{0}{1}", session.RemoteEndPoint, capabilities.MessageCallbackUrl);
+
+                var controller = session.SessionController as HttpSessionController;
+
+                if (controller == null)
+                {
+                    session.SessionController = new HttpSessionController(_httpClient, _jsonSerializer, session, postUrl);
+                }
+            }
+
             EventHelper.FireEventIfNotNull(CapabilitiesChanged, this, new SessionEventArgs
             EventHelper.FireEventIfNotNull(CapabilitiesChanged, this, new SessionEventArgs
             {
             {
                 SessionInfo = session
                 SessionInfo = session

+ 3 - 5
MediaBrowser.Server.Implementations/Session/SessionWebSocketListener.cs

@@ -35,19 +35,17 @@ namespace MediaBrowser.Server.Implementations.Session
         /// The _dto service
         /// The _dto service
         /// </summary>
         /// </summary>
         private readonly IJsonSerializer _json;
         private readonly IJsonSerializer _json;
-        private readonly IServerApplicationHost _appHost;
 
 
         /// <summary>
         /// <summary>
         /// Initializes a new instance of the <see cref="SessionWebSocketListener" /> class.
         /// Initializes a new instance of the <see cref="SessionWebSocketListener" /> class.
         /// </summary>
         /// </summary>
         /// <param name="sessionManager">The session manager.</param>
         /// <param name="sessionManager">The session manager.</param>
         /// <param name="logManager">The log manager.</param>
         /// <param name="logManager">The log manager.</param>
-        /// <param name="appHost">The application host.</param>
-        public SessionWebSocketListener(ISessionManager sessionManager, ILogManager logManager, IServerApplicationHost appHost, IJsonSerializer json)
+        /// <param name="json">The json.</param>
+        public SessionWebSocketListener(ISessionManager sessionManager, ILogManager logManager, IJsonSerializer json)
         {
         {
             _sessionManager = sessionManager;
             _sessionManager = sessionManager;
             _logger = logManager.GetLogger(GetType().Name);
             _logger = logManager.GetLogger(GetType().Name);
-            _appHost = appHost;
             _json = json;
             _json = json;
         }
         }
 
 
@@ -138,7 +136,7 @@ namespace MediaBrowser.Server.Implementations.Session
 
 
                 if (controller == null)
                 if (controller == null)
                 {
                 {
-                    controller = new WebSocketController(session, _appHost, _logger, _sessionManager);
+                    controller = new WebSocketController(session, _logger, _sessionManager);
                 }
                 }
 
 
                 controller.AddWebSocket(message.Connection);
                 controller.AddWebSocket(message.Connection);

+ 4 - 6
MediaBrowser.Server.Implementations/Session/WebSocketController.cs

@@ -1,5 +1,4 @@
 using MediaBrowser.Common.Net;
 using MediaBrowser.Common.Net;
-using MediaBrowser.Controller;
 using MediaBrowser.Controller.Session;
 using MediaBrowser.Controller.Session;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Logging;
@@ -19,15 +18,13 @@ namespace MediaBrowser.Server.Implementations.Session
         public SessionInfo Session { get; private set; }
         public SessionInfo Session { get; private set; }
         public IReadOnlyList<IWebSocketConnection> Sockets { get; private set; }
         public IReadOnlyList<IWebSocketConnection> Sockets { get; private set; }
 
 
-        private readonly IServerApplicationHost _appHost;
         private readonly ILogger _logger;
         private readonly ILogger _logger;
 
 
         private readonly ISessionManager _sessionManager;
         private readonly ISessionManager _sessionManager;
 
 
-        public WebSocketController(SessionInfo session, IServerApplicationHost appHost, ILogger logger, ISessionManager sessionManager)
+        public WebSocketController(SessionInfo session, ILogger logger, ISessionManager sessionManager)
         {
         {
             Session = session;
             Session = session;
-            _appHost = appHost;
             _logger = logger;
             _logger = logger;
             _sessionManager = sessionManager;
             _sessionManager = sessionManager;
             Sockets = new List<IWebSocketConnection>();
             Sockets = new List<IWebSocketConnection>();
@@ -121,14 +118,15 @@ namespace MediaBrowser.Server.Implementations.Session
         /// <summary>
         /// <summary>
         /// Sends the restart required message.
         /// Sends the restart required message.
         /// </summary>
         /// </summary>
+        /// <param name="info">The information.</param>
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>Task.</returns>
         /// <returns>Task.</returns>
-        public Task SendRestartRequiredNotification(CancellationToken cancellationToken)
+        public Task SendRestartRequiredNotification(SystemInfo info, CancellationToken cancellationToken)
         {
         {
             return SendMessages(new WebSocketMessage<SystemInfo>
             return SendMessages(new WebSocketMessage<SystemInfo>
             {
             {
                 MessageType = "RestartRequired",
                 MessageType = "RestartRequired",
-                Data = _appHost.GetSystemInfo()
+                Data = info
 
 
             }, cancellationToken);
             }, cancellationToken);
         }
         }

+ 1 - 1
MediaBrowser.ServerApplication/ApplicationHost.cs

@@ -496,7 +496,7 @@ namespace MediaBrowser.ServerApplication
             DtoService = new DtoService(Logger, LibraryManager, UserManager, UserDataManager, ItemRepository, ImageProcessor, ServerConfigurationManager, FileSystemManager, ProviderManager);
             DtoService = new DtoService(Logger, LibraryManager, UserManager, UserDataManager, ItemRepository, ImageProcessor, ServerConfigurationManager, FileSystemManager, ProviderManager);
             RegisterSingleInstance(DtoService);
             RegisterSingleInstance(DtoService);
 
 
-            SessionManager = new SessionManager(UserDataManager, ServerConfigurationManager, Logger, UserRepository, LibraryManager, UserManager, musicManager, DtoService, ImageProcessor, ItemRepository);
+            SessionManager = new SessionManager(UserDataManager, ServerConfigurationManager, Logger, UserRepository, LibraryManager, UserManager, musicManager, DtoService, ImageProcessor, ItemRepository, JsonSerializer, this, HttpClient);
             RegisterSingleInstance(SessionManager);
             RegisterSingleInstance(SessionManager);
 
 
             var newsService = new Server.Implementations.News.NewsService(ApplicationPaths, JsonSerializer);
             var newsService = new Server.Implementations.News.NewsService(ApplicationPaths, JsonSerializer);

+ 2 - 2
Nuget/MediaBrowser.Common.Internal.nuspec

@@ -2,7 +2,7 @@
 <package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
 <package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
     <metadata>
     <metadata>
         <id>MediaBrowser.Common.Internal</id>
         <id>MediaBrowser.Common.Internal</id>
-        <version>3.0.367</version>
+        <version>3.0.369</version>
         <title>MediaBrowser.Common.Internal</title>
         <title>MediaBrowser.Common.Internal</title>
         <authors>Luke</authors>
         <authors>Luke</authors>
         <owners>ebr,Luke,scottisafool</owners>
         <owners>ebr,Luke,scottisafool</owners>
@@ -12,7 +12,7 @@
         <description>Contains common components shared by Media Browser Theater and Media Browser Server. Not intended for plugin developer consumption.</description>
         <description>Contains common components shared by Media Browser Theater and Media Browser Server. Not intended for plugin developer consumption.</description>
         <copyright>Copyright © Media Browser 2013</copyright>
         <copyright>Copyright © Media Browser 2013</copyright>
         <dependencies>
         <dependencies>
-            <dependency id="MediaBrowser.Common" version="3.0.367" />
+            <dependency id="MediaBrowser.Common" version="3.0.369" />
             <dependency id="NLog" version="2.1.0" />
             <dependency id="NLog" version="2.1.0" />
             <dependency id="SimpleInjector" version="2.5.0" />
             <dependency id="SimpleInjector" version="2.5.0" />
             <dependency id="sharpcompress" version="0.10.2" />
             <dependency id="sharpcompress" version="0.10.2" />

+ 1 - 1
Nuget/MediaBrowser.Common.nuspec

@@ -2,7 +2,7 @@
 <package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
 <package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
     <metadata>
     <metadata>
         <id>MediaBrowser.Common</id>
         <id>MediaBrowser.Common</id>
-        <version>3.0.367</version>
+        <version>3.0.369</version>
         <title>MediaBrowser.Common</title>
         <title>MediaBrowser.Common</title>
         <authors>Media Browser Team</authors>
         <authors>Media Browser Team</authors>
         <owners>ebr,Luke,scottisafool</owners>
         <owners>ebr,Luke,scottisafool</owners>

+ 2 - 2
Nuget/MediaBrowser.Server.Core.nuspec

@@ -2,7 +2,7 @@
 <package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
 <package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
     <metadata>
     <metadata>
         <id>MediaBrowser.Server.Core</id>
         <id>MediaBrowser.Server.Core</id>
-        <version>3.0.367</version>
+        <version>3.0.369</version>
         <title>Media Browser.Server.Core</title>
         <title>Media Browser.Server.Core</title>
         <authors>Media Browser Team</authors>
         <authors>Media Browser Team</authors>
         <owners>ebr,Luke,scottisafool</owners>
         <owners>ebr,Luke,scottisafool</owners>
@@ -12,7 +12,7 @@
         <description>Contains core components required to build plugins for Media Browser Server.</description>
         <description>Contains core components required to build plugins for Media Browser Server.</description>
         <copyright>Copyright © Media Browser 2013</copyright>
         <copyright>Copyright © Media Browser 2013</copyright>
         <dependencies>
         <dependencies>
-            <dependency id="MediaBrowser.Common" version="3.0.367" />
+            <dependency id="MediaBrowser.Common" version="3.0.369" />
         </dependencies>
         </dependencies>
     </metadata>
     </metadata>
     <files>
     <files>