Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More stream selection refactors #10733

Open
wants to merge 14 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 5 additions & 24 deletions app/src/main/java/org/schabi/newpipe/player/Player.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,6 @@
import static org.schabi.newpipe.player.notification.NotificationConstants.ACTION_RECREATE_NOTIFICATION;
import static org.schabi.newpipe.player.notification.NotificationConstants.ACTION_REPEAT;
import static org.schabi.newpipe.player.notification.NotificationConstants.ACTION_SHUFFLE;
import static org.schabi.newpipe.util.ListHelper.getPopupResolutionIndex;
import static org.schabi.newpipe.util.ListHelper.getResolutionIndex;
import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage;
import static java.util.concurrent.TimeUnit.MILLISECONDS;

Expand Down Expand Up @@ -116,7 +114,6 @@
import org.schabi.newpipe.player.ui.PopupPlayerUi;
import org.schabi.newpipe.player.ui.VideoPlayerUi;
import org.schabi.newpipe.util.DependentPreferenceHelper;
import org.schabi.newpipe.util.ListHelper;
import org.schabi.newpipe.util.NavigationHelper;
import org.schabi.newpipe.util.image.PicassoHelper;
import org.schabi.newpipe.util.SerializedCache;
Expand Down Expand Up @@ -292,7 +289,7 @@ public Player(@NonNull final PlayerService service) {
context.getString(
R.string.use_exoplayer_decoder_fallback_key), false));

videoResolver = new VideoPlaybackResolver(context, dataSource, getQualityResolver());
videoResolver = new VideoPlaybackResolver(context, dataSource);
audioResolver = new AudioPlaybackResolver(context, dataSource);

currentThumbnailTarget = getCurrentThumbnailTarget();
Expand All @@ -306,25 +303,6 @@ public Player(@NonNull final PlayerService service) {
new NotificationPlayerUi(this)
);
}

private VideoPlaybackResolver.QualityResolver getQualityResolver() {
return new VideoPlaybackResolver.QualityResolver() {
@Override
public int getDefaultResolutionIndex(final List<VideoStream> sortedVideos) {
return videoPlayerSelected()
? ListHelper.getDefaultResolutionIndex(context, sortedVideos)
: ListHelper.getPopupDefaultResolutionIndex(context, sortedVideos);
}

@Override
public int getOverrideResolutionIndex(final List<VideoStream> sortedVideos,
final String playbackQuality) {
return videoPlayerSelected()
? getResolutionIndex(context, sortedVideos, playbackQuality)
: getPopupResolutionIndex(context, sortedVideos, playbackQuality);
}
};
}
//endregion


Expand Down Expand Up @@ -1908,7 +1886,10 @@ public MediaSource sourceOf(final PlayQueueItem item, final StreamInfo info) {
// Note that the video is not fetched when the app is in background because the video
// renderer is fully disabled (see useVideoSource method), except for HLS streams
// (see https://github.com/google/ExoPlayer/issues/9282).
return videoResolver.resolve(info);
return videoResolver.resolve(info, videoPlayerSelected()
? VideoPlaybackResolver.SelectedPlayer.MAIN
: VideoPlaybackResolver.SelectedPlayer.POPUP
);
}

public void disablePreloadingOfCurrentTrack() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,19 +106,28 @@ default MediaItem asMediaItem() {
final class Quality {
@NonNull
private final List<VideoStream> sortedVideoStreams;

/** Invariant: Index exists in sortedVideoStreams. */
private final int selectedVideoStreamIndex;

private Quality(@NonNull final List<VideoStream> sortedVideoStreams,

/** Create a new video Quality. The index must be valid in `sortedVideoStreams`.
*
* @param sortedVideoStreams
* @param selectedVideoStreamIndex
* @throws ArrayIndexOutOfBoundsException if index does not exist in `sortedVideoStreams`
*/
public Quality(@NonNull final List<VideoStream> sortedVideoStreams,
final int selectedVideoStreamIndex) {
if (selectedVideoStreamIndex < 0
|| selectedVideoStreamIndex >= sortedVideoStreams.size()) {
throw new ArrayIndexOutOfBoundsException(
"selectedVideoStreamIndex does not exist in sortedVideoStreams");
}
this.sortedVideoStreams = sortedVideoStreams;
this.selectedVideoStreamIndex = selectedVideoStreamIndex;
}

static Quality of(@NonNull final List<VideoStream> sortedVideoStreams,
final int selectedVideoStreamIndex) {
return new Quality(sortedVideoStreams, selectedVideoStreamIndex);
}

@NonNull
public List<VideoStream> getSortedVideoStreams() {
return sortedVideoStreams;
Expand All @@ -128,30 +137,35 @@ public int getSelectedVideoStreamIndex() {
return selectedVideoStreamIndex;
}

@Nullable
@NonNull
public VideoStream getSelectedVideoStream() {
return selectedVideoStreamIndex < 0
|| selectedVideoStreamIndex >= sortedVideoStreams.size()
? null : sortedVideoStreams.get(selectedVideoStreamIndex);
return sortedVideoStreams.get(selectedVideoStreamIndex);
}
}

final class AudioTrack {
@NonNull
private final List<AudioStream> audioStreams;
/** Invariant: Index exists in audioStreams. */
private final int selectedAudioStreamIndex;

private AudioTrack(@NonNull final List<AudioStream> audioStreams,
/** Create a new AudioTrack. The index must be valid in `audioStreams`.
*
* @param audioStreams
* @param selectedAudioStreamIndex
* @throws ArrayIndexOutOfBoundsException if index does not exist in audioStreams.
*/
public AudioTrack(@NonNull final List<AudioStream> audioStreams,
final int selectedAudioStreamIndex) {
if (selectedAudioStreamIndex < 0
|| selectedAudioStreamIndex >= audioStreams.size()) {
throw new ArrayIndexOutOfBoundsException(
"selectedAudioStreamIndex does not exist in audioStreams");
}
this.audioStreams = audioStreams;
this.selectedAudioStreamIndex = selectedAudioStreamIndex;
}

static AudioTrack of(@NonNull final List<AudioStream> audioStreams,
final int selectedAudioStreamIndex) {
return new AudioTrack(audioStreams, selectedAudioStreamIndex);
}

@NonNull
public List<AudioStream> getAudioStreams() {
return audioStreams;
Expand All @@ -161,11 +175,9 @@ public int getSelectedAudioStreamIndex() {
return selectedAudioStreamIndex;
}

@Nullable
@NonNull
public AudioStream getSelectedAudioStream() {
return selectedAudioStreamIndex < 0
|| selectedAudioStreamIndex >= audioStreams.size()
? null : audioStreams.get(selectedAudioStreamIndex);
return audioStreams.get(selectedAudioStreamIndex);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@

import com.google.android.exoplayer2.MediaItem;

import org.schabi.newpipe.extractor.stream.AudioStream;
import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.extractor.stream.StreamType;
import org.schabi.newpipe.extractor.stream.VideoStream;
import org.schabi.newpipe.util.image.ImageStrategy;

import java.util.Collections;
Expand All @@ -31,7 +29,7 @@ public final class StreamInfoTag implements MediaItemTag {
@Nullable
private final Object extras;

private StreamInfoTag(@NonNull final StreamInfo streamInfo,
public StreamInfoTag(@NonNull final StreamInfo streamInfo,
@Nullable final MediaItemTag.Quality quality,
@Nullable final MediaItemTag.AudioTrack audioTrack,
@Nullable final Object extras) {
Expand All @@ -41,29 +39,6 @@ private StreamInfoTag(@NonNull final StreamInfo streamInfo,
this.extras = extras;
}

public static StreamInfoTag of(@NonNull final StreamInfo streamInfo,
@NonNull final List<VideoStream> sortedVideoStreams,
final int selectedVideoStreamIndex,
@NonNull final List<AudioStream> audioStreams,
final int selectedAudioStreamIndex) {
final Quality quality = Quality.of(sortedVideoStreams, selectedVideoStreamIndex);
final AudioTrack audioTrack =
AudioTrack.of(audioStreams, selectedAudioStreamIndex);
return new StreamInfoTag(streamInfo, quality, audioTrack, null);
}

public static StreamInfoTag of(@NonNull final StreamInfo streamInfo,
@NonNull final List<AudioStream> audioStreams,
final int selectedAudioStreamIndex) {
final AudioTrack audioTrack =
AudioTrack.of(audioStreams, selectedAudioStreamIndex);
return new StreamInfoTag(streamInfo, null, audioTrack, null);
}

public static StreamInfoTag of(@NonNull final StreamInfo streamInfo) {
return new StreamInfoTag(streamInfo, null, null, null);
}

@Override
public List<Exception> getErrors() {
return Collections.emptyList();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@
import org.schabi.newpipe.player.mediaitem.StreamInfoTag;
import org.schabi.newpipe.util.ListHelper;

import java.util.Collections;
import java.util.List;
import java.util.Objects;

public class AudioPlaybackResolver implements PlaybackResolver {
private static final String TAG = AudioPlaybackResolver.class.getSimpleName();
Expand All @@ -45,7 +47,6 @@ public AudioPlaybackResolver(@NonNull final Context context,
* @param info of the stream
* @return the audio source to use or null if none could be found
*/
@Override
@Nullable
public MediaSource resolve(@NonNull final StreamInfo info) {
final MediaSource liveSource = PlaybackResolver.maybeBuildLiveMediaSource(dataSource, info);
Expand All @@ -54,22 +55,33 @@ public MediaSource resolve(@NonNull final StreamInfo info) {
}

final List<AudioStream> audioStreams =
getFilteredAudioStreams(context, info.getAudioStreams());
getFilteredAudioStreams(
context,
// TODO: getAudioStreams should be @NonNull
Objects.requireNonNullElse(info.getAudioStreams(), Collections.emptyList())
);
final Stream stream;
final MediaItemTag tag;

if (!audioStreams.isEmpty()) {
final int audioIndex =
ListHelper.getAudioFormatIndex(context, audioStreams, audioTrack);
stream = getStreamForIndex(audioIndex, audioStreams);
tag = StreamInfoTag.of(info, audioStreams, audioIndex);
assert audioIndex != -1;
final MediaItemTag.AudioTrack audio =
new MediaItemTag.AudioTrack(audioStreams, audioIndex);
tag = new StreamInfoTag(info, null, audio, null);
stream = audio.getSelectedAudioStream();
} else {
final List<VideoStream> videoStreams =
getPlayableStreams(info.getVideoStreams(), info.getServiceId());
if (!videoStreams.isEmpty()) {
final int index = ListHelper.getDefaultResolutionIndex(context, videoStreams);
stream = getStreamForIndex(index, videoStreams);
tag = StreamInfoTag.of(info);
final int videoIndex = ListHelper.getDefaultResolutionIndex(context, videoStreams);
assert videoIndex != -1;
final MediaItemTag.Quality video =
new MediaItemTag.Quality(videoStreams, videoIndex);
// why are we not passing `video` as quality here?
tag = new StreamInfoTag(info, null, null, null);
stream = video.getSelectedVideoStream();
} else {
return null;
}
Expand All @@ -84,20 +96,11 @@ public MediaSource resolve(@NonNull final StreamInfo info) {
}
}

@Nullable
Stream getStreamForIndex(final int index, @NonNull final List<? extends Stream> streams) {
if (index >= 0 && index < streams.size()) {
return streams.get(index);
}
return null;
}

@Nullable
public String getAudioTrack() {
return audioTrack;
}

public void setAudioTrack(@Nullable final String audioLanguage) {
this.audioTrack = audioLanguage;
/** Set audio track to be used the next time {@link #resolve(StreamInfo)} is called.
*
* @param audioTrack the {@link AudioStream} audioTrackId that should be selected on resolve
*/
public void setAudioTrack(@Nullable final String audioTrack) {
this.audioTrack = audioTrack;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,10 @@
import java.util.Objects;

/**
* This interface is just a shorthand for {@link Resolver} with {@link StreamInfo} as source and
* {@link MediaSource} as product. It contains many static methods that can be used by classes
* This interface contains many static methods that can be used by classes
* implementing this interface, and nothing else.
*/
public interface PlaybackResolver extends Resolver<StreamInfo, MediaSource> {
public interface PlaybackResolver {
String TAG = PlaybackResolver.class.getSimpleName();


Expand Down Expand Up @@ -200,7 +199,7 @@ static MediaSource maybeBuildLiveMediaSource(final PlayerDataSource dataSource,
}

try {
final StreamInfoTag tag = StreamInfoTag.of(info);
final StreamInfoTag tag = new StreamInfoTag(info, null, null, null);
if (!info.getHlsUrl().isEmpty()) {
return buildLiveMediaSource(dataSource, info.getHlsUrl(), C.CONTENT_TYPE_HLS, tag);
} else if (!info.getDashMpdUrl().isEmpty()) {
Expand Down Expand Up @@ -416,6 +415,7 @@ private static MediaSource createYoutubeMediaSource(final Stream stream,
// (which is the last segment of the stream)

try {
// We know that itagItem has to be set, because it’s youtube-specific
final ItagItem itagItem = Objects.requireNonNull(stream.getItagItem());
final String manifestString = YoutubePostLiveStreamDvrDashManifestCreator
.fromPostLiveStreamDvrStreamingUrl(stream.getContent(),
Expand Down Expand Up @@ -449,6 +449,7 @@ private static MediaSource createYoutubeMediaSourceOfVideoStreamType(
try {
final String manifestString = YoutubeProgressiveDashManifestCreator
.fromProgressiveStreamingUrl(stream.getContent(),
// We know that itagItem has to be set, because it’s youtube-specific
Objects.requireNonNull(stream.getItagItem()),
streamInfo.getDuration());
return buildYoutubeManualDashMediaSource(dataSource,
Expand Down Expand Up @@ -476,6 +477,7 @@ private static MediaSource createYoutubeMediaSourceOfVideoStreamType(
try {
final String manifestString = YoutubeOtfDashManifestCreator
.fromOtfStreamingUrl(stream.getContent(),
// We know that itagItem has to be set, because it’s youtube-specific
Objects.requireNonNull(stream.getItagItem()),
streamInfo.getDuration());
return buildYoutubeManualDashMediaSource(dataSource,
Expand Down

This file was deleted.

Loading