aboutsummaryrefslogtreecommitdiff
path: root/Jellyfin.Api/Controllers/UniversalAudioController.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Jellyfin.Api/Controllers/UniversalAudioController.cs')
-rw-r--r--Jellyfin.Api/Controllers/UniversalAudioController.cs281
1 files changed, 141 insertions, 140 deletions
diff --git a/Jellyfin.Api/Controllers/UniversalAudioController.cs b/Jellyfin.Api/Controllers/UniversalAudioController.cs
index 75df16aa7..3994fb995 100644
--- a/Jellyfin.Api/Controllers/UniversalAudioController.cs
+++ b/Jellyfin.Api/Controllers/UniversalAudioController.cs
@@ -2,17 +2,20 @@
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
-using System.Net.Http;
using System.Threading.Tasks;
using Jellyfin.Api.Constants;
using Jellyfin.Api.Helpers;
-using Jellyfin.Api.Models.VideoDtos;
+using Jellyfin.Api.Models.StreamingDtos;
+using MediaBrowser.Controller.Devices;
+using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Controller.Net;
using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.MediaInfo;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Logging;
namespace Jellyfin.Api.Controllers
{
@@ -23,27 +26,39 @@ namespace Jellyfin.Api.Controllers
public class UniversalAudioController : BaseJellyfinApiController
{
private readonly IAuthorizationContext _authorizationContext;
- private readonly MediaInfoController _mediaInfoController;
- private readonly DynamicHlsController _dynamicHlsController;
- private readonly AudioController _audioController;
+ private readonly IDeviceManager _deviceManager;
+ private readonly ILibraryManager _libraryManager;
+ private readonly ILogger<UniversalAudioController> _logger;
+ private readonly MediaInfoHelper _mediaInfoHelper;
+ private readonly AudioHelper _audioHelper;
+ private readonly DynamicHlsHelper _dynamicHlsHelper;
/// <summary>
/// Initializes a new instance of the <see cref="UniversalAudioController"/> class.
/// </summary>
/// <param name="authorizationContext">Instance of the <see cref="IAuthorizationContext"/> interface.</param>
- /// <param name="mediaInfoController">Instance of the <see cref="MediaInfoController"/>.</param>
- /// <param name="dynamicHlsController">Instance of the <see cref="DynamicHlsController"/>.</param>
- /// <param name="audioController">Instance of the <see cref="AudioController"/>.</param>
+ /// <param name="deviceManager">Instance of the <see cref="IDeviceManager"/> interface.</param>
+ /// <param name="libraryManager">Instance of the <see cref="ILibraryManager"/> interface.</param>
+ /// <param name="logger">Instance of the <see cref="ILogger{UniversalAudioController}"/> interface.</param>
+ /// <param name="mediaInfoHelper">Instance of <see cref="MediaInfoHelper"/>.</param>
+ /// <param name="audioHelper">Instance of <see cref="AudioHelper"/>.</param>
+ /// <param name="dynamicHlsHelper">Instance of <see cref="DynamicHlsHelper"/>.</param>
public UniversalAudioController(
IAuthorizationContext authorizationContext,
- MediaInfoController mediaInfoController,
- DynamicHlsController dynamicHlsController,
- AudioController audioController)
+ IDeviceManager deviceManager,
+ ILibraryManager libraryManager,
+ ILogger<UniversalAudioController> logger,
+ MediaInfoHelper mediaInfoHelper,
+ AudioHelper audioHelper,
+ DynamicHlsHelper dynamicHlsHelper)
{
_authorizationContext = authorizationContext;
- _mediaInfoController = mediaInfoController;
- _dynamicHlsController = dynamicHlsController;
- _audioController = audioController;
+ _deviceManager = deviceManager;
+ _libraryManager = libraryManager;
+ _logger = logger;
+ _mediaInfoHelper = mediaInfoHelper;
+ _audioHelper = audioHelper;
+ _dynamicHlsHelper = dynamicHlsHelper;
}
/// <summary>
@@ -95,24 +110,68 @@ namespace Jellyfin.Api.Controllers
[FromQuery] bool breakOnNonKeyFrames,
[FromQuery] bool enableRedirection = true)
{
- bool isHeadRequest = Request.Method == System.Net.WebRequestMethods.Http.Head;
var deviceProfile = GetDeviceProfile(container, transcodingContainer, audioCodec, transcodingProtocol, breakOnNonKeyFrames, transcodingAudioChannels, maxAudioSampleRate, maxAudioBitDepth, maxAudioChannels);
_authorizationContext.GetAuthorizationInfo(Request).DeviceId = deviceId;
- var playbackInfoResult = await _mediaInfoController.GetPostedPlaybackInfo(
- itemId,
- userId,
- maxStreamingBitrate,
- startTimeTicks,
- null,
- null,
- maxAudioChannels,
- mediaSourceId,
- null,
- new DeviceProfileDto { DeviceProfile = deviceProfile })
+ var authInfo = _authorizationContext.GetAuthorizationInfo(Request);
+
+ _logger.LogInformation("GetPostedPlaybackInfo profile: {@Profile}", deviceProfile);
+
+ if (deviceProfile == null)
+ {
+ var clientCapabilities = _deviceManager.GetCapabilities(authInfo.DeviceId);
+ if (clientCapabilities != null)
+ {
+ deviceProfile = clientCapabilities.DeviceProfile;
+ }
+ }
+
+ var info = await _mediaInfoHelper.GetPlaybackInfo(
+ itemId,
+ userId,
+ mediaSourceId)
.ConfigureAwait(false);
- var mediaSource = playbackInfoResult.Value.MediaSources[0];
+ if (deviceProfile != null)
+ {
+ // set device specific data
+ var item = _libraryManager.GetItemById(itemId);
+
+ foreach (var sourceInfo in info.MediaSources)
+ {
+ _mediaInfoHelper.SetDeviceSpecificData(
+ item,
+ sourceInfo,
+ deviceProfile,
+ authInfo,
+ maxStreamingBitrate ?? deviceProfile.MaxStreamingBitrate,
+ startTimeTicks ?? 0,
+ mediaSourceId ?? string.Empty,
+ null,
+ null,
+ maxAudioChannels,
+ info!.PlaySessionId!,
+ userId ?? Guid.Empty,
+ true,
+ true,
+ true,
+ true,
+ true,
+ Request.HttpContext.Connection.RemoteIpAddress.ToString());
+ }
+
+ _mediaInfoHelper.SortMediaSources(info, maxStreamingBitrate);
+ }
+
+ if (info.MediaSources != null)
+ {
+ foreach (var source in info.MediaSources)
+ {
+ _mediaInfoHelper.NormalizeMediaSourceContainer(source, deviceProfile!, DlnaProfileType.Video);
+ }
+ }
+
+ var mediaSource = info.MediaSources![0];
if (mediaSource.SupportsDirectPlay && mediaSource.Protocol == MediaProtocol.Http)
{
if (enableRedirection)
@@ -127,129 +186,71 @@ namespace Jellyfin.Api.Controllers
var isStatic = mediaSource.SupportsDirectStream;
if (!isStatic && string.Equals(mediaSource.TranscodingSubProtocol, "hls", StringComparison.OrdinalIgnoreCase))
{
- var transcodingProfile = deviceProfile.TranscodingProfiles[0];
-
// hls segment container can only be mpegts or fmp4 per ffmpeg documentation
// TODO: remove this when we switch back to the segment muxer
var supportedHlsContainers = new[] { "mpegts", "fmp4" };
- if (isHeadRequest)
+ var dynamicHlsRequestDto = new HlsAudioRequestDto
{
- _dynamicHlsController.Request.Method = HttpMethod.Head.Method;
- }
-
- return await _dynamicHlsController.GetMasterHlsAudioPlaylist(
- itemId,
- ".m3u8",
- isStatic,
- null,
- null,
- null,
- playbackInfoResult.Value.PlaySessionId,
+ Id = itemId,
+ Container = ".m3u8",
+ Static = isStatic,
+ PlaySessionId = info.PlaySessionId,
// fallback to mpegts if device reports some weird value unsupported by hls
- Array.Exists(supportedHlsContainers, element => element == transcodingContainer) ? transcodingContainer : "mpegts",
- null,
- null,
- mediaSource.Id,
- deviceId,
- transcodingProfile.AudioCodec,
- null,
- null,
- null,
- transcodingProfile.BreakOnNonKeyFrames,
- maxAudioSampleRate,
- maxAudioBitDepth,
- null,
- isStatic ? (int?)null : Convert.ToInt32(Math.Min(maxStreamingBitrate ?? 192000, int.MaxValue)),
- maxAudioChannels,
- null,
- null,
- null,
- null,
- null,
- startTimeTicks,
- null,
- null,
- null,
- null,
- SubtitleDeliveryMethod.Hls,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- mediaSource.TranscodeReasons == null ? null : string.Join(",", mediaSource.TranscodeReasons.Select(i => i.ToString()).ToArray()),
- null,
- null,
- EncodingContext.Static,
- new Dictionary<string, string>())
+ SegmentContainer = Array.Exists(supportedHlsContainers, element => element == transcodingContainer) ? transcodingContainer : "mpegts",
+ MediaSourceId = mediaSourceId,
+ DeviceId = deviceId,
+ AudioCodec = audioCodec,
+ EnableAutoStreamCopy = true,
+ AllowAudioStreamCopy = true,
+ AllowVideoStreamCopy = true,
+ BreakOnNonKeyFrames = breakOnNonKeyFrames,
+ AudioSampleRate = maxAudioSampleRate,
+ MaxAudioChannels = maxAudioChannels,
+ MaxAudioBitDepth = maxAudioBitDepth,
+ AudioChannels = isStatic ? (int?)null : Convert.ToInt32(Math.Min(maxStreamingBitrate ?? 192000, int.MaxValue)),
+ StartTimeTicks = startTimeTicks,
+ SubtitleMethod = SubtitleDeliveryMethod.Hls,
+ RequireAvc = true,
+ DeInterlace = true,
+ RequireNonAnamorphic = true,
+ EnableMpegtsM2TsMode = true,
+ TranscodeReasons = mediaSource.TranscodeReasons == null ? null : string.Join(",", mediaSource.TranscodeReasons.Select(i => i.ToString()).ToArray()),
+ Context = EncodingContext.Static,
+ StreamOptions = new Dictionary<string, string>(),
+ EnableAdaptiveBitrateStreaming = true
+ };
+
+ return await _dynamicHlsHelper.GetMasterHlsPlaylist(TranscodingJobType.Hls, dynamicHlsRequestDto, true)
.ConfigureAwait(false);
}
- else
+
+ var audioStreamingDto = new StreamingRequestDto
{
- if (isHeadRequest)
- {
- _audioController.Request.Method = HttpMethod.Head.Method;
- }
+ Id = itemId,
+ Container = isStatic ? null : ("." + mediaSource.TranscodingContainer),
+ Static = isStatic,
+ PlaySessionId = info.PlaySessionId,
+ MediaSourceId = mediaSourceId,
+ DeviceId = deviceId,
+ AudioCodec = audioCodec,
+ EnableAutoStreamCopy = true,
+ AllowAudioStreamCopy = true,
+ AllowVideoStreamCopy = true,
+ BreakOnNonKeyFrames = breakOnNonKeyFrames,
+ AudioSampleRate = maxAudioSampleRate,
+ MaxAudioChannels = maxAudioChannels,
+ AudioBitRate = isStatic ? (int?)null : Convert.ToInt32(Math.Min(maxStreamingBitrate ?? 192000, int.MaxValue)),
+ MaxAudioBitDepth = maxAudioBitDepth,
+ AudioChannels = maxAudioChannels,
+ CopyTimestamps = true,
+ StartTimeTicks = startTimeTicks,
+ SubtitleMethod = SubtitleDeliveryMethod.Embed,
+ TranscodeReasons = mediaSource.TranscodeReasons == null ? null : string.Join(",", mediaSource.TranscodeReasons.Select(i => i.ToString()).ToArray()),
+ Context = EncodingContext.Static
+ };
- return await _audioController.GetAudioStream(
- itemId,
- isStatic ? null : ("." + mediaSource.TranscodingContainer),
- isStatic,
- null,
- null,
- null,
- playbackInfoResult.Value.PlaySessionId,
- null,
- null,
- null,
- mediaSource.Id,
- deviceId,
- audioCodec,
- null,
- null,
- null,
- breakOnNonKeyFrames,
- maxAudioSampleRate,
- maxAudioBitDepth,
- isStatic ? (int?)null : Convert.ToInt32(Math.Min(maxStreamingBitrate ?? 192000, int.MaxValue)),
- null,
- maxAudioChannels,
- null,
- null,
- null,
- null,
- null,
- startTimeTicks,
- null,
- null,
- null,
- null,
- SubtitleDeliveryMethod.Embed,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- mediaSource.TranscodeReasons == null ? null : string.Join(",", mediaSource.TranscodeReasons.Select(i => i.ToString()).ToArray()),
- null,
- null,
- null,
- null)
- .ConfigureAwait(false);
- }
+ return await _audioHelper.GetAudioStream(TranscodingJobType.Progressive, audioStreamingDto).ConfigureAwait(false);
}
private DeviceProfile GetDeviceProfile(