Skip to content

Commit

Permalink
Merge pull request #8020 from karyogamy/exo-update-v17
Browse files Browse the repository at this point in the history
ExoPlayer 2.17.1 update and MediaSource management rework
  • Loading branch information
litetex authored Apr 2, 2022
2 parents ac00c8f + a00bc95 commit 860d28e
Show file tree
Hide file tree
Showing 29 changed files with 1,013 additions and 610 deletions.
2 changes: 1 addition & 1 deletion app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ ext {
androidxWorkVersion = '2.7.1'

icepickVersion = '3.2.0'
exoPlayerVersion = '2.14.2'
exoPlayerVersion = '2.17.1'
googleAutoServiceVersion = '1.0.1'
groupieVersion = '2.10.0'
markwonVersion = '4.6.2'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
import androidx.core.content.ContextCompat;
import androidx.preference.PreferenceManager;

import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.PlaybackException;
import com.google.android.exoplayer2.PlaybackParameters;
import com.google.android.material.appbar.AppBarLayout;
import com.google.android.material.bottomsheet.BottomSheetBehavior;
Expand Down Expand Up @@ -1884,9 +1884,8 @@ public void onMetadataUpdate(final StreamInfo info, final PlayQueue queue) {
}

@Override
public void onPlayerError(final ExoPlaybackException error) {
if (error.type == ExoPlaybackException.TYPE_SOURCE
|| error.type == ExoPlaybackException.TYPE_UNEXPECTED) {
public void onPlayerError(final PlaybackException error, final boolean isCatchableException) {
if (!isCatchableException) {
// Properly exit from fullscreen
toggleFullscreenIfInFullscreenMode();
hideMainPlayerOnLoadingNewStream();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.PlaybackException;

import org.schabi.newpipe.R;
import org.schabi.newpipe.databinding.ListRadioIconItemBinding;
Expand All @@ -28,6 +29,10 @@
import java.util.Map;
import java.util.function.Supplier;

import static com.google.android.exoplayer2.PlaybackException.ERROR_CODE_BEHIND_LIVE_WINDOW;
import static com.google.android.exoplayer2.PlaybackException.ERROR_CODE_DECODING_FAILED;
import static com.google.android.exoplayer2.PlaybackException.ERROR_CODE_UNSPECIFIED;

/**
* Outsourced logic for crashing the player in the {@link VideoDetailFragment}.
*/
Expand All @@ -51,7 +56,8 @@ private static Map<String, Supplier<ExoPlaybackException>> getExceptionTypes() {
exceptionTypes.put(
"Source",
() -> ExoPlaybackException.createForSource(
new IOException(defaultMsg)
new IOException(defaultMsg),
ERROR_CODE_BEHIND_LIVE_WINDOW
)
);
exceptionTypes.put(
Expand All @@ -61,13 +67,16 @@ private static Map<String, Supplier<ExoPlaybackException>> getExceptionTypes() {
"Dummy renderer",
0,
null,
C.FORMAT_HANDLED
C.FORMAT_HANDLED,
/*isRecoverable=*/false,
ERROR_CODE_DECODING_FAILED
)
);
exceptionTypes.put(
"Unexpected",
() -> ExoPlaybackException.createForUnexpected(
new RuntimeException(defaultMsg)
new RuntimeException(defaultMsg),
ERROR_CODE_UNSPECIFIED
)
);
exceptionTypes.put(
Expand Down Expand Up @@ -139,7 +148,7 @@ public static void onCrashThePlayer(

/**
* Note that this method does not crash the underlying exoplayer directly (it's not possible).
* It simply supplies a Exception to {@link Player#onPlayerError(ExoPlaybackException)}.
* It simply supplies a Exception to {@link Player#onPlayerError(PlaybackException)}.
* @param player
* @param exception
*/
Expand Down
473 changes: 248 additions & 225 deletions app/src/main/java/org/schabi/newpipe/player/Player.java

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package org.schabi.newpipe.player.event;

import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.PlaybackException;

public interface PlayerServiceEventListener extends PlayerEventListener {
void onFullscreenStateChanged(boolean fullscreen);
Expand All @@ -9,7 +9,7 @@ public interface PlayerServiceEventListener extends PlayerEventListener {

void onMoreOptionsLongClicked();

void onPlayerError(ExoPlaybackException error);
void onPlayerError(PlaybackException error, boolean isCatchableException);

void hideSystemUiIfNeeded();
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
import androidx.media.AudioFocusRequestCompat;
import androidx.media.AudioManagerCompat;

import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.analytics.AnalyticsListener;

public class AudioReactor implements AudioManager.OnAudioFocusChangeListener, AnalyticsListener {
Expand All @@ -27,14 +27,14 @@ public class AudioReactor implements AudioManager.OnAudioFocusChangeListener, An
private static final int FOCUS_GAIN_TYPE = AudioManagerCompat.AUDIOFOCUS_GAIN;
private static final int STREAM_TYPE = AudioManager.STREAM_MUSIC;

private final SimpleExoPlayer player;
private final ExoPlayer player;
private final Context context;
private final AudioManager audioManager;

private final AudioFocusRequestCompat request;

public AudioReactor(@NonNull final Context context,
@NonNull final SimpleExoPlayer player) {
@NonNull final ExoPlayer player) {
this.player = player;
this.context = context;
this.audioManager = ContextCompat.getSystemService(context, AudioManager.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,10 @@
import android.content.Context;
import android.util.Log;

import androidx.annotation.NonNull;

import com.google.android.exoplayer2.database.ExoDatabaseProvider;
import com.google.android.exoplayer2.database.StandaloneDatabaseProvider;
import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.upstream.DefaultDataSource;
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
import com.google.android.exoplayer2.upstream.DefaultHttpDataSource;
import com.google.android.exoplayer2.upstream.FileDataSource;
import com.google.android.exoplayer2.upstream.TransferListener;
import com.google.android.exoplayer2.upstream.cache.CacheDataSink;
Expand All @@ -18,14 +16,16 @@

import java.io.File;

import androidx.annotation.NonNull;

/* package-private */ class CacheFactory implements DataSource.Factory {
private static final String TAG = "CacheFactory";

private static final String CACHE_FOLDER_NAME = "exoplayer";
private static final int CACHE_FLAGS = CacheDataSource.FLAG_BLOCK_ON_CACHE
| CacheDataSource.FLAG_IGNORE_CACHE_ON_ERROR;

private final DefaultDataSourceFactory dataSourceFactory;
private final DataSource.Factory dataSourceFactory;
private final File cacheDir;
private final long maxFileSize;

Expand All @@ -49,7 +49,9 @@ private CacheFactory(@NonNull final Context context,
final long maxFileSize) {
this.maxFileSize = maxFileSize;

dataSourceFactory = new DefaultDataSourceFactory(context, userAgent, transferListener);
dataSourceFactory = new DefaultDataSource
.Factory(context, new DefaultHttpDataSource.Factory().setUserAgent(userAgent))
.setTransferListener(transferListener);
cacheDir = new File(context.getExternalCacheDir(), CACHE_FOLDER_NAME);
if (!cacheDir.exists()) {
//noinspection ResultOfMethodCallIgnored
Expand All @@ -59,7 +61,7 @@ private CacheFactory(@NonNull final Context context,
if (cache == null) {
final LeastRecentlyUsedCacheEvictor evictor
= new LeastRecentlyUsedCacheEvictor(maxCacheSize);
cache = new SimpleCache(cacheDir, evictor, new ExoDatabaseProvider(context));
cache = new SimpleCache(cacheDir, evictor, new StandaloneDatabaseProvider(context));
}
}

Expand All @@ -68,7 +70,7 @@ private CacheFactory(@NonNull final Context context,
public DataSource createDataSource() {
Log.d(TAG, "initExoPlayerCache: cacheDir = " + cacheDir.getAbsolutePath());

final DefaultDataSource dataSource = dataSourceFactory.createDataSource();
final DataSource dataSource = dataSourceFactory.createDataSource();
final FileDataSource fileSource = new FileDataSource();
final CacheDataSink dataSink = new CacheDataSink(cache, maxFileSize);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
import org.schabi.newpipe.MainActivity;
import org.schabi.newpipe.player.mediasession.MediaSessionCallback;
import org.schabi.newpipe.player.mediasession.PlayQueueNavigator;
import org.schabi.newpipe.player.mediasession.PlayQueuePlaybackController;

import java.util.Optional;

Expand Down Expand Up @@ -55,7 +54,6 @@ public MediaSessionManager(@NonNull final Context context,
.build());

sessionConnector = new MediaSessionConnector(mediaSession);
sessionConnector.setControlDispatcher(new PlayQueuePlaybackController(callback));
sessionConnector.setQueueNavigator(new PlayQueueNavigator(mediaSession, callback));
sessionConnector.setPlayer(player);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@

import android.content.Context;

import androidx.annotation.NonNull;

import com.google.android.exoplayer2.source.ProgressiveMediaSource;
import com.google.android.exoplayer2.source.SingleSampleMediaSource;
import com.google.android.exoplayer2.source.dash.DashMediaSource;
Expand All @@ -13,10 +11,13 @@
import com.google.android.exoplayer2.source.smoothstreaming.DefaultSsChunkSource;
import com.google.android.exoplayer2.source.smoothstreaming.SsMediaSource;
import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
import com.google.android.exoplayer2.upstream.DefaultDataSource;
import com.google.android.exoplayer2.upstream.DefaultHttpDataSource;
import com.google.android.exoplayer2.upstream.DefaultLoadErrorHandlingPolicy;
import com.google.android.exoplayer2.upstream.TransferListener;

import androidx.annotation.NonNull;

public class PlayerDataSource {

public static final int LIVE_STREAM_EDGE_GAP_MILLIS = 10000;
Expand All @@ -35,12 +36,14 @@ public class PlayerDataSource {
private final DataSource.Factory cacheDataSourceFactory;
private final DataSource.Factory cachelessDataSourceFactory;

public PlayerDataSource(@NonNull final Context context, @NonNull final String userAgent,
public PlayerDataSource(@NonNull final Context context,
@NonNull final String userAgent,
@NonNull final TransferListener transferListener) {
continueLoadingCheckIntervalBytes = PlayerHelper.getProgressiveLoadIntervalBytes(context);
cacheDataSourceFactory = new CacheFactory(context, userAgent, transferListener);
cachelessDataSourceFactory
= new DefaultDataSourceFactory(context, userAgent, transferListener);
cachelessDataSourceFactory = new DefaultDataSource
.Factory(context, new DefaultHttpDataSource.Factory().setUserAgent(userAgent))
.setTransferListener(transferListener);
}

public SsMediaSource.Factory getLiveSsMediaSourceFactory() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;

import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.PlaybackException;
import com.google.android.exoplayer2.PlaybackParameters;

import org.schabi.newpipe.App;
Expand Down Expand Up @@ -233,9 +233,10 @@ public void onMoreOptionsLongClicked() {
}

@Override
public void onPlayerError(final ExoPlaybackException error) {
public void onPlayerError(final PlaybackException error,
final boolean isCatchableException) {
if (listener != null) {
listener.onPlayerError(error);
listener.onPlayerError(error, isCatchableException);
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package org.schabi.newpipe.player.mediaitem;

import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.extractor.stream.StreamType;
import org.schabi.newpipe.player.playqueue.PlayQueueItem;

import java.util.List;
import java.util.Optional;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

/**
* This {@link MediaItemTag} object is designed to contain metadata for a stream
* that has failed to load. It supplies metadata from an underlying
* {@link PlayQueueItem}, which is used by the internal players to resolve actual
* playback info.
*
* This {@link MediaItemTag} does not contain any {@link StreamInfo} that can be
* used to start playback and can be detected by checking {@link ExceptionTag#getErrors()}
* when in generic form.
**/
public final class ExceptionTag implements MediaItemTag {
@NonNull
private final PlayQueueItem item;
@NonNull
private final List<Exception> errors;
@Nullable
private final Object extras;

private ExceptionTag(@NonNull final PlayQueueItem item,
@NonNull final List<Exception> errors,
@Nullable final Object extras) {
this.item = item;
this.errors = errors;
this.extras = extras;
}

public static ExceptionTag of(@NonNull final PlayQueueItem playQueueItem,
@NonNull final List<Exception> errors) {
return new ExceptionTag(playQueueItem, errors, null);
}

@NonNull
@Override
public List<Exception> getErrors() {
return errors;
}

@Override
public int getServiceId() {
return item.getServiceId();
}

@Override
public String getTitle() {
return item.getTitle();
}

@Override
public String getUploaderName() {
return item.getUploader();
}

@Override
public long getDurationSeconds() {
return item.getDuration();
}

@Override
public String getStreamUrl() {
return item.getUrl();
}

@Override
public String getThumbnailUrl() {
return item.getThumbnailUrl();
}

@Override
public String getUploaderUrl() {
return item.getUploaderUrl();
}

@Override
public StreamType getStreamType() {
return item.getStreamType();
}

@Override
public <T> Optional<T> getMaybeExtras(@NonNull final Class<T> type) {
return Optional.ofNullable(extras).map(type::cast);
}

@Override
public <T> MediaItemTag withExtras(@NonNull final T extra) {
return new ExceptionTag(item, errors, extra);
}
}
Loading

0 comments on commit 860d28e

Please sign in to comment.