123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370 |
- using System;
- using System.Collections.Generic;
- using System.Globalization;
- using System.Linq;
- using System.Threading.Tasks;
- using MediaBrowser.Api.Playback.Hls;
- using MediaBrowser.Api.Playback.Progressive;
- using MediaBrowser.Common.Net;
- using MediaBrowser.Controller.Configuration;
- using MediaBrowser.Controller.Devices;
- using MediaBrowser.Controller.Dlna;
- using MediaBrowser.Controller.Library;
- using MediaBrowser.Controller.MediaEncoding;
- using MediaBrowser.Controller.Net;
- using MediaBrowser.Model.Dlna;
- using MediaBrowser.Model.IO;
- using MediaBrowser.Model.MediaInfo;
- using MediaBrowser.Model.Serialization;
- using MediaBrowser.Model.Services;
- using Microsoft.Extensions.Logging;
- namespace MediaBrowser.Api.Playback
- {
- public class BaseUniversalRequest
- {
- /// <summary>
- /// Gets or sets the id.
- /// </summary>
- /// <value>The id.</value>
- [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
- public Guid Id { get; set; }
- [ApiMember(Name = "MediaSourceId", Description = "The media version id, if playing an alternate version", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
- public string MediaSourceId { get; set; }
- [ApiMember(Name = "DeviceId", Description = "The device id of the client requesting. Used to stop encoding processes when needed.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
- public string DeviceId { get; set; }
- public Guid UserId { get; set; }
- public string AudioCodec { get; set; }
- public string Container { get; set; }
- public int? MaxAudioChannels { get; set; }
- public int? TranscodingAudioChannels { get; set; }
- public long? MaxStreamingBitrate { get; set; }
- [ApiMember(Name = "StartTimeTicks", Description = "Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
- public long? StartTimeTicks { get; set; }
- public string TranscodingContainer { get; set; }
- public string TranscodingProtocol { get; set; }
- public int? MaxAudioSampleRate { get; set; }
- public int? MaxAudioBitDepth { get; set; }
- public bool EnableRedirection { get; set; }
- public bool EnableRemoteMedia { get; set; }
- public bool BreakOnNonKeyFrames { get; set; }
- public BaseUniversalRequest()
- {
- EnableRedirection = true;
- }
- }
- [Route("/Audio/{Id}/universal.{Container}", "GET", Summary = "Gets an audio stream")]
- [Route("/Audio/{Id}/universal", "GET", Summary = "Gets an audio stream")]
- [Route("/Audio/{Id}/universal.{Container}", "HEAD", Summary = "Gets an audio stream")]
- [Route("/Audio/{Id}/universal", "HEAD", Summary = "Gets an audio stream")]
- public class GetUniversalAudioStream : BaseUniversalRequest
- {
- }
- [Authenticated]
- public class UniversalAudioService : BaseApiService
- {
- private readonly ILoggerFactory _loggerFactory;
- private readonly EncodingHelper _encodingHelper;
- public UniversalAudioService(
- IHttpClient httpClient,
- IServerConfigurationManager serverConfigurationManager,
- IUserManager userManager,
- ILibraryManager libraryManager,
- IIsoManager isoManager,
- IMediaEncoder mediaEncoder,
- IFileSystem fileSystem,
- IDlnaManager dlnaManager,
- IDeviceManager deviceManager,
- IMediaSourceManager mediaSourceManager,
- IJsonSerializer jsonSerializer,
- IAuthorizationContext authorizationContext,
- INetworkManager networkManager,
- ILoggerFactory loggerFactory,
- EncodingHelper encodingHelper)
- {
- HttpClient = httpClient;
- ServerConfigurationManager = serverConfigurationManager;
- UserManager = userManager;
- LibraryManager = libraryManager;
- IsoManager = isoManager;
- MediaEncoder = mediaEncoder;
- FileSystem = fileSystem;
- DlnaManager = dlnaManager;
- DeviceManager = deviceManager;
- MediaSourceManager = mediaSourceManager;
- JsonSerializer = jsonSerializer;
- AuthorizationContext = authorizationContext;
- NetworkManager = networkManager;
- _loggerFactory = loggerFactory;
- _encodingHelper = encodingHelper;
- }
- protected IHttpClient HttpClient { get; private set; }
- protected IServerConfigurationManager ServerConfigurationManager { get; private set; }
- protected IUserManager UserManager { get; private set; }
- protected ILibraryManager LibraryManager { get; private set; }
- protected IIsoManager IsoManager { get; private set; }
- protected IMediaEncoder MediaEncoder { get; private set; }
- protected IFileSystem FileSystem { get; private set; }
- protected IDlnaManager DlnaManager { get; private set; }
- protected IDeviceManager DeviceManager { get; private set; }
- protected IMediaSourceManager MediaSourceManager { get; private set; }
- protected IJsonSerializer JsonSerializer { get; private set; }
- protected IAuthorizationContext AuthorizationContext { get; private set; }
- protected INetworkManager NetworkManager { get; private set; }
- public Task<object> Get(GetUniversalAudioStream request)
- {
- return GetUniversalStream(request, false);
- }
- public Task<object> Head(GetUniversalAudioStream request)
- {
- return GetUniversalStream(request, true);
- }
- private DeviceProfile GetDeviceProfile(GetUniversalAudioStream request)
- {
- var deviceProfile = new DeviceProfile();
- var directPlayProfiles = new List<DirectPlayProfile>();
- var containers = (request.Container ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
- foreach (var container in containers)
- {
- var parts = container.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
- var audioCodecs = parts.Length == 1 ? null : string.Join(",", parts.Skip(1).ToArray());
- directPlayProfiles.Add(new DirectPlayProfile
- {
- Type = DlnaProfileType.Audio,
- Container = parts[0],
- AudioCodec = audioCodecs
- });
- }
- deviceProfile.DirectPlayProfiles = directPlayProfiles.ToArray();
- deviceProfile.TranscodingProfiles = new[]
- {
- new TranscodingProfile
- {
- Type = DlnaProfileType.Audio,
- Context = EncodingContext.Streaming,
- Container = request.TranscodingContainer,
- AudioCodec = request.AudioCodec,
- Protocol = request.TranscodingProtocol,
- BreakOnNonKeyFrames = request.BreakOnNonKeyFrames,
- MaxAudioChannels = request.TranscodingAudioChannels.HasValue ? request.TranscodingAudioChannels.Value.ToString(CultureInfo.InvariantCulture) : null
- }
- };
- var codecProfiles = new List<CodecProfile>();
- var conditions = new List<ProfileCondition>();
- if (request.MaxAudioSampleRate.HasValue)
- {
- // codec profile
- conditions.Add(new ProfileCondition
- {
- Condition = ProfileConditionType.LessThanEqual,
- IsRequired = false,
- Property = ProfileConditionValue.AudioSampleRate,
- Value = request.MaxAudioSampleRate.Value.ToString(CultureInfo.InvariantCulture)
- });
- }
- if (request.MaxAudioBitDepth.HasValue)
- {
- // codec profile
- conditions.Add(new ProfileCondition
- {
- Condition = ProfileConditionType.LessThanEqual,
- IsRequired = false,
- Property = ProfileConditionValue.AudioBitDepth,
- Value = request.MaxAudioBitDepth.Value.ToString(CultureInfo.InvariantCulture)
- });
- }
- if (request.MaxAudioChannels.HasValue)
- {
- // codec profile
- conditions.Add(new ProfileCondition
- {
- Condition = ProfileConditionType.LessThanEqual,
- IsRequired = false,
- Property = ProfileConditionValue.AudioChannels,
- Value = request.MaxAudioChannels.Value.ToString(CultureInfo.InvariantCulture)
- });
- }
- if (conditions.Count > 0)
- {
- // codec profile
- codecProfiles.Add(new CodecProfile
- {
- Type = CodecType.Audio,
- Container = request.Container,
- Conditions = conditions.ToArray()
- });
- }
- deviceProfile.CodecProfiles = codecProfiles.ToArray();
- return deviceProfile;
- }
- private async Task<object> GetUniversalStream(GetUniversalAudioStream request, bool isHeadRequest)
- {
- var deviceProfile = GetDeviceProfile(request);
- AuthorizationContext.GetAuthorizationInfo(Request).DeviceId = request.DeviceId;
- var mediaInfoService = new MediaInfoService(
- MediaSourceManager,
- DeviceManager,
- LibraryManager,
- ServerConfigurationManager,
- NetworkManager,
- MediaEncoder,
- UserManager,
- JsonSerializer,
- AuthorizationContext,
- _loggerFactory)
- {
- Request = Request
- };
- var playbackInfoResult = await mediaInfoService.GetPlaybackInfo(new GetPostedPlaybackInfo
- {
- Id = request.Id,
- MaxAudioChannels = request.MaxAudioChannels,
- MaxStreamingBitrate = request.MaxStreamingBitrate,
- StartTimeTicks = request.StartTimeTicks,
- UserId = request.UserId,
- DeviceProfile = deviceProfile,
- MediaSourceId = request.MediaSourceId
- }).ConfigureAwait(false);
- var mediaSource = playbackInfoResult.MediaSources[0];
- if (mediaSource.SupportsDirectPlay && mediaSource.Protocol == MediaProtocol.Http)
- {
- if (request.EnableRedirection)
- {
- if (mediaSource.IsRemote && request.EnableRemoteMedia)
- {
- return ResultFactory.GetRedirectResult(mediaSource.Path);
- }
- }
- }
- var isStatic = mediaSource.SupportsDirectStream;
- if (!isStatic && string.Equals(mediaSource.TranscodingSubProtocol, "hls", StringComparison.OrdinalIgnoreCase))
- {
- var service = new DynamicHlsService(
- ServerConfigurationManager,
- UserManager,
- LibraryManager,
- IsoManager,
- MediaEncoder,
- FileSystem,
- DlnaManager,
- DeviceManager,
- MediaSourceManager,
- JsonSerializer,
- AuthorizationContext,
- NetworkManager,
- _encodingHelper)
- {
- Request = Request
- };
- var transcodingProfile = deviceProfile.TranscodingProfiles[0];
- var newRequest = new GetMasterHlsAudioPlaylist
- {
- AudioBitRate = isStatic ? (int?)null : Convert.ToInt32(Math.Min(request.MaxStreamingBitrate ?? 192000, int.MaxValue)),
- AudioCodec = transcodingProfile.AudioCodec,
- Container = ".m3u8",
- DeviceId = request.DeviceId,
- Id = request.Id,
- MaxAudioChannels = request.MaxAudioChannels,
- MediaSourceId = mediaSource.Id,
- PlaySessionId = playbackInfoResult.PlaySessionId,
- StartTimeTicks = request.StartTimeTicks,
- Static = isStatic,
- SegmentContainer = request.TranscodingContainer,
- AudioSampleRate = request.MaxAudioSampleRate,
- MaxAudioBitDepth = request.MaxAudioBitDepth,
- BreakOnNonKeyFrames = transcodingProfile.BreakOnNonKeyFrames,
- TranscodeReasons = mediaSource.TranscodeReasons == null ? null : string.Join(",", mediaSource.TranscodeReasons.Select(i => i.ToString()).ToArray())
- };
- if (isHeadRequest)
- {
- return await service.Head(newRequest).ConfigureAwait(false);
- }
- return await service.Get(newRequest).ConfigureAwait(false);
- }
- else
- {
- var service = new AudioService(HttpClient,
- ServerConfigurationManager,
- UserManager,
- LibraryManager,
- IsoManager,
- MediaEncoder,
- FileSystem,
- DlnaManager,
- DeviceManager,
- MediaSourceManager,
- JsonSerializer,
- AuthorizationContext,
- _encodingHelper)
- {
- Request = Request
- };
- var newRequest = new GetAudioStream
- {
- AudioBitRate = isStatic ? (int?)null : Convert.ToInt32(Math.Min(request.MaxStreamingBitrate ?? 192000, int.MaxValue)),
- AudioCodec = request.AudioCodec,
- Container = isStatic ? null : ("." + mediaSource.TranscodingContainer),
- DeviceId = request.DeviceId,
- Id = request.Id,
- MaxAudioChannels = request.MaxAudioChannels,
- MediaSourceId = mediaSource.Id,
- PlaySessionId = playbackInfoResult.PlaySessionId,
- StartTimeTicks = request.StartTimeTicks,
- Static = isStatic,
- AudioSampleRate = request.MaxAudioSampleRate,
- MaxAudioBitDepth = request.MaxAudioBitDepth,
- TranscodeReasons = mediaSource.TranscodeReasons == null ? null : string.Join(",", mediaSource.TranscodeReasons.Select(i => i.ToString()).ToArray())
- };
- if (isHeadRequest)
- {
- return await service.Head(newRequest).ConfigureAwait(false);
- }
- return await service.Get(newRequest).ConfigureAwait(false);
- }
- }
- }
- }
|