diff --git a/README.md b/README.md index 96c17151..a7c8430e 100644 --- a/README.md +++ b/README.md @@ -295,6 +295,7 @@ var styles = StyleSheet.create({ * [onLoad](#onload) * [onLoadStart](#onloadstart) * [onProgress](#onprogress) +* [onSeek](#onseek) * [onTimedMetadata](#ontimedmetadata) ### Methods @@ -848,6 +849,29 @@ Example: Platforms: all +#### onSeek +Callback function that is called when a seek completes. + +Payload: + +Property | Type | Description +--- | --- | --- +currentTime | number | The current time after the seek +seekTime | number | The requested time + +Example: +``` +{ + currentTime: 100.5 + seekTime: 100 +} +``` + +Both the currentTime & seekTime are reported because the video player may not seek to the exact requested position in order to improve seek performance. + + +Platforms: Android ExoPlayer, Android MediaPlayer, iOS, Windows UWP + #### onTimedMetadata Callback function that is called when timed metadata becomes available @@ -941,7 +965,7 @@ Platforms: iOS Seek to the specified position represented by seconds. seconds is a float value. -`seek()` can only be called after the `onLoad` event has fired. +`seek()` can only be called after the `onLoad` event has fired. Once completed, the [onSeek](#onseek) event will be called. Example: ``` diff --git a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java index 7d69368e..dc49402d 100644 --- a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java +++ b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java @@ -110,6 +110,7 @@ class ReactExoplayerView extends FrameLayout implements private boolean isBuffering; private float rate = 1f; private float audioVolume = 1f; + private long seekTime = C.TIME_UNSET; private int minBufferMs = DefaultLoadControl.DEFAULT_MIN_BUFFER_MS; private int maxBufferMs = DefaultLoadControl.DEFAULT_MAX_BUFFER_MS; @@ -605,7 +606,8 @@ class ReactExoplayerView extends FrameLayout implements @Override public void onSeekProcessed() { - // Do nothing. + eventEmitter.seek(player.getCurrentPosition(), seekTime); + seekTime = C.TIME_UNSET; } @Override @@ -892,7 +894,7 @@ class ReactExoplayerView extends FrameLayout implements public void seekTo(long positionMs) { if (player != null) { - eventEmitter.seek(player.getCurrentPosition(), positionMs); + seekTime = positionMs; player.seekTo(positionMs); } } diff --git a/android/src/main/java/com/brentvatne/react/ReactVideoView.java b/android/src/main/java/com/brentvatne/react/ReactVideoView.java index 3ff17a1f..0be1a3ad 100644 --- a/android/src/main/java/com/brentvatne/react/ReactVideoView.java +++ b/android/src/main/java/com/brentvatne/react/ReactVideoView.java @@ -47,6 +47,7 @@ public class ReactVideoView extends ScalableVideoView implements MediaPlayer.OnPreparedListener, MediaPlayer.OnErrorListener, MediaPlayer.OnBufferingUpdateListener, + MediaPlayer.OnSeekCompleteListener, MediaPlayer.OnCompletionListener, MediaPlayer.OnInfoListener, LifecycleEventListener, @@ -127,6 +128,7 @@ public class ReactVideoView extends ScalableVideoView implements private float mProgressUpdateInterval = 250.0f; private float mRate = 1.0f; private float mActiveRate = 1.0f; + private long mSeekTime = 0; private boolean mPlayInBackground = false; private boolean mBackgroundPaused = false; private boolean mIsFullscreen = false; @@ -213,6 +215,7 @@ public class ReactVideoView extends ScalableVideoView implements mMediaPlayer.setOnErrorListener(this); mMediaPlayer.setOnPreparedListener(this); mMediaPlayer.setOnBufferingUpdateListener(this); + mMediaPlayer.setOnSeekCompleteListener(this); mMediaPlayer.setOnCompletionListener(this); mMediaPlayer.setOnInfoListener(this); if (Build.VERSION.SDK_INT >= 23) { @@ -606,15 +609,18 @@ public class ReactVideoView extends ScalableVideoView implements mVideoBufferedDuration = (int) Math.round((double) (mVideoDuration * percent) / 100.0); } + public void onSeekComplete(MediaPlayer mp) { + WritableMap event = Arguments.createMap(); + event.putDouble(EVENT_PROP_CURRENT_TIME, getCurrentPosition() / 1000.0); + event.putDouble(EVENT_PROP_SEEK_TIME, mSeekTime / 1000.0); + mEventEmitter.receiveEvent(getId(), Events.EVENT_SEEK.toString(), event); + mSeekTime = 0; + } + @Override public void seekTo(int msec) { - if (mMediaPlayerValid) { - WritableMap event = Arguments.createMap(); - event.putDouble(EVENT_PROP_CURRENT_TIME, getCurrentPosition() / 1000.0); - event.putDouble(EVENT_PROP_SEEK_TIME, msec / 1000.0); - mEventEmitter.receiveEvent(getId(), Events.EVENT_SEEK.toString(), event); - + mSeekTime = msec; super.seekTo(msec); if (isCompleted && mVideoDuration != 0 && msec < mVideoDuration) { isCompleted = false;