Update ExoPlayer to 2.9.6, including httook dependency and deprecations

This commit is contained in:
Robin 2019-03-05 18:05:44 +01:00
parent 8b4a94e5aa
commit 4d80bdcc9f
17 changed files with 63 additions and 198 deletions

View file

@ -44,10 +44,10 @@ android {
ext { ext {
supportLibVersion = '28.0.0' supportLibVersion = '28.0.0'
exoPlayerLibVersion = '2.8.4' //2.9.0 exoPlayerLibVersion = '2.9.6'
roomDbLibVersion = '1.1.1' roomDbLibVersion = '1.1.1'
leakCanaryLibVersion = '1.5.4' //1.6.1 leakCanaryLibVersion = '1.5.4' //1.6.1
okHttpLibVersion = '3.11.0' okHttpLibVersion = '3.12.1'
icepickLibVersion = '3.2.0' icepickLibVersion = '3.2.0'
stethoLibVersion = '1.5.0' stethoLibVersion = '1.5.0'
} }

View file

@ -47,7 +47,7 @@ public class DownloadActivity extends AppCompatActivity {
@Override @Override
public void onGlobalLayout() { public void onGlobalLayout() {
updateFragments(); updateFragments();
getWindow().getDecorView().getViewTreeObserver().removeGlobalOnLayoutListener(this); getWindow().getDecorView().getViewTreeObserver().removeOnGlobalLayoutListener(this);
} }
}); });
} }

View file

@ -44,6 +44,7 @@ import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.source.BehindLiveWindowException; import com.google.android.exoplayer2.source.BehindLiveWindowException;
import com.google.android.exoplayer2.source.MediaSource; import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.source.TrackGroupArray; import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
import com.google.android.exoplayer2.trackselection.TrackSelection; import com.google.android.exoplayer2.trackselection.TrackSelection;
import com.google.android.exoplayer2.trackselection.TrackSelectionArray; import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter; import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter;
@ -63,7 +64,6 @@ import org.schabi.newpipe.player.helper.PlayerDataSource;
import org.schabi.newpipe.player.helper.PlayerHelper; import org.schabi.newpipe.player.helper.PlayerHelper;
import org.schabi.newpipe.player.mediasource.FailedMediaSource; import org.schabi.newpipe.player.mediasource.FailedMediaSource;
import org.schabi.newpipe.player.playback.BasePlayerMediaSession; import org.schabi.newpipe.player.playback.BasePlayerMediaSession;
import org.schabi.newpipe.player.playback.CustomTrackSelector;
import org.schabi.newpipe.player.playback.MediaSourceManager; import org.schabi.newpipe.player.playback.MediaSourceManager;
import org.schabi.newpipe.player.playback.PlaybackListener; import org.schabi.newpipe.player.playback.PlaybackListener;
import org.schabi.newpipe.player.playqueue.PlayQueue; import org.schabi.newpipe.player.playqueue.PlayQueue;
@ -113,7 +113,7 @@ public abstract class BasePlayer implements
final protected HistoryRecordManager recordManager; final protected HistoryRecordManager recordManager;
@NonNull @NonNull
final protected CustomTrackSelector trackSelector; final protected DefaultTrackSelector trackSelector;
@NonNull @NonNull
final protected PlayerDataSource dataSource; final protected PlayerDataSource dataSource;
@ -207,9 +207,8 @@ public abstract class BasePlayer implements
final DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter(); final DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
this.dataSource = new PlayerDataSource(context, userAgent, bandwidthMeter); this.dataSource = new PlayerDataSource(context, userAgent, bandwidthMeter);
final TrackSelection.Factory trackSelectionFactory = final TrackSelection.Factory trackSelectionFactory = PlayerHelper.getQualitySelector(context);
PlayerHelper.getQualitySelector(context, bandwidthMeter); this.trackSelector = new DefaultTrackSelector(trackSelectionFactory);
this.trackSelector = new CustomTrackSelector(trackSelectionFactory);
this.loadControl = new LoadController(context); this.loadControl = new LoadController(context);
this.renderFactory = new DefaultRenderersFactory(context); this.renderFactory = new DefaultRenderersFactory(context);
@ -225,7 +224,7 @@ public abstract class BasePlayer implements
public void initPlayer(final boolean playOnReady) { public void initPlayer(final boolean playOnReady) {
if (DEBUG) Log.d(TAG, "initPlayer() called with: context = [" + context + "]"); if (DEBUG) Log.d(TAG, "initPlayer() called with: context = [" + context + "]");
simpleExoPlayer = ExoPlayerFactory.newSimpleInstance(renderFactory, trackSelector, loadControl); simpleExoPlayer = ExoPlayerFactory.newSimpleInstance(context, renderFactory, trackSelector, loadControl);
simpleExoPlayer.addListener(this); simpleExoPlayer.addListener(this);
simpleExoPlayer.setPlayWhenReady(playOnReady); simpleExoPlayer.setPlayWhenReady(playOnReady);
simpleExoPlayer.setSeekParameters(PlayerHelper.getSeekParameters(context)); simpleExoPlayer.setSeekParameters(PlayerHelper.getSeekParameters(context));

View file

@ -288,6 +288,7 @@ public final class MainVideoPlayer extends AppCompatActivity
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION; | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
} else { } else {
//noinspection deprecation
visibility = View.STATUS_BAR_VISIBLE; visibility = View.STATUS_BAR_VISIBLE;
} }
@ -361,6 +362,7 @@ public final class MainVideoPlayer extends AppCompatActivity
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
shuffleButton.setImageAlpha(shuffleAlpha); shuffleButton.setImageAlpha(shuffleAlpha);
} else { } else {
//noinspection deprecation
shuffleButton.setAlpha(shuffleAlpha); shuffleButton.setAlpha(shuffleAlpha);
} }
} }

View file

@ -656,6 +656,7 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
shuffleButton.setImageAlpha(shuffleAlpha); shuffleButton.setImageAlpha(shuffleAlpha);
} else { } else {
//noinspection deprecation
shuffleButton.setAlpha(shuffleAlpha); shuffleButton.setAlpha(shuffleAlpha);
} }
} }

View file

@ -212,7 +212,6 @@ public abstract class VideoPlayer extends BasePlayer
@Override @Override
public void initListeners() { public void initListeners() {
super.initListeners();
playbackSeekBar.setOnSeekBarChangeListener(this); playbackSeekBar.setOnSeekBarChangeListener(this);
playbackSpeedTextView.setOnClickListener(this); playbackSpeedTextView.setOnClickListener(this);
qualityTextView.setOnClickListener(this); qualityTextView.setOnClickListener(this);
@ -306,9 +305,9 @@ public abstract class VideoPlayer extends BasePlayer
captionItem.setOnMenuItemClickListener(menuItem -> { captionItem.setOnMenuItemClickListener(menuItem -> {
final int textRendererIndex = getRendererIndex(C.TRACK_TYPE_TEXT); final int textRendererIndex = getRendererIndex(C.TRACK_TYPE_TEXT);
if (textRendererIndex != RENDERER_UNAVAILABLE) { if (textRendererIndex != RENDERER_UNAVAILABLE) {
trackSelector.setPreferredTextLanguage(captionLanguage);
trackSelector.setParameters(trackSelector.buildUponParameters() trackSelector.setParameters(trackSelector.buildUponParameters()
.setRendererDisabled(textRendererIndex, false)); .setRendererDisabled(textRendererIndex, false)
.setPreferredTextLanguage(captionLanguage));
} }
return true; return true;
}); });
@ -509,7 +508,7 @@ public abstract class VideoPlayer extends BasePlayer
} }
// Normalize mismatching language strings // Normalize mismatching language strings
final String preferredLanguage = trackSelector.getPreferredTextLanguage(); final String preferredLanguage = trackSelector.getParameters().preferredTextLanguage;
// Build UI // Build UI
buildCaptionMenu(availableLanguages); buildCaptionMenu(availableLanguages);

View file

@ -12,13 +12,11 @@ import android.os.Build;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.util.Log; import android.util.Log;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.SimpleExoPlayer; import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.audio.AudioRendererEventListener; import com.google.android.exoplayer2.analytics.AnalyticsListener;
import com.google.android.exoplayer2.decoder.DecoderCounters;
public class AudioReactor implements AudioManager.OnAudioFocusChangeListener, public class AudioReactor implements AudioManager.OnAudioFocusChangeListener,
AudioRendererEventListener { AnalyticsListener {
private static final String TAG = "AudioFocusReactor"; private static final String TAG = "AudioFocusReactor";
@ -42,7 +40,7 @@ public class AudioReactor implements AudioManager.OnAudioFocusChangeListener,
this.player = player; this.player = player;
this.context = context; this.context = context;
this.audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); this.audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
player.addAudioDebugListener(this); player.addAnalyticsListener(this);
if (SHOULD_BUILD_FOCUS_REQUEST) { if (SHOULD_BUILD_FOCUS_REQUEST) {
request = new AudioFocusRequest.Builder(FOCUS_GAIN_TYPE) request = new AudioFocusRequest.Builder(FOCUS_GAIN_TYPE)
@ -57,7 +55,7 @@ public class AudioReactor implements AudioManager.OnAudioFocusChangeListener,
public void dispose() { public void dispose() {
abandonAudioFocus(); abandonAudioFocus();
player.removeAudioDebugListener(this); player.removeAnalyticsListener(this);
} }
/*////////////////////////////////////////////////////////////////////////// /*//////////////////////////////////////////////////////////////////////////
@ -164,29 +162,12 @@ public class AudioReactor implements AudioManager.OnAudioFocusChangeListener,
//////////////////////////////////////////////////////////////////////////*/ //////////////////////////////////////////////////////////////////////////*/
@Override @Override
public void onAudioSessionId(int i) { public void onAudioSessionId(EventTime eventTime, int audioSessionId) {
if (!PlayerHelper.isUsingDSP(context)) return; if (!PlayerHelper.isUsingDSP(context)) return;
final Intent intent = new Intent(AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION); final Intent intent = new Intent(AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION);
intent.putExtra(AudioEffect.EXTRA_AUDIO_SESSION, i); intent.putExtra(AudioEffect.EXTRA_AUDIO_SESSION, audioSessionId);
intent.putExtra(AudioEffect.EXTRA_PACKAGE_NAME, context.getPackageName()); intent.putExtra(AudioEffect.EXTRA_PACKAGE_NAME, context.getPackageName());
context.sendBroadcast(intent); context.sendBroadcast(intent);
} }
@Override
public void onAudioEnabled(DecoderCounters decoderCounters) {}
@Override
public void onAudioDecoderInitialized(String s, long l, long l1) {}
@Override
public void onAudioInputFormatChanged(Format format) {}
@Override
public void onAudioSinkUnderrun(int bufferSize,
long bufferSizeMs,
long elapsedSinceLastFeedMs) {}
@Override
public void onAudioDisabled(DecoderCounters decoderCounters) {}
} }

View file

@ -33,14 +33,14 @@ import java.io.File;
public CacheFactory(@NonNull final Context context, public CacheFactory(@NonNull final Context context,
@NonNull final String userAgent, @NonNull final String userAgent,
@NonNull final TransferListener<? super DataSource> transferListener) { @NonNull final TransferListener transferListener) {
this(context, userAgent, transferListener, PlayerHelper.getPreferredCacheSize(context), this(context, userAgent, transferListener, PlayerHelper.getPreferredCacheSize(context),
PlayerHelper.getPreferredFileSize(context)); PlayerHelper.getPreferredFileSize(context));
} }
private CacheFactory(@NonNull final Context context, private CacheFactory(@NonNull final Context context,
@NonNull final String userAgent, @NonNull final String userAgent,
@NonNull final TransferListener<? super DataSource> transferListener, @NonNull final TransferListener transferListener,
final long maxCacheSize, final long maxCacheSize,
final long maxFileSize) { final long maxFileSize) {
this.maxFileSize = maxFileSize; this.maxFileSize = maxFileSize;

View file

@ -2,17 +2,12 @@ package org.schabi.newpipe.player.helper;
import android.content.Context; import android.content.Context;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.DefaultLoadControl; import com.google.android.exoplayer2.DefaultLoadControl;
import com.google.android.exoplayer2.LoadControl; import com.google.android.exoplayer2.LoadControl;
import com.google.android.exoplayer2.Renderer; import com.google.android.exoplayer2.Renderer;
import com.google.android.exoplayer2.source.TrackGroupArray; import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.android.exoplayer2.trackselection.TrackSelectionArray; import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
import com.google.android.exoplayer2.upstream.Allocator; import com.google.android.exoplayer2.upstream.Allocator;
import com.google.android.exoplayer2.upstream.DefaultAllocator;
import static com.google.android.exoplayer2.DefaultLoadControl.DEFAULT_PRIORITIZE_TIME_OVER_SIZE_THRESHOLDS;
import static com.google.android.exoplayer2.DefaultLoadControl.DEFAULT_TARGET_BUFFER_BYTES;
public class LoadController implements LoadControl { public class LoadController implements LoadControl {
@ -36,15 +31,10 @@ public class LoadController implements LoadControl {
final int optimalPlaybackBufferMs) { final int optimalPlaybackBufferMs) {
this.initialPlaybackBufferUs = initialPlaybackBufferMs * 1000; this.initialPlaybackBufferUs = initialPlaybackBufferMs * 1000;
final DefaultAllocator allocator = new DefaultAllocator(true, DefaultLoadControl.Builder builder = new DefaultLoadControl.Builder();
C.DEFAULT_BUFFER_SEGMENT_SIZE); builder.setBufferDurationsMs(minimumPlaybackbufferMs, optimalPlaybackBufferMs,
initialPlaybackBufferMs, initialPlaybackBufferMs);
internalLoadControl = new DefaultLoadControl(allocator, internalLoadControl = builder.createDefaultLoadControl();
/*minBufferMs=*/minimumPlaybackbufferMs,
/*maxBufferMs=*/optimalPlaybackBufferMs,
/*bufferForPlaybackMs=*/initialPlaybackBufferMs,
/*bufferForPlaybackAfterRebufferMs=*/initialPlaybackBufferMs,
DEFAULT_TARGET_BUFFER_BYTES, DEFAULT_PRIORITIZE_TIME_OVER_SIZE_THRESHOLDS);
} }
/*////////////////////////////////////////////////////////////////////////// /*//////////////////////////////////////////////////////////////////////////

View file

@ -12,6 +12,7 @@ import com.google.android.exoplayer2.source.smoothstreaming.DefaultSsChunkSource
import com.google.android.exoplayer2.source.smoothstreaming.SsMediaSource; import com.google.android.exoplayer2.source.smoothstreaming.SsMediaSource;
import com.google.android.exoplayer2.upstream.DataSource; import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory; import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
import com.google.android.exoplayer2.upstream.DefaultLoadErrorHandlingPolicy;
import com.google.android.exoplayer2.upstream.TransferListener; import com.google.android.exoplayer2.upstream.TransferListener;
public class PlayerDataSource { public class PlayerDataSource {
@ -24,7 +25,7 @@ public class PlayerDataSource {
public PlayerDataSource(@NonNull final Context context, public PlayerDataSource(@NonNull final Context context,
@NonNull final String userAgent, @NonNull final String userAgent,
@NonNull final TransferListener<? super DataSource> transferListener) { @NonNull final TransferListener transferListener) {
cacheDataSourceFactory = new CacheFactory(context, userAgent, transferListener); cacheDataSourceFactory = new CacheFactory(context, userAgent, transferListener);
cachelessDataSourceFactory = new DefaultDataSourceFactory(context, userAgent, transferListener); cachelessDataSourceFactory = new DefaultDataSourceFactory(context, userAgent, transferListener);
} }
@ -32,21 +33,21 @@ public class PlayerDataSource {
public SsMediaSource.Factory getLiveSsMediaSourceFactory() { public SsMediaSource.Factory getLiveSsMediaSourceFactory() {
return new SsMediaSource.Factory(new DefaultSsChunkSource.Factory( return new SsMediaSource.Factory(new DefaultSsChunkSource.Factory(
cachelessDataSourceFactory), cachelessDataSourceFactory) cachelessDataSourceFactory), cachelessDataSourceFactory)
.setMinLoadableRetryCount(MANIFEST_MINIMUM_RETRY) .setLoadErrorHandlingPolicy(new DefaultLoadErrorHandlingPolicy(MANIFEST_MINIMUM_RETRY))
.setLivePresentationDelayMs(LIVE_STREAM_EDGE_GAP_MILLIS); .setLivePresentationDelayMs(LIVE_STREAM_EDGE_GAP_MILLIS);
} }
public HlsMediaSource.Factory getLiveHlsMediaSourceFactory() { public HlsMediaSource.Factory getLiveHlsMediaSourceFactory() {
return new HlsMediaSource.Factory(cachelessDataSourceFactory) return new HlsMediaSource.Factory(cachelessDataSourceFactory)
.setAllowChunklessPreparation(true) .setAllowChunklessPreparation(true)
.setMinLoadableRetryCount(MANIFEST_MINIMUM_RETRY); .setLoadErrorHandlingPolicy(new DefaultLoadErrorHandlingPolicy(MANIFEST_MINIMUM_RETRY));
} }
public DashMediaSource.Factory getLiveDashMediaSourceFactory() { public DashMediaSource.Factory getLiveDashMediaSourceFactory() {
return new DashMediaSource.Factory(new DefaultDashChunkSource.Factory( return new DashMediaSource.Factory(new DefaultDashChunkSource.Factory(
cachelessDataSourceFactory), cachelessDataSourceFactory) cachelessDataSourceFactory), cachelessDataSourceFactory)
.setMinLoadableRetryCount(MANIFEST_MINIMUM_RETRY) .setLoadErrorHandlingPolicy(new DefaultLoadErrorHandlingPolicy(MANIFEST_MINIMUM_RETRY))
.setLivePresentationDelayMs(LIVE_STREAM_EDGE_GAP_MILLIS); .setLivePresentationDelayMs(LIVE_STREAM_EDGE_GAP_MILLIS, true);
} }
public SsMediaSource.Factory getSsMediaSourceFactory() { public SsMediaSource.Factory getSsMediaSourceFactory() {
@ -65,7 +66,7 @@ public class PlayerDataSource {
public ExtractorMediaSource.Factory getExtractorMediaSourceFactory() { public ExtractorMediaSource.Factory getExtractorMediaSourceFactory() {
return new ExtractorMediaSource.Factory(cacheDataSourceFactory) return new ExtractorMediaSource.Factory(cacheDataSourceFactory)
.setMinLoadableRetryCount(EXTRACTOR_MINIMUM_RETRY); .setLoadErrorHandlingPolicy(new DefaultLoadErrorHandlingPolicy(EXTRACTOR_MINIMUM_RETRY));
} }
public ExtractorMediaSource.Factory getExtractorMediaSourceFactory(@NonNull final String key) { public ExtractorMediaSource.Factory getExtractorMediaSourceFactory(@NonNull final String key) {

View file

@ -14,7 +14,6 @@ import com.google.android.exoplayer2.text.CaptionStyleCompat;
import com.google.android.exoplayer2.trackselection.AdaptiveTrackSelection; import com.google.android.exoplayer2.trackselection.AdaptiveTrackSelection;
import com.google.android.exoplayer2.trackselection.TrackSelection; import com.google.android.exoplayer2.trackselection.TrackSelection;
import com.google.android.exoplayer2.ui.AspectRatioFrameLayout; import com.google.android.exoplayer2.ui.AspectRatioFrameLayout;
import com.google.android.exoplayer2.upstream.BandwidthMeter;
import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.MimeTypes;
import org.schabi.newpipe.R; import org.schabi.newpipe.R;
@ -240,9 +239,8 @@ public class PlayerHelper {
return 60000; return 60000;
} }
public static TrackSelection.Factory getQualitySelector(@NonNull final Context context, public static TrackSelection.Factory getQualitySelector(@NonNull final Context context) {
@NonNull final BandwidthMeter meter) { return new AdaptiveTrackSelection.Factory(
return new AdaptiveTrackSelection.Factory(meter,
/*bufferDurationRequiredForQualityIncrease=*/1000, /*bufferDurationRequiredForQualityIncrease=*/1000,
AdaptiveTrackSelection.DEFAULT_MAX_DURATION_FOR_QUALITY_DECREASE_MS, AdaptiveTrackSelection.DEFAULT_MAX_DURATION_FOR_QUALITY_DECREASE_MS,
AdaptiveTrackSelection.DEFAULT_MIN_DURATION_TO_RETAIN_AFTER_DISCARD_MS, AdaptiveTrackSelection.DEFAULT_MIN_DURATION_TO_RETAIN_AFTER_DISCARD_MS,

View file

@ -1,12 +1,13 @@
package org.schabi.newpipe.player.mediasource; package org.schabi.newpipe.player.mediasource;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log; import android.util.Log;
import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.source.BaseMediaSource; import com.google.android.exoplayer2.source.BaseMediaSource;
import com.google.android.exoplayer2.source.MediaPeriod; import com.google.android.exoplayer2.source.MediaPeriod;
import com.google.android.exoplayer2.upstream.Allocator; import com.google.android.exoplayer2.upstream.Allocator;
import com.google.android.exoplayer2.upstream.TransferListener;
import org.schabi.newpipe.player.playqueue.PlayQueueItem; import org.schabi.newpipe.player.playqueue.PlayQueueItem;
@ -79,7 +80,7 @@ public class FailedMediaSource extends BaseMediaSource implements ManagedMediaSo
} }
@Override @Override
public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator) { public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator, long startPositionUs) {
return null; return null;
} }
@ -88,7 +89,7 @@ public class FailedMediaSource extends BaseMediaSource implements ManagedMediaSo
@Override @Override
protected void prepareSourceInternal(ExoPlayer player, boolean isTopLevelSource) { protected void prepareSourceInternal(@Nullable TransferListener mediaTransferListener) {
Log.e(TAG, "Loading failed source: ", error); Log.e(TAG, "Loading failed source: ", error);
} }

View file

@ -2,12 +2,13 @@ package org.schabi.newpipe.player.mediasource;
import android.os.Handler; import android.os.Handler;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.source.MediaPeriod; import com.google.android.exoplayer2.source.MediaPeriod;
import com.google.android.exoplayer2.source.MediaSource; import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.source.MediaSourceEventListener; import com.google.android.exoplayer2.source.MediaSourceEventListener;
import com.google.android.exoplayer2.upstream.Allocator; import com.google.android.exoplayer2.upstream.Allocator;
import com.google.android.exoplayer2.upstream.TransferListener;
import org.schabi.newpipe.player.playqueue.PlayQueueItem; import org.schabi.newpipe.player.playqueue.PlayQueueItem;
@ -36,9 +37,8 @@ public class LoadedMediaSource implements ManagedMediaSource {
} }
@Override @Override
public void prepareSource(ExoPlayer player, boolean isTopLevelSource, public void prepareSource(SourceInfoRefreshListener listener, @Nullable TransferListener mediaTransferListener) {
SourceInfoRefreshListener listener) { source.prepareSource(listener, mediaTransferListener);
source.prepareSource(player, isTopLevelSource, listener);
} }
@Override @Override
@ -47,8 +47,8 @@ public class LoadedMediaSource implements ManagedMediaSource {
} }
@Override @Override
public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator) { public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator, long startPositionUs) {
return source.createPeriod(id, allocator); return source.createPeriod(id, allocator, startPositionUs);
} }
@Override @Override

View file

@ -1,5 +1,5 @@
package org.schabi.newpipe.player.mediasource; package org.schabi.newpipe.player.mediasource;
import android.os.Handler;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
@ -86,21 +86,22 @@ public class ManagedMediaSourcePlaylist {
/** /**
* Invalidates the {@link ManagedMediaSource} at the given index by replacing it * Invalidates the {@link ManagedMediaSource} at the given index by replacing it
* with a {@link PlaceholderMediaSource}. * with a {@link PlaceholderMediaSource}.
* @see #update(int, ManagedMediaSource, Runnable) * @see #update(int, ManagedMediaSource, Handler, Runnable)
* */ * */
public synchronized void invalidate(final int index, public synchronized void invalidate(final int index,
@Nullable final Handler handler,
@Nullable final Runnable finalizingAction) { @Nullable final Runnable finalizingAction) {
if (get(index) instanceof PlaceholderMediaSource) return; if (get(index) instanceof PlaceholderMediaSource) return;
update(index, new PlaceholderMediaSource(), finalizingAction); update(index, new PlaceholderMediaSource(), handler, finalizingAction);
} }
/** /**
* Updates the {@link ManagedMediaSource} in {@link ConcatenatingMediaSource} * Updates the {@link ManagedMediaSource} in {@link ConcatenatingMediaSource}
* at the given index with a given {@link ManagedMediaSource}. * at the given index with a given {@link ManagedMediaSource}.
* @see #update(int, ManagedMediaSource, Runnable) * @see #update(int, ManagedMediaSource, Handler, Runnable)
* */ * */
public synchronized void update(final int index, @NonNull final ManagedMediaSource source) { public synchronized void update(final int index, @NonNull final ManagedMediaSource source) {
update(index, source, /*doNothing=*/null); update(index, source, null, /*doNothing=*/null);
} }
/** /**
@ -108,9 +109,10 @@ public class ManagedMediaSourcePlaylist {
* at the given index with a given {@link ManagedMediaSource}. If the index is out of bound, * at the given index with a given {@link ManagedMediaSource}. If the index is out of bound,
* then the replacement is ignored. * then the replacement is ignored.
* @see ConcatenatingMediaSource#addMediaSource * @see ConcatenatingMediaSource#addMediaSource
* @see ConcatenatingMediaSource#removeMediaSource(int, Runnable) * @see ConcatenatingMediaSource#removeMediaSource(int, Handler, Runnable)
* */ * */
public synchronized void update(final int index, @NonNull final ManagedMediaSource source, public synchronized void update(final int index, @NonNull final ManagedMediaSource source,
@Nullable final Handler handler,
@Nullable final Runnable finalizingAction) { @Nullable final Runnable finalizingAction) {
if (index < 0 || index >= internalSource.getSize()) return; if (index < 0 || index >= internalSource.getSize()) return;
@ -126,6 +128,6 @@ public class ManagedMediaSourcePlaylist {
// Because of the above race condition, it is thus only safe to synchronize the player // Because of the above race condition, it is thus only safe to synchronize the player
// in the finalizing action AFTER the removal is complete and the timeline has changed. // in the finalizing action AFTER the removal is complete and the timeline has changed.
internalSource.removeMediaSource(index, finalizingAction); internalSource.removeMediaSource(index, handler, finalizingAction);
} }
} }

View file

@ -1,20 +1,21 @@
package org.schabi.newpipe.player.mediasource; package org.schabi.newpipe.player.mediasource;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.source.BaseMediaSource; import com.google.android.exoplayer2.source.BaseMediaSource;
import com.google.android.exoplayer2.source.MediaPeriod; import com.google.android.exoplayer2.source.MediaPeriod;
import com.google.android.exoplayer2.upstream.Allocator; import com.google.android.exoplayer2.upstream.Allocator;
import com.google.android.exoplayer2.upstream.TransferListener;
import org.schabi.newpipe.player.playqueue.PlayQueueItem; import org.schabi.newpipe.player.playqueue.PlayQueueItem;
public class PlaceholderMediaSource extends BaseMediaSource implements ManagedMediaSource { public class PlaceholderMediaSource extends BaseMediaSource implements ManagedMediaSource {
// Do nothing, so this will stall the playback // Do nothing, so this will stall the playback
@Override public void maybeThrowSourceInfoRefreshError() {} @Override public void maybeThrowSourceInfoRefreshError() {}
@Override public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator) { return null; } @Override public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator, long startPositionUs) { return null; }
@Override public void releasePeriod(MediaPeriod mediaPeriod) {} @Override public void releasePeriod(MediaPeriod mediaPeriod) {}
@Override protected void prepareSourceInternal(ExoPlayer player, boolean isTopLevelSource) {} @Override protected void prepareSourceInternal(@Nullable TransferListener mediaTransferListener) {}
@Override protected void releaseSourceInternal() {} @Override protected void releaseSourceInternal() {}
@Override @Override

View file

@ -1,112 +0,0 @@
package org.schabi.newpipe.player.playback;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.source.TrackGroup;
import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
import com.google.android.exoplayer2.trackselection.FixedTrackSelection;
import com.google.android.exoplayer2.trackselection.TrackSelection;
import com.google.android.exoplayer2.util.Assertions;
/**
* This class allows irregular text language labels for use when selecting text captions and
* is mostly a copy-paste from {@link DefaultTrackSelector}.
*
* This is a hack and should be removed once ExoPlayer fixes language normalization to accept
* a broader set of languages.
* */
public class CustomTrackSelector extends DefaultTrackSelector {
private static final int WITHIN_RENDERER_CAPABILITIES_BONUS = 1000;
private String preferredTextLanguage;
public CustomTrackSelector(TrackSelection.Factory adaptiveTrackSelectionFactory) {
super(adaptiveTrackSelectionFactory);
}
public String getPreferredTextLanguage() {
return preferredTextLanguage;
}
public void setPreferredTextLanguage(@NonNull final String label) {
Assertions.checkNotNull(label);
if (!label.equals(preferredTextLanguage)) {
preferredTextLanguage = label;
invalidate();
}
}
/** @see DefaultTrackSelector#formatHasLanguage(Format, String)*/
protected static boolean formatHasLanguage(Format format, String language) {
return language != null && TextUtils.equals(language, format.language);
}
/** @see DefaultTrackSelector#formatHasNoLanguage(Format)*/
protected static boolean formatHasNoLanguage(Format format) {
return TextUtils.isEmpty(format.language) || formatHasLanguage(format, C.LANGUAGE_UNDETERMINED);
}
/** @see DefaultTrackSelector#selectTextTrack(TrackGroupArray, int[][], Parameters) */
@Override
protected TrackSelection selectTextTrack(TrackGroupArray groups, int[][] formatSupport,
Parameters params) {
TrackGroup selectedGroup = null;
int selectedTrackIndex = 0;
int selectedTrackScore = 0;
for (int groupIndex = 0; groupIndex < groups.length; groupIndex++) {
TrackGroup trackGroup = groups.get(groupIndex);
int[] trackFormatSupport = formatSupport[groupIndex];
for (int trackIndex = 0; trackIndex < trackGroup.length; trackIndex++) {
if (isSupported(trackFormatSupport[trackIndex],
params.exceedRendererCapabilitiesIfNecessary)) {
Format format = trackGroup.getFormat(trackIndex);
int maskedSelectionFlags =
format.selectionFlags & ~params.disabledTextTrackSelectionFlags;
boolean isDefault = (maskedSelectionFlags & C.SELECTION_FLAG_DEFAULT) != 0;
boolean isForced = (maskedSelectionFlags & C.SELECTION_FLAG_FORCED) != 0;
int trackScore;
boolean preferredLanguageFound = formatHasLanguage(format, preferredTextLanguage);
if (preferredLanguageFound
|| (params.selectUndeterminedTextLanguage && formatHasNoLanguage(format))) {
if (isDefault) {
trackScore = 8;
} else if (!isForced) {
// Prefer non-forced to forced if a preferred text language has been specified. Where
// both are provided the non-forced track will usually contain the forced subtitles as
// a subset.
trackScore = 6;
} else {
trackScore = 4;
}
trackScore += preferredLanguageFound ? 1 : 0;
} else if (isDefault) {
trackScore = 3;
} else if (isForced) {
if (formatHasLanguage(format, params.preferredAudioLanguage)) {
trackScore = 2;
} else {
trackScore = 1;
}
} else {
// Track should not be selected.
continue;
}
if (isSupported(trackFormatSupport[trackIndex], false)) {
trackScore += WITHIN_RENDERER_CAPABILITIES_BONUS;
}
if (trackScore > selectedTrackScore) {
selectedGroup = trackGroup;
selectedTrackIndex = trackIndex;
selectedTrackScore = trackScore;
}
}
}
}
return selectedGroup == null ? null
: new FixedTrackSelection(selectedGroup, selectedTrackIndex);
}
}

View file

@ -1,5 +1,5 @@
package org.schabi.newpipe.player.playback; package org.schabi.newpipe.player.playback;
import android.os.Handler;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.v4.util.ArraySet; import android.support.v4.util.ArraySet;
@ -103,6 +103,8 @@ public class MediaSourceManager {
@NonNull private ManagedMediaSourcePlaylist playlist; @NonNull private ManagedMediaSourcePlaylist playlist;
private Handler removeMediaSourceHandler = new Handler();
public MediaSourceManager(@NonNull final PlaybackListener listener, public MediaSourceManager(@NonNull final PlaybackListener listener,
@NonNull final PlayQueue playQueue) { @NonNull final PlayQueue playQueue) {
this(listener, playQueue, /*loadDebounceMillis=*/400L, this(listener, playQueue, /*loadDebounceMillis=*/400L,
@ -395,7 +397,7 @@ public class MediaSourceManager {
if (isCorrectionNeeded(item)) { if (isCorrectionNeeded(item)) {
if (DEBUG) Log.d(TAG, "MediaSource - Updating index=[" + itemIndex + "] with " + if (DEBUG) Log.d(TAG, "MediaSource - Updating index=[" + itemIndex + "] with " +
"title=[" + item.getTitle() + "] at url=[" + item.getUrl() + "]"); "title=[" + item.getTitle() + "] at url=[" + item.getUrl() + "]");
playlist.update(itemIndex, mediaSource, this::maybeSynchronizePlayer); playlist.update(itemIndex, mediaSource, removeMediaSourceHandler, this::maybeSynchronizePlayer);
} }
} }
@ -441,7 +443,7 @@ public class MediaSourceManager {
if (DEBUG) Log.d(TAG, "MediaSource - Reloading currently playing, " + if (DEBUG) Log.d(TAG, "MediaSource - Reloading currently playing, " +
"index=[" + currentIndex + "], item=[" + currentItem.getTitle() + "]"); "index=[" + currentIndex + "], item=[" + currentItem.getTitle() + "]");
playlist.invalidate(currentIndex, this::loadImmediate); playlist.invalidate(currentIndex, removeMediaSourceHandler, this::loadImmediate);
} }
private void maybeClearLoaders() { private void maybeClearLoaders() {