|  | @@ -1,8 +1,11 @@
 | 
	
		
			
				|  |  | -using MediaBrowser.Controller.Library;
 | 
	
		
			
				|  |  | +using MediaBrowser.Controller.Devices;
 | 
	
		
			
				|  |  | +using MediaBrowser.Controller.Entities;
 | 
	
		
			
				|  |  | +using MediaBrowser.Controller.Library;
 | 
	
		
			
				|  |  |  using MediaBrowser.Controller.Net;
 | 
	
		
			
				|  |  |  using MediaBrowser.Model.Dlna;
 | 
	
		
			
				|  |  |  using MediaBrowser.Model.Dto;
 | 
	
		
			
				|  |  |  using MediaBrowser.Model.MediaInfo;
 | 
	
		
			
				|  |  | +using MediaBrowser.Model.Session;
 | 
	
		
			
				|  |  |  using ServiceStack;
 | 
	
		
			
				|  |  |  using System;
 | 
	
		
			
				|  |  |  using System.Collections.Generic;
 | 
	
	
		
			
				|  | @@ -13,7 +16,7 @@ using System.Threading.Tasks;
 | 
	
		
			
				|  |  |  namespace MediaBrowser.Api.Playback
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |      [Route("/Items/{Id}/MediaInfo", "GET", Summary = "Gets live playback media info for an item")]
 | 
	
		
			
				|  |  | -    public class GetLiveMediaInfo : IReturn<LiveMediaInfoResult>
 | 
	
		
			
				|  |  | +    public class GetLiveMediaInfo : IReturn<PlaybackInfoResponse>
 | 
	
		
			
				|  |  |      {
 | 
	
		
			
				|  |  |          [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
 | 
	
		
			
				|  |  |          public string Id { get; set; }
 | 
	
	
		
			
				|  | @@ -23,7 +26,17 @@ namespace MediaBrowser.Api.Playback
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      [Route("/Items/{Id}/PlaybackInfo", "GET", Summary = "Gets live playback media info for an item")]
 | 
	
		
			
				|  |  | -    public class GetPlaybackInfo : IReturn<LiveMediaInfoResult>
 | 
	
		
			
				|  |  | +    public class GetPlaybackInfo : IReturn<PlaybackInfoResponse>
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +        [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
 | 
	
		
			
				|  |  | +        public string Id { get; set; }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
 | 
	
		
			
				|  |  | +        public string UserId { get; set; }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    [Route("/Items/{Id}/PlaybackInfo", "POST", Summary = "Gets live playback media info for an item")]
 | 
	
		
			
				|  |  | +    public class GetPostedPlaybackInfo : PlaybackInfoRequest, IReturn<PlaybackInfoResponse>
 | 
	
		
			
				|  |  |      {
 | 
	
		
			
				|  |  |          [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
 | 
	
		
			
				|  |  |          public string Id { get; set; }
 | 
	
	
		
			
				|  | @@ -36,26 +49,55 @@ namespace MediaBrowser.Api.Playback
 | 
	
		
			
				|  |  |      public class MediaInfoService : BaseApiService
 | 
	
		
			
				|  |  |      {
 | 
	
		
			
				|  |  |          private readonly IMediaSourceManager _mediaSourceManager;
 | 
	
		
			
				|  |  | +        private readonly IDeviceManager _deviceManager;
 | 
	
		
			
				|  |  | +        private readonly ILibraryManager _libraryManager;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        public MediaInfoService(IMediaSourceManager mediaSourceManager)
 | 
	
		
			
				|  |  | +        public MediaInfoService(IMediaSourceManager mediaSourceManager, IDeviceManager deviceManager, ILibraryManager libraryManager)
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  |              _mediaSourceManager = mediaSourceManager;
 | 
	
		
			
				|  |  | +            _deviceManager = deviceManager;
 | 
	
		
			
				|  |  | +            _libraryManager = libraryManager;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        public async Task<object> Get(GetPlaybackInfo request)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            var result = await GetPlaybackInfo(request.Id, request.UserId).ConfigureAwait(false);
 | 
	
		
			
				|  |  | +            return ToOptimizedResult(result);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        public Task<object> Get(GetPlaybackInfo request)
 | 
	
		
			
				|  |  | +        public async Task<object> Get(GetLiveMediaInfo request)
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  | -            return GetPlaybackInfo(request.Id, request.UserId);
 | 
	
		
			
				|  |  | +            var result = await GetPlaybackInfo(request.Id, request.UserId).ConfigureAwait(false);
 | 
	
		
			
				|  |  | +            return ToOptimizedResult(result);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        public Task<object> Get(GetLiveMediaInfo request)
 | 
	
		
			
				|  |  | +        public async Task<object> Post(GetPostedPlaybackInfo request)
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  | -            return GetPlaybackInfo(request.Id, request.UserId);
 | 
	
		
			
				|  |  | +            var info = await GetPlaybackInfo(request.Id, request.UserId).ConfigureAwait(false);
 | 
	
		
			
				|  |  | +            var authInfo = AuthorizationContext.GetAuthorizationInfo(Request);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            var profile = request.DeviceProfile;
 | 
	
		
			
				|  |  | +            //if (profile == null)
 | 
	
		
			
				|  |  | +            //{
 | 
	
		
			
				|  |  | +            //    var caps = _deviceManager.GetCapabilities(authInfo.DeviceId);
 | 
	
		
			
				|  |  | +            //    if (caps != null)
 | 
	
		
			
				|  |  | +            //    {
 | 
	
		
			
				|  |  | +            //        profile = caps.DeviceProfile;
 | 
	
		
			
				|  |  | +            //    }
 | 
	
		
			
				|  |  | +            //}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            if (profile != null)
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                SetDeviceSpecificData(request.Id, info, profile, authInfo, null);
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            return ToOptimizedResult(info);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        private async Task<object> GetPlaybackInfo(string id, string userId)
 | 
	
		
			
				|  |  | +        private async Task<PlaybackInfoResponse> GetPlaybackInfo(string id, string userId)
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  |              IEnumerable<MediaSourceInfo> mediaSources;
 | 
	
		
			
				|  |  | -            var result = new LiveMediaInfoResult();
 | 
	
		
			
				|  |  | +            var result = new PlaybackInfoResponse();
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |              try
 | 
	
		
			
				|  |  |              {
 | 
	
	
		
			
				|  | @@ -68,9 +110,89 @@ namespace MediaBrowser.Api.Playback
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |              result.MediaSources = mediaSources.ToList();
 | 
	
		
			
				|  |  | -            result.StreamId = Guid.NewGuid().ToString("N");
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            return ToOptimizedResult(result);
 | 
	
		
			
				|  |  | +            if (result.MediaSources.Count == 0)
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                if (!result.ErrorCode.HasValue)
 | 
	
		
			
				|  |  | +                {
 | 
	
		
			
				|  |  | +                    result.ErrorCode = PlaybackErrorCode.NoCompatibleStream;
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            else
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                result.StreamId = Guid.NewGuid().ToString("N");
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            return result;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        private void SetDeviceSpecificData(string itemId, PlaybackInfoResponse result, DeviceProfile profile, AuthorizationInfo auth, int? maxBitrate)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            var streamBuilder = new StreamBuilder();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            var item = _libraryManager.GetItemById(itemId);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            foreach (var mediaSource in result.MediaSources)
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                var options = new VideoOptions
 | 
	
		
			
				|  |  | +                {
 | 
	
		
			
				|  |  | +                    MediaSources = new List<MediaSourceInfo> { mediaSource },
 | 
	
		
			
				|  |  | +                    Context = EncodingContext.Streaming,
 | 
	
		
			
				|  |  | +                    DeviceId = auth.DeviceId,
 | 
	
		
			
				|  |  | +                    ItemId = item.Id.ToString("N"),
 | 
	
		
			
				|  |  | +                    Profile = profile,
 | 
	
		
			
				|  |  | +                    MaxBitrate = maxBitrate
 | 
	
		
			
				|  |  | +                };
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                if (mediaSource.SupportsDirectPlay)
 | 
	
		
			
				|  |  | +                {
 | 
	
		
			
				|  |  | +                    var supportsDirectStream = mediaSource.SupportsDirectStream;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                    // Dummy this up to fool StreamBuilder
 | 
	
		
			
				|  |  | +                    mediaSource.SupportsDirectStream = true;
 | 
	
		
			
				|  |  | +                    
 | 
	
		
			
				|  |  | +                    // The MediaSource supports direct stream, now test to see if the client supports it
 | 
	
		
			
				|  |  | +                    var streamInfo = item is Video ?
 | 
	
		
			
				|  |  | +                        streamBuilder.BuildVideoItem(options) :
 | 
	
		
			
				|  |  | +                        streamBuilder.BuildAudioItem(options);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                    if (streamInfo == null || !streamInfo.IsDirectStream)
 | 
	
		
			
				|  |  | +                    {
 | 
	
		
			
				|  |  | +                        mediaSource.SupportsDirectPlay = false;
 | 
	
		
			
				|  |  | +                    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                    // Set this back to what it was
 | 
	
		
			
				|  |  | +                    mediaSource.SupportsDirectStream = supportsDirectStream;
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                if (mediaSource.SupportsDirectStream)
 | 
	
		
			
				|  |  | +                {
 | 
	
		
			
				|  |  | +                    // The MediaSource supports direct stream, now test to see if the client supports it
 | 
	
		
			
				|  |  | +                    var streamInfo = item is Video ?
 | 
	
		
			
				|  |  | +                        streamBuilder.BuildVideoItem(options) :
 | 
	
		
			
				|  |  | +                        streamBuilder.BuildAudioItem(options);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                    if (streamInfo == null || !streamInfo.IsDirectStream)
 | 
	
		
			
				|  |  | +                    {
 | 
	
		
			
				|  |  | +                        mediaSource.SupportsDirectStream = false;
 | 
	
		
			
				|  |  | +                    }
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                if (mediaSource.SupportsTranscoding)
 | 
	
		
			
				|  |  | +                {
 | 
	
		
			
				|  |  | +                    // The MediaSource supports direct stream, now test to see if the client supports it
 | 
	
		
			
				|  |  | +                    var streamInfo = item is Video ?
 | 
	
		
			
				|  |  | +                        streamBuilder.BuildVideoItem(options) :
 | 
	
		
			
				|  |  | +                        streamBuilder.BuildAudioItem(options);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                    if (streamInfo != null && streamInfo.PlayMethod == PlayMethod.Transcode)
 | 
	
		
			
				|  |  | +                    {
 | 
	
		
			
				|  |  | +                        mediaSource.TranscodingUrl = streamInfo.ToUrl("-", auth.Token).Substring(1);
 | 
	
		
			
				|  |  | +                        mediaSource.TranscodingContainer = streamInfo.Container;
 | 
	
		
			
				|  |  | +                        mediaSource.TranscodingSubProtocol = streamInfo.SubProtocol;
 | 
	
		
			
				|  |  | +                    }
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 |