public async Task <object> Post(OpenMediaSource request) { 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, request.PlaySessionId, request.UserId); } else { if (!string.IsNullOrWhiteSpace(result.MediaSource.TranscodingUrl)) { result.MediaSource.TranscodingUrl += "&LiveStreamId=" + result.MediaSource.LiveStreamId; } } return(ToOptimizedResult(result)); }
public async Task <object> Post(GetPostedPlaybackInfo request) { var authInfo = AuthorizationContext.GetAuthorizationInfo(Request); var profile = request.DeviceProfile; //Logger.Info("GetPostedPlaybackInfo profile: {0}", _json.SerializeToString(profile)); if (profile == null) { var caps = _deviceManager.GetCapabilities(authInfo.DeviceId); if (caps != null) { profile = caps.DeviceProfile; } } var info = await GetPlaybackInfo(request.Id, request.UserId, new[] { MediaType.Audio, MediaType.Video }, request.MediaSourceId, request.LiveStreamId).ConfigureAwait(false); if (profile != null) { var mediaSourceId = request.MediaSourceId; SetDeviceSpecificData(request.Id, info, profile, authInfo, request.MaxStreamingBitrate ?? profile.MaxStreamingBitrate, request.StartTimeTicks ?? 0, mediaSourceId, request.AudioStreamIndex, request.SubtitleStreamIndex, request.UserId); } return(ToOptimizedResult(info)); }
public async Task <object> Post(CreateCollection request) { var userId = AuthorizationContext.GetAuthorizationInfo(Request).UserId; var parentId = string.IsNullOrWhiteSpace(request.ParentId) ? (Guid?)null : new Guid(request.ParentId); var item = await _collectionManager.CreateCollection(new CollectionCreationOptions { IsLocked = request.IsLocked, Name = request.Name, ParentId = parentId, ItemIdList = (request.Ids ?? string.Empty).Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).Select(i => new Guid(i)).ToList(), UserIds = new List <Guid> { new Guid(userId) } }).ConfigureAwait(false); var dtoOptions = GetDtoOptions(request); var dto = _dtoService.GetBaseItemDto(item, dtoOptions); return(ToOptimizedResult(new CollectionCreationResult { Id = dto.Id })); }
public async Task PostAsync(UpdateUserPassword request) { AssertCanUpdateUser(_userManager, request.Id); var user = _userManager.GetUserById(request.Id); if (user == null) { throw new ResourceNotFoundException("User not found"); } if (request.ResetPassword) { await _userManager.ResetPassword(user).ConfigureAwait(false); } else { var success = await _userManager.AuthenticateUser(user.Name, request.CurrentPassword, Request.RemoteIp).ConfigureAwait(false); if (!success) { throw new ArgumentException("Invalid user or password entered."); } await _userManager.ChangePassword(user, request.NewPassword).ConfigureAwait(false); var currentToken = AuthorizationContext.GetAuthorizationInfo(Request).Token; await _sessionMananger.RevokeUserTokens(user.Id.ToString("N"), currentToken).ConfigureAwait(false); } }
public async Task <object> Post(AuthenticateUserByName request) { var auth = AuthorizationContext.GetAuthorizationInfo(Request); if (string.IsNullOrWhiteSpace(auth.Client)) { auth.Client = "Unknown app"; } if (string.IsNullOrWhiteSpace(auth.Device)) { auth.Device = "Unknown device"; } if (string.IsNullOrWhiteSpace(auth.Version)) { auth.Version = "Unknown version"; } if (string.IsNullOrWhiteSpace(auth.DeviceId)) { auth.DeviceId = "Unknown device id"; } var result = await _sessionMananger.AuthenticateNewSession(new AuthenticationRequest { App = auth.Client, AppVersion = auth.Version, DeviceId = auth.DeviceId, DeviceName = auth.Device, PasswordSha1 = request.Password, PasswordMd5 = request.PasswordMd5, RemoteEndPoint = Request.RemoteIp, Username = request.Username }).ConfigureAwait(false); return(ToOptimizedResult(result)); }
private void AddSubtitles(StreamState state, IEnumerable <MediaStream> subtitles, StringBuilder builder) { var selectedIndex = state.SubtitleStream == null || state.SubtitleDeliveryMethod != SubtitleDeliveryMethod.Hls ? (int?)null : state.SubtitleStream.Index; foreach (var stream in subtitles) { const string format = "#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID=\"subs\",NAME=\"{0}\",DEFAULT={1},FORCED={2},AUTOSELECT=YES,URI=\"{3}\",LANGUAGE=\"{4}\""; var name = stream.DisplayTitle; var isDefault = selectedIndex.HasValue && selectedIndex.Value == stream.Index; var isForced = stream.IsForced; var url = string.Format("{0}/Subtitles/{1}/subtitles.m3u8?SegmentLength={2}&api_key={3}", state.Request.MediaSourceId, stream.Index.ToString(CultureInfo.InvariantCulture), 30.ToString(CultureInfo.InvariantCulture), AuthorizationContext.GetAuthorizationInfo(Request).Token); var line = string.Format(format, name, isDefault ? "YES" : "NO", isForced ? "YES" : "NO", url, stream.Language ?? "Unknown"); builder.AppendLine(line); } }
private async Task UpdateUserPolicy(UpdateUserPolicy request) { var user = _userManager.GetUserById(request.Id); // If removing admin access if (!request.IsAdministrator && user.Policy.IsAdministrator) { if (_userManager.Users.Count(i => i.Policy.IsAdministrator) == 1) { throw new ArgumentException("There must be at least one user in the system with administrative access."); } } // If disabling if (request.IsDisabled && user.Policy.IsAdministrator) { throw new ArgumentException("Administrators cannot be disabled."); } // If disabling if (request.IsDisabled && !user.Policy.IsDisabled) { if (_userManager.Users.Count(i => !i.Policy.IsDisabled) == 1) { throw new ArgumentException("There must be at least one enabled user in the system."); } var currentToken = AuthorizationContext.GetAuthorizationInfo(Request).Token; await _sessionMananger.RevokeUserTokens(user.Id.ToString("N"), currentToken).ConfigureAwait(false); } await _userManager.UpdateUserPolicy(request.Id, request).ConfigureAwait(false); }
public async Task <object> Get(GetRecording request) { var user = string.IsNullOrEmpty(request.UserId) ? null : _userManager.GetUserById(request.UserId); var options = new DtoOptions(); options.DeviceId = AuthorizationContext.GetAuthorizationInfo(Request).DeviceId; var result = await _liveTvManager.GetRecording(request.Id, options, CancellationToken.None, user).ConfigureAwait(false); return(ToOptimizedSerializedResultUsingCache(result)); }
public object Get(GetSyncDialogOptions request) { var result = new SyncDialogOptions(); result.Targets = _syncManager.GetSyncTargets(request.UserId) .ToList(); if (!string.IsNullOrWhiteSpace(request.TargetId)) { result.Targets = result.Targets .Where(i => string.Equals(i.Id, request.TargetId, StringComparison.OrdinalIgnoreCase)) .ToList(); result.QualityOptions = _syncManager .GetQualityOptions(request.TargetId) .ToList(); result.ProfileOptions = _syncManager .GetProfileOptions(request.TargetId) .ToList(); } if (request.Category.HasValue) { result.Options = SyncHelper.GetSyncOptions(request.Category.Value); } else { var dtoOptions = new DtoOptions { Fields = new List <ItemFields> { ItemFields.SyncInfo } }; var auth = AuthorizationContext.GetAuthorizationInfo(Request); var authenticatedUser = _userManager.GetUserById(auth.UserId); var items = request.ItemIds.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries) .Select(_libraryManager.GetItemById) .Where(i => i != null); var dtos = _dtoService.GetBaseItemDtos(items, dtoOptions, authenticatedUser) .ToList(); result.Options = SyncHelper.GetSyncOptions(dtos); } return(ToOptimizedResult(result)); }
public void Post(ReportPlaybackStopped request) { if (!string.IsNullOrWhiteSpace(request.PlaySessionId)) { ApiEntryPoint.Instance.KillTranscodingJobs(AuthorizationContext.GetAuthorizationInfo(Request).DeviceId, request.PlaySessionId, s => true); } request.SessionId = GetSession().Result.Id; var task = _sessionManager.OnPlaybackStopped(request); Task.WaitAll(task); }
public void Post(ValidatePinRequest request) { MyPinStatus status; if (!_activeRequests.TryGetValue(request.Pin, out status)) { throw new ResourceNotFoundException(); } EnsureValid(status); status.IsConfirmed = true; status.UserId = AuthorizationContext.GetAuthorizationInfo(Request).UserId; }
public async Task <object> Get(GetSubtitlePlaylist request) { var item = (Video)_libraryManager.GetItemById(new Guid(request.Id)); var mediaSource = await _mediaSourceManager.GetMediaSource(item, request.MediaSourceId, null, false, CancellationToken.None).ConfigureAwait(false); var builder = new StringBuilder(); var runtime = mediaSource.RunTimeTicks ?? -1; if (runtime <= 0) { throw new ArgumentException("HLS Subtitles are not supported for this media."); } builder.AppendLine("#EXTM3U"); builder.AppendLine("#EXT-X-TARGETDURATION:" + request.SegmentLength.ToString(CultureInfo.InvariantCulture)); builder.AppendLine("#EXT-X-VERSION:3"); builder.AppendLine("#EXT-X-MEDIA-SEQUENCE:0"); builder.AppendLine("#EXT-X-PLAYLIST-TYPE:VOD"); long positionTicks = 0; var segmentLengthTicks = TimeSpan.FromSeconds(request.SegmentLength).Ticks; var accessToken = AuthorizationContext.GetAuthorizationInfo(Request).Token; while (positionTicks < runtime) { var remaining = runtime - positionTicks; var lengthTicks = Math.Min(remaining, segmentLengthTicks); builder.AppendLine("#EXTINF:" + TimeSpan.FromTicks(lengthTicks).TotalSeconds.ToString(CultureInfo.InvariantCulture) + ","); var endPositionTicks = Math.Min(runtime, positionTicks + segmentLengthTicks); var url = string.Format("stream.vtt?CopyTimestamps=true&AddVttTimeMap=true&StartPositionTicks={0}&EndPositionTicks={1}&api_key={2}", positionTicks.ToString(CultureInfo.InvariantCulture), endPositionTicks.ToString(CultureInfo.InvariantCulture), accessToken); builder.AppendLine(url); positionTicks += segmentLengthTicks; } builder.AppendLine("#EXT-X-ENDLIST"); return(ResultFactory.GetResult(builder.ToString(), MimeTypes.GetMimeType("playlist.m3u8"), new Dictionary <string, string>())); }
public async Task <object> Get(GetUserViews request) { var query = new UserViewQuery { UserId = request.UserId }; if (request.IncludeExternalContent.HasValue) { query.IncludeExternalContent = request.IncludeExternalContent.Value; } if (!string.IsNullOrWhiteSpace(request.PresetViews)) { query.PresetViews = request.PresetViews.Split(','); } var app = AuthorizationContext.GetAuthorizationInfo(Request).Client ?? string.Empty; if (app.IndexOf("emby rt", StringComparison.OrdinalIgnoreCase) != -1) { query.PresetViews = new[] { CollectionType.Music, CollectionType.Movies, CollectionType.TvShows }; } //query.PresetViews = new[] { CollectionType.Music, CollectionType.Movies, CollectionType.TvShows }; var folders = await _userViewManager.GetUserViews(query, CancellationToken.None).ConfigureAwait(false); var dtoOptions = GetDtoOptions(request); dtoOptions.Fields = new List <ItemFields>(); dtoOptions.Fields.Add(ItemFields.PrimaryImageAspectRatio); dtoOptions.Fields.Add(ItemFields.DisplayPreferencesId); var user = _userManager.GetUserById(request.UserId); var dtos = folders.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user)) .ToArray(); var result = new QueryResult <BaseItemDto> { Items = dtos, TotalRecordCount = dtos.Length }; return(ToOptimizedResult(result)); }
public async Task <object> Post(AuthenticateUserByName request) { var auth = AuthorizationContext.GetAuthorizationInfo(Request); var result = await _sessionMananger.AuthenticateNewSession(new AuthenticationRequest { App = auth.Client, AppVersion = auth.Version, DeviceId = auth.DeviceId, DeviceName = auth.Device, PasswordSha1 = request.Password, PasswordMd5 = request.PasswordMd5, RemoteEndPoint = Request.RemoteIp, Username = request.Username }).ConfigureAwait(false); return(ToOptimizedResult(result)); }
public async Task <object> Get(GetRecordings request) { var options = GetDtoOptions(request); options.DeviceId = AuthorizationContext.GetAuthorizationInfo(Request).DeviceId; var result = await _liveTvManager.GetRecordings(new RecordingQuery { ChannelId = request.ChannelId, UserId = request.UserId, GroupId = request.GroupId, StartIndex = request.StartIndex, Limit = request.Limit, Status = request.Status, SeriesTimerId = request.SeriesTimerId, IsInProgress = request.IsInProgress }, options, CancellationToken.None).ConfigureAwait(false); return(ToOptimizedResult(result)); }
public async Task <object> Get(GetLocalUser request) { var user = await _connectManager.GetLocalUser(request.ConnectUserId).ConfigureAwait(false); if (user == null) { throw new ResourceNotFoundException(); } var auth = AuthorizationContext.GetAuthorizationInfo(Request); if (string.IsNullOrWhiteSpace(auth.Client)) { return(ToOptimizedResult(new ConnectAuthenticationExchangeResult { AccessToken = user.ConnectAccessKey, LocalUserId = user.Id.ToString("N") })); } var session = await _sessionManager.CreateNewSession(new AuthenticationRequest { App = auth.Client, AppVersion = auth.Version, DeviceId = auth.DeviceId, DeviceName = auth.Device, RemoteEndPoint = Request.RemoteIp, Username = user.Name, UserId = user.Id.ToString("N") }).ConfigureAwait(false); return(ToOptimizedResult(new ConnectAuthenticationExchangeResult { AccessToken = session.AccessToken, LocalUserId = session.User.Id })); }
private object Get(GetUsers request, bool filterByDevice) { var users = _userManager.Users; if (request.IsDisabled.HasValue) { users = users.Where(i => i.Policy.IsDisabled == request.IsDisabled.Value); } if (request.IsHidden.HasValue) { users = users.Where(i => i.Policy.IsHidden == request.IsHidden.Value); } if (request.IsGuest.HasValue) { users = users.Where(i => (i.ConnectLinkType.HasValue && i.ConnectLinkType.Value == UserLinkType.Guest) == request.IsGuest.Value); } if (filterByDevice) { var deviceId = AuthorizationContext.GetAuthorizationInfo(Request).DeviceId; if (!string.IsNullOrWhiteSpace(deviceId)) { users = users.Where(i => _deviceManager.CanAccessDevice(i.Id.ToString("N"), deviceId)); } } var result = users .OrderBy(u => u.Name) .Select(i => _userManager.GetUserDto(i, Request.RemoteIp)) .ToList(); return(ToOptimizedResult(result)); }
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, SubtitleEncoder, DeviceManager, MediaSourceManager, JsonSerializer, AuthorizationContext, NetworkManager) { 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, SubtitleEncoder, DeviceManager, MediaSourceManager, JsonSerializer, AuthorizationContext, EnvironmentInfo) { 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)); } }
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) { 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]; var isStatic = mediaSource.SupportsDirectStream; if (!isStatic && string.Equals(mediaSource.TranscodingSubProtocol, "hls", StringComparison.OrdinalIgnoreCase)) { var service = new DynamicHlsService(ServerConfigurationManager, UserManager, LibraryManager, IsoManager, MediaEncoder, FileSystem, DlnaManager, SubtitleEncoder, DeviceManager, MediaSourceManager, ZipClient, JsonSerializer, AuthorizationContext, NetworkManager) { 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 }; if (isHeadRequest) { return(await service.Head(newRequest).ConfigureAwait(false)); } return(await service.Get(newRequest).ConfigureAwait(false)); } else { var service = new AudioService(ServerConfigurationManager, UserManager, LibraryManager, IsoManager, MediaEncoder, FileSystem, DlnaManager, SubtitleEncoder, DeviceManager, MediaSourceManager, ZipClient, JsonSerializer, AuthorizationContext, ImageProcessor) { 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 }; if (isHeadRequest) { return(await service.Head(newRequest).ConfigureAwait(false)); } return(await service.Get(newRequest).ConfigureAwait(false)); } }
/// <summary> /// Gets the state. /// </summary> /// <param name="request">The request.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>StreamState.</returns> protected async Task <StreamState> GetState(StreamRequest request, CancellationToken cancellationToken) { ParseDlnaHeaders(request); if (!string.IsNullOrWhiteSpace(request.Params)) { ParseParams(request); } var url = Request.PathInfo; if (string.IsNullOrEmpty(request.AudioCodec)) { request.AudioCodec = EncodingHelper.InferAudioCodec(url); } var state = new StreamState(MediaSourceManager, Logger, TranscodingJobType) { Request = request, RequestedUrl = url, UserAgent = Request.UserAgent }; var auth = AuthorizationContext.GetAuthorizationInfo(Request); if (!string.IsNullOrWhiteSpace(auth.UserId)) { state.User = UserManager.GetUserById(auth.UserId); } //if ((Request.UserAgent ?? string.Empty).IndexOf("iphone", StringComparison.OrdinalIgnoreCase) != -1 || // (Request.UserAgent ?? string.Empty).IndexOf("ipad", StringComparison.OrdinalIgnoreCase) != -1 || // (Request.UserAgent ?? string.Empty).IndexOf("ipod", StringComparison.OrdinalIgnoreCase) != -1) //{ // state.SegmentLength = 6; //} if (state.VideoRequest != null) { if (!string.IsNullOrWhiteSpace(state.VideoRequest.VideoCodec)) { state.SupportedVideoCodecs = state.VideoRequest.VideoCodec.Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToList(); state.VideoRequest.VideoCodec = state.SupportedVideoCodecs.FirstOrDefault(); } } if (!string.IsNullOrWhiteSpace(request.AudioCodec)) { state.SupportedAudioCodecs = request.AudioCodec.Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToList(); state.Request.AudioCodec = state.SupportedAudioCodecs.FirstOrDefault(i => MediaEncoder.CanEncodeToAudioCodec(i)) ?? state.SupportedAudioCodecs.FirstOrDefault(); } if (!string.IsNullOrWhiteSpace(request.SubtitleCodec)) { state.SupportedSubtitleCodecs = request.SubtitleCodec.Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToList(); state.Request.SubtitleCodec = state.SupportedSubtitleCodecs.FirstOrDefault(i => MediaEncoder.CanEncodeToSubtitleCodec(i)) ?? state.SupportedSubtitleCodecs.FirstOrDefault(); } var item = LibraryManager.GetItemById(request.Id); state.IsInputVideo = string.Equals(item.MediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase); MediaSourceInfo mediaSource = null; if (string.IsNullOrWhiteSpace(request.LiveStreamId)) { TranscodingJob currentJob = !string.IsNullOrWhiteSpace(request.PlaySessionId) ? ApiEntryPoint.Instance.GetTranscodingJob(request.PlaySessionId) : null; if (currentJob != null) { mediaSource = currentJob.MediaSource; } if (mediaSource == null) { var mediaSources = (await MediaSourceManager.GetPlayackMediaSources(request.Id, null, false, new[] { MediaType.Audio, MediaType.Video }, cancellationToken).ConfigureAwait(false)).ToList(); mediaSource = string.IsNullOrEmpty(request.MediaSourceId) ? mediaSources.First() : mediaSources.FirstOrDefault(i => string.Equals(i.Id, request.MediaSourceId)); if (mediaSource == null && string.Equals(request.Id, request.MediaSourceId, StringComparison.OrdinalIgnoreCase)) { mediaSource = mediaSources.First(); } } } else { var liveStreamInfo = await MediaSourceManager.GetLiveStreamWithDirectStreamProvider(request.LiveStreamId, cancellationToken).ConfigureAwait(false); mediaSource = liveStreamInfo.Item1; state.DirectStreamProvider = liveStreamInfo.Item2; } var videoRequest = request as VideoStreamRequest; EncodingHelper.AttachMediaSourceInfo(state, mediaSource, url); var container = Path.GetExtension(state.RequestedUrl); if (string.IsNullOrEmpty(container)) { container = request.Static ? state.InputContainer : (Path.GetExtension(GetOutputFilePath(state)) ?? string.Empty).TrimStart('.'); } state.OutputContainer = (container ?? string.Empty).TrimStart('.'); state.OutputAudioBitrate = EncodingHelper.GetAudioBitrateParam(state.Request, state.AudioStream); state.OutputAudioSampleRate = request.AudioSampleRate; state.OutputAudioCodec = state.Request.AudioCodec; state.OutputAudioChannels = EncodingHelper.GetNumAudioChannelsParam(state.Request, state.AudioStream, state.OutputAudioCodec); if (videoRequest != null) { state.OutputVideoCodec = state.VideoRequest.VideoCodec; state.OutputVideoBitrate = EncodingHelper.GetVideoBitrateParamValue(state.VideoRequest, state.VideoStream, state.OutputVideoCodec); if (videoRequest != null) { EncodingHelper.TryStreamCopy(state); } if (state.OutputVideoBitrate.HasValue && !string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase)) { var resolution = ResolutionNormalizer.Normalize( state.VideoStream == null ? (int?)null : state.VideoStream.BitRate, state.OutputVideoBitrate.Value, state.VideoStream == null ? null : state.VideoStream.Codec, state.OutputVideoCodec, videoRequest.MaxWidth, videoRequest.MaxHeight); videoRequest.MaxWidth = resolution.MaxWidth; videoRequest.MaxHeight = resolution.MaxHeight; } ApplyDeviceProfileSettings(state); } else { ApplyDeviceProfileSettings(state); } state.OutputFilePath = GetOutputFilePath(state); return(state); }
/// <summary> /// Starts the FFMPEG. /// </summary> /// <param name="state">The state.</param> /// <param name="outputPath">The output path.</param> /// <param name="cancellationTokenSource">The cancellation token source.</param> /// <param name="workingDirectory">The working directory.</param> /// <returns>Task.</returns> protected async Task <TranscodingJob> StartFfMpeg(StreamState state, string outputPath, CancellationTokenSource cancellationTokenSource, string workingDirectory = null) { FileSystem.CreateDirectory(FileSystem.GetDirectoryName(outputPath)); await AcquireResources(state, cancellationTokenSource).ConfigureAwait(false); if (state.VideoRequest != null && !string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase)) { var auth = AuthorizationContext.GetAuthorizationInfo(Request); if (!string.IsNullOrWhiteSpace(auth.UserId)) { var user = UserManager.GetUserById(auth.UserId); if (!user.Policy.EnableVideoPlaybackTranscoding) { ApiEntryPoint.Instance.OnTranscodeFailedToStart(outputPath, TranscodingJobType, state); throw new ArgumentException("User does not have access to video transcoding"); } } } var transcodingId = Guid.NewGuid().ToString("N"); var commandLineArgs = GetCommandLineArguments(outputPath, state, true); var process = ApiEntryPoint.Instance.ProcessFactory.Create(new ProcessOptions { CreateNoWindow = true, UseShellExecute = false, // Must consume both stdout and stderr or deadlocks may occur //RedirectStandardOutput = true, RedirectStandardError = true, RedirectStandardInput = true, FileName = MediaEncoder.EncoderPath, Arguments = commandLineArgs, IsHidden = true, ErrorDialog = false, EnableRaisingEvents = true, WorkingDirectory = !string.IsNullOrWhiteSpace(workingDirectory) ? workingDirectory : null }); var transcodingJob = ApiEntryPoint.Instance.OnTranscodeBeginning(outputPath, state.Request.PlaySessionId, state.MediaSource.LiveStreamId, transcodingId, TranscodingJobType, process, state.Request.DeviceId, state, cancellationTokenSource); var commandLineLogMessage = process.StartInfo.FileName + " " + process.StartInfo.Arguments; Logger.Info(commandLineLogMessage); var logFilePrefix = "ffmpeg-transcode"; if (state.VideoRequest != null && string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase) && string.Equals(state.OutputAudioCodec, "copy", StringComparison.OrdinalIgnoreCase)) { logFilePrefix = "ffmpeg-directstream"; } else if (state.VideoRequest != null && string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase)) { logFilePrefix = "ffmpeg-remux"; } var logFilePath = Path.Combine(ServerConfigurationManager.ApplicationPaths.LogDirectoryPath, logFilePrefix + "-" + Guid.NewGuid() + ".txt"); FileSystem.CreateDirectory(FileSystem.GetDirectoryName(logFilePath)); // FFMpeg writes debug/error info to stderr. This is useful when debugging so let's put it in the log directory. state.LogFileStream = FileSystem.GetFileStream(logFilePath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, true); var commandLineLogMessageBytes = Encoding.UTF8.GetBytes(Request.AbsoluteUri + Environment.NewLine + Environment.NewLine + JsonSerializer.SerializeToString(state.MediaSource) + Environment.NewLine + Environment.NewLine + commandLineLogMessage + Environment.NewLine + Environment.NewLine); await state.LogFileStream.WriteAsync(commandLineLogMessageBytes, 0, commandLineLogMessageBytes.Length, cancellationTokenSource.Token).ConfigureAwait(false); process.Exited += (sender, args) => OnFfMpegProcessExited(process, transcodingJob, state); try { process.Start(); } catch (Exception ex) { Logger.ErrorException("Error starting ffmpeg", ex); ApiEntryPoint.Instance.OnTranscodeFailedToStart(outputPath, TranscodingJobType, state); throw; } // MUST read both stdout and stderr asynchronously or a deadlock may occurr //process.BeginOutputReadLine(); state.TranscodingJob = transcodingJob; // Important - don't await the log task or we won't be able to kill ffmpeg when the user stops playback new JobLogger(Logger).StartStreamingLog(state, process.StandardError.BaseStream, state.LogFileStream); // Wait for the file to exist before proceeeding while (!FileSystem.FileExists(state.WaitForPath ?? outputPath) && !transcodingJob.HasExited) { await Task.Delay(100, cancellationTokenSource.Token).ConfigureAwait(false); } if (state.IsInputVideo && transcodingJob.Type == TranscodingJobType.Progressive && !transcodingJob.HasExited) { await Task.Delay(1000, cancellationTokenSource.Token).ConfigureAwait(false); if (state.ReadInputAtNativeFramerate && !transcodingJob.HasExited) { await Task.Delay(1500, cancellationTokenSource.Token).ConfigureAwait(false); } } if (!transcodingJob.HasExited) { StartThrottler(state, transcodingJob); } return(transcodingJob); }
/// <summary> /// Gets the state. /// </summary> /// <param name="request">The request.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>StreamState.</returns> protected async Task <StreamState> GetState(StreamRequest request, CancellationToken cancellationToken) { ParseDlnaHeaders(request); if (!string.IsNullOrWhiteSpace(request.Params)) { ParseParams(request); } ParseStreamOptions(request); var url = Request.PathInfo; if (string.IsNullOrEmpty(request.AudioCodec)) { request.AudioCodec = EncodingHelper.InferAudioCodec(url); } var enableDlnaHeaders = !string.IsNullOrWhiteSpace(request.Params) || string.Equals(GetHeader("GetContentFeatures.DLNA.ORG"), "1", StringComparison.OrdinalIgnoreCase); var state = new StreamState(MediaSourceManager, TranscodingJobType) { Request = request, RequestedUrl = url, UserAgent = Request.UserAgent, EnableDlnaHeaders = enableDlnaHeaders }; var auth = AuthorizationContext.GetAuthorizationInfo(Request); if (!auth.UserId.Equals(Guid.Empty)) { state.User = UserManager.GetUserById(auth.UserId); } //if ((Request.UserAgent ?? string.Empty).IndexOf("iphone", StringComparison.OrdinalIgnoreCase) != -1 || // (Request.UserAgent ?? string.Empty).IndexOf("ipad", StringComparison.OrdinalIgnoreCase) != -1 || // (Request.UserAgent ?? string.Empty).IndexOf("ipod", StringComparison.OrdinalIgnoreCase) != -1) //{ // state.SegmentLength = 6; //} if (state.VideoRequest != null && !string.IsNullOrWhiteSpace(state.VideoRequest.VideoCodec)) { state.SupportedVideoCodecs = state.VideoRequest.VideoCodec.Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToArray(); state.VideoRequest.VideoCodec = state.SupportedVideoCodecs.FirstOrDefault(); } if (!string.IsNullOrWhiteSpace(request.AudioCodec)) { state.SupportedAudioCodecs = request.AudioCodec.Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToArray(); state.Request.AudioCodec = state.SupportedAudioCodecs.FirstOrDefault(i => MediaEncoder.CanEncodeToAudioCodec(i)) ?? state.SupportedAudioCodecs.FirstOrDefault(); } if (!string.IsNullOrWhiteSpace(request.SubtitleCodec)) { state.SupportedSubtitleCodecs = request.SubtitleCodec.Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToArray(); state.Request.SubtitleCodec = state.SupportedSubtitleCodecs.FirstOrDefault(i => MediaEncoder.CanEncodeToSubtitleCodec(i)) ?? state.SupportedSubtitleCodecs.FirstOrDefault(); } var item = LibraryManager.GetItemById(request.Id); state.IsInputVideo = string.Equals(item.MediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase); //var primaryImage = item.GetImageInfo(ImageType.Primary, 0) ?? // item.Parents.Select(i => i.GetImageInfo(ImageType.Primary, 0)).FirstOrDefault(i => i != null); //if (primaryImage != null) //{ // state.AlbumCoverPath = primaryImage.Path; //} MediaSourceInfo mediaSource = null; if (string.IsNullOrWhiteSpace(request.LiveStreamId)) { var currentJob = !string.IsNullOrWhiteSpace(request.PlaySessionId) ? ApiEntryPoint.Instance.GetTranscodingJob(request.PlaySessionId) : null; if (currentJob != null) { mediaSource = currentJob.MediaSource; } if (mediaSource == null) { var mediaSources = (await MediaSourceManager.GetPlayackMediaSources(LibraryManager.GetItemById(request.Id), null, false, false, cancellationToken).ConfigureAwait(false)).ToList(); mediaSource = string.IsNullOrEmpty(request.MediaSourceId) ? mediaSources[0] : mediaSources.Find(i => string.Equals(i.Id, request.MediaSourceId)); if (mediaSource == null && request.MediaSourceId.Equals(request.Id)) { mediaSource = mediaSources[0]; } } } else { var liveStreamInfo = await MediaSourceManager.GetLiveStreamWithDirectStreamProvider(request.LiveStreamId, cancellationToken).ConfigureAwait(false); mediaSource = liveStreamInfo.Item1; state.DirectStreamProvider = liveStreamInfo.Item2; } var videoRequest = request as VideoStreamRequest; EncodingHelper.AttachMediaSourceInfo(state, mediaSource, url); var container = Path.GetExtension(state.RequestedUrl); if (string.IsNullOrEmpty(container)) { container = request.Container; } if (string.IsNullOrEmpty(container)) { container = request.Static ? StreamBuilder.NormalizeMediaSourceFormatIntoSingleContainer(state.InputContainer, state.MediaPath, null, DlnaProfileType.Audio) : GetOutputFileExtension(state); } state.OutputContainer = (container ?? string.Empty).TrimStart('.'); state.OutputAudioBitrate = EncodingHelper.GetAudioBitrateParam(state.Request, state.AudioStream); state.OutputAudioCodec = state.Request.AudioCodec; state.OutputAudioChannels = EncodingHelper.GetNumAudioChannelsParam(state, state.AudioStream, state.OutputAudioCodec); if (videoRequest != null) { state.OutputVideoCodec = state.VideoRequest.VideoCodec; state.OutputVideoBitrate = EncodingHelper.GetVideoBitrateParamValue(state.VideoRequest, state.VideoStream, state.OutputVideoCodec); if (videoRequest != null) { EncodingHelper.TryStreamCopy(state); } if (state.OutputVideoBitrate.HasValue && !string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase)) { var resolution = ResolutionNormalizer.Normalize( state.VideoStream?.BitRate, state.VideoStream?.Width, state.VideoStream?.Height, state.OutputVideoBitrate.Value, state.VideoStream?.Codec, state.OutputVideoCodec, videoRequest.MaxWidth, videoRequest.MaxHeight); videoRequest.MaxWidth = resolution.MaxWidth; videoRequest.MaxHeight = resolution.MaxHeight; } } ApplyDeviceProfileSettings(state); var ext = string.IsNullOrWhiteSpace(state.OutputContainer) ? GetOutputFileExtension(state) : ('.' + state.OutputContainer); var encodingOptions = ApiEntryPoint.Instance.GetEncodingOptions(); state.OutputFilePath = GetOutputFilePath(state, encodingOptions, ext); return(state); }
/// <summary> /// Starts the FFMPEG. /// </summary> /// <param name="state">The state.</param> /// <param name="outputPath">The output path.</param> /// <param name="cancellationTokenSource">The cancellation token source.</param> /// <param name="workingDirectory">The working directory.</param> /// <returns>Task.</returns> protected async Task <TranscodingJob> StartFfMpeg( StreamState state, string outputPath, CancellationTokenSource cancellationTokenSource, string workingDirectory = null) { Directory.CreateDirectory(Path.GetDirectoryName(outputPath)); await AcquireResources(state, cancellationTokenSource).ConfigureAwait(false); if (state.VideoRequest != null && !string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase)) { var auth = AuthorizationContext.GetAuthorizationInfo(Request); if (auth.User != null && !auth.User.Policy.EnableVideoPlaybackTranscoding) { ApiEntryPoint.Instance.OnTranscodeFailedToStart(outputPath, TranscodingJobType, state); throw new ArgumentException("User does not have access to video transcoding"); } } var encodingOptions = ApiEntryPoint.Instance.GetEncodingOptions(); var process = new Process() { StartInfo = new ProcessStartInfo() { WindowStyle = ProcessWindowStyle.Hidden, CreateNoWindow = true, UseShellExecute = false, // Must consume both stdout and stderr or deadlocks may occur //RedirectStandardOutput = true, RedirectStandardError = true, RedirectStandardInput = true, FileName = MediaEncoder.EncoderPath, Arguments = GetCommandLineArguments(outputPath, encodingOptions, state, true), WorkingDirectory = string.IsNullOrWhiteSpace(workingDirectory) ? null : workingDirectory, ErrorDialog = false }, EnableRaisingEvents = true }; var transcodingJob = ApiEntryPoint.Instance.OnTranscodeBeginning(outputPath, state.Request.PlaySessionId, state.MediaSource.LiveStreamId, Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture), TranscodingJobType, process, state.Request.DeviceId, state, cancellationTokenSource); var commandLineLogMessage = process.StartInfo.FileName + " " + process.StartInfo.Arguments; Logger.LogInformation(commandLineLogMessage); var logFilePrefix = "ffmpeg-transcode"; if (state.VideoRequest != null && string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase)) { if (string.Equals(state.OutputAudioCodec, "copy", StringComparison.OrdinalIgnoreCase)) { logFilePrefix = "ffmpeg-directstream"; } else { logFilePrefix = "ffmpeg-remux"; } } var logFilePath = Path.Combine(ServerConfigurationManager.ApplicationPaths.LogDirectoryPath, logFilePrefix + "-" + Guid.NewGuid() + ".txt"); // FFMpeg writes debug/error info to stderr. This is useful when debugging so let's put it in the log directory. Stream logStream = FileSystem.GetFileStream(logFilePath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, true); var commandLineLogMessageBytes = Encoding.UTF8.GetBytes(Request.AbsoluteUri + Environment.NewLine + Environment.NewLine + JsonSerializer.SerializeToString(state.MediaSource) + Environment.NewLine + Environment.NewLine + commandLineLogMessage + Environment.NewLine + Environment.NewLine); await logStream.WriteAsync(commandLineLogMessageBytes, 0, commandLineLogMessageBytes.Length, cancellationTokenSource.Token).ConfigureAwait(false); process.Exited += (sender, args) => OnFfMpegProcessExited(process, transcodingJob, state); try { process.Start(); } catch (Exception ex) { Logger.LogError(ex, "Error starting ffmpeg"); ApiEntryPoint.Instance.OnTranscodeFailedToStart(outputPath, TranscodingJobType, state); throw; } Logger.LogDebug("Launched ffmpeg process"); state.TranscodingJob = transcodingJob; // Important - don't await the log task or we won't be able to kill ffmpeg when the user stops playback _ = new JobLogger(Logger).StartStreamingLog(state, process.StandardError.BaseStream, logStream); // Wait for the file to exist before proceeeding var ffmpegTargetFile = state.WaitForPath ?? outputPath; Logger.LogDebug("Waiting for the creation of {0}", ffmpegTargetFile); while (!File.Exists(ffmpegTargetFile) && !transcodingJob.HasExited) { await Task.Delay(100, cancellationTokenSource.Token).ConfigureAwait(false); } Logger.LogDebug("File {0} created or transcoding has finished", ffmpegTargetFile); if (state.IsInputVideo && transcodingJob.Type == TranscodingJobType.Progressive && !transcodingJob.HasExited) { await Task.Delay(1000, cancellationTokenSource.Token).ConfigureAwait(false); if (state.ReadInputAtNativeFramerate && !transcodingJob.HasExited) { await Task.Delay(1500, cancellationTokenSource.Token).ConfigureAwait(false); } } if (!transcodingJob.HasExited) { StartThrottler(state, transcodingJob); } Logger.LogDebug("StartFfMpeg() finished successfully"); return(transcodingJob); }
private async Task <object> GetUniversalStream(GetUniversalAudioStream request, bool isHeadRequest) { var deviceProfile = GetDeviceProfile(request); AuthorizationContext.GetAuthorizationInfo(Request).DeviceId = request.DeviceId; var mediaInfoService = new MediaInfoService( _loggerFactory.CreateLogger <MediaInfoService>(), ServerConfigurationManager, ResultFactory, MediaSourceManager, DeviceManager, LibraryManager, NetworkManager, MediaEncoder, UserManager, AuthorizationContext) { 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( _loggerFactory.CreateLogger <DynamicHlsService>(), ServerConfigurationManager, ResultFactory, UserManager, LibraryManager, IsoManager, MediaEncoder, FileSystem, DlnaManager, DeviceManager, MediaSourceManager, JsonSerializer, AuthorizationContext, NetworkManager, _encodingHelper) { Request = Request }; 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" }; 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, // fallback to mpegts if device reports some weird value unsupported by hls SegmentContainer = Array.Exists(supportedHLSContainers, element => element == request.TranscodingContainer) ? request.TranscodingContainer : "mpegts", 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( _loggerFactory.CreateLogger <AudioService>(), ServerConfigurationManager, ResultFactory, HttpClient, 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)); } }