private void SetDeviceSpecificData(string itemId, PlaybackInfoResponse result, DeviceProfile profile, AuthorizationInfo auth, int?maxBitrate, long startTimeTicks, string mediaSourceId, int?audioStreamIndex, int?subtitleStreamIndex, int?maxAudioChannels, string userId) { var item = _libraryManager.GetItemById(itemId); foreach (var mediaSource in result.MediaSources) { SetDeviceSpecificData(item, mediaSource, profile, auth, maxBitrate, startTimeTicks, mediaSourceId, audioStreamIndex, subtitleStreamIndex, maxAudioChannels, result.PlaySessionId, userId); } SortMediaSources(result, maxBitrate); }
/// <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> /// Get playback info. /// </summary> /// <param name="id">Item id.</param> /// <param name="userId">User Id.</param> /// <param name="mediaSourceId">Media source id.</param> /// <param name="liveStreamId">Live stream id.</param> /// <returns>A <see cref="Task"/> containing the <see cref="PlaybackInfoResponse"/>.</returns> public async Task <PlaybackInfoResponse> GetPlaybackInfo( Guid id, Guid?userId, string?mediaSourceId = null, string?liveStreamId = null) { var user = userId.HasValue && !userId.Equals(Guid.Empty) ? _userManager.GetUserById(userId.Value) : null; var item = _libraryManager.GetItemById(id); var result = new PlaybackInfoResponse(); MediaSourceInfo[] mediaSources; if (string.IsNullOrWhiteSpace(liveStreamId)) { // TODO (moved from MediaBrowser.Api) handle supportedLiveMediaTypes? var mediaSourcesList = await _mediaSourceManager.GetPlaybackMediaSources(item, user, true, true, CancellationToken.None).ConfigureAwait(false); if (string.IsNullOrWhiteSpace(mediaSourceId)) { mediaSources = mediaSourcesList.ToArray(); } else { mediaSources = mediaSourcesList .Where(i => string.Equals(i.Id, mediaSourceId, StringComparison.OrdinalIgnoreCase)) .ToArray(); } } else { var mediaSource = await _mediaSourceManager.GetLiveStream(liveStreamId, CancellationToken.None).ConfigureAwait(false); mediaSources = new[] { mediaSource }; } if (mediaSources.Length == 0) { result.MediaSources = Array.Empty <MediaSourceInfo>(); result.ErrorCode ??= PlaybackErrorCode.NoCompatibleStream; } else { // Since we're going to be setting properties on MediaSourceInfos that come out of _mediaSourceManager, we should clone it // Should we move this directly into MediaSourceManager? var mediaSourcesClone = JsonSerializer.Deserialize <MediaSourceInfo[]>(JsonSerializer.SerializeToUtf8Bytes(mediaSources)); if (mediaSourcesClone != null) { result.MediaSources = mediaSourcesClone; } result.PlaySessionId = Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture); } if (item is IHasCanReplay replayable) { if (!replayable.CanReplay(user)) { result.ErrorCode ??= PlaybackErrorCode.NotAllowed; } } return(result); }