feat: add isSeeking to onPlaybackStateChanged (#3899)

* feat: add `isSeeking` to `onPlaybackStateChanged``

* refactor `onSeek` event emit logic

* fix rebase
This commit is contained in:
Krzysztof Moch 2024-07-11 10:08:36 +02:00 committed by GitHub
parent b25e43ee79
commit 111a5d2163
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 36 additions and 9 deletions

View File

@ -69,7 +69,7 @@ class VideoEventEmitter {
lateinit var onVideoError: (errorString: String, exception: Exception, errorCode: String) -> Unit lateinit var onVideoError: (errorString: String, exception: Exception, errorCode: String) -> Unit
lateinit var onVideoProgress: (currentPosition: Long, bufferedDuration: Long, seekableDuration: Long, currentPlaybackTime: Double) -> Unit lateinit var onVideoProgress: (currentPosition: Long, bufferedDuration: Long, seekableDuration: Long, currentPlaybackTime: Double) -> Unit
lateinit var onVideoBandwidthUpdate: (bitRateEstimate: Long, height: Int, width: Int, trackId: String) -> Unit lateinit var onVideoBandwidthUpdate: (bitRateEstimate: Long, height: Int, width: Int, trackId: String) -> Unit
lateinit var onVideoPlaybackStateChanged: (isPlaying: Boolean) -> Unit lateinit var onVideoPlaybackStateChanged: (isPlaying: Boolean, isSeeking: Boolean) -> Unit
lateinit var onVideoSeek: (currentPosition: Long, seekTime: Long) -> Unit lateinit var onVideoSeek: (currentPosition: Long, seekTime: Long) -> Unit
lateinit var onVideoEnd: () -> Unit lateinit var onVideoEnd: () -> Unit
lateinit var onVideoFullscreenPlayerWillPresent: () -> Unit lateinit var onVideoFullscreenPlayerWillPresent: () -> Unit
@ -158,9 +158,10 @@ class VideoEventEmitter {
putString("trackId", trackId) putString("trackId", trackId)
} }
} }
onVideoPlaybackStateChanged = { isPlaying -> onVideoPlaybackStateChanged = { isPlaying, isSeeking ->
event.dispatch(EventTypes.EVENT_PLAYBACK_STATE_CHANGED) { event.dispatch(EventTypes.EVENT_PLAYBACK_STATE_CHANGED) {
putBoolean("isPlaying", isPlaying) putBoolean("isPlaying", isPlaying)
putBoolean("isSeeking", isSeeking)
} }
} }
onVideoSeek = { currentPosition, seekTime -> onVideoSeek = { currentPosition, seekTime ->

View File

@ -221,6 +221,13 @@ public class ReactExoplayerView extends FrameLayout implements
private boolean useCache = false; private boolean useCache = false;
private ControlsConfig controlsConfig = new ControlsConfig(); private ControlsConfig controlsConfig = new ControlsConfig();
/*
* When user is seeking first called is on onPositionDiscontinuity -> DISCONTINUITY_REASON_SEEK
* Then we set if to false when playback is back in onIsPlayingChanged -> true
*/
private boolean isSeeking = false;
private long seekPosition = -1;
// Props from React // Props from React
private Source source = new Source(); private Source source = new Source();
private boolean repeat; private boolean repeat;
@ -1618,6 +1625,11 @@ public class ReactExoplayerView extends FrameLayout implements
return; return;
} }
if (isPaused && isSeeking && !buffering) {
eventEmitter.onVideoSeek.invoke(player.getCurrentPosition(), seekPosition);
isSeeking = false;
}
isBuffering = buffering; isBuffering = buffering;
eventEmitter.onVideoBuffer.invoke(buffering); eventEmitter.onVideoBuffer.invoke(buffering);
} }
@ -1625,7 +1637,8 @@ public class ReactExoplayerView extends FrameLayout implements
@Override @Override
public void onPositionDiscontinuity(@NonNull Player.PositionInfo oldPosition, @NonNull Player.PositionInfo newPosition, @Player.DiscontinuityReason int reason) { public void onPositionDiscontinuity(@NonNull Player.PositionInfo oldPosition, @NonNull Player.PositionInfo newPosition, @Player.DiscontinuityReason int reason) {
if (reason == Player.DISCONTINUITY_REASON_SEEK) { if (reason == Player.DISCONTINUITY_REASON_SEEK) {
eventEmitter.onVideoSeek.invoke(player.getCurrentPosition(), newPosition.positionMs % 1000); // time are in seconds /°\ isSeeking = true;
seekPosition = newPosition.positionMs;
if (isUsingContentResolution) { if (isUsingContentResolution) {
// We need to update the selected track to make sure that it still matches user selection if track list has changed in this period // We need to update the selected track to make sure that it still matches user selection if track list has changed in this period
setSelectedTrack(C.TRACK_TYPE_VIDEO, videoTrackType, videoTrackValue); setSelectedTrack(C.TRACK_TYPE_VIDEO, videoTrackType, videoTrackValue);
@ -1676,7 +1689,15 @@ public class ReactExoplayerView extends FrameLayout implements
@Override @Override
public void onIsPlayingChanged(boolean isPlaying) { public void onIsPlayingChanged(boolean isPlaying) {
eventEmitter.onVideoPlaybackStateChanged.invoke(isPlaying); if (isPlaying && isSeeking) {
eventEmitter.onVideoSeek.invoke(player.getCurrentPosition(), seekPosition);
}
eventEmitter.onVideoPlaybackStateChanged.invoke(isPlaying, isSeeking);
if (isPlaying) {
isSeeking = false;
}
} }
@Override @Override

View File

@ -296,15 +296,17 @@ Callback function that is called when the playback state changes.
Payload: Payload:
| Property | Type | Description | | Property | Type | Description |
| --------- | ----------- | ------------------------------------------------- | | --------- | ----------- | -------------------------------------------------- |
| isPlaying | boolean | Boolean indicating if the media is playing or not | | isPlaying | boolean | Boolean indicating if the media is playing or not |
| isSeeking | boolean | Boolean indicating if the player is seeking or not |
Example: Example:
```javascript ```javascript
{ {
isPlaying: true, isPlaying: true,
isSeeking: false
} }
``` ```

View File

@ -758,8 +758,10 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
let seekTime: NSNumber! = info["time"] as! NSNumber let seekTime: NSNumber! = info["time"] as! NSNumber
let seekTolerance: NSNumber! = info["tolerance"] as! NSNumber let seekTolerance: NSNumber! = info["tolerance"] as! NSNumber
let item: AVPlayerItem? = _player?.currentItem let item: AVPlayerItem? = _player?.currentItem
_pendingSeek = true
guard item != nil, let player = _player, let item, item.status == AVPlayerItem.Status.readyToPlay else { guard item != nil, let player = _player, let item, item.status == AVPlayerItem.Status.readyToPlay else {
_pendingSeek = true
_pendingSeekTime = seekTime.floatValue _pendingSeekTime = seekTime.floatValue
return return
} }
@ -1486,7 +1488,7 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
guard _isPlaying != isPlaying else { return } guard _isPlaying != isPlaying else { return }
_isPlaying = isPlaying _isPlaying = isPlaying
onVideoPlaybackStateChanged?(["isPlaying": isPlaying, "target": reactTag as Any]) onVideoPlaybackStateChanged?(["isPlaying": isPlaying, "isSeeking": self._pendingSeek == true, "target": reactTag as Any])
} }
func handlePlaybackRateChange(player: AVPlayer, change: NSKeyValueObservedChange<Float>) { func handlePlaybackRateChange(player: AVPlayer, change: NSKeyValueObservedChange<Float>) {

View File

@ -189,6 +189,7 @@ export type OnSeekData = Readonly<{
export type OnPlaybackStateChangedData = Readonly<{ export type OnPlaybackStateChangedData = Readonly<{
isPlaying: boolean; isPlaying: boolean;
isSeeking: boolean;
}>; }>;
export type OnTimedMetadataData = Readonly<{ export type OnTimedMetadataData = Readonly<{