Update ExoPlayer to r2.2.0 (#505)
This commit is contained in:
parent
5a4730cb8c
commit
e76936b4fc
@ -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'
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user