Skip to content

Commit 4e459b3

Browse files
committed
updated: ExoPlayer to 2.17.1.
added: MediaItemTag for ManagedMediaSources. added: silent track for FailedMediaSource. added: keyframe fast forward at initial playback buffer. added: error notification on silently skipped streams.
1 parent 8c5e8bd commit 4e459b3

29 files changed

+885
-606
lines changed

app/build.gradle

+1-1
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ ext {
104104
androidxRoomVersion = '2.4.2'
105105

106106
icepickVersion = '3.2.0'
107-
exoPlayerVersion = '2.14.2'
107+
exoPlayerVersion = '2.17.1'
108108
googleAutoServiceVersion = '1.0.1'
109109
groupieVersion = '2.10.0'
110110
markwonVersion = '4.6.2'

app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java

+3-4
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
import androidx.core.content.ContextCompat;
4444
import androidx.preference.PreferenceManager;
4545

46-
import com.google.android.exoplayer2.ExoPlaybackException;
46+
import com.google.android.exoplayer2.PlaybackException;
4747
import com.google.android.exoplayer2.PlaybackParameters;
4848
import com.google.android.material.appbar.AppBarLayout;
4949
import com.google.android.material.bottomsheet.BottomSheetBehavior;
@@ -1884,9 +1884,8 @@ public void onMetadataUpdate(final StreamInfo info, final PlayQueue queue) {
18841884
}
18851885

18861886
@Override
1887-
public void onPlayerError(final ExoPlaybackException error) {
1888-
if (error.type == ExoPlaybackException.TYPE_SOURCE
1889-
|| error.type == ExoPlaybackException.TYPE_UNEXPECTED) {
1887+
public void onPlayerError(final PlaybackException error, final boolean isCatchableException) {
1888+
if (!isCatchableException) {
18901889
// Properly exit from fullscreen
18911890
toggleFullscreenIfInFullscreenMode();
18921891
hideMainPlayerOnLoadingNewStream();

app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailPlayerCrasher.java

+13-4
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
import com.google.android.exoplayer2.C;
1717
import com.google.android.exoplayer2.ExoPlaybackException;
18+
import com.google.android.exoplayer2.PlaybackException;
1819

1920
import org.schabi.newpipe.R;
2021
import org.schabi.newpipe.databinding.ListRadioIconItemBinding;
@@ -28,6 +29,10 @@
2829
import java.util.Map;
2930
import java.util.function.Supplier;
3031

32+
import static com.google.android.exoplayer2.PlaybackException.ERROR_CODE_BEHIND_LIVE_WINDOW;
33+
import static com.google.android.exoplayer2.PlaybackException.ERROR_CODE_DECODING_FAILED;
34+
import static com.google.android.exoplayer2.PlaybackException.ERROR_CODE_UNSPECIFIED;
35+
3136
/**
3237
* Outsourced logic for crashing the player in the {@link VideoDetailFragment}.
3338
*/
@@ -51,7 +56,8 @@ private static Map<String, Supplier<ExoPlaybackException>> getExceptionTypes() {
5156
exceptionTypes.put(
5257
"Source",
5358
() -> ExoPlaybackException.createForSource(
54-
new IOException(defaultMsg)
59+
new IOException(defaultMsg),
60+
ERROR_CODE_BEHIND_LIVE_WINDOW
5561
)
5662
);
5763
exceptionTypes.put(
@@ -61,13 +67,16 @@ private static Map<String, Supplier<ExoPlaybackException>> getExceptionTypes() {
6167
"Dummy renderer",
6268
0,
6369
null,
64-
C.FORMAT_HANDLED
70+
C.FORMAT_HANDLED,
71+
/*isRecoverable=*/false,
72+
ERROR_CODE_DECODING_FAILED
6573
)
6674
);
6775
exceptionTypes.put(
6876
"Unexpected",
6977
() -> ExoPlaybackException.createForUnexpected(
70-
new RuntimeException(defaultMsg)
78+
new RuntimeException(defaultMsg),
79+
ERROR_CODE_UNSPECIFIED
7180
)
7281
);
7382
exceptionTypes.put(
@@ -139,7 +148,7 @@ public static void onCrashThePlayer(
139148

140149
/**
141150
* Note that this method does not crash the underlying exoplayer directly (it's not possible).
142-
* It simply supplies a Exception to {@link Player#onPlayerError(ExoPlaybackException)}.
151+
* It simply supplies a Exception to {@link Player#onPlayerError(PlaybackException)}.
143152
* @param player
144153
* @param exception
145154
*/

app/src/main/java/org/schabi/newpipe/player/Player.java

+226-224
Large diffs are not rendered by default.
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package org.schabi.newpipe.player.event;
22

3-
import com.google.android.exoplayer2.ExoPlaybackException;
3+
import com.google.android.exoplayer2.PlaybackException;
44

55
public interface PlayerServiceEventListener extends PlayerEventListener {
66
void onFullscreenStateChanged(boolean fullscreen);
@@ -9,7 +9,7 @@ public interface PlayerServiceEventListener extends PlayerEventListener {
99

1010
void onMoreOptionsLongClicked();
1111

12-
void onPlayerError(ExoPlaybackException error);
12+
void onPlayerError(PlaybackException error, boolean isCatchableException);
1313

1414
void hideSystemUiIfNeeded();
1515
}

app/src/main/java/org/schabi/newpipe/player/helper/AudioReactor.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
import androidx.media.AudioFocusRequestCompat;
1515
import androidx.media.AudioManagerCompat;
1616

17-
import com.google.android.exoplayer2.SimpleExoPlayer;
17+
import com.google.android.exoplayer2.ExoPlayer;
1818
import com.google.android.exoplayer2.analytics.AnalyticsListener;
1919

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

30-
private final SimpleExoPlayer player;
30+
private final ExoPlayer player;
3131
private final Context context;
3232
private final AudioManager audioManager;
3333

3434
private final AudioFocusRequestCompat request;
3535

3636
public AudioReactor(@NonNull final Context context,
37-
@NonNull final SimpleExoPlayer player) {
37+
@NonNull final ExoPlayer player) {
3838
this.player = player;
3939
this.context = context;
4040
this.audioManager = ContextCompat.getSystemService(context, AudioManager.class);

app/src/main/java/org/schabi/newpipe/player/helper/CacheFactory.java

+10-8
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,10 @@
33
import android.content.Context;
44
import android.util.Log;
55

6-
import androidx.annotation.NonNull;
7-
8-
import com.google.android.exoplayer2.database.ExoDatabaseProvider;
6+
import com.google.android.exoplayer2.database.StandaloneDatabaseProvider;
97
import com.google.android.exoplayer2.upstream.DataSource;
108
import com.google.android.exoplayer2.upstream.DefaultDataSource;
11-
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
9+
import com.google.android.exoplayer2.upstream.DefaultHttpDataSource;
1210
import com.google.android.exoplayer2.upstream.FileDataSource;
1311
import com.google.android.exoplayer2.upstream.TransferListener;
1412
import com.google.android.exoplayer2.upstream.cache.CacheDataSink;
@@ -18,14 +16,16 @@
1816

1917
import java.io.File;
2018

19+
import androidx.annotation.NonNull;
20+
2121
/* package-private */ class CacheFactory implements DataSource.Factory {
2222
private static final String TAG = "CacheFactory";
2323

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

28-
private final DefaultDataSourceFactory dataSourceFactory;
28+
private final DataSource.Factory dataSourceFactory;
2929
private final File cacheDir;
3030
private final long maxFileSize;
3131

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

52-
dataSourceFactory = new DefaultDataSourceFactory(context, userAgent, transferListener);
52+
dataSourceFactory = new DefaultDataSource
53+
.Factory(context, new DefaultHttpDataSource.Factory().setUserAgent(userAgent))
54+
.setTransferListener(transferListener);
5355
cacheDir = new File(context.getExternalCacheDir(), CACHE_FOLDER_NAME);
5456
if (!cacheDir.exists()) {
5557
//noinspection ResultOfMethodCallIgnored
@@ -59,7 +61,7 @@ private CacheFactory(@NonNull final Context context,
5961
if (cache == null) {
6062
final LeastRecentlyUsedCacheEvictor evictor
6163
= new LeastRecentlyUsedCacheEvictor(maxCacheSize);
62-
cache = new SimpleCache(cacheDir, evictor, new ExoDatabaseProvider(context));
64+
cache = new SimpleCache(cacheDir, evictor, new StandaloneDatabaseProvider(context));
6365
}
6466
}
6567

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

71-
final DefaultDataSource dataSource = dataSourceFactory.createDataSource();
73+
final DataSource dataSource = dataSourceFactory.createDataSource();
7274
final FileDataSource fileSource = new FileDataSource();
7375
final CacheDataSink dataSink = new CacheDataSink(cache, maxFileSize);
7476

app/src/main/java/org/schabi/newpipe/player/helper/MediaSessionManager.java

-2
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
import org.schabi.newpipe.MainActivity;
2020
import org.schabi.newpipe.player.mediasession.MediaSessionCallback;
2121
import org.schabi.newpipe.player.mediasession.PlayQueueNavigator;
22-
import org.schabi.newpipe.player.mediasession.PlayQueuePlaybackController;
2322

2423
import java.util.Optional;
2524

@@ -55,7 +54,6 @@ public MediaSessionManager(@NonNull final Context context,
5554
.build());
5655

5756
sessionConnector = new MediaSessionConnector(mediaSession);
58-
sessionConnector.setControlDispatcher(new PlayQueuePlaybackController(callback));
5957
sessionConnector.setQueueNavigator(new PlayQueueNavigator(mediaSession, callback));
6058
sessionConnector.setPlayer(player);
6159
}

app/src/main/java/org/schabi/newpipe/player/helper/PlayerDataSource.java

+9-6
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22

33
import android.content.Context;
44

5-
import androidx.annotation.NonNull;
6-
75
import com.google.android.exoplayer2.source.ProgressiveMediaSource;
86
import com.google.android.exoplayer2.source.SingleSampleMediaSource;
97
import com.google.android.exoplayer2.source.dash.DashMediaSource;
@@ -13,10 +11,13 @@
1311
import com.google.android.exoplayer2.source.smoothstreaming.DefaultSsChunkSource;
1412
import com.google.android.exoplayer2.source.smoothstreaming.SsMediaSource;
1513
import com.google.android.exoplayer2.upstream.DataSource;
16-
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
14+
import com.google.android.exoplayer2.upstream.DefaultDataSource;
15+
import com.google.android.exoplayer2.upstream.DefaultHttpDataSource;
1716
import com.google.android.exoplayer2.upstream.DefaultLoadErrorHandlingPolicy;
1817
import com.google.android.exoplayer2.upstream.TransferListener;
1918

19+
import androidx.annotation.NonNull;
20+
2021
public class PlayerDataSource {
2122

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

38-
public PlayerDataSource(@NonNull final Context context, @NonNull final String userAgent,
39+
public PlayerDataSource(@NonNull final Context context,
40+
@NonNull final String userAgent,
3941
@NonNull final TransferListener transferListener) {
4042
continueLoadingCheckIntervalBytes = PlayerHelper.getProgressiveLoadIntervalBytes(context);
4143
cacheDataSourceFactory = new CacheFactory(context, userAgent, transferListener);
42-
cachelessDataSourceFactory
43-
= new DefaultDataSourceFactory(context, userAgent, transferListener);
44+
cachelessDataSourceFactory = new DefaultDataSource
45+
.Factory(context, new DefaultHttpDataSource.Factory().setUserAgent(userAgent))
46+
.setTransferListener(transferListener);
4447
}
4548

4649
public SsMediaSource.Factory getLiveSsMediaSourceFactory() {

app/src/main/java/org/schabi/newpipe/player/helper/PlayerHolder.java

+4-3
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
import androidx.annotation.Nullable;
1111
import androidx.core.content.ContextCompat;
1212

13-
import com.google.android.exoplayer2.ExoPlaybackException;
13+
import com.google.android.exoplayer2.PlaybackException;
1414
import com.google.android.exoplayer2.PlaybackParameters;
1515

1616
import org.schabi.newpipe.App;
@@ -233,9 +233,10 @@ public void onMoreOptionsLongClicked() {
233233
}
234234

235235
@Override
236-
public void onPlayerError(final ExoPlaybackException error) {
236+
public void onPlayerError(final PlaybackException error,
237+
final boolean isCatchableException) {
237238
if (listener != null) {
238-
listener.onPlayerError(error);
239+
listener.onPlayerError(error, isCatchableException);
239240
}
240241
}
241242

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
package org.schabi.newpipe.player.mediaitem;
2+
3+
import org.schabi.newpipe.extractor.stream.StreamInfo;
4+
import org.schabi.newpipe.extractor.stream.StreamType;
5+
import org.schabi.newpipe.player.playqueue.PlayQueueItem;
6+
7+
import java.util.List;
8+
import java.util.Optional;
9+
10+
import androidx.annotation.NonNull;
11+
import androidx.annotation.Nullable;
12+
13+
public final class ExceptionTag implements MediaItemTag {
14+
@NonNull
15+
private final PlayQueueItem item;
16+
@NonNull
17+
private final List<Throwable> errors;
18+
@Nullable
19+
private final Object extras;
20+
21+
private ExceptionTag(@NonNull final PlayQueueItem item,
22+
@NonNull final List<Throwable> errors,
23+
@Nullable final Object extras) {
24+
this.item = item;
25+
this.errors = errors;
26+
this.extras = extras;
27+
}
28+
29+
public static ExceptionTag of(@NonNull final PlayQueueItem playQueueItem,
30+
@NonNull final List<Throwable> errors) {
31+
return new ExceptionTag(playQueueItem, errors, null);
32+
}
33+
34+
@NonNull
35+
@Override
36+
public List<Throwable> getErrors() {
37+
return errors;
38+
}
39+
40+
@Override
41+
public int getServiceId() {
42+
return item.getServiceId();
43+
}
44+
45+
@Override
46+
public String getTitle() {
47+
return item.getTitle();
48+
}
49+
50+
@Override
51+
public String getUploaderName() {
52+
return item.getUploader();
53+
}
54+
55+
@Override
56+
public long getDurationSeconds() {
57+
return item.getDuration();
58+
}
59+
60+
@Override
61+
public String getStreamUrl() {
62+
return item.getUrl();
63+
}
64+
65+
@Override
66+
public String getThumbnailUrl() {
67+
return item.getThumbnailUrl();
68+
}
69+
70+
@Override
71+
public String getUploaderUrl() {
72+
return item.getUploaderUrl();
73+
}
74+
75+
@Override
76+
public StreamType getStreamType() {
77+
return item.getStreamType();
78+
}
79+
80+
@Override
81+
public Optional<StreamInfo> getMaybeStreamInfo() {
82+
return Optional.empty();
83+
}
84+
85+
@Override
86+
public Optional<Quality> getMaybeQuality() {
87+
return Optional.empty();
88+
}
89+
90+
@Override
91+
public <T> Optional<T> getMaybeExtras(@NonNull final Class<T> type) {
92+
return Optional.ofNullable(extras).map(type::cast);
93+
}
94+
95+
@Override
96+
public <T> MediaItemTag withExtras(@NonNull final T extra) {
97+
return new ExceptionTag(item, errors, extra);
98+
}
99+
}

0 commit comments

Comments
 (0)