diff --git a/android/src/main/java/com/brentvatne/common/react/VideoEventEmitter.kt b/android/src/main/java/com/brentvatne/common/react/VideoEventEmitter.kt index b227bfc1..fa6dd107 100644 --- a/android/src/main/java/com/brentvatne/common/react/VideoEventEmitter.kt +++ b/android/src/main/java/com/brentvatne/common/react/VideoEventEmitter.kt @@ -22,6 +22,7 @@ enum class EventTypes(val eventName: String) { EVENT_BANDWIDTH("onVideoBandwidthUpdate"), EVENT_CONTROLS_VISIBILITY_CHANGE("onControlsVisibilityChange"), EVENT_SEEK("onVideoSeek"), + EVENT_SEEK_COMPLETE("onVideoSeekComplete"), EVENT_END("onVideoEnd"), EVENT_FULLSCREEN_WILL_PRESENT("onVideoFullscreenPlayerWillPresent"), EVENT_FULLSCREEN_DID_PRESENT("onVideoFullscreenPlayerDidPresent"), @@ -71,6 +72,7 @@ class VideoEventEmitter { lateinit var onVideoBandwidthUpdate: (bitRateEstimate: Long, height: Int, width: Int, trackId: String) -> Unit lateinit var onVideoPlaybackStateChanged: (isPlaying: Boolean, isSeeking: Boolean) -> Unit lateinit var onVideoSeek: (currentPosition: Long, seekTime: Long) -> Unit + lateinit var onVideoSeekComplete: (currentPosition: Long) -> Unit lateinit var onVideoEnd: () -> Unit lateinit var onVideoFullscreenPlayerWillPresent: () -> Unit lateinit var onVideoFullscreenPlayerDidPresent: () -> Unit @@ -170,6 +172,11 @@ class VideoEventEmitter { putDouble("seekTime", seekTime / 1000.0) } } + onVideoSeekComplete = { currentPosition -> + event.dispatch(EventTypes.EVENT_SEEK_COMPLETE) { + putDouble("currentTime", currentPosition / 1000.0) + } + } onVideoEnd = { event.dispatch(EventTypes.EVENT_END) } diff --git a/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java b/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java index 6f854efb..95eb11b9 100644 --- a/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java +++ b/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java @@ -23,6 +23,7 @@ import android.os.IBinder; import android.os.Looper; import android.os.Message; import android.text.TextUtils; +import android.util.Log; import android.view.View; import android.view.Window; import android.view.accessibility.CaptioningManager; @@ -228,6 +229,7 @@ public class ReactExoplayerView extends FrameLayout implements */ private boolean isSeeking = false; private long seekPosition = -1; + private boolean isSeekInProgress = false; // Props from React private Source source = new Source(); @@ -303,6 +305,16 @@ public class ReactExoplayerView extends FrameLayout implements } }; + private void handleSeekCompletion() { + if (player != null && player.getPlaybackState() == Player.STATE_READY && isSeekInProgress) { + Log.d("ReactExoplayerView", "handleSeekCompletion: currentPosition=" + player.getCurrentPosition()); + eventEmitter.onVideoSeekComplete.invoke(player.getCurrentPosition()); + isSeeking = false; + seekPosition = -1; + isSeekInProgress = false; + } + } + public double getPositionInFirstPeriodMsForCurrentWindow(long currentPosition) { Timeline.Window window = new Timeline.Window(); if(!player.getCurrentTimeline().isEmpty()) { @@ -761,7 +773,8 @@ public class ReactExoplayerView extends FrameLayout implements .setBandwidthMeter(bandwidthMeter) .setLoadControl(loadControl) .setMediaSourceFactory(mediaSourceFactory) - .build(); + .build(); + player.addListener(self); ReactNativeVideoManager.Companion.getInstance().onInstanceCreated(instanceId, player); refreshDebugState(); player.addListener(self); @@ -1338,6 +1351,7 @@ public class ReactExoplayerView extends FrameLayout implements if (events.contains(Player.EVENT_PLAYBACK_STATE_CHANGED) || events.contains(Player.EVENT_PLAY_WHEN_READY_CHANGED)) { int playbackState = player.getPlaybackState(); boolean playWhenReady = player.getPlayWhenReady(); + Log.d("ReactExoplayerView", "onEvents: playbackState=" + playbackState + ", playWhenReady=" + playWhenReady); String text = "onStateChanged: playWhenReady=" + playWhenReady + ", playbackState="; eventEmitter.onPlaybackRateChange.invoke(playWhenReady && playbackState == ExoPlayer.STATE_READY ? 1.0f : 0.0f); switch (playbackState) { @@ -1371,6 +1385,10 @@ public class ReactExoplayerView extends FrameLayout implements playerControlView.show(); } setKeepScreenOn(preventsDisplaySleepDuringVideoPlayback); + Log.d("ReactExoplayerView", "Player STATE_READY: currentPosition=" + player.getCurrentPosition()); + if (isSeekInProgress) { + handleSeekCompletion(); + } break; case Player.STATE_ENDED: text += "ended"; @@ -1634,6 +1652,7 @@ public class ReactExoplayerView extends FrameLayout implements @Override public void onPositionDiscontinuity(@NonNull Player.PositionInfo oldPosition, @NonNull Player.PositionInfo newPosition, @Player.DiscontinuityReason int reason) { + Log.d("ReactExoplayerView", "onPositionDiscontinuity: reason=" + reason + ", oldPosition=" + oldPosition.positionMs + ", newPosition=" + newPosition.positionMs); if (reason == Player.DISCONTINUITY_REASON_SEEK) { isSeeking = true; seekPosition = newPosition.positionMs; @@ -2137,6 +2156,10 @@ public class ReactExoplayerView extends FrameLayout implements public void seekTo(long positionMs) { if (player != null) { + Log.d("ReactExoplayerView", "seekTo: positionMs=" + positionMs); + isSeekInProgress = true; + isSeeking = true; + seekPosition = positionMs; player.seekTo(positionMs); } }