Browse Source

added out of network bitrate limit

Luke Pulverenti 10 năm trước cách đây
mục cha
commit
b9c656e859
24 tập tin đã thay đổi với 136 bổ sung73 xóa
  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>