2
0
Эх сурвалжийг харах

added out of network bitrate limit

Luke Pulverenti 10 жил өмнө
parent
commit
b9c656e859
24 өөрчлөгдсөн 136 нэмэгдсэн , 73 устгасан
  1. 7 2
      Emby.Drawing/GDI/GDIImageEncoder.cs
  2. 5 0
      Emby.Drawing/IImageEncoder.cs
  3. 5 0
      Emby.Drawing/ImageMagick/ImageMagickEncoder.cs
  4. 3 3
      MediaBrowser.Api/LiveTv/LiveTvService.cs
  5. 1 1
      MediaBrowser.Api/Playback/BaseStreamingService.cs
  6. 26 11
      MediaBrowser.Api/Playback/MediaInfoService.cs
  7. 2 2
      MediaBrowser.Api/Subtitles/SubtitleService.cs
  8. 4 9
      MediaBrowser.Common.Implementations/BaseApplicationHost.cs
  9. 8 4
      MediaBrowser.Common.Implementations/Networking/BaseNetworkManager.cs
  10. 4 12
      MediaBrowser.Controller/Library/IMediaSourceManager.cs
  11. 1 2
      MediaBrowser.Controller/Providers/IImageEnhancer.cs
  12. 1 1
      MediaBrowser.Dlna/PlayTo/PlayToController.cs
  13. 1 1
      MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs
  14. 1 1
      MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs
  15. 1 0
      MediaBrowser.Model/Configuration/ServerConfiguration.cs
  16. 2 0
      MediaBrowser.Model/Session/ClientCapabilities.cs
  17. 6 4
      MediaBrowser.Model/Users/UserPolicy.cs
  18. 18 10
      MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs
  19. 1 1
      MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json
  20. 6 2
      MediaBrowser.Server.Implementations/Localization/Server/server.json
  21. 2 5
      MediaBrowser.Server.Implementations/Session/SessionManager.cs
  22. 24 2
      MediaBrowser.Server.Implementations/Sync/CloudSyncProfile.cs
  23. 1 0
      MediaBrowser.WebDashboard/Api/PackageCreator.cs
  24. 6 0
      MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj

+ 7 - 2
Emby.Drawing/GDI/GDIImageEncoder.cs

@@ -1,5 +1,4 @@
-using System.Linq;
-using MediaBrowser.Common.IO;
+using MediaBrowser.Common.IO;
 using MediaBrowser.Controller.Drawing;
 using MediaBrowser.Model.Drawing;
 using MediaBrowser.Model.Logging;
@@ -8,6 +7,7 @@ using System.Drawing;
 using System.Drawing.Drawing2D;
 using System.Drawing.Imaging;
 using System.IO;
+using System.Linq;
 using ImageFormat = MediaBrowser.Model.Drawing.ImageFormat;
 
 namespace Emby.Drawing.GDI
@@ -245,5 +245,10 @@ namespace Emby.Drawing.GDI
         public void Dispose()
         {
         }
+
+        public string Name
+        {
+            get { return "GDI"; }
+        }
     }
 }

+ 5 - 0
Emby.Drawing/IImageEncoder.cs

@@ -44,5 +44,10 @@ namespace Emby.Drawing
         /// </summary>
         /// <param name="options">The options.</param>
         void CreateImageCollage(ImageCollageOptions options);
+        /// <summary>
+        /// Gets the name.
+        /// </summary>
+        /// <value>The name.</value>
+        string Name { get; }
     }
 }

+ 5 - 0
Emby.Drawing/ImageMagick/ImageMagickEncoder.cs

@@ -206,6 +206,11 @@ namespace Emby.Drawing.ImageMagick
             }
         }
 
+        public string Name
+        {
+            get { return "ImageMagick"; }
+        }
+
         private bool _disposed;
         public void Dispose()
         {

+ 3 - 3
MediaBrowser.Api/LiveTv/LiveTvService.cs

@@ -433,7 +433,7 @@ namespace MediaBrowser.Api.LiveTv
 
             var result = await _liveTvManager.GetPrograms(query, CancellationToken.None).ConfigureAwait(false);
 
-            return ToOptimizedSerializedResultUsingCache(result);
+            return ToOptimizedResult(result);
         }
 
         public async Task<object> Get(GetRecommendedPrograms request)
@@ -450,7 +450,7 @@ namespace MediaBrowser.Api.LiveTv
 
             var result = await _liveTvManager.GetRecommendedPrograms(query, CancellationToken.None).ConfigureAwait(false);
 
-            return ToOptimizedSerializedResultUsingCache(result);
+            return ToOptimizedResult(result);
         }
 
         public object Post(GetPrograms request)
@@ -473,7 +473,7 @@ namespace MediaBrowser.Api.LiveTv
 
             }, CancellationToken.None).ConfigureAwait(false);
 
-            return ToOptimizedSerializedResultUsingCache(result);
+            return ToOptimizedResult(result);
         }
 
         public async Task<object> Get(GetRecording request)

+ 1 - 1
MediaBrowser.Api/Playback/BaseStreamingService.cs

@@ -1627,7 +1627,7 @@ namespace MediaBrowser.Api.Playback
             MediaSourceInfo mediaSource;
             if (string.IsNullOrWhiteSpace(request.LiveStreamId))
             {
-                var mediaSources = (await MediaSourceManager.GetPlayackMediaSources(request.Id, false, cancellationToken).ConfigureAwait(false)).ToList();
+                var mediaSources = (await MediaSourceManager.GetPlayackMediaSources(request.Id, null, false, new[] { MediaType.Audio, MediaType.Video }, cancellationToken).ConfigureAwait(false)).ToList();
 
                 mediaSource = string.IsNullOrEmpty(request.MediaSourceId)
                    ? mediaSources.First()

+ 26 - 11
MediaBrowser.Api/Playback/MediaInfoService.cs

@@ -1,4 +1,6 @@
-using MediaBrowser.Controller.Devices;
+using MediaBrowser.Common.Net;
+using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.Devices;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Net;
@@ -59,23 +61,27 @@ namespace MediaBrowser.Api.Playback
         private readonly IMediaSourceManager _mediaSourceManager;
         private readonly IDeviceManager _deviceManager;
         private readonly ILibraryManager _libraryManager;
+        private readonly IServerConfigurationManager _config;
+        private readonly INetworkManager _networkManager;
 
-        public MediaInfoService(IMediaSourceManager mediaSourceManager, IDeviceManager deviceManager, ILibraryManager libraryManager)
+        public MediaInfoService(IMediaSourceManager mediaSourceManager, IDeviceManager deviceManager, ILibraryManager libraryManager, IServerConfigurationManager config, INetworkManager networkManager)
         {
             _mediaSourceManager = mediaSourceManager;
             _deviceManager = deviceManager;
             _libraryManager = libraryManager;
+            _config = config;
+            _networkManager = networkManager;
         }
 
         public async Task<object> Get(GetPlaybackInfo request)
         {
-            var result = await GetPlaybackInfo(request.Id, request.UserId).ConfigureAwait(false);
+            var result = await GetPlaybackInfo(request.Id, request.UserId, new[] { MediaType.Audio, MediaType.Video }).ConfigureAwait(false);
             return ToOptimizedResult(result);
         }
 
         public async Task<object> Get(GetLiveMediaInfo request)
         {
-            var result = await GetPlaybackInfo(request.Id, request.UserId).ConfigureAwait(false);
+            var result = await GetPlaybackInfo(request.Id, request.UserId, new[] { MediaType.Audio, MediaType.Video }).ConfigureAwait(false);
             return ToOptimizedResult(result);
         }
 
@@ -122,29 +128,38 @@ namespace MediaBrowser.Api.Playback
 
         public async Task<object> Post(GetPostedPlaybackInfo request)
         {
-            var info = await GetPlaybackInfo(request.Id, request.UserId, request.MediaSourceId, request.LiveStreamId).ConfigureAwait(false);
             var authInfo = AuthorizationContext.GetAuthorizationInfo(Request);
 
             var profile = request.DeviceProfile;
-            if (profile == null)
+
+            var caps = _deviceManager.GetCapabilities(authInfo.DeviceId);
+            if (caps != null)
             {
-                var caps = _deviceManager.GetCapabilities(authInfo.DeviceId);
-                if (caps != null)
+                if (profile == null)
                 {
                     profile = caps.DeviceProfile;
                 }
             }
 
+            var maxBitrate = request.MaxStreamingBitrate;
+
+            if (_config.Configuration.RemoteClientBitrateLimit > 0 && !_networkManager.IsInLocalNetwork(Request.RemoteIp))
+            {
+                maxBitrate = Math.Min(maxBitrate ?? _config.Configuration.RemoteClientBitrateLimit, _config.Configuration.RemoteClientBitrateLimit);
+            }
+
+            var info = await GetPlaybackInfo(request.Id, request.UserId, new[] { MediaType.Audio, MediaType.Video }, request.MediaSourceId, request.LiveStreamId).ConfigureAwait(false);
+
             if (profile != null)
             {
                 var mediaSourceId = request.MediaSourceId;
-                SetDeviceSpecificData(request.Id, info, profile, authInfo, request.MaxStreamingBitrate, request.StartTimeTicks ?? 0, mediaSourceId, request.AudioStreamIndex, request.SubtitleStreamIndex);
+                SetDeviceSpecificData(request.Id, info, profile, authInfo, maxBitrate, request.StartTimeTicks ?? 0, mediaSourceId, request.AudioStreamIndex, request.SubtitleStreamIndex);
             }
 
             return ToOptimizedResult(info);
         }
 
-        private async Task<PlaybackInfoResponse> GetPlaybackInfo(string id, string userId, string mediaSourceId = null, string liveStreamId = null)
+        private async Task<PlaybackInfoResponse> GetPlaybackInfo(string id, string userId, string[] supportedLiveMediaTypes, string mediaSourceId = null, string liveStreamId = null)
         {
             var result = new PlaybackInfoResponse();
 
@@ -153,7 +168,7 @@ namespace MediaBrowser.Api.Playback
                 IEnumerable<MediaSourceInfo> mediaSources;
                 try
                 {
-                    mediaSources = await _mediaSourceManager.GetPlayackMediaSources(id, userId, true, CancellationToken.None).ConfigureAwait(false);
+                    mediaSources = await _mediaSourceManager.GetPlayackMediaSources(id, userId, true, supportedLiveMediaTypes, CancellationToken.None).ConfigureAwait(false);
                 }
                 catch (PlaybackException ex)
                 {

+ 2 - 2
MediaBrowser.Api/Subtitles/SubtitleService.cs

@@ -136,11 +136,11 @@ namespace MediaBrowser.Api.Subtitles
             _providerManager = providerManager;
         }
 
-        public object Get(GetSubtitlePlaylist request)
+        public async Task<object> Get(GetSubtitlePlaylist request)
         {
             var item = (Video)_libraryManager.GetItemById(new Guid(request.Id));
 
-            var mediaSource = _mediaSourceManager.GetStaticMediaSource(item, request.MediaSourceId, false);
+            var mediaSource = await _mediaSourceManager.GetMediaSource(item, request.MediaSourceId, false).ConfigureAwait(false);
 
             var builder = new StringBuilder();
 

+ 4 - 9
MediaBrowser.Common.Implementations/BaseApplicationHost.cs

@@ -101,12 +101,6 @@ namespace MediaBrowser.Common.Implementations
         /// <value>The failed assemblies.</value>
         public List<string> FailedAssemblies { get; protected set; }
 
-        /// <summary>
-        /// Gets all types within all running assemblies
-        /// </summary>
-        /// <value>All types.</value>
-        public Type[] AllTypes { get; protected set; }
-
         /// <summary>
         /// Gets all concrete types.
         /// </summary>
@@ -438,9 +432,10 @@ namespace MediaBrowser.Common.Implementations
                 Logger.Info("Loading {0}", assembly.FullName);
             }
 
-            AllTypes = assemblies.SelectMany(GetTypes).ToArray();
-
-            AllConcreteTypes = AllTypes.Where(t => t.IsClass && !t.IsAbstract && !t.IsInterface && !t.IsGenericType).ToArray();
+            AllConcreteTypes = assemblies
+                .SelectMany(GetTypes)
+                .Where(t => t.IsClass && !t.IsAbstract && !t.IsInterface && !t.IsGenericType)
+                .ToArray();
         }
 
         /// <summary>

+ 8 - 4
MediaBrowser.Common.Implementations/Networking/BaseNetworkManager.cs

@@ -172,11 +172,11 @@ namespace MediaBrowser.Common.Implementations.Networking
                 Uri uri;
                 if (Uri.TryCreate(endpoint, UriKind.RelativeOrAbsolute, out uri))
                 {
-                    var host = uri.DnsSafeHost;
-                    Logger.Debug("Resolving host {0}", host);
-
                     try
                     {
+                        var host = uri.DnsSafeHost;
+                        Logger.Debug("Resolving host {0}", host);
+
                         address = GetIpAddresses(host).FirstOrDefault();
 
                         if (address != null)
@@ -186,9 +186,13 @@ namespace MediaBrowser.Common.Implementations.Networking
                             return IsInLocalNetworkInternal(address.ToString(), false);
                         }
                     }
+                    catch (InvalidOperationException)
+                    {
+                        // Can happen with reverse proxy or IIS url rewriting
+                    }
                     catch (Exception ex)
                     {
-                        Logger.ErrorException("Error resovling hostname {0}", ex, host);
+                        Logger.ErrorException("Error resovling hostname", ex);
                     }
                 }
             }

+ 4 - 12
MediaBrowser.Controller/Library/IMediaSourceManager.cs

@@ -43,18 +43,10 @@ namespace MediaBrowser.Controller.Library
         /// <param name="id">The identifier.</param>
         /// <param name="userId">The user identifier.</param>
         /// <param name="enablePathSubstitution">if set to <c>true</c> [enable path substitution].</param>
+        /// <param name="supportedLiveMediaTypes">The supported live media types.</param>
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>IEnumerable&lt;MediaSourceInfo&gt;.</returns>
-        Task<IEnumerable<MediaSourceInfo>> GetPlayackMediaSources(string id, string userId, bool enablePathSubstitution, CancellationToken cancellationToken);
-
-        /// <summary>
-        /// Gets the playack media sources.
-        /// </summary>
-        /// <param name="id">The identifier.</param>
-        /// <param name="enablePathSubstitution">if set to <c>true</c> [enable path substitution].</param>
-        /// <param name="cancellationToken">The cancellation token.</param>
-        /// <returns>Task&lt;IEnumerable&lt;MediaSourceInfo&gt;&gt;.</returns>
-        Task<IEnumerable<MediaSourceInfo>> GetPlayackMediaSources(string id, bool enablePathSubstitution, CancellationToken cancellationToken);
+        Task<IEnumerable<MediaSourceInfo>> GetPlayackMediaSources(string id, string userId, bool enablePathSubstitution, string[] supportedLiveMediaTypes, CancellationToken cancellationToken);
 
         /// <summary>
         /// Gets the static media sources.
@@ -64,7 +56,7 @@ namespace MediaBrowser.Controller.Library
         /// <param name="user">The user.</param>
         /// <returns>IEnumerable&lt;MediaSourceInfo&gt;.</returns>
         IEnumerable<MediaSourceInfo> GetStaticMediaSources(IHasMediaSources item, bool enablePathSubstitution, User user = null);
-        
+
         /// <summary>
         /// Gets the static media source.
         /// </summary>
@@ -72,7 +64,7 @@ namespace MediaBrowser.Controller.Library
         /// <param name="mediaSourceId">The media source identifier.</param>
         /// <param name="enablePathSubstitution">if set to <c>true</c> [enable path substitution].</param>
         /// <returns>MediaSourceInfo.</returns>
-        MediaSourceInfo GetStaticMediaSource(IHasMediaSources item, string mediaSourceId, bool enablePathSubstitution);
+        Task<MediaSourceInfo> GetMediaSource(IHasMediaSources item, string mediaSourceId, bool enablePathSubstitution);
 
         /// <summary>
         /// Opens the media source.

+ 1 - 2
MediaBrowser.Controller/Providers/IImageEnhancer.cs

@@ -1,5 +1,4 @@
-using MediaBrowser.Controller.Drawing;
-using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities;
 using MediaBrowser.Model.Drawing;
 using MediaBrowser.Model.Entities;
 using System.Threading.Tasks;

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

@@ -892,7 +892,7 @@ namespace MediaBrowser.Dlna.PlayTo
 
                 request.MediaSource = hasMediaSources == null ?
                     null :
-                    mediaSourceManager.GetStaticMediaSource(hasMediaSources, request.MediaSourceId, false);
+                    mediaSourceManager.GetMediaSource(hasMediaSources, request.MediaSourceId, false).Result;
 
 
 

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

@@ -59,7 +59,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
 
             state.IsInputVideo = string.Equals(item.MediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase);
 
-            var mediaSources = await _mediaSourceManager.GetPlayackMediaSources(request.ItemId, false, cancellationToken).ConfigureAwait(false);
+            var mediaSources = await _mediaSourceManager.GetPlayackMediaSources(request.ItemId, null, false, new[] { MediaType.Audio, MediaType.Video }, cancellationToken).ConfigureAwait(false);
 
             var mediaSource = string.IsNullOrEmpty(request.MediaSourceId)
                ? mediaSources.First()

+ 1 - 1
MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs

@@ -132,7 +132,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
             int subtitleStreamIndex,
             CancellationToken cancellationToken)
         {
-            var mediaSources = await _mediaSourceManager.GetPlayackMediaSources(itemId, false, cancellationToken).ConfigureAwait(false);
+            var mediaSources = await _mediaSourceManager.GetPlayackMediaSources(itemId, null, false, new[] { MediaType.Audio, MediaType.Video }, cancellationToken).ConfigureAwait(false);
 
             var mediaSource = mediaSources
                 .First(i => string.Equals(i.Id, mediaSourceId));

+ 1 - 0
MediaBrowser.Model/Configuration/ServerConfiguration.cs

@@ -208,6 +208,7 @@ namespace MediaBrowser.Model.Configuration
 
         public bool EnableAudioArchiveFiles { get; set; }
         public bool EnableVideoArchiveFiles { get; set; }
+        public int RemoteClientBitrateLimit { get; set; }
 
         /// <summary>
         /// Initializes a new instance of the <see cref="ServerConfiguration" /> class.

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

@@ -19,12 +19,14 @@ namespace MediaBrowser.Model.Session
         public bool SupportsOfflineAccess { get; set; }
 
         public DeviceProfile DeviceProfile { get; set; }
+        public List<string> SupportedLiveMediaTypes { get; set; }
 
         public ClientCapabilities()
         {
             PlayableMediaTypes = new List<string>();
             SupportedCommands = new List<string>();
             SupportsPersistentIdentifier = true;
+            SupportedLiveMediaTypes = new List<string>();
         }
     }
 }

+ 6 - 4
MediaBrowser.Model/Users/UserPolicy.cs

@@ -39,8 +39,9 @@ namespace MediaBrowser.Model.Users
         public bool EnableLiveTvAccess { get; set; }
 
         public bool EnableMediaPlayback { get; set; }
-        public bool EnableMediaPlaybackTranscoding { get; set; }
-        
+        public bool EnableAudioPlaybackTranscoding { get; set; }
+        public bool EnableVideoPlaybackTranscoding { get; set; }
+   
         public bool EnableContentDeletion { get; set; }
         public bool EnableContentDownloading { get; set; }
 
@@ -68,8 +69,9 @@ namespace MediaBrowser.Model.Users
             EnableSyncTranscoding = true;
 
             EnableMediaPlayback = true;
-            EnableMediaPlaybackTranscoding = true;
-            
+            EnableAudioPlaybackTranscoding = true;
+            EnableVideoPlaybackTranscoding = true;
+     
             EnableLiveTvManagement = true;
             EnableLiveTvAccess = true;
 

+ 18 - 10
MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs

@@ -129,12 +129,7 @@ namespace MediaBrowser.Server.Implementations.Library
             return list;
         }
 
-        public Task<IEnumerable<MediaSourceInfo>> GetPlayackMediaSources(string id, bool enablePathSubstitution, CancellationToken cancellationToken)
-        {
-            return GetPlayackMediaSources(id, null, enablePathSubstitution, cancellationToken);
-        }
-
-        public async Task<IEnumerable<MediaSourceInfo>> GetPlayackMediaSources(string id, string userId, bool enablePathSubstitution, CancellationToken cancellationToken)
+        public async Task<IEnumerable<MediaSourceInfo>> GetPlayackMediaSources(string id, string userId, bool enablePathSubstitution, string[] supportedLiveMediaTypes, CancellationToken cancellationToken)
         {
             var item = _libraryManager.GetItemById(id);
 
@@ -184,9 +179,19 @@ namespace MediaBrowser.Server.Implementations.Library
             {
                 if (user != null)
                 {
-                    if (!user.Policy.EnableMediaPlaybackTranscoding)
+                    if (string.Equals(item.MediaType, MediaType.Audio, StringComparison.OrdinalIgnoreCase))
                     {
-                        source.SupportsTranscoding = false;
+                        if (!user.Policy.EnableAudioPlaybackTranscoding)
+                        {
+                            source.SupportsTranscoding = false;
+                        }
+                    }
+                    else if (string.Equals(item.MediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase))
+                    {
+                        if (!user.Policy.EnableVideoPlaybackTranscoding)
+                        {
+                            source.SupportsTranscoding = false;
+                        }
                     }
                 }
             }
@@ -238,9 +243,12 @@ namespace MediaBrowser.Server.Implementations.Library
             }
         }
 
-        public MediaSourceInfo GetStaticMediaSource(IHasMediaSources item, string mediaSourceId, bool enablePathSubstitution)
+        public async Task<MediaSourceInfo> GetMediaSource(IHasMediaSources item, string mediaSourceId, bool enablePathSubstitution)
         {
-            return GetStaticMediaSources(item, enablePathSubstitution).FirstOrDefault(i => string.Equals(i.Id, mediaSourceId, StringComparison.OrdinalIgnoreCase));
+            var sources = await GetPlayackMediaSources(item.Id.ToString("N"), null, enablePathSubstitution, new[] { MediaType.Audio, MediaType.Video },
+                        CancellationToken.None).ConfigureAwait(false);
+
+            return sources.FirstOrDefault(i => string.Equals(i.Id, mediaSourceId, StringComparison.OrdinalIgnoreCase));
         }
 
         public IEnumerable<MediaSourceInfo> GetStaticMediaSources(IHasMediaSources item, bool enablePathSubstitution, User user = null)

+ 1 - 1
MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json

@@ -122,7 +122,7 @@
     "LabelFree": "Free",
     "HeaderPlaybackError": "Playback Error",
     "MessagePlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.",
-    "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later.",
+    "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later or contact your system administrator for details.",
     "MessagePlaybackErrorRateLimitExceeded": "Your playback rate limit has been exceeded. Please contact your system administrator for details.",
     "MessagePlaybackErrorPlaceHolder": "The content chosen is not playable from this device.",
     "HeaderSelectAudio": "Select Audio",

+ 6 - 2
MediaBrowser.Server.Implementations/Localization/Server/server.json

@@ -1410,6 +1410,10 @@
     "LabelUploadSpeedLimit": "Upload speed limit (mbps):",
     "OptionAllowSyncTranscoding": "Allow syncing that requires transcoding",
     "HeaderPlayback": "Media Playback",
-    "OptionAllowMediaPlaybackTranscoding": "Allow media playback that requires transcoding",
-    "OptionAllowMediaPlaybackTranscodingHelp": "Users will receive friendly messages when content is unplayable based on policy."
+    "OptionAllowAudioPlaybackTranscoding": "Allow audio playback that requires transcoding",
+    "OptionAllowVideoPlaybackTranscoding": "Allow video playback that requires transcoding",
+    "OptionAllowMediaPlaybackTranscodingHelp": "Users will receive friendly messages when content is unplayable based on policy.",
+    "TabStreaming": "Streaming",
+    "LabelRemoteClientBitrateLimit": "Remote client bitrate limit (mbps):",
+    "LabelRemoteClientBitrateLimitHelp": "An optional streaming bitrate limit for all remote clients. This is useful to prevent clients from requesting a higher bitrate than your connection can handle."
 }

+ 2 - 5
MediaBrowser.Server.Implementations/Session/SessionManager.cs

@@ -305,12 +305,9 @@ namespace MediaBrowser.Server.Implementations.Session
             }
         }
 
-        private async Task<MediaSourceInfo> GetMediaSource(IHasMediaSources item, string mediaSourceId)
+        private Task<MediaSourceInfo> GetMediaSource(IHasMediaSources item, string mediaSourceId)
         {
-            var sources = await _mediaSourceManager.GetPlayackMediaSources(item.Id.ToString("N"), false, CancellationToken.None)
-                        .ConfigureAwait(false);
-
-            return sources.FirstOrDefault(i => string.Equals(i.Id, mediaSourceId, StringComparison.OrdinalIgnoreCase));
+            return _mediaSourceManager.GetMediaSource(item, mediaSourceId, false);
         }
 
         /// <summary>

+ 24 - 2
MediaBrowser.Server.Implementations/Sync/CloudSyncProfile.cs

@@ -195,17 +195,39 @@ namespace MediaBrowser.Server.Implementations.Sync
                 }
             };
 
-            var maxAudioChannels = supportsAc3 || supportsDca ? "5" : "2";
             codecProfiles.Add(new CodecProfile
             {
                 Type = CodecType.VideoAudio,
+                Codec = "ac3",
                 Conditions = new[]
                     {
                         new ProfileCondition
                         {
                             Condition = ProfileConditionType.LessThanEqual,
                             Property = ProfileConditionValue.AudioChannels,
-                            Value = maxAudioChannels,
+                            Value = "5",
+                            IsRequired = true
+                        },
+                        new ProfileCondition
+                        {
+                            Condition = ProfileConditionType.Equals,
+                            Property = ProfileConditionValue.IsSecondaryAudio,
+                            Value = "false",
+                            IsRequired = false
+                        }
+                    }
+            });
+            codecProfiles.Add(new CodecProfile
+            {
+                Type = CodecType.VideoAudio,
+                Codec = "ac3",
+                Conditions = new[]
+                    {
+                        new ProfileCondition
+                        {
+                            Condition = ProfileConditionType.LessThanEqual,
+                            Property = ProfileConditionValue.AudioChannels,
+                            Value = "2",
                             IsRequired = true
                         },
                         new ProfileCondition

+ 1 - 0
MediaBrowser.WebDashboard/Api/PackageCreator.cs

@@ -482,6 +482,7 @@ namespace MediaBrowser.WebDashboard.Api
                                 "selectserver.js",
                                 "serversecurity.js",
                                 "songs.js",
+                                "streamingsettings.js",
                                 "supporterkeypage.js",
                                 "supporterpage.js",
                                 "syncactivity.js",

+ 6 - 0
MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj

@@ -150,6 +150,9 @@
     <Content Include="dashboard-ui\scripts\selectserver.js">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
+    <Content Include="dashboard-ui\scripts\streamingsettings.js">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
     <Content Include="dashboard-ui\scripts\syncjob.js">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
@@ -174,6 +177,9 @@
     <Content Include="dashboard-ui\selectserver.html">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
+    <Content Include="dashboard-ui\streamingsettings.html">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
     <Content Include="dashboard-ui\syncjob.html">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>