Update ExoPlayer to r2.2.0 (#505)

This commit is contained in:
Andrew Jack 2017-03-21 20:25:17 +00:00 committed by Matt Apperson
parent 5a4730cb8c
commit e76936b4fc
3 changed files with 56 additions and 35 deletions

View File

@ -12,8 +12,8 @@ android {
dependencies { dependencies {
provided 'com.facebook.react:react-native:+' provided 'com.facebook.react:react-native:+'
compile 'com.google.android.exoplayer:exoplayer:r2.1.1' compile 'com.google.android.exoplayer:exoplayer:r2.2.0'
compile('com.google.android.exoplayer:extension-okhttp:r2.1.1') { compile('com.google.android.exoplayer:extension-okhttp:r2.2.0') {
exclude group: 'com.squareup.okhttp3', module: 'okhttp' exclude group: 'com.squareup.okhttp3', module: 'okhttp'
} }
compile 'com.squareup.okhttp3:okhttp:3.4.2' compile 'com.squareup.okhttp3:okhttp:3.4.2'

View File

@ -28,6 +28,7 @@ import com.google.android.exoplayer2.mediacodec.MediaCodecRenderer;
import com.google.android.exoplayer2.mediacodec.MediaCodecUtil; import com.google.android.exoplayer2.mediacodec.MediaCodecUtil;
import com.google.android.exoplayer2.metadata.Metadata; import com.google.android.exoplayer2.metadata.Metadata;
import com.google.android.exoplayer2.metadata.MetadataRenderer; import com.google.android.exoplayer2.metadata.MetadataRenderer;
import com.google.android.exoplayer2.source.BehindLiveWindowException;
import com.google.android.exoplayer2.source.ExtractorMediaSource; import com.google.android.exoplayer2.source.ExtractorMediaSource;
import com.google.android.exoplayer2.source.LoopingMediaSource; import com.google.android.exoplayer2.source.LoopingMediaSource;
import com.google.android.exoplayer2.source.MediaSource; import com.google.android.exoplayer2.source.MediaSource;
@ -51,14 +52,12 @@ import java.net.CookieManager;
import java.net.CookiePolicy; import java.net.CookiePolicy;
@SuppressLint("ViewConstructor") @SuppressLint("ViewConstructor")
class ReactExoplayerView extends FrameLayout implements class ReactExoplayerView extends FrameLayout implements
LifecycleEventListener, LifecycleEventListener,
ExoPlayer.EventListener, ExoPlayer.EventListener,
BecomingNoisyListener, BecomingNoisyListener,
AudioManager.OnAudioFocusChangeListener, AudioManager.OnAudioFocusChangeListener,
MetadataRenderer.Output MetadataRenderer.Output {
{
private static final String TAG = "ReactExoplayerView"; private static final String TAG = "ReactExoplayerView";
@ -74,7 +73,6 @@ class ReactExoplayerView extends FrameLayout implements
private final VideoEventEmitter eventEmitter; private final VideoEventEmitter eventEmitter;
private Handler mainHandler; private Handler mainHandler;
private Timeline.Window window;
private ExoPlayerView exoPlayerView; private ExoPlayerView exoPlayerView;
private DataSource.Factory mediaDataSourceFactory; private DataSource.Factory mediaDataSourceFactory;
@ -82,13 +80,11 @@ class ReactExoplayerView extends FrameLayout implements
private MappingTrackSelector trackSelector; private MappingTrackSelector trackSelector;
private boolean playerNeedsSource; private boolean playerNeedsSource;
private boolean shouldRestorePosition; private int resumeWindow;
private int playerWindow; private long resumePosition;
private long playerPosition;
private boolean loadVideoStarted; private boolean loadVideoStarted;
private boolean isPaused = true; private boolean isPaused = true;
private boolean isBuffering; private boolean isBuffering;
private boolean isTimelineStatic;
// Props from React // Props from React
private Uri srcUri; private Uri srcUri;
@ -129,6 +125,8 @@ class ReactExoplayerView extends FrameLayout implements
audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
themedReactContext.addLifecycleEventListener(this); themedReactContext.addLifecycleEventListener(this);
audioBecomingNoisyReceiver = new AudioBecomingNoisyReceiver(themedReactContext); audioBecomingNoisyReceiver = new AudioBecomingNoisyReceiver(themedReactContext);
initializePlayer();
} }
@ -139,9 +137,9 @@ class ReactExoplayerView extends FrameLayout implements
} }
private void createViews() { private void createViews() {
clearResumePosition();
mediaDataSourceFactory = buildDataSourceFactory(true); mediaDataSourceFactory = buildDataSourceFactory(true);
mainHandler = new Handler(); mainHandler = new Handler();
window = new Timeline.Window();
if (CookieHandler.getDefault() != DEFAULT_COOKIE_MANAGER) { if (CookieHandler.getDefault() != DEFAULT_COOKIE_MANAGER) {
CookieHandler.setDefault(DEFAULT_COOKIE_MANAGER); CookieHandler.setDefault(DEFAULT_COOKIE_MANAGER);
} }
@ -199,13 +197,6 @@ class ReactExoplayerView extends FrameLayout implements
player.addListener(this); player.addListener(this);
player.setMetadataOutput(this); player.setMetadataOutput(this);
exoPlayerView.setPlayer(player); exoPlayerView.setPlayer(player);
if (isTimelineStatic) {
if (playerPosition == C.TIME_UNSET) {
player.seekToDefaultPosition(playerWindow);
} else {
player.seekTo(playerWindow, playerPosition);
}
}
audioBecomingNoisyReceiver.setListener(this); audioBecomingNoisyReceiver.setListener(this);
setPlayWhenReady(!isPaused); setPlayWhenReady(!isPaused);
playerNeedsSource = true; playerNeedsSource = true;
@ -213,7 +204,11 @@ class ReactExoplayerView extends FrameLayout implements
if (playerNeedsSource && srcUri != null) { if (playerNeedsSource && srcUri != null) {
MediaSource mediaSource = buildMediaSource(srcUri, extension); MediaSource mediaSource = buildMediaSource(srcUri, extension);
mediaSource = repeat ? new LoopingMediaSource(mediaSource) : mediaSource; mediaSource = repeat ? new LoopingMediaSource(mediaSource) : mediaSource;
player.prepare(mediaSource, !shouldRestorePosition, true); boolean haveResumePosition = resumeWindow != C.INDEX_UNSET;
if (haveResumePosition) {
player.seekTo(resumeWindow, resumePosition);
}
player.prepare(mediaSource, !haveResumePosition, false);
playerNeedsSource = false; playerNeedsSource = false;
eventEmitter.loadStart(); eventEmitter.loadStart();
@ -245,13 +240,7 @@ class ReactExoplayerView extends FrameLayout implements
private void releasePlayer() { private void releasePlayer() {
if (player != null) { if (player != null) {
isPaused = player.getPlayWhenReady(); isPaused = player.getPlayWhenReady();
shouldRestorePosition = false; updateResumePosition();
playerWindow = player.getCurrentWindowIndex();
playerPosition = C.TIME_UNSET;
Timeline timeline = player.getCurrentTimeline();
if (!timeline.isEmpty() && timeline.getWindow(playerWindow, window).isSeekable) {
playerPosition = player.getCurrentPosition();
}
player.release(); player.release();
player.setMetadataOutput(null); player.setMetadataOutput(null);
player = null; player = null;
@ -331,6 +320,17 @@ class ReactExoplayerView extends FrameLayout implements
audioManager.abandonAudioFocus(this); audioManager.abandonAudioFocus(this);
} }
private void updateResumePosition() {
resumeWindow = player.getCurrentWindowIndex();
resumePosition = player.isCurrentWindowSeekable() ? Math.max(0, player.getCurrentPosition())
: C.TIME_UNSET;
}
private void clearResumePosition() {
resumeWindow = C.INDEX_UNSET;
resumePosition = C.TIME_UNSET;
}
/** /**
* Returns a new DataSource factory. * Returns a new DataSource factory.
* *
@ -442,13 +442,17 @@ class ReactExoplayerView extends FrameLayout implements
@Override @Override
public void onPositionDiscontinuity() { public void onPositionDiscontinuity() {
// Do nothing. if (playerNeedsSource) {
// This will only occur if the user has performed a seek whilst in the error state. Update the
// resume position so that if the user then retries, playback will resume from the position to
// which they seeked.
updateResumePosition();
}
} }
@Override @Override
public void onTimelineChanged(Timeline timeline, Object manifest) { public void onTimelineChanged(Timeline timeline, Object manifest) {
isTimelineStatic = !timeline.isEmpty() // Do nothing.
&& !timeline.getWindow(timeline.getWindowCount() - 1, window).isDynamic;
} }
@Override @Override
@ -485,6 +489,26 @@ class ReactExoplayerView extends FrameLayout implements
eventEmitter.error(errorString, e); eventEmitter.error(errorString, e);
} }
playerNeedsSource = true; playerNeedsSource = true;
if (isBehindLiveWindow(e)) {
clearResumePosition();
initializePlayer();
} else {
updateResumePosition();
}
}
private static boolean isBehindLiveWindow(ExoPlaybackException e) {
if (e.type != ExoPlaybackException.TYPE_SOURCE) {
return false;
}
Throwable cause = e.getSourceException();
while (cause != null) {
if (cause instanceof BehindLiveWindowException) {
return true;
}
cause = cause.getCause();
}
return false;
} }
@Override @Override

View File

@ -9,14 +9,11 @@ import com.facebook.react.bridge.WritableArray;
import com.facebook.react.bridge.WritableMap; import com.facebook.react.bridge.WritableMap;
import com.facebook.react.uimanager.events.RCTEventEmitter; import com.facebook.react.uimanager.events.RCTEventEmitter;
import com.google.android.exoplayer2.metadata.Metadata; import com.google.android.exoplayer2.metadata.Metadata;
import com.google.android.exoplayer2.metadata.id3.BinaryFrame;
import com.google.android.exoplayer2.metadata.id3.Id3Frame; import com.google.android.exoplayer2.metadata.id3.Id3Frame;
import com.google.android.exoplayer2.metadata.id3.TxxxFrame; import com.google.android.exoplayer2.metadata.id3.TextInformationFrame;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.util.HashMap;
import java.util.Map;
class VideoEventEmitter { class VideoEventEmitter {
@ -191,8 +188,8 @@ class VideoEventEmitter {
String value = ""; String value = "";
if (frame instanceof TxxxFrame) { if (frame instanceof TextInformationFrame) {
TxxxFrame txxxFrame = (TxxxFrame) frame; TextInformationFrame txxxFrame = (TextInformationFrame) frame;
value = txxxFrame.value; value = txxxFrame.value;
} }