diff options
Diffstat (limited to 'Jellyfin.Api/Helpers/AudioHelper.cs')
| -rw-r--r-- | Jellyfin.Api/Helpers/AudioHelper.cs | 273 |
1 files changed, 136 insertions, 137 deletions
diff --git a/Jellyfin.Api/Helpers/AudioHelper.cs b/Jellyfin.Api/Helpers/AudioHelper.cs index be410ebcd..2b18c389d 100644 --- a/Jellyfin.Api/Helpers/AudioHelper.cs +++ b/Jellyfin.Api/Helpers/AudioHelper.cs @@ -16,165 +16,164 @@ using MediaBrowser.Model.Net; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; -namespace Jellyfin.Api.Helpers +namespace Jellyfin.Api.Helpers; + +/// <summary> +/// Audio helper. +/// </summary> +public class AudioHelper { + private readonly IDlnaManager _dlnaManager; + private readonly IUserManager _userManager; + private readonly ILibraryManager _libraryManager; + private readonly IMediaSourceManager _mediaSourceManager; + private readonly IServerConfigurationManager _serverConfigurationManager; + private readonly IMediaEncoder _mediaEncoder; + private readonly IDeviceManager _deviceManager; + private readonly TranscodingJobHelper _transcodingJobHelper; + private readonly IHttpClientFactory _httpClientFactory; + private readonly IHttpContextAccessor _httpContextAccessor; + private readonly EncodingHelper _encodingHelper; + /// <summary> - /// Audio helper. + /// Initializes a new instance of the <see cref="AudioHelper"/> class. /// </summary> - public class AudioHelper + /// <param name="dlnaManager">Instance of the <see cref="IDlnaManager"/> interface.</param> + /// <param name="userManager">Instance of the <see cref="IUserManager"/> interface.</param> + /// <param name="libraryManager">Instance of the <see cref="ILibraryManager"/> interface.</param> + /// <param name="mediaSourceManager">Instance of the <see cref="IMediaSourceManager"/> interface.</param> + /// <param name="serverConfigurationManager">Instance of the <see cref="IServerConfigurationManager"/> interface.</param> + /// <param name="mediaEncoder">Instance of the <see cref="IMediaEncoder"/> interface.</param> + /// <param name="deviceManager">Instance of the <see cref="IDeviceManager"/> interface.</param> + /// <param name="transcodingJobHelper">Instance of <see cref="TranscodingJobHelper"/>.</param> + /// <param name="httpClientFactory">Instance of the <see cref="IHttpClientFactory"/> interface.</param> + /// <param name="httpContextAccessor">Instance of the <see cref="IHttpContextAccessor"/> interface.</param> + /// <param name="encodingHelper">Instance of <see cref="EncodingHelper"/>.</param> + public AudioHelper( + IDlnaManager dlnaManager, + IUserManager userManager, + ILibraryManager libraryManager, + IMediaSourceManager mediaSourceManager, + IServerConfigurationManager serverConfigurationManager, + IMediaEncoder mediaEncoder, + IDeviceManager deviceManager, + TranscodingJobHelper transcodingJobHelper, + IHttpClientFactory httpClientFactory, + IHttpContextAccessor httpContextAccessor, + EncodingHelper encodingHelper) { - private readonly IDlnaManager _dlnaManager; - private readonly IUserManager _userManager; - private readonly ILibraryManager _libraryManager; - private readonly IMediaSourceManager _mediaSourceManager; - private readonly IServerConfigurationManager _serverConfigurationManager; - private readonly IMediaEncoder _mediaEncoder; - private readonly IDeviceManager _deviceManager; - private readonly TranscodingJobHelper _transcodingJobHelper; - private readonly IHttpClientFactory _httpClientFactory; - private readonly IHttpContextAccessor _httpContextAccessor; - private readonly EncodingHelper _encodingHelper; - - /// <summary> - /// Initializes a new instance of the <see cref="AudioHelper"/> class. - /// </summary> - /// <param name="dlnaManager">Instance of the <see cref="IDlnaManager"/> interface.</param> - /// <param name="userManager">Instance of the <see cref="IUserManager"/> interface.</param> - /// <param name="libraryManager">Instance of the <see cref="ILibraryManager"/> interface.</param> - /// <param name="mediaSourceManager">Instance of the <see cref="IMediaSourceManager"/> interface.</param> - /// <param name="serverConfigurationManager">Instance of the <see cref="IServerConfigurationManager"/> interface.</param> - /// <param name="mediaEncoder">Instance of the <see cref="IMediaEncoder"/> interface.</param> - /// <param name="deviceManager">Instance of the <see cref="IDeviceManager"/> interface.</param> - /// <param name="transcodingJobHelper">Instance of <see cref="TranscodingJobHelper"/>.</param> - /// <param name="httpClientFactory">Instance of the <see cref="IHttpClientFactory"/> interface.</param> - /// <param name="httpContextAccessor">Instance of the <see cref="IHttpContextAccessor"/> interface.</param> - /// <param name="encodingHelper">Instance of <see cref="EncodingHelper"/>.</param> - public AudioHelper( - IDlnaManager dlnaManager, - IUserManager userManager, - ILibraryManager libraryManager, - IMediaSourceManager mediaSourceManager, - IServerConfigurationManager serverConfigurationManager, - IMediaEncoder mediaEncoder, - IDeviceManager deviceManager, - TranscodingJobHelper transcodingJobHelper, - IHttpClientFactory httpClientFactory, - IHttpContextAccessor httpContextAccessor, - EncodingHelper encodingHelper) + _dlnaManager = dlnaManager; + _userManager = userManager; + _libraryManager = libraryManager; + _mediaSourceManager = mediaSourceManager; + _serverConfigurationManager = serverConfigurationManager; + _mediaEncoder = mediaEncoder; + _deviceManager = deviceManager; + _transcodingJobHelper = transcodingJobHelper; + _httpClientFactory = httpClientFactory; + _httpContextAccessor = httpContextAccessor; + _encodingHelper = encodingHelper; + } + + /// <summary> + /// Get audio stream. + /// </summary> + /// <param name="transcodingJobType">Transcoding job type.</param> + /// <param name="streamingRequest">Streaming controller.Request dto.</param> + /// <returns>A <see cref="Task"/> containing the resulting <see cref="ActionResult"/>.</returns> + public async Task<ActionResult> GetAudioStream( + TranscodingJobType transcodingJobType, + StreamingRequestDto streamingRequest) + { + if (_httpContextAccessor.HttpContext is null) { - _dlnaManager = dlnaManager; - _userManager = userManager; - _libraryManager = libraryManager; - _mediaSourceManager = mediaSourceManager; - _serverConfigurationManager = serverConfigurationManager; - _mediaEncoder = mediaEncoder; - _deviceManager = deviceManager; - _transcodingJobHelper = transcodingJobHelper; - _httpClientFactory = httpClientFactory; - _httpContextAccessor = httpContextAccessor; - _encodingHelper = encodingHelper; + throw new ResourceNotFoundException(nameof(_httpContextAccessor.HttpContext)); } - /// <summary> - /// Get audio stream. - /// </summary> - /// <param name="transcodingJobType">Transcoding job type.</param> - /// <param name="streamingRequest">Streaming controller.Request dto.</param> - /// <returns>A <see cref="Task"/> containing the resulting <see cref="ActionResult"/>.</returns> - public async Task<ActionResult> GetAudioStream( - TranscodingJobType transcodingJobType, - StreamingRequestDto streamingRequest) - { - if (_httpContextAccessor.HttpContext is null) - { - throw new ResourceNotFoundException(nameof(_httpContextAccessor.HttpContext)); - } + bool isHeadRequest = _httpContextAccessor.HttpContext.Request.Method == System.Net.WebRequestMethods.Http.Head; - bool isHeadRequest = _httpContextAccessor.HttpContext.Request.Method == System.Net.WebRequestMethods.Http.Head; - - // CTS lifecycle is managed internally. - var cancellationTokenSource = new CancellationTokenSource(); - - using var state = await StreamingHelpers.GetStreamingState( - streamingRequest, - _httpContextAccessor.HttpContext, - _mediaSourceManager, - _userManager, - _libraryManager, - _serverConfigurationManager, - _mediaEncoder, - _encodingHelper, - _dlnaManager, - _deviceManager, - _transcodingJobHelper, - transcodingJobType, - cancellationTokenSource.Token) - .ConfigureAwait(false); - - if (streamingRequest.Static && state.DirectStreamProvider is not null) - { - StreamingHelpers.AddDlnaHeaders(state, _httpContextAccessor.HttpContext.Response.Headers, true, streamingRequest.StartTimeTicks, _httpContextAccessor.HttpContext.Request, _dlnaManager); + // CTS lifecycle is managed internally. + var cancellationTokenSource = new CancellationTokenSource(); - var liveStreamInfo = _mediaSourceManager.GetLiveStreamInfo(streamingRequest.LiveStreamId); - if (liveStreamInfo is null) - { - throw new FileNotFoundException(); - } + using var state = await StreamingHelpers.GetStreamingState( + streamingRequest, + _httpContextAccessor.HttpContext, + _mediaSourceManager, + _userManager, + _libraryManager, + _serverConfigurationManager, + _mediaEncoder, + _encodingHelper, + _dlnaManager, + _deviceManager, + _transcodingJobHelper, + transcodingJobType, + cancellationTokenSource.Token) + .ConfigureAwait(false); - var liveStream = new ProgressiveFileStream(liveStreamInfo.GetStream()); - // TODO (moved from MediaBrowser.Api): Don't hardcode contentType - return new FileStreamResult(liveStream, MimeTypes.GetMimeType("file.ts")); - } + if (streamingRequest.Static && state.DirectStreamProvider is not null) + { + StreamingHelpers.AddDlnaHeaders(state, _httpContextAccessor.HttpContext.Response.Headers, true, streamingRequest.StartTimeTicks, _httpContextAccessor.HttpContext.Request, _dlnaManager); - // Static remote stream - if (streamingRequest.Static && state.InputProtocol == MediaProtocol.Http) + var liveStreamInfo = _mediaSourceManager.GetLiveStreamInfo(streamingRequest.LiveStreamId); + if (liveStreamInfo is null) { - StreamingHelpers.AddDlnaHeaders(state, _httpContextAccessor.HttpContext.Response.Headers, true, streamingRequest.StartTimeTicks, _httpContextAccessor.HttpContext.Request, _dlnaManager); - - var httpClient = _httpClientFactory.CreateClient(NamedClient.Default); - return await FileStreamResponseHelpers.GetStaticRemoteStreamResult(state, httpClient, _httpContextAccessor.HttpContext).ConfigureAwait(false); + throw new FileNotFoundException(); } - if (streamingRequest.Static && state.InputProtocol != MediaProtocol.File) - { - return new BadRequestObjectResult($"Input protocol {state.InputProtocol} cannot be streamed statically"); - } + var liveStream = new ProgressiveFileStream(liveStreamInfo.GetStream()); + // TODO (moved from MediaBrowser.Api): Don't hardcode contentType + return new FileStreamResult(liveStream, MimeTypes.GetMimeType("file.ts")); + } - var outputPath = state.OutputFilePath; - var outputPathExists = File.Exists(outputPath); + // Static remote stream + if (streamingRequest.Static && state.InputProtocol == MediaProtocol.Http) + { + StreamingHelpers.AddDlnaHeaders(state, _httpContextAccessor.HttpContext.Response.Headers, true, streamingRequest.StartTimeTicks, _httpContextAccessor.HttpContext.Request, _dlnaManager); - var transcodingJob = _transcodingJobHelper.GetTranscodingJob(outputPath, TranscodingJobType.Progressive); - var isTranscodeCached = outputPathExists && transcodingJob is not null; + var httpClient = _httpClientFactory.CreateClient(NamedClient.Default); + return await FileStreamResponseHelpers.GetStaticRemoteStreamResult(state, httpClient, _httpContextAccessor.HttpContext).ConfigureAwait(false); + } - StreamingHelpers.AddDlnaHeaders(state, _httpContextAccessor.HttpContext.Response.Headers, streamingRequest.Static || isTranscodeCached, streamingRequest.StartTimeTicks, _httpContextAccessor.HttpContext.Request, _dlnaManager); + if (streamingRequest.Static && state.InputProtocol != MediaProtocol.File) + { + return new BadRequestObjectResult($"Input protocol {state.InputProtocol} cannot be streamed statically"); + } - // Static stream - if (streamingRequest.Static) - { - var contentType = state.GetMimeType("." + state.OutputContainer, false) ?? state.GetMimeType(state.MediaPath); + var outputPath = state.OutputFilePath; + var outputPathExists = File.Exists(outputPath); - if (state.MediaSource.IsInfiniteStream) - { - var stream = new ProgressiveFileStream(state.MediaPath, null, _transcodingJobHelper); - return new FileStreamResult(stream, contentType); - } + var transcodingJob = _transcodingJobHelper.GetTranscodingJob(outputPath, TranscodingJobType.Progressive); + var isTranscodeCached = outputPathExists && transcodingJob is not null; - return FileStreamResponseHelpers.GetStaticFileResult( - state.MediaPath, - contentType); + StreamingHelpers.AddDlnaHeaders(state, _httpContextAccessor.HttpContext.Response.Headers, streamingRequest.Static || isTranscodeCached, streamingRequest.StartTimeTicks, _httpContextAccessor.HttpContext.Request, _dlnaManager); + + // Static stream + if (streamingRequest.Static) + { + var contentType = state.GetMimeType("." + state.OutputContainer, false) ?? state.GetMimeType(state.MediaPath); + + if (state.MediaSource.IsInfiniteStream) + { + var stream = new ProgressiveFileStream(state.MediaPath, null, _transcodingJobHelper); + return new FileStreamResult(stream, contentType); } - // Need to start ffmpeg (because media can't be returned directly) - var encodingOptions = _serverConfigurationManager.GetEncodingOptions(); - var ffmpegCommandLineArguments = _encodingHelper.GetProgressiveAudioFullCommandLine(state, encodingOptions, outputPath); - return await FileStreamResponseHelpers.GetTranscodedFile( - state, - isHeadRequest, - _httpContextAccessor.HttpContext, - _transcodingJobHelper, - ffmpegCommandLineArguments, - transcodingJobType, - cancellationTokenSource).ConfigureAwait(false); + return FileStreamResponseHelpers.GetStaticFileResult( + state.MediaPath, + contentType); } + + // Need to start ffmpeg (because media can't be returned directly) + var encodingOptions = _serverConfigurationManager.GetEncodingOptions(); + var ffmpegCommandLineArguments = _encodingHelper.GetProgressiveAudioFullCommandLine(state, encodingOptions, outputPath); + return await FileStreamResponseHelpers.GetTranscodedFile( + state, + isHeadRequest, + _httpContextAccessor.HttpContext, + _transcodingJobHelper, + ffmpegCommandLineArguments, + transcodingJobType, + cancellationTokenSource).ConfigureAwait(false); } } |
