Luke Pulverenti 10 лет назад
Родитель
Сommit
a79962b7eb

+ 6 - 3
MediaBrowser.Api/Playback/BaseStreamingService.cs

@@ -936,10 +936,13 @@ namespace MediaBrowser.Api.Playback
 
             if (state.MediaSource.RequiresOpening)
             {
-                var mediaSource = await MediaSourceManager.OpenLiveStream(state.MediaSource.OpenToken, false, cancellationTokenSource.Token)
-                            .ConfigureAwait(false);
+                var liveStreamResponse = await MediaSourceManager.OpenLiveStream(new LiveStreamRequest
+                {
+                    OpenToken = state.MediaSource.OpenToken
+
+                }, false, cancellationTokenSource.Token).ConfigureAwait(false);
 
-                AttachMediaSourceInfo(state, mediaSource, state.VideoRequest, state.RequestedUrl);
+                AttachMediaSourceInfo(state, liveStreamResponse.MediaSource, state.VideoRequest, state.RequestedUrl);
 
                 if (state.VideoRequest != null)
                 {

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

@@ -698,7 +698,7 @@ namespace MediaBrowser.Api.Playback.Hls
             {
                 var outputTsArg = Path.Combine(Path.GetDirectoryName(outputPath), Path.GetFileNameWithoutExtension(outputPath)) + "%d.ts";
 
-                return string.Format("{0} {1} -map_metadata -1 -threads {2} {3} {4} -copyts -flags -global_header {5} -f segment -segment_time {6} -segment_start_number {7} -segment_list \"{8}\" -y \"{9}\"",
+                return string.Format("{0} {1} -map_metadata -1 -threads {2} {3} {4} -copyts -flags -global_header -sc_threshold 0 {5} -f segment -segment_time {6} -segment_start_number {7} -segment_list \"{8}\" -y \"{9}\"",
                     inputModifier,
                     GetInputArgument(state),
                     threads,
@@ -712,7 +712,7 @@ namespace MediaBrowser.Api.Playback.Hls
                     ).Trim();
             }
 
-            return string.Format("{0} {1} -map_metadata -1 -threads {2} {3} {4} -copyts -flags -global_header {5} -hls_time {6} -start_number {7} -hls_list_size {8} -y \"{9}\"",
+            return string.Format("{0} {1} -map_metadata -1 -threads {2} {3} {4} -copyts -flags -global_header -sc_threshold 0 {5} -hls_time {6} -start_number {7} -hls_list_size {8} -y \"{9}\"",
                             inputModifier,
                             GetInputArgument(state),
                             threads,

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

@@ -61,14 +61,12 @@ namespace MediaBrowser.Api.Playback
         public string MediaSourceId { get; set; }
     }
 
-    [Route("/MediaSources/Open", "POST", Summary = "Opens a media source")]
-    public class OpenMediaSource : IReturn<MediaSourceInfo>
+    [Route("/LiveStreams/Open", "POST", Summary = "Opens a media source")]
+    public class OpenMediaSource : LiveStreamRequest, IReturn<LiveStreamResponse>
     {
-        [ApiMember(Name = "OpenToken", Description = "OpenToken", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
-        public string OpenToken { get; set; }
     }
 
-    [Route("/MediaSources/Close", "POST", Summary = "Closes a media source")]
+    [Route("/LiveStreams/Close", "POST", Summary = "Closes a media source")]
     public class CloseMediaSource : IReturnVoid
     {
         [ApiMember(Name = "LiveStreamId", Description = "LiveStreamId", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
@@ -103,7 +101,32 @@ namespace MediaBrowser.Api.Playback
 
         public async Task<object> Post(OpenMediaSource request)
         {
-            var result = await _mediaSourceManager.OpenLiveStream(request.OpenToken, false, CancellationToken.None).ConfigureAwait(false);
+            var authInfo = AuthorizationContext.GetAuthorizationInfo(Request);
+
+            var result = await _mediaSourceManager.OpenLiveStream(request, false, CancellationToken.None).ConfigureAwait(false);
+
+            var profile = request.DeviceProfile;
+            if (profile == null)
+            {
+                var caps = _deviceManager.GetCapabilities(authInfo.DeviceId);
+                if (caps != null)
+                {
+                    profile = caps.DeviceProfile;
+                }
+            }
+
+            if (profile != null)
+            {
+                var item = _libraryManager.GetItemById(request.ItemId);
+
+                SetDeviceSpecificData(item, result.MediaSource, profile, authInfo, request.MaxStreamingBitrate, request.StartTimeTicks ?? 0, result.MediaSource.Id, request.AudioStreamIndex, request.SubtitleStreamIndex);
+            }
+
+            if (!string.IsNullOrWhiteSpace(result.MediaSource.TranscodingUrl))
+            {
+                result.MediaSource.TranscodingUrl += "&LiveStreamId=" + result.MediaSource.LiveStreamId;
+            }
+
             return ToOptimizedResult(result);
         }
 
@@ -177,11 +200,11 @@ namespace MediaBrowser.Api.Playback
             return result;
         }
 
-        private void SetDeviceSpecificData(string itemId, 
-            PlaybackInfoResponse result, 
-            DeviceProfile profile, 
-            AuthorizationInfo auth, 
-            int? maxBitrate, 
+        private void SetDeviceSpecificData(string itemId,
+            PlaybackInfoResponse result,
+            DeviceProfile profile,
+            AuthorizationInfo auth,
+            int? maxBitrate,
             long startTimeTicks,
             string mediaSourceId,
             int? audioStreamIndex,

+ 3 - 2
MediaBrowser.Controller/Library/IMediaSourceManager.cs

@@ -2,6 +2,7 @@
 using MediaBrowser.Controller.Persistence;
 using MediaBrowser.Model.Dto;
 using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.MediaInfo;
 using System;
 using System.Collections.Generic;
 using System.Threading;
@@ -84,11 +85,11 @@ namespace MediaBrowser.Controller.Library
         /// <summary>
         /// Opens the media source.
         /// </summary>
-        /// <param name="openToken">The open token.</param>
+        /// <param name="request">The request.</param>
         /// <param name="enableAutoClose">if set to <c>true</c> [enable automatic close].</param>
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>Task&lt;MediaSourceInfo&gt;.</returns>
-        Task<MediaSourceInfo> OpenLiveStream(string openToken, bool enableAutoClose, CancellationToken cancellationToken);
+        Task<LiveStreamResponse> OpenLiveStream(LiveStreamRequest request, bool enableAutoClose, CancellationToken cancellationToken);
 
         /// <summary>
         /// Gets the live stream.

+ 6 - 0
MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj

@@ -803,6 +803,12 @@
     <Compile Include="..\MediaBrowser.Model\MediaInfo\IBlurayExaminer.cs">
       <Link>MediaInfo\IBlurayExaminer.cs</Link>
     </Compile>
+    <Compile Include="..\MediaBrowser.Model\MediaInfo\LiveStreamRequest.cs">
+      <Link>MediaInfo\LiveStreamRequest.cs</Link>
+    </Compile>
+    <Compile Include="..\MediaBrowser.Model\MediaInfo\LiveStreamResponse.cs">
+      <Link>MediaInfo\LiveStreamResponse.cs</Link>
+    </Compile>
     <Compile Include="..\MediaBrowser.Model\MediaInfo\MediaProtocol.cs">
       <Link>MediaInfo\MediaProtocol.cs</Link>
     </Compile>

+ 6 - 0
MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj

@@ -759,6 +759,12 @@
     <Compile Include="..\MediaBrowser.Model\MediaInfo\IBlurayExaminer.cs">
       <Link>MediaInfo\IBlurayExaminer.cs</Link>
     </Compile>
+    <Compile Include="..\MediaBrowser.Model\MediaInfo\LiveStreamRequest.cs">
+      <Link>MediaInfo\LiveStreamRequest.cs</Link>
+    </Compile>
+    <Compile Include="..\MediaBrowser.Model\MediaInfo\LiveStreamResponse.cs">
+      <Link>MediaInfo\LiveStreamResponse.cs</Link>
+    </Compile>
     <Compile Include="..\MediaBrowser.Model\MediaInfo\MediaProtocol.cs">
       <Link>MediaInfo\MediaProtocol.cs</Link>
     </Compile>

+ 6 - 0
MediaBrowser.Model/ApiClient/IConnectionManager.cs

@@ -172,5 +172,11 @@ namespace MediaBrowser.Model.ApiClient
         /// <param name="rememberCredentials">if set to <c>true</c> [remember credentials].</param>
         /// <returns>Task.</returns>
         Task AuthenticateOffline(UserDto user, string password, bool rememberCredentials);
+
+        /// <summary>
+        /// Gets the offline users.
+        /// </summary>
+        /// <returns>Task&lt;List&lt;UserDto&gt;&gt;.</returns>
+        Task<List<UserDto>> GetOfflineUsers();
     }
 }

+ 2 - 0
MediaBrowser.Model/MediaBrowser.Model.csproj

@@ -141,6 +141,8 @@
     <Compile Include="Dto\MetadataEditorInfo.cs" />
     <Compile Include="Dto\NameIdPair.cs" />
     <Compile Include="Dto\NameValuePair.cs" />
+    <Compile Include="MediaInfo\LiveStreamRequest.cs" />
+    <Compile Include="MediaInfo\LiveStreamResponse.cs" />
     <Compile Include="MediaInfo\PlaybackInfoRequest.cs" />
     <Compile Include="MediaInfo\PlaybackInfoResponse.cs" />
     <Compile Include="Dto\MediaSourceType.cs" />

+ 16 - 0
MediaBrowser.Model/MediaInfo/LiveStreamRequest.cs

@@ -0,0 +1,16 @@
+using MediaBrowser.Model.Dlna;
+
+namespace MediaBrowser.Model.MediaInfo
+{
+    public class LiveStreamRequest
+    {
+        public string OpenToken { get; set; }
+        public string UserId { get; set; }
+        public int? MaxStreamingBitrate { get; set; }
+        public long? StartTimeTicks { get; set; }
+        public int? AudioStreamIndex { get; set; }
+        public int? SubtitleStreamIndex { get; set; }
+        public string ItemId { get; set; }
+        public DeviceProfile DeviceProfile { get; set; }
+    }
+}

+ 9 - 0
MediaBrowser.Model/MediaInfo/LiveStreamResponse.cs

@@ -0,0 +1,9 @@
+using MediaBrowser.Model.Dto;
+
+namespace MediaBrowser.Model.MediaInfo
+{
+    public class LiveStreamResponse
+    {
+        public MediaSourceInfo MediaSource { get; set; }
+    }
+}

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

@@ -1,5 +1,4 @@
-using System.Collections.Concurrent;
-using MediaBrowser.Common.Extensions;
+using MediaBrowser.Common.Extensions;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.MediaEncoding;
@@ -8,13 +7,14 @@ using MediaBrowser.Model.Dto;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.MediaInfo;
+using MediaBrowser.Model.Serialization;
 using System;
+using System.Collections.Concurrent;
 using System.Collections.Generic;
 using System.IO;
 using System.Linq;
 using System.Threading;
 using System.Threading.Tasks;
-using MediaBrowser.Server.Implementations.LiveTv;
 
 namespace MediaBrowser.Server.Implementations.Library
 {
@@ -23,16 +23,18 @@ namespace MediaBrowser.Server.Implementations.Library
         private readonly IItemRepository _itemRepo;
         private readonly IUserManager _userManager;
         private readonly ILibraryManager _libraryManager;
+        private readonly IJsonSerializer _jsonSerializer;
 
         private IMediaSourceProvider[] _providers;
         private readonly ILogger _logger;
 
-        public MediaSourceManager(IItemRepository itemRepo, IUserManager userManager, ILibraryManager libraryManager, ILogger logger)
+        public MediaSourceManager(IItemRepository itemRepo, IUserManager userManager, ILibraryManager libraryManager, ILogger logger, IJsonSerializer jsonSerializer)
         {
             _itemRepo = itemRepo;
             _userManager = userManager;
             _libraryManager = libraryManager;
             _logger = logger;
+            _jsonSerializer = jsonSerializer;
         }
 
         public void AddParts(IEnumerable<IMediaSourceProvider> providers)
@@ -317,13 +319,13 @@ namespace MediaBrowser.Server.Implementations.Library
         private readonly ConcurrentDictionary<string, LiveStreamInfo> _openStreams = new ConcurrentDictionary<string, LiveStreamInfo>();
         private readonly SemaphoreSlim _liveStreamSemaphore = new SemaphoreSlim(1, 1);
 
-        public async Task<MediaSourceInfo> OpenLiveStream(string openToken, bool enableAutoClose, CancellationToken cancellationToken)
+        public async Task<LiveStreamResponse> OpenLiveStream(LiveStreamRequest request, bool enableAutoClose, CancellationToken cancellationToken)
         {
             await _liveStreamSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
 
             try
             {
-                var tuple = GetProvider(openToken);
+                var tuple = GetProvider(request.OpenToken);
                 var provider = tuple.Item1;
 
                 var mediaSource = await provider.OpenMediaSource(tuple.Item2, cancellationToken).ConfigureAwait(false);
@@ -344,12 +346,19 @@ namespace MediaBrowser.Server.Implementations.Library
                     StartCloseTimer();
                 }
 
-                if (!string.IsNullOrWhiteSpace(mediaSource.TranscodingUrl))
+                var json = _jsonSerializer.SerializeToString(mediaSource);
+                var clone = _jsonSerializer.DeserializeFromString<MediaSourceInfo>(json);
+
+                if (!string.IsNullOrWhiteSpace(request.UserId))
                 {
-                    mediaSource.TranscodingUrl += "&LiveStreamId=" + mediaSource.LiveStreamId;
+                    var user = _userManager.GetUserById(request.UserId);
+                    SetUserProperties(clone, user);
                 }
 
-                return mediaSource;
+                return new LiveStreamResponse
+                {
+                    MediaSource = clone
+                };
             }
             finally
             {

+ 36 - 21
MediaBrowser.Server.Implementations/Session/SessionManager.cs

@@ -14,6 +14,7 @@ using MediaBrowser.Controller.Persistence;
 using MediaBrowser.Controller.Security;
 using MediaBrowser.Controller.Session;
 using MediaBrowser.Model.Devices;
+using MediaBrowser.Model.Dto;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Events;
 using MediaBrowser.Model.Library;
@@ -304,13 +305,21 @@ namespace MediaBrowser.Server.Implementations.Session
             }
         }
 
+        private async Task<MediaSourceInfo> GetMediaSource(BaseItem 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));
+        }
+
         /// <summary>
         /// Updates the now playing item id.
         /// </summary>
         /// <param name="session">The session.</param>
         /// <param name="info">The information.</param>
         /// <param name="libraryItem">The library item.</param>
-        private void UpdateNowPlayingItem(SessionInfo session, PlaybackProgressInfo info, BaseItem libraryItem)
+        private async Task UpdateNowPlayingItem(SessionInfo session, PlaybackProgressInfo info, BaseItem libraryItem)
         {
             if (string.IsNullOrWhiteSpace(info.MediaSourceId))
             {
@@ -319,29 +328,27 @@ namespace MediaBrowser.Server.Implementations.Session
 
             if (!string.IsNullOrWhiteSpace(info.ItemId) && info.Item == null && libraryItem != null)
             {
-                var runtimeTicks = libraryItem.RunTimeTicks;
+                var current = session.NowPlayingItem;
 
-                if (!string.Equals(info.ItemId, info.MediaSourceId) &&
-                    !string.IsNullOrWhiteSpace(info.MediaSourceId))
+                if (current == null || !string.Equals(current.Id, info.ItemId, StringComparison.OrdinalIgnoreCase))
                 {
-                    var runtimeItem = _libraryManager.GetItemById(new Guid(info.MediaSourceId)) ??
-                                      _libraryManager.GetItemById(info.ItemId);
+                    var runtimeTicks = libraryItem.RunTimeTicks;
 
-                    runtimeTicks = runtimeItem.RunTimeTicks;
-                }
+                    var mediaSource = await GetMediaSource(libraryItem, info.MediaSourceId).ConfigureAwait(false);
 
-                var current = session.NowPlayingItem;
+                    if (mediaSource != null)
+                    {
+                        runtimeTicks = mediaSource.RunTimeTicks;
+                    }
 
-                if (current == null || !string.Equals(current.Id, info.ItemId, StringComparison.OrdinalIgnoreCase))
-                {
-                    info.Item = GetItemInfo(libraryItem, libraryItem, info.MediaSourceId);
+                    info.Item = GetItemInfo(libraryItem, libraryItem, mediaSource);
+
+                    info.Item.RunTimeTicks = runtimeTicks;
                 }
                 else
                 {
                     info.Item = current;
                 }
-
-                info.Item.RunTimeTicks = runtimeTicks;
             }
 
             session.NowPlayingItem = info.Item;
@@ -432,6 +439,12 @@ namespace MediaBrowser.Server.Implementations.Session
 
                 device = device ?? _deviceManager.GetDevice(deviceId);
 
+                if (device == null)
+                {
+                    var userIdString = userId.HasValue ? userId.Value.ToString("N") : null;
+                    device = await _deviceManager.RegisterDevice(deviceId, deviceName, appName, appVersion, userIdString).ConfigureAwait(false);
+                }
+
                 if (device != null)
                 {
                     if (!string.IsNullOrEmpty(device.CustomName))
@@ -570,7 +583,7 @@ namespace MediaBrowser.Server.Implementations.Session
                 ? null
                 : _libraryManager.GetItemById(new Guid(info.ItemId));
 
-            UpdateNowPlayingItem(session, info, libraryItem);
+            await UpdateNowPlayingItem(session, info, libraryItem).ConfigureAwait(false);
 
             if (!string.IsNullOrEmpty(session.DeviceId) && info.PlayMethod != PlayMethod.Transcode)
             {
@@ -652,7 +665,7 @@ namespace MediaBrowser.Server.Implementations.Session
                 ? null
                 : _libraryManager.GetItemById(new Guid(info.ItemId));
 
-            UpdateNowPlayingItem(session, info, libraryItem);
+            await UpdateNowPlayingItem(session, info, libraryItem).ConfigureAwait(false);
 
             var users = GetUsers(session);
 
@@ -731,7 +744,9 @@ namespace MediaBrowser.Server.Implementations.Session
 
                 if (current == null || !string.Equals(current.Id, info.ItemId, StringComparison.OrdinalIgnoreCase))
                 {
-                    info.Item = GetItemInfo(libraryItem, libraryItem, info.MediaSourceId);
+                    var mediaSource = await GetMediaSource(libraryItem, info.MediaSourceId).ConfigureAwait(false);
+
+                    info.Item = GetItemInfo(libraryItem, libraryItem, mediaSource);
                 }
                 else
                 {
@@ -1439,10 +1454,10 @@ namespace MediaBrowser.Server.Implementations.Session
         /// </summary>
         /// <param name="item">The item.</param>
         /// <param name="chapterOwner">The chapter owner.</param>
-        /// <param name="mediaSourceId">The media source identifier.</param>
+        /// <param name="mediaSource">The media source.</param>
         /// <returns>BaseItemInfo.</returns>
         /// <exception cref="System.ArgumentNullException">item</exception>
-        private BaseItemInfo GetItemInfo(BaseItem item, BaseItem chapterOwner, string mediaSourceId)
+        private BaseItemInfo GetItemInfo(BaseItem item, BaseItem chapterOwner, MediaSourceInfo mediaSource)
         {
             if (item == null)
             {
@@ -1593,9 +1608,9 @@ namespace MediaBrowser.Server.Implementations.Session
                 info.Chapters = _dtoService.GetChapterInfoDtos(chapterOwner).ToList();
             }
 
-            if (!string.IsNullOrWhiteSpace(mediaSourceId))
+            if (mediaSource != null)
             {
-                info.MediaStreams = _mediaSourceManager.GetMediaStreams(mediaSourceId).ToList();
+                info.MediaStreams = mediaSource.MediaStreams;
             }
 
             return info;

+ 1 - 1
MediaBrowser.Server.Startup.Common/ApplicationHost.cs

@@ -472,7 +472,7 @@ namespace MediaBrowser.Server.Startup.Common
             ChannelManager = new ChannelManager(UserManager, DtoService, LibraryManager, LogManager.GetLogger("ChannelManager"), ServerConfigurationManager, FileSystemManager, UserDataManager, JsonSerializer, LocalizationManager, HttpClient);
             RegisterSingleInstance(ChannelManager);
 
-            MediaSourceManager = new MediaSourceManager(ItemRepository, UserManager, LibraryManager, LogManager.GetLogger("MediaSourceManager"));
+            MediaSourceManager = new MediaSourceManager(ItemRepository, UserManager, LibraryManager, LogManager.GetLogger("MediaSourceManager"), JsonSerializer);
             RegisterSingleInstance(MediaSourceManager);
 
             SessionManager = new SessionManager(UserDataManager, LogManager.GetLogger("SessionManager"), UserRepository, LibraryManager, UserManager, musicManager, DtoService, ImageProcessor, JsonSerializer, this, HttpClient, AuthenticationRepository, DeviceManager, MediaSourceManager);