private List <PlayMethod> GetAudioDirectPlayMethods(MediaSourceInfo item, AudioOptions options) { MediaStream audioStream = item.DefaultAudioStream; DirectPlayProfile directPlayProfile = null; foreach (DirectPlayProfile i in options.Profile.DirectPlayProfiles) { if (i.Type == DlnaProfileType.Audio && IsAudioDirectPlaySupported(i, item, audioStream)) { directPlayProfile = i; break; } } List <PlayMethod> playMethods = new List <PlayMethod>(); if (directPlayProfile != null) { // While options takes the network and other factors into account. Only applies to direct stream if (item.SupportsDirectStream && IsAudioEligibleForDirectPlay(item, options.GetMaxBitrate())) { playMethods.Add(PlayMethod.DirectStream); } // The profile describes what the device supports // If device requirements are satisfied then allow both direct stream and direct play if (IsAudioEligibleForDirectPlay(item, options.Profile.MaxStaticBitrate)) { playMethods.Add(PlayMethod.DirectPlay); } } return(playMethods); }
public StreamInfo BuildAudioItem(AudioOptions options) { ValidateAudioInput(options); var mediaSources = options.MediaSources; // If the client wants a specific media soure, filter now if (!string.IsNullOrEmpty(options.MediaSourceId)) { // Avoid implicitly captured closure var mediaSourceId = options.MediaSourceId; mediaSources = mediaSources .Where(i => string.Equals(i.Id, mediaSourceId, StringComparison.OrdinalIgnoreCase)) .ToList(); } var streams = mediaSources.Select(i => BuildAudioItem(i, options)).ToList(); foreach (var stream in streams) { stream.DeviceId = options.DeviceId; stream.DeviceProfileId = options.Profile.Id; } return(GetOptimalStream(streams)); }
public StreamInfo BuildAudioItem(AudioOptions options) { ValidateAudioInput(options); var mediaSources = options.MediaSources; // If the client wants a specific media soure, filter now if (!string.IsNullOrEmpty(options.MediaSourceId)) { // Avoid implicitly captured closure var mediaSourceId = options.MediaSourceId; mediaSources = mediaSources .Where(i => string.Equals(i.Id, mediaSourceId, StringComparison.OrdinalIgnoreCase)) .ToList(); } var streams = mediaSources.Select(i => BuildAudioItem(i, options)).ToList(); foreach (var stream in streams) { stream.DeviceId = options.DeviceId; stream.DeviceProfileId = options.Profile.Id; } return GetOptimalStream(streams); }
public StreamInfo BuildAudioItem(AudioOptions options) { ValidateAudioInput(options); List<MediaSourceInfo> mediaSources = new List<MediaSourceInfo>(); foreach (MediaSourceInfo i in options.MediaSources) { if (string.IsNullOrEmpty(options.MediaSourceId) || StringHelper.EqualsIgnoreCase(i.Id, options.MediaSourceId)) { mediaSources.Add(i); } } List<StreamInfo> streams = new List<StreamInfo>(); foreach (MediaSourceInfo i in mediaSources) { StreamInfo streamInfo = BuildAudioItem(i, options); if (streamInfo != null) { streams.Add(streamInfo); } } foreach (StreamInfo stream in streams) { stream.DeviceId = options.DeviceId; stream.DeviceProfileId = options.Profile.Id; } return GetOptimalStream(streams); }
public StreamInfo BuildAudioItem(AudioOptions options) { ValidateAudioInput(options); List <MediaSourceInfo> mediaSources = new List <MediaSourceInfo>(); foreach (MediaSourceInfo i in options.MediaSources) { if (string.IsNullOrEmpty(options.MediaSourceId) || StringHelper.EqualsIgnoreCase(i.Id, options.MediaSourceId)) { mediaSources.Add(i); } } List <StreamInfo> streams = new List <StreamInfo>(); foreach (MediaSourceInfo i in mediaSources) { StreamInfo streamInfo = BuildAudioItem(i, options); if (streamInfo != null) { streams.Add(streamInfo); } } foreach (StreamInfo stream in streams) { stream.DeviceId = options.DeviceId; stream.DeviceProfileId = options.Profile.Id; } return(GetOptimalStream(streams, options.GetMaxBitrate())); }
internal static async Task<PlaylistItem> ToPlaylistItem(this BaseItemDto item, IApiClient apiClient, IPlaybackManager playbackManager) { var profile = VideoProfileHelper.GetWindowsPhoneProfile(); var options = new AudioOptions { Profile = profile, ItemId = item.Id, DeviceId = apiClient.DeviceId, MediaSources = item.MediaSources }; //var streamInfo = await playbackManager.GetAudioStreamInfo(App.ServerInfo.Id, options, true, apiClient); var streamBuilder = new StreamBuilder(new MBLogger()); var streamInfo = streamBuilder.BuildAudioItem(options); var streamUrl = streamInfo.ToUrl(apiClient.GetApiUrl("/"), apiClient.AccessToken); return new PlaylistItem { Album = item.Album, Artist = item.AlbumArtist, TrackName = item.Name, TrackUrl = streamUrl.Replace(App.ServerInfo.LocalAddress, !string.IsNullOrEmpty(App.ServerInfo.ManualAddress) ? App.ServerInfo.ManualAddress : App.ServerInfo.RemoteAddress), MediaBrowserId = item.Id, IsJustAdded = true, ImageUrl = (string) ImageConverter.Convert(item, typeof (string), null, null), BackgroundImageUrl = (string) ImageConverter.Convert(item, typeof (string), "backdrop", null), RunTimeTicks = item.RunTimeTicks ?? 0 }; }
public StreamInfo BuildAudioItem(AudioOptions options) { ValidateAudioInput(options); List<MediaSourceInfo> mediaSources = options.MediaSources; // If the client wants a specific media soure, filter now if (!string.IsNullOrEmpty(options.MediaSourceId)) { // Avoid implicitly captured closure string mediaSourceId = options.MediaSourceId; mediaSources = new List<MediaSourceInfo>(); foreach (MediaSourceInfo i in mediaSources) { if (StringHelper.EqualsIgnoreCase(i.Id, mediaSourceId)) mediaSources.Add(i); } } List<StreamInfo> streams = new List<StreamInfo>(); foreach (MediaSourceInfo i in mediaSources) streams.Add(BuildAudioItem(i, options)); foreach (StreamInfo stream in streams) { stream.DeviceId = options.DeviceId; stream.DeviceProfileId = options.Profile.Id; } return GetOptimalStream(streams); }
private int?GetBitrateForDirectPlayCheck(MediaSourceInfo item, AudioOptions options) { if (item.Protocol == MediaProtocol.File) { return(options.Profile.MaxStaticBitrate); } return(options.GetMaxBitrate()); }
public LiveStreamRequest(AudioOptions options) { MaxStreamingBitrate = options.MaxBitrate; ItemId = options.ItemId; DeviceProfile = options.Profile; VideoOptions videoOptions = options as VideoOptions; if (videoOptions != null) { AudioStreamIndex = videoOptions.AudioStreamIndex; SubtitleStreamIndex = videoOptions.SubtitleStreamIndex; } }
private static string GetStreamedPath(BaseItemDto item, IApiClient apiClient, long? startTimeTicks, int? maxBitrate) { var profile = new MediaBrowserTheaterProfile(); StreamInfo info; if (item.IsAudio) { var options = new AudioOptions { Context = EncodingContext.Streaming, DeviceId = apiClient.DeviceId, ItemId = item.Id, // TODO: Reduce to 2 is user only has stereo speakers MaxAudioChannels = 6, MaxBitrate = maxBitrate, MediaSources = item.MediaSources, Profile = profile }; info = new StreamBuilder().BuildAudioItem(options); info.StartPositionTicks = startTimeTicks ?? 0; return info.ToUrl(apiClient.ServerAddress + "/mediabrowser"); } else { var options = new VideoOptions { Context = EncodingContext.Streaming, DeviceId = apiClient.DeviceId, ItemId = item.Id, // TODO: Reduce to 2 is user only has stereo speakers MaxAudioChannels = 6, MaxBitrate = maxBitrate, MediaSources = item.MediaSources, Profile = profile }; info = new StreamBuilder().BuildVideoItem(options); info.StartPositionTicks = startTimeTicks ?? 0; return info.ToUrl(apiClient.ServerAddress + "/mediabrowser") + "&EnableAdaptiveBitrateStreaming=false"; } }
private void ValidateAudioInput(AudioOptions options) { if (string.IsNullOrEmpty(options.ItemId)) { throw new ArgumentException("ItemId is required"); } if (string.IsNullOrEmpty(options.DeviceId)) { throw new ArgumentException("DeviceId is required"); } if (options.Profile == null) { throw new ArgumentException("Profile is required"); } if (options.MediaSources == null) { throw new ArgumentException("MediaSources is required"); } }
public StreamInfo BuildAudioItem(AudioOptions options) { ValidateAudioInput(options); List <MediaSourceInfo> mediaSources = options.MediaSources; // If the client wants a specific media soure, filter now if (!string.IsNullOrEmpty(options.MediaSourceId)) { // Avoid implicitly captured closure string mediaSourceId = options.MediaSourceId; mediaSources = new List <MediaSourceInfo>(); foreach (MediaSourceInfo i in mediaSources) { if (StringHelper.EqualsIgnoreCase(i.Id, mediaSourceId)) { mediaSources.Add(i); } } } List <StreamInfo> streams = new List <StreamInfo>(); foreach (MediaSourceInfo i in mediaSources) { streams.Add(BuildAudioItem(i, options)); } foreach (StreamInfo stream in streams) { stream.DeviceId = options.DeviceId; stream.DeviceProfileId = options.Profile.Id; } return(GetOptimalStream(streams)); }
private async Task Sync(SyncJobItem jobItem, Audio item, DeviceProfile profile, CancellationToken cancellationToken) { var options = new AudioOptions { Context = EncodingContext.Static, ItemId = item.Id.ToString("N"), DeviceId = jobItem.TargetId, Profile = profile, MediaSources = item.GetMediaSources(false).ToList() }; var streamInfo = new StreamBuilder().BuildAudioItem(options); var mediaSource = streamInfo.MediaSource; jobItem.MediaSourceId = streamInfo.MediaSourceId; if (streamInfo.PlayMethod == PlayMethod.Transcode) { jobItem.Status = SyncJobItemStatus.Converting; await _syncRepo.Update(jobItem).ConfigureAwait(false); jobItem.OutputPath = await _mediaEncoder.EncodeAudio(new EncodingJobOptions(streamInfo, profile), new Progress<double>(), cancellationToken); } else { if (mediaSource.Protocol == MediaProtocol.File) { jobItem.OutputPath = mediaSource.Path; } else if (mediaSource.Protocol == MediaProtocol.Http) { jobItem.OutputPath = await DownloadFile(jobItem, mediaSource, cancellationToken).ConfigureAwait(false); } else { throw new InvalidOperationException(string.Format("Cannot direct stream {0} protocol", mediaSource.Protocol)); } } jobItem.Progress = 50; jobItem.Status = SyncJobItemStatus.Transferring; await _syncRepo.Update(jobItem).ConfigureAwait(false); }
private void ValidateAudioInput(AudioOptions options) { if (string.IsNullOrEmpty(options.ItemId)) { throw new ArgumentException("ItemId is required"); } if (string.IsNullOrEmpty(options.DeviceId)) { throw new ArgumentException("DeviceId is required"); } if (options.Profile == null) { throw new ArgumentException("Profile is required"); } if (options.MediaSources == null) { throw new ArgumentException("MediaSources is required"); } }
private async Task<string> Sync(SyncJobItem jobItem, Audio item, DeviceProfile profile, CancellationToken cancellationToken) { var options = new AudioOptions { Context = EncodingContext.Streaming, ItemId = item.Id.ToString("N"), DeviceId = jobItem.TargetId, Profile = profile, MediaSources = item.GetMediaSources(false).ToList() }; var streamInfo = new StreamBuilder().BuildAudioItem(options); var mediaSource = streamInfo.MediaSource; if (streamInfo.PlayMethod != PlayMethod.Transcode) { if (mediaSource.Protocol == MediaProtocol.File) { return mediaSource.Path; } if (mediaSource.Protocol == MediaProtocol.Http) { return await DownloadFile(jobItem, mediaSource, cancellationToken).ConfigureAwait(false); } throw new InvalidOperationException(string.Format("Cannot direct stream {0} protocol", mediaSource.Protocol)); } // TODO: Transcode return mediaSource.Path; }
private List<PlayMethod> GetAudioDirectPlayMethods(MediaSourceInfo item, MediaStream audioStream, AudioOptions options) { DirectPlayProfile directPlayProfile = null; foreach (DirectPlayProfile i in options.Profile.DirectPlayProfiles) { if (i.Type == DlnaProfileType.Audio && IsAudioDirectPlaySupported(i, item, audioStream)) { directPlayProfile = i; break; } } List<PlayMethod> playMethods = new List<PlayMethod>(); if (directPlayProfile != null) { // While options takes the network and other factors into account. Only applies to direct stream if (item.SupportsDirectStream && IsAudioEligibleForDirectPlay(item, options.GetMaxBitrate())) { playMethods.Add(PlayMethod.DirectStream); } // The profile describes what the device supports // If device requirements are satisfied then allow both direct stream and direct play if (item.SupportsDirectPlay && IsAudioEligibleForDirectPlay(item, GetBitrateForDirectPlayCheck(item, options))) { playMethods.Add(PlayMethod.DirectPlay); } } return playMethods; }
private async Task Sync(SyncJobItem jobItem, SyncJob job, Audio item, User user, bool enableConversion, SyncOptions syncOptions, IProgress<double> progress, CancellationToken cancellationToken) { var jobOptions = _syncManager.GetAudioOptions(jobItem, job); var conversionOptions = new AudioOptions { Profile = jobOptions.DeviceProfile }; conversionOptions.DeviceId = jobItem.TargetId; conversionOptions.Context = EncodingContext.Static; conversionOptions.ItemId = item.Id.ToString("N"); conversionOptions.MediaSources = _mediaSourceManager.GetStaticMediaSources(item, false, user).ToList(); var streamInfo = new StreamBuilder(_logger).BuildAudioItem(conversionOptions); var mediaSource = streamInfo.MediaSource; jobItem.MediaSourceId = streamInfo.MediaSourceId; jobItem.TemporaryPath = GetTemporaryPath(jobItem); if (streamInfo.PlayMethod == PlayMethod.Transcode && jobOptions.IsConverting) { if (!enableConversion) { return; } jobItem.Status = SyncJobItemStatus.Converting; await _syncManager.UpdateSyncJobItemInternal(jobItem).ConfigureAwait(false); await UpdateJobStatus(job).ConfigureAwait(false); try { var lastJobUpdate = DateTime.MinValue; var innerProgress = new ActionableProgress<double>(); innerProgress.RegisterAction(async pct => { progress.Report(pct); if ((DateTime.UtcNow - lastJobUpdate).TotalSeconds >= DatabaseProgressUpdateIntervalSeconds) { jobItem.Progress = pct / 2; await _syncManager.UpdateSyncJobItemInternal(jobItem).ConfigureAwait(false); await UpdateJobStatus(job).ConfigureAwait(false); } }); jobItem.OutputPath = await _mediaEncoder.EncodeAudio(new EncodingJobOptions(streamInfo, conversionOptions.Profile) { OutputDirectory = jobItem.TemporaryPath, CpuCoreLimit = syncOptions.TranscodingCpuCoreLimit }, innerProgress, cancellationToken); } catch (OperationCanceledException) { jobItem.Status = SyncJobItemStatus.Queued; jobItem.Progress = 0; } catch (Exception ex) { jobItem.Status = SyncJobItemStatus.Failed; _logger.ErrorException("Error during sync transcoding", ex); } if (jobItem.Status == SyncJobItemStatus.Failed || jobItem.Status == SyncJobItemStatus.Queued) { await _syncManager.UpdateSyncJobItemInternal(jobItem).ConfigureAwait(false); return; } jobItem.MediaSource = await GetEncodedMediaSource(jobItem.OutputPath, user, false).ConfigureAwait(false); } else { if (mediaSource.Protocol == MediaProtocol.File) { jobItem.OutputPath = mediaSource.Path; } else if (mediaSource.Protocol == MediaProtocol.Http) { jobItem.OutputPath = await DownloadFile(jobItem, mediaSource, cancellationToken).ConfigureAwait(false); } else { throw new InvalidOperationException(string.Format("Cannot direct stream {0} protocol", mediaSource.Protocol)); } jobItem.MediaSource = mediaSource; } jobItem.MediaSource.SupportsTranscoding = false; jobItem.Progress = 50; jobItem.Status = SyncJobItemStatus.ReadyToTransfer; await _syncManager.UpdateSyncJobItemInternal(jobItem).ConfigureAwait(false); }
private StreamInfo BuildAudioItem(MediaSourceInfo item, AudioOptions options) { var playlistItem = new StreamInfo { ItemId = options.ItemId, MediaType = DlnaProfileType.Audio, MediaSource = item, RunTimeTicks = item.RunTimeTicks }; var maxBitrateSetting = options.MaxBitrate ?? options.Profile.MaxBitrate; var audioStream = item.MediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Audio); // Honor the max bitrate setting if (IsAudioEligibleForDirectPlay(item, maxBitrateSetting)) { var directPlay = options.Profile.DirectPlayProfiles .FirstOrDefault(i => i.Type == playlistItem.MediaType && IsAudioDirectPlaySupported(i, item, audioStream)); if (directPlay != null) { var audioCodec = audioStream == null ? null : audioStream.Codec; // Make sure audio codec profiles are satisfied if (!string.IsNullOrEmpty(audioCodec)) { var conditionProcessor = new ConditionProcessor(); var conditions = options.Profile.CodecProfiles.Where(i => i.Type == CodecType.Audio && i.ContainsCodec(audioCodec)) .SelectMany(i => i.Conditions); var audioChannels = audioStream == null ? null : audioStream.Channels; var audioBitrate = audioStream == null ? null : audioStream.BitRate; if (conditions.All(c => conditionProcessor.IsAudioConditionSatisfied(c, audioChannels, audioBitrate))) { playlistItem.IsDirectStream = true; playlistItem.Container = item.Container; return(playlistItem); } } } } var transcodingProfile = options.Profile.TranscodingProfiles .FirstOrDefault(i => i.Type == playlistItem.MediaType); if (transcodingProfile != null) { playlistItem.IsDirectStream = false; playlistItem.TranscodeSeekInfo = transcodingProfile.TranscodeSeekInfo; playlistItem.EstimateContentLength = transcodingProfile.EstimateContentLength; playlistItem.Container = transcodingProfile.Container; playlistItem.AudioCodec = transcodingProfile.AudioCodec; playlistItem.Protocol = transcodingProfile.Protocol; var audioTranscodingConditions = options.Profile.CodecProfiles .Where(i => i.Type == CodecType.Audio && i.ContainsCodec(transcodingProfile.AudioCodec)) .Take(1) .SelectMany(i => i.Conditions); ApplyTranscodingConditions(playlistItem, audioTranscodingConditions); // Honor requested max channels if (options.MaxAudioChannels.HasValue) { var currentValue = playlistItem.MaxAudioChannels ?? options.MaxAudioChannels.Value; playlistItem.MaxAudioChannels = Math.Min(options.MaxAudioChannels.Value, currentValue); } // Honor requested max bitrate if (maxBitrateSetting.HasValue) { var currentValue = playlistItem.AudioBitrate ?? maxBitrateSetting.Value; playlistItem.AudioBitrate = Math.Min(maxBitrateSetting.Value, currentValue); } } return(playlistItem); }
private bool IsAudioEligibleForDirectPlay(MediaSourceInfo item, AudioOptions options) { // Honor the max bitrate setting return !options.MaxBitrate.HasValue || (item.Bitrate.HasValue && item.Bitrate.Value <= options.MaxBitrate.Value); }
private StreamInfo BuildAudioItem(MediaSourceInfo item, AudioOptions options) { StreamInfo playlistItem = new StreamInfo { ItemId = options.ItemId, MediaType = DlnaProfileType.Audio, MediaSource = item, RunTimeTicks = item.RunTimeTicks, Context = options.Context }; int?maxBitrateSetting = options.GetMaxBitrate(); MediaStream audioStream = item.DefaultAudioStream; // Honor the max bitrate setting if (IsAudioEligibleForDirectPlay(item, maxBitrateSetting)) { DirectPlayProfile directPlay = null; foreach (DirectPlayProfile i in options.Profile.DirectPlayProfiles) { if (i.Type == playlistItem.MediaType && IsAudioDirectPlaySupported(i, item, audioStream)) { directPlay = i; break; } } if (directPlay != null) { string audioCodec = audioStream == null ? null : audioStream.Codec; // Make sure audio codec profiles are satisfied if (!string.IsNullOrEmpty(audioCodec)) { ConditionProcessor conditionProcessor = new ConditionProcessor(); List <ProfileCondition> conditions = new List <ProfileCondition>(); foreach (CodecProfile i in options.Profile.CodecProfiles) { if (i.Type == CodecType.Audio && i.ContainsCodec(audioCodec)) { foreach (ProfileCondition c in i.Conditions) { conditions.Add(c); } } } int?audioChannels = audioStream.Channels; int?audioBitrate = audioStream.BitRate; bool all = true; foreach (ProfileCondition c in conditions) { if (!conditionProcessor.IsAudioConditionSatisfied(c, audioChannels, audioBitrate)) { all = false; break; } } if (all) { playlistItem.PlayMethod = PlayMethod.DirectStream; playlistItem.Container = item.Container; return(playlistItem); } } } } TranscodingProfile transcodingProfile = null; foreach (TranscodingProfile i in options.Profile.TranscodingProfiles) { if (i.Type == playlistItem.MediaType && i.Context == options.Context) { transcodingProfile = i; break; } } if (transcodingProfile != null) { playlistItem.PlayMethod = PlayMethod.Transcode; playlistItem.TranscodeSeekInfo = transcodingProfile.TranscodeSeekInfo; playlistItem.EstimateContentLength = transcodingProfile.EstimateContentLength; playlistItem.Container = transcodingProfile.Container; playlistItem.AudioCodec = transcodingProfile.AudioCodec; playlistItem.Protocol = transcodingProfile.Protocol; List <CodecProfile> audioCodecProfiles = new List <CodecProfile>(); foreach (CodecProfile i in options.Profile.CodecProfiles) { if (i.Type == CodecType.Audio && i.ContainsCodec(transcodingProfile.AudioCodec)) { audioCodecProfiles.Add(i); } if (audioCodecProfiles.Count >= 1) { break; } } List <ProfileCondition> audioTranscodingConditions = new List <ProfileCondition>(); foreach (CodecProfile i in audioCodecProfiles) { foreach (ProfileCondition c in i.Conditions) { audioTranscodingConditions.Add(c); } } ApplyTranscodingConditions(playlistItem, audioTranscodingConditions); // Honor requested max channels if (options.MaxAudioChannels.HasValue) { int currentValue = playlistItem.MaxAudioChannels ?? options.MaxAudioChannels.Value; playlistItem.MaxAudioChannels = Math.Min(options.MaxAudioChannels.Value, currentValue); } int configuredBitrate = options.AudioTranscodingBitrate ?? (options.Context == EncodingContext.Static ? options.Profile.MusicSyncBitrate : options.Profile.MusicStreamingTranscodingBitrate) ?? 128000; playlistItem.AudioBitrate = Math.Min(configuredBitrate, playlistItem.AudioBitrate ?? configuredBitrate); } return(playlistItem); }
private StreamInfo BuildAudioItem(MediaSourceInfo item, AudioOptions options) { StreamInfo playlistItem = new StreamInfo { ItemId = options.ItemId, MediaType = DlnaProfileType.Audio, MediaSource = item, RunTimeTicks = item.RunTimeTicks }; int? maxBitrateSetting = options.GetMaxBitrate(); MediaStream audioStream = item.DefaultAudioStream; // Honor the max bitrate setting if (IsAudioEligibleForDirectPlay(item, maxBitrateSetting)) { DirectPlayProfile directPlay = null; foreach (DirectPlayProfile i in options.Profile.DirectPlayProfiles) { if (i.Type == playlistItem.MediaType && IsAudioDirectPlaySupported(i, item, audioStream)) { directPlay = i; break; } } if (directPlay != null) { string audioCodec = audioStream == null ? null : audioStream.Codec; // Make sure audio codec profiles are satisfied if (!string.IsNullOrEmpty(audioCodec)) { ConditionProcessor conditionProcessor = new ConditionProcessor(); List<ProfileCondition> conditions = new List<ProfileCondition>(); foreach (CodecProfile i in options.Profile.CodecProfiles) { if (i.Type == CodecType.Audio && i.ContainsCodec(audioCodec)) { foreach (var c in i.Conditions) { conditions.Add(c); } } } int? audioChannels = audioStream.Channels; int? audioBitrate = audioStream.BitRate; bool all = true; foreach (ProfileCondition c in conditions) { if (!conditionProcessor.IsAudioConditionSatisfied(c, audioChannels, audioBitrate)) { all = false; break; } } if (all) { playlistItem.PlayMethod = PlayMethod.DirectStream; playlistItem.Container = item.Container; return playlistItem; } } } } TranscodingProfile transcodingProfile = null; foreach (TranscodingProfile i in options.Profile.TranscodingProfiles) { if (i.Type == playlistItem.MediaType && i.Context == options.Context) { transcodingProfile = i; break; } } if (transcodingProfile != null) { playlistItem.PlayMethod = PlayMethod.Transcode; playlistItem.TranscodeSeekInfo = transcodingProfile.TranscodeSeekInfo; playlistItem.EstimateContentLength = transcodingProfile.EstimateContentLength; playlistItem.Container = transcodingProfile.Container; playlistItem.AudioCodec = transcodingProfile.AudioCodec; playlistItem.Protocol = transcodingProfile.Protocol; List<CodecProfile> audioCodecProfiles = new List<CodecProfile>(); foreach (CodecProfile i in options.Profile.CodecProfiles) { if (i.Type == CodecType.Audio && i.ContainsCodec(transcodingProfile.AudioCodec)) { audioCodecProfiles.Add(i); } if (audioCodecProfiles.Count >= 1) break; } List<ProfileCondition> audioTranscodingConditions = new List<ProfileCondition>(); foreach (CodecProfile i in audioCodecProfiles) { foreach (var c in i.Conditions) { audioTranscodingConditions.Add(c); } } ApplyTranscodingConditions(playlistItem, audioTranscodingConditions); // Honor requested max channels if (options.MaxAudioChannels.HasValue) { int currentValue = playlistItem.MaxAudioChannels ?? options.MaxAudioChannels.Value; playlistItem.MaxAudioChannels = Math.Min(options.MaxAudioChannels.Value, currentValue); } if (!playlistItem.AudioBitrate.HasValue) { playlistItem.AudioBitrate = 128000; } } return playlistItem; }
/// <summary> /// Gets the audio stream information. /// </summary> /// <param name="serverId">The server identifier.</param> /// <param name="options">The options.</param> /// <param name="isOffline">if set to <c>true</c> [is offline].</param> /// <param name="apiClient">The API client.</param> /// <returns>Task<StreamInfo>.</returns> public async Task<StreamInfo> GetAudioStreamInfo(string serverId, AudioOptions options, bool isOffline, IApiClient apiClient) { var streamBuilder = GetStreamBuilder(); var localItem = await _localAssetManager.GetLocalItem(serverId, options.ItemId); if (localItem != null) { var localMediaSource = localItem.Item.MediaSources[0]; // Use the local media source, unless a specific server media source was requested if (string.IsNullOrWhiteSpace(options.MediaSourceId) || string.Equals(localMediaSource.Id, options.MediaSourceId, StringComparison.OrdinalIgnoreCase)) { // Finally, check to make sure the local file is actually available at this time var fileExists = await _localAssetManager.FileExists(localMediaSource.Path).ConfigureAwait(false); if (fileExists) { options.MediaSources = localItem.Item.MediaSources; var result = streamBuilder.BuildAudioItem(options); if (result == null) { _logger.Warn("LocalItem returned no compatible streams. Will dummy up a StreamInfo to force it to direct play."); var mediaSource = localItem.Item.MediaSources.First(); result = GetForcedDirectPlayStreamInfo(DlnaProfileType.Audio, options, mediaSource); } result.PlayMethod = PlayMethod.DirectPlay; return result; } } } PlaybackInfoResponse playbackInfo = null; string playSessionId = null; if (!isOffline) { playbackInfo = await apiClient.GetPlaybackInfo(new PlaybackInfoRequest { Id = options.ItemId, UserId = apiClient.CurrentUserId, MaxStreamingBitrate = options.MaxBitrate, MediaSourceId = options.MediaSourceId }).ConfigureAwait(false); if (playbackInfo.ErrorCode.HasValue) { throw new PlaybackException { ErrorCode = playbackInfo.ErrorCode.Value }; } options.MediaSources = playbackInfo.MediaSources; playSessionId = playbackInfo.PlaySessionId; } var streamInfo = streamBuilder.BuildAudioItem(options); EnsureSuccess(streamInfo); if (!isOffline) { var liveMediaSource = await GetLiveStreamInfo(playSessionId, streamInfo.MediaSource, options, apiClient).ConfigureAwait(false); if (liveMediaSource != null) { options.MediaSources = new List<MediaSourceInfo> { liveMediaSource }; streamInfo = GetStreamBuilder().BuildAudioItem(options); EnsureSuccess(streamInfo); } } if (playbackInfo != null) { streamInfo.AllMediaSources = playbackInfo.MediaSources.ToList(); streamInfo.PlaySessionId = playbackInfo.PlaySessionId; } return streamInfo; }
/// <summary> /// Sets the live stream. /// </summary> /// <param name="mediaSource">The media source.</param> /// <param name="options">The options.</param> /// <param name="apiClient">The API client.</param> /// <returns>Task.</returns> private async Task<MediaSourceInfo> GetLiveStreamInfo(string playSessionId, MediaSourceInfo mediaSource, AudioOptions options, IApiClient apiClient) { if (mediaSource.RequiresOpening) { var liveStreamResponse = await apiClient.OpenLiveStream(new LiveStreamRequest(options) { OpenToken = mediaSource.OpenToken, UserId = apiClient.CurrentUserId, PlaySessionId = playSessionId }, CancellationToken.None).ConfigureAwait(false); return liveStreamResponse.MediaSource; } return null; }
public Task<StreamInfo> GetAudioStreamInfo(string serverId, AudioOptions options) { var apiClient = _connectionManager.GetApiClient(serverId); options.DeviceId = _connectionManager.Device.DeviceId; return _apiPlaybackManager.GetAudioStreamInfo(serverId, options, false, apiClient); }
private static PlayableItem GetStreamedItem(BaseItemDto item, List<MediaSourceInfo> mediaSources, IApiClient apiClient, long? startTimeTicks, int? maxBitrate) { var profile = new MediaBrowserTheaterProfile(); StreamInfo info; if (item.IsAudio) { var options = new AudioOptions { Context = EncodingContext.Streaming, DeviceId = apiClient.DeviceId, ItemId = item.Id, // TODO: Reduce to 2 is user only has stereo speakers MaxAudioChannels = 6, MaxBitrate = maxBitrate, MediaSources = mediaSources, Profile = profile }; info = new StreamBuilder().BuildAudioItem(options); info.StartPositionTicks = startTimeTicks ?? 0; if (info.MediaSource.Protocol == MediaProtocol.File && File.Exists(info.MediaSource.Path)) { return new PlayableItem { OriginalItem = item, PlayablePath = info.MediaSource.Path, MediaSource = info.MediaSource, StreamInfo = info }; } return new PlayableItem { OriginalItem = item, PlayablePath = info.ToUrl(apiClient.ServerAddress + "/mediabrowser"), MediaSource = info.MediaSource, StreamInfo = info }; } else { var options = new VideoOptions { Context = EncodingContext.Streaming, DeviceId = apiClient.DeviceId, ItemId = item.Id, // TODO: Reduce to 2 is user only has stereo speakers MaxAudioChannels = 6, MaxBitrate = maxBitrate, MediaSources = mediaSources, Profile = profile }; info = new StreamBuilder().BuildVideoItem(options); info.StartPositionTicks = startTimeTicks ?? 0; if (info.MediaSource.Protocol == MediaProtocol.File && File.Exists(info.MediaSource.Path)) { return new PlayableItem { OriginalItem = item, PlayablePath = info.MediaSource.Path, MediaSource = info.MediaSource, StreamInfo = info }; } //info.Container = "ts"; //info.VideoCodec = "copy"; //info.AudioCodec = "copy"; //info.Protocol = "http"; //if (item.IsType("tvchannel")) //{ // info.VideoCodec = "copy"; //} var playable = new PlayableItem { OriginalItem = item, PlayablePath = info.ToUrl(apiClient.ServerAddress + "/mediabrowser"), MediaSource = info.MediaSource, StreamInfo = info }; if (!info.IsDirectStream) { playable.PlayablePath += "&EnableAdaptiveBitrateStreaming=false"; } return playable; } }
private StreamInfo BuildAudioItem(MediaSourceInfo item, AudioOptions options) { var playlistItem = new StreamInfo { ItemId = options.ItemId, MediaType = DlnaProfileType.Audio, MediaSourceId = item.Id }; var audioStream = item.MediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Audio); // Honor the max bitrate setting if (IsAudioEligibleForDirectPlay(item, options)) { var directPlay = options.Profile.DirectPlayProfiles .FirstOrDefault(i => i.Type == playlistItem.MediaType && IsAudioDirectPlaySupported(i, item, audioStream)); if (directPlay != null) { var audioCodec = audioStream == null ? null : audioStream.Codec; // Make sure audio codec profiles are satisfied if (!string.IsNullOrEmpty(audioCodec) && options.Profile.CodecProfiles.Where(i => i.Type == CodecType.Audio && i.ContainsCodec(audioCodec)) .All(i => AreConditionsSatisfied(i.Conditions, item.Path, null, audioStream))) { playlistItem.IsDirectStream = true; playlistItem.Container = item.Container; return playlistItem; } } } var transcodingProfile = options.Profile.TranscodingProfiles .FirstOrDefault(i => i.Type == playlistItem.MediaType); if (transcodingProfile != null) { playlistItem.IsDirectStream = false; playlistItem.Container = transcodingProfile.Container; playlistItem.AudioCodec = transcodingProfile.AudioCodec; var audioTranscodingConditions = options.Profile.CodecProfiles .Where(i => i.Type == CodecType.Audio && i.ContainsCodec(transcodingProfile.AudioCodec)) .Take(1) .SelectMany(i => i.Conditions); ApplyTranscodingConditions(playlistItem, audioTranscodingConditions); // Honor requested max channels if (options.MaxAudioChannels.HasValue) { var currentValue = playlistItem.MaxAudioChannels ?? options.MaxAudioChannels.Value; playlistItem.MaxAudioChannels = Math.Min(options.MaxAudioChannels.Value, currentValue); } // Honor requested max bitrate if (options.MaxBitrate.HasValue) { var currentValue = playlistItem.AudioBitrate ?? options.MaxBitrate.Value; playlistItem.AudioBitrate = Math.Min(options.MaxBitrate.Value, currentValue); } } return playlistItem; }
private StreamInfo BuildAudioItem(MediaSourceInfo item, AudioOptions options) { StreamInfo playlistItem = new StreamInfo { ItemId = options.ItemId, MediaType = DlnaProfileType.Audio, MediaSource = item, RunTimeTicks = item.RunTimeTicks, Context = options.Context, DeviceProfile = options.Profile }; MediaStream audioStream = item.GetDefaultAudioStream(null); List <PlayMethod> directPlayMethods = GetAudioDirectPlayMethods(item, audioStream, options); if (directPlayMethods.Count > 0) { string audioCodec = audioStream == null ? null : audioStream.Codec; // Make sure audio codec profiles are satisfied if (!string.IsNullOrEmpty(audioCodec)) { ConditionProcessor conditionProcessor = new ConditionProcessor(); List <ProfileCondition> conditions = new List <ProfileCondition>(); foreach (CodecProfile i in options.Profile.CodecProfiles) { if (i.Type == CodecType.Audio && i.ContainsCodec(audioCodec, item.Container)) { foreach (ProfileCondition c in i.Conditions) { conditions.Add(c); } } } int?audioChannels = audioStream.Channels; int?audioBitrate = audioStream.BitRate; bool all = true; foreach (ProfileCondition c in conditions) { if (!conditionProcessor.IsAudioConditionSatisfied(c, audioChannels, audioBitrate)) { LogConditionFailure(options.Profile, "AudioCodecProfile", c, item); all = false; break; } } if (all) { if (item.Protocol == MediaProtocol.File && directPlayMethods.Contains(PlayMethod.DirectPlay) && _localPlayer.CanAccessFile(item.Path)) { playlistItem.PlayMethod = PlayMethod.DirectPlay; } else if (item.Protocol == MediaProtocol.Http && directPlayMethods.Contains(PlayMethod.DirectPlay) && _localPlayer.CanAccessUrl(item.Path, item.RequiredHttpHeaders.Count > 0)) { playlistItem.PlayMethod = PlayMethod.DirectPlay; } else if (directPlayMethods.Contains(PlayMethod.DirectStream)) { playlistItem.PlayMethod = PlayMethod.DirectStream; } playlistItem.Container = item.Container; return(playlistItem); } } } TranscodingProfile transcodingProfile = null; foreach (TranscodingProfile i in options.Profile.TranscodingProfiles) { if (i.Type == playlistItem.MediaType && i.Context == options.Context) { if (_transcoderSupport.CanEncodeToAudioCodec(i.AudioCodec ?? i.Container)) { transcodingProfile = i; break; } } } if (transcodingProfile != null) { if (!item.SupportsTranscoding) { return(null); } playlistItem.PlayMethod = PlayMethod.Transcode; playlistItem.TranscodeSeekInfo = transcodingProfile.TranscodeSeekInfo; playlistItem.EstimateContentLength = transcodingProfile.EstimateContentLength; playlistItem.Container = transcodingProfile.Container; if (string.IsNullOrEmpty(transcodingProfile.AudioCodec)) { playlistItem.AudioCodecs = new string[] { }; } else { playlistItem.AudioCodecs = transcodingProfile.AudioCodec.Split(','); } playlistItem.SubProtocol = transcodingProfile.Protocol; List <CodecProfile> audioCodecProfiles = new List <CodecProfile>(); foreach (CodecProfile i in options.Profile.CodecProfiles) { if (i.Type == CodecType.Audio && i.ContainsCodec(transcodingProfile.AudioCodec, transcodingProfile.Container)) { audioCodecProfiles.Add(i); } if (audioCodecProfiles.Count >= 1) { break; } } List <ProfileCondition> audioTranscodingConditions = new List <ProfileCondition>(); foreach (CodecProfile i in audioCodecProfiles) { foreach (ProfileCondition c in i.Conditions) { audioTranscodingConditions.Add(c); } } ApplyTranscodingConditions(playlistItem, audioTranscodingConditions); // Honor requested max channels if (options.MaxAudioChannels.HasValue) { int currentValue = playlistItem.MaxAudioChannels ?? options.MaxAudioChannels.Value; playlistItem.MaxAudioChannels = Math.Min(options.MaxAudioChannels.Value, currentValue); } int configuredBitrate = options.AudioTranscodingBitrate ?? (options.Context == EncodingContext.Static ? options.Profile.MusicSyncBitrate : options.Profile.MusicStreamingTranscodingBitrate) ?? 128000; playlistItem.AudioBitrate = Math.Min(configuredBitrate, playlistItem.AudioBitrate ?? configuredBitrate); } return(playlistItem); }
private StreamInfo BuildAudioItem(MediaSourceInfo item, AudioOptions options) { StreamInfo playlistItem = new StreamInfo { ItemId = options.ItemId, MediaType = DlnaProfileType.Audio, MediaSource = item, RunTimeTicks = item.RunTimeTicks, Context = options.Context, DeviceProfile = options.Profile }; if (options.ForceDirectPlay) { playlistItem.PlayMethod = PlayMethod.DirectPlay; playlistItem.Container = item.Container; return playlistItem; } if (options.ForceDirectStream) { playlistItem.PlayMethod = PlayMethod.DirectStream; playlistItem.Container = item.Container; return playlistItem; } MediaStream audioStream = item.GetDefaultAudioStream(null); List<PlayMethod> directPlayMethods = GetAudioDirectPlayMethods(item, audioStream, options); ConditionProcessor conditionProcessor = new ConditionProcessor(); int? inputAudioChannels = audioStream == null ? null : audioStream.Channels; int? inputAudioBitrate = audioStream == null ? null : audioStream.BitDepth; if (directPlayMethods.Count > 0) { string audioCodec = audioStream == null ? null : audioStream.Codec; // Make sure audio codec profiles are satisfied if (!string.IsNullOrEmpty(audioCodec)) { List<ProfileCondition> conditions = new List<ProfileCondition>(); foreach (CodecProfile i in options.Profile.CodecProfiles) { if (i.Type == CodecType.Audio && i.ContainsCodec(audioCodec, item.Container)) { bool applyConditions = true; foreach (ProfileCondition applyCondition in i.ApplyConditions) { if (!conditionProcessor.IsAudioConditionSatisfied(applyCondition, inputAudioChannels, inputAudioBitrate)) { LogConditionFailure(options.Profile, "AudioCodecProfile", applyCondition, item); applyConditions = false; break; } } if (applyConditions) { foreach (ProfileCondition c in i.Conditions) { conditions.Add(c); } } } } bool all = true; foreach (ProfileCondition c in conditions) { if (!conditionProcessor.IsAudioConditionSatisfied(c, inputAudioChannels, inputAudioBitrate)) { LogConditionFailure(options.Profile, "AudioCodecProfile", c, item); all = false; break; } } if (all) { if (directPlayMethods.Contains(PlayMethod.DirectStream)) { playlistItem.PlayMethod = PlayMethod.DirectStream; } playlistItem.Container = item.Container; return playlistItem; } } } TranscodingProfile transcodingProfile = null; foreach (TranscodingProfile i in options.Profile.TranscodingProfiles) { if (i.Type == playlistItem.MediaType && i.Context == options.Context) { if (_transcoderSupport.CanEncodeToAudioCodec(i.AudioCodec ?? i.Container)) { transcodingProfile = i; break; } } } if (transcodingProfile != null) { if (!item.SupportsTranscoding) { return null; } playlistItem.PlayMethod = PlayMethod.Transcode; playlistItem.TranscodeSeekInfo = transcodingProfile.TranscodeSeekInfo; playlistItem.EstimateContentLength = transcodingProfile.EstimateContentLength; playlistItem.Container = transcodingProfile.Container; if (string.IsNullOrEmpty(transcodingProfile.AudioCodec)) { playlistItem.AudioCodecs = new string[] { }; } else { playlistItem.AudioCodecs = transcodingProfile.AudioCodec.Split(','); } playlistItem.SubProtocol = transcodingProfile.Protocol; List<CodecProfile> audioCodecProfiles = new List<CodecProfile>(); foreach (CodecProfile i in options.Profile.CodecProfiles) { if (i.Type == CodecType.Audio && i.ContainsCodec(transcodingProfile.AudioCodec, transcodingProfile.Container)) { audioCodecProfiles.Add(i); } if (audioCodecProfiles.Count >= 1) break; } List<ProfileCondition> audioTranscodingConditions = new List<ProfileCondition>(); foreach (CodecProfile i in audioCodecProfiles) { bool applyConditions = true; foreach (ProfileCondition applyCondition in i.ApplyConditions) { if (!conditionProcessor.IsAudioConditionSatisfied(applyCondition, inputAudioChannels, inputAudioBitrate)) { LogConditionFailure(options.Profile, "AudioCodecProfile", applyCondition, item); applyConditions = false; break; } } if (applyConditions) { foreach (ProfileCondition c in i.Conditions) { audioTranscodingConditions.Add(c); } } } ApplyTranscodingConditions(playlistItem, audioTranscodingConditions); // Honor requested max channels if (options.MaxAudioChannels.HasValue) { int currentValue = playlistItem.MaxAudioChannels ?? options.MaxAudioChannels.Value; playlistItem.MaxAudioChannels = Math.Min(options.MaxAudioChannels.Value, currentValue); } int transcodingBitrate = options.AudioTranscodingBitrate ?? options.Profile.MusicStreamingTranscodingBitrate ?? 128000; int? configuredBitrate = options.GetMaxBitrate(true); if (configuredBitrate.HasValue) { transcodingBitrate = Math.Min(configuredBitrate.Value, transcodingBitrate); } playlistItem.AudioBitrate = Math.Min(transcodingBitrate, playlistItem.AudioBitrate ?? transcodingBitrate); } return playlistItem; }
private List <PlayMethod> GetAudioDirectPlayMethods(MediaSourceInfo item, MediaStream audioStream, AudioOptions options) { DirectPlayProfile directPlayProfile = null; foreach (DirectPlayProfile i in options.Profile.DirectPlayProfiles) { if (i.Type == DlnaProfileType.Audio && IsAudioDirectPlaySupported(i, item, audioStream)) { directPlayProfile = i; break; } } List <PlayMethod> playMethods = new List <PlayMethod>(); if (directPlayProfile != null) { // While options takes the network and other factors into account. Only applies to direct stream if (item.SupportsDirectStream && IsAudioEligibleForDirectPlay(item, options.GetMaxBitrate())) { playMethods.Add(PlayMethod.DirectStream); } // The profile describes what the device supports // If device requirements are satisfied then allow both direct stream and direct play if (item.SupportsDirectPlay && IsAudioEligibleForDirectPlay(item, GetBitrateForDirectPlayCheck(item, options))) { playMethods.Add(PlayMethod.DirectPlay); } } else { _logger.Info("Profile: {0}, No direct play profiles found for Path: {1}", options.Profile.Name ?? "Unknown Profile", item.Path ?? "Unknown path"); } return(playMethods); }
private StreamInfo BuildAudioItem(MediaSourceInfo item, AudioOptions options) { StreamInfo playlistItem = new StreamInfo { ItemId = options.ItemId, MediaType = DlnaProfileType.Audio, MediaSource = item, RunTimeTicks = item.RunTimeTicks, Context = options.Context, DeviceProfile = options.Profile }; MediaStream audioStream = item.GetDefaultAudioStream(null); List<PlayMethod> directPlayMethods = GetAudioDirectPlayMethods(item, audioStream, options); if (directPlayMethods.Count > 0) { string audioCodec = audioStream == null ? null : audioStream.Codec; // Make sure audio codec profiles are satisfied if (!string.IsNullOrEmpty(audioCodec)) { ConditionProcessor conditionProcessor = new ConditionProcessor(); List<ProfileCondition> conditions = new List<ProfileCondition>(); foreach (CodecProfile i in options.Profile.CodecProfiles) { if (i.Type == CodecType.Audio && i.ContainsCodec(audioCodec, item.Container)) { foreach (ProfileCondition c in i.Conditions) { conditions.Add(c); } } } int? audioChannels = audioStream.Channels; int? audioBitrate = audioStream.BitRate; bool all = true; foreach (ProfileCondition c in conditions) { if (!conditionProcessor.IsAudioConditionSatisfied(c, audioChannels, audioBitrate)) { all = false; break; } } if (all) { if (item.Protocol == MediaProtocol.File && directPlayMethods.Contains(PlayMethod.DirectPlay) && _localPlayer.CanAccessFile(item.Path)) { playlistItem.PlayMethod = PlayMethod.DirectPlay; } else if (item.Protocol == MediaProtocol.Http && directPlayMethods.Contains(PlayMethod.DirectPlay) && _localPlayer.CanAccessUrl(item.Path, item.RequiredHttpHeaders.Count > 0)) { playlistItem.PlayMethod = PlayMethod.DirectPlay; } else if (directPlayMethods.Contains(PlayMethod.DirectStream)) { playlistItem.PlayMethod = PlayMethod.DirectStream; } playlistItem.Container = item.Container; return playlistItem; } } } TranscodingProfile transcodingProfile = null; foreach (TranscodingProfile i in options.Profile.TranscodingProfiles) { if (i.Type == playlistItem.MediaType && i.Context == options.Context) { transcodingProfile = i; break; } } if (transcodingProfile != null) { if (!item.SupportsTranscoding) { return null; } playlistItem.PlayMethod = PlayMethod.Transcode; playlistItem.TranscodeSeekInfo = transcodingProfile.TranscodeSeekInfo; playlistItem.EstimateContentLength = transcodingProfile.EstimateContentLength; playlistItem.Container = transcodingProfile.Container; playlistItem.AudioCodec = transcodingProfile.AudioCodec; playlistItem.SubProtocol = transcodingProfile.Protocol; List<CodecProfile> audioCodecProfiles = new List<CodecProfile>(); foreach (CodecProfile i in options.Profile.CodecProfiles) { if (i.Type == CodecType.Audio && i.ContainsCodec(transcodingProfile.AudioCodec, transcodingProfile.Container)) { audioCodecProfiles.Add(i); } if (audioCodecProfiles.Count >= 1) break; } List<ProfileCondition> audioTranscodingConditions = new List<ProfileCondition>(); foreach (CodecProfile i in audioCodecProfiles) { foreach (ProfileCondition c in i.Conditions) { audioTranscodingConditions.Add(c); } } ApplyTranscodingConditions(playlistItem, audioTranscodingConditions); // Honor requested max channels if (options.MaxAudioChannels.HasValue) { int currentValue = playlistItem.MaxAudioChannels ?? options.MaxAudioChannels.Value; playlistItem.MaxAudioChannels = Math.Min(options.MaxAudioChannels.Value, currentValue); } int configuredBitrate = options.AudioTranscodingBitrate ?? (options.Context == EncodingContext.Static ? options.Profile.MusicSyncBitrate : options.Profile.MusicStreamingTranscodingBitrate) ?? 128000; playlistItem.AudioBitrate = Math.Min(configuredBitrate, playlistItem.AudioBitrate ?? configuredBitrate); } return playlistItem; }
private int? GetBitrateForDirectPlayCheck(MediaSourceInfo item, AudioOptions options) { if (item.Protocol == MediaProtocol.File) { return options.Profile.MaxStaticBitrate; } return options.GetMaxBitrate(); }
private StreamInfo GetForcedDirectPlayStreamInfo(DlnaProfileType mediaType, AudioOptions options, MediaSourceInfo mediaSource) { return new StreamInfo { ItemId = options.ItemId, MediaType = mediaType, MediaSource = mediaSource, RunTimeTicks = mediaSource.RunTimeTicks, Context = options.Context, DeviceProfile = options.Profile, Container = mediaSource.Container, PlayMethod = PlayMethod.DirectPlay }; }