Skip to content

Commit

Permalink
fix: improve Progress Data management
Browse files Browse the repository at this point in the history
  • Loading branch information
olivier committed Oct 15, 2023
1 parent ab0398d commit 687ebec
Show file tree
Hide file tree
Showing 4 changed files with 187 additions and 26 deletions.
19 changes: 19 additions & 0 deletions android/src/main/java/com/brentvatne/common/API/ProgressData.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.brentvatne.common.API

/*
* This class is a helper to build onProgress notification
*/

class ProgressData {
var position: Long
var bufferedDuration: Long
var duration: Long
var isOnLivePoint: Boolean

init {
position = -1
bufferedDuration = -1
duration = -1
isOnLivePoint = false
}
}
18 changes: 2 additions & 16 deletions android/src/main/java/com/brentvatne/common/API/ResizeMode.kt
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package com.brentvatne.common.API

import androidx.annotation.IntDef
import java.lang.annotation.Retention
import java.lang.annotation.RetentionPolicy

internal object ResizeMode {
/**
Expand All @@ -29,20 +27,8 @@ internal object ResizeMode {
* Keeps the aspect ratio but takes up the view's size.
*/
const val RESIZE_MODE_CENTER_CROP = 4
@JvmStatic
@Mode
fun toResizeMode(ordinal: Int): Int {
return when (ordinal) {
RESIZE_MODE_FIXED_WIDTH -> RESIZE_MODE_FIXED_WIDTH
RESIZE_MODE_FIXED_HEIGHT -> RESIZE_MODE_FIXED_HEIGHT
RESIZE_MODE_FILL -> RESIZE_MODE_FILL
RESIZE_MODE_CENTER_CROP -> RESIZE_MODE_CENTER_CROP
RESIZE_MODE_FIT -> RESIZE_MODE_FIT
else -> RESIZE_MODE_FIT
}
}

@Retention(RetentionPolicy.SOURCE)
@Retention(AnnotationRetention.SOURCE)
@IntDef(
RESIZE_MODE_FIT,
RESIZE_MODE_FIXED_WIDTH,
Expand All @@ -51,4 +37,4 @@ internal object ResizeMode {
RESIZE_MODE_CENTER_CROP
)
annotation class Mode
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import com.brentvatne.common.API.TimedMetadata;
import com.brentvatne.common.API.Track;
import com.brentvatne.common.API.VideoTrack;
import com.brentvatne.common.toolbox.DebugLog;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.WritableArray;
Expand All @@ -22,6 +23,8 @@ public class VideoEventEmitter {

private final RCTEventEmitter eventEmitter;

private final String TAG = "VideoEventEmitter";

private int viewId = View.NO_ID;

public VideoEventEmitter(ReactContext reactContext) {
Expand Down Expand Up @@ -411,11 +414,11 @@ public void audioBecomingNoisy() {
public void receiveAdEvent(String event) {
WritableMap map = Arguments.createMap();
map.putString("event", event);

receiveEvent(EVENT_ON_RECEIVE_AD_EVENT, map);
}

private void receiveEvent(@VideoEvents String type, WritableMap event) {
DebugLog.d(TAG,"send event viewId: " + viewId + " type: " + type + " " + (event == null ? "" : event.toString()) );
eventEmitter.receiveEvent(viewId, type, event);
}
}
171 changes: 162 additions & 9 deletions android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import androidx.annotation.WorkerThread;
import androidx.activity.OnBackPressedCallback;

import com.brentvatne.common.API.ProgressData;
import com.brentvatne.common.API.ResizeMode;
import com.brentvatne.common.API.SubtitleStyle;
import com.brentvatne.common.API.TimedMetadata;
Expand Down Expand Up @@ -176,7 +177,6 @@ public class ReactExoplayerView extends FrameLayout implements
private float audioVolume = 1f;
private int minLoadRetryCount = 3;
private int maxBitRate = 0;
private long seekTime = C.TIME_UNSET;
private boolean hasDrmFailed = false;
private boolean isUsingContentResolution = false;
private boolean selectTrackWhenReady = false;
Expand Down Expand Up @@ -232,6 +232,94 @@ public class ReactExoplayerView extends FrameLayout implements
private long lastBufferDuration = -1;
private long lastDuration = -1;


// Seek handling
private long seekTime = C.TIME_UNSET;
private long nextSeekTime = C.TIME_UNSET;
private boolean waitForDiscontinuity = false;
private boolean waitForSeekProcessed = false;
private boolean waitForPlayWhenReady = false;
private boolean initialSeekInProgress = false;

public ProgressData getProgressData() {
ProgressData data = new ProgressData();
data.setPosition(getCurrentPosition());
data.setOnLivePoint(isOnLivePoint());
long bufferedDuration = data.getBufferedDuration();
if (bufferedDuration < 0) {
bufferedDuration = 0;
}
data.setBufferedDuration(bufferedDuration);
long duration = getDuration();
if (duration < 0) {
duration = 0;
}
data.setDuration(duration);
return data;
}

public boolean isOnLivePoint() {
if (player == null || !isOnLivePlaylist())
return false;

final Timeline.Window window = new Timeline.Window();
Timeline timeline = player.getCurrentTimeline();
if (timeline.isEmpty()) {
return false;
}
timeline.getWindow(player.getCurrentWindowIndex(), window);
long offsetFromDefaultPositionMs = window.getDefaultPositionMs() - player.getCurrentPosition();
if (window.getDefaultPositionMs() != 0 && offsetFromDefaultPositionMs < 7000) {
return true;
}
return false;
}

public long getBufferedDuration() {
if (player == null)
return 0;
if (isOnLivePlaylist()) {
return getDuration();
}
return player.getBufferedPercentage() * player.getDuration() / 100;
}

boolean isOnLivePlaylist() {
if (player != null) {
return player.isCurrentMediaItemLive();
}
return false;
}

public long getCurrentPosition() {
DebugLog.checkUIThread(TAG, "position");

if (player == null)
return 0;
if (isOnLivePlaylist()) {
// TODO on exoplayer 2.13 there is a new api getCurrentLiveOffset To be integrated once this version available
if (isOnLivePoint()) {
return player.getDuration();
} else {
return player.getCurrentPosition();
}
}
if (nextSeekTime != C.TIME_UNSET) {
// multiple seek in progress
return nextSeekTime;
} else if (seekTime != C.TIME_UNSET) {
// We are seeking
return seekTime;
}
return player.getCurrentPosition();
}

public long getDuration() {
if (player == null)
return 0;
return player.getDuration();
}

private final Handler progressHandler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
Expand All @@ -251,7 +339,8 @@ public void handleMessage(Message msg) {
lastPos = pos;
lastBufferDuration = bufferedDuration;
lastDuration = duration;
eventEmitter.progressChanged(pos, bufferedDuration, player.getDuration(), getPositionInFirstPeriodMsForCurrentWindow(pos));
ProgressData data = getProgressData();
eventEmitter.progressChanged(lastPos, lastBufferDuration, lastBufferDuration, lastDuration);
}
msg = obtainMessage(SHOW_PROGRESS);
sendMessageDelayed(msg, Math.round(mProgressUpdateInterval));
Expand Down Expand Up @@ -716,11 +805,32 @@ private void initializePlayerSource(ReactExoplayerView self, DrmSessionManager d
}
}

boolean haveResumePosition = resumeWindow != C.INDEX_UNSET;
if (haveResumePosition) {
player.seekTo(resumeWindow, resumePosition);
seekTime = C.TIME_UNSET;
nextSeekTime = C.TIME_UNSET;
waitForSeekProcessed = false;
waitForDiscontinuity = false;
waitForPlayWhenReady = false;
initialSeekInProgress = false;

boolean needInitialSeek = false;

long startPosition = 0; // FIXME genericPlayerView.getStartPosition();
if (startPosition >= 0 || resumeWindow != C.INDEX_UNSET) {
needInitialSeek = true;
}
loadVideoStarted = true;
DebugLog.d(TAG, "player initialized");
if (needInitialSeek) {
boolean haveResumePosition = startPosition >= 0;
if (haveResumePosition) {
DebugLog.d(TAG, "resume position at " + startPosition);
seekTo(startPosition);
initialSeekInProgress = true;
}
}
player.prepare(mediaSource, !haveResumePosition, false);
player.prepare();
player.setMediaSource(mediaSource);

playerNeedsSource = false;

reLayout(exoPlayerView);
Expand Down Expand Up @@ -1078,6 +1188,10 @@ public void onEvents(@NonNull Player player, Player.Events events) {
boolean playWhenReady = player.getPlayWhenReady();
String text = "onStateChanged: playWhenReady=" + playWhenReady + ", playbackState=";
eventEmitter.playbackRateChange(playWhenReady && playbackState == ExoPlayer.STATE_READY ? 1.0f : 0.0f);
if (playWhenReady && playbackState == Player.STATE_READY) {
waitForPlayWhenReady = false;
tryNotifyEndOfSeek();
}
switch (playbackState) {
case Player.STATE_IDLE:
text += "idle";
Expand Down Expand Up @@ -1383,8 +1497,10 @@ public void onPositionDiscontinuity(@NonNull Player.PositionInfo oldPosition, @N
if (reason == Player.DISCONTINUITY_REASON_AUTO_TRANSITION
&& player.getRepeatMode() == Player.REPEAT_MODE_ONE) {
eventEmitter.end();
} else if (reason == Player.DISCONTINUITY_REASON_SEEK) {
waitForDiscontinuity = false;
tryNotifyEndOfSeek();
}

}

@Override
Expand Down Expand Up @@ -1871,9 +1987,46 @@ public void setVolumeModifier(float volume) {
}

public void seekTo(long positionMs) {
if (player != null) {
if (player != null && !waitForDiscontinuity && !waitForSeekProcessed && !waitForPlayWhenReady) {
seekTime = positionMs;
waitForDiscontinuity = true;
waitForSeekProcessed = true;
waitForPlayWhenReady = true;
player.seekTo(positionMs);
eventEmitter.seek(player.getCurrentPosition(), positionMs);
} else {
nextSeekTime = positionMs;
DebugLog.d(TAG, "don't seek now : nextSeekTime " + nextSeekTime + "ms");
}
}

void tryNotifyEndOfSeek() {
if (!waitForDiscontinuity && !waitForSeekProcessed && !waitForPlayWhenReady && seekTime != C.TIME_UNSET) {
long saveSeekTime = seekTime;
seekTime = C.TIME_UNSET;
if (nextSeekTime != C.TIME_UNSET) {
DebugLog.d(TAG, "seek buffered " + nextSeekTime);
seekTo(nextSeekTime);
nextSeekTime = C.TIME_UNSET;
} else if (player != null) {
DebugLog.d(TAG, "seek finish " + saveSeekTime + "ms");
eventEmitter.seek(player.getCurrentPosition(), saveSeekTime);
}
}
}

// Seeks are processed without delay. Listen to onPositionDiscontinuity(Player.PositionInfo, Player.PositionInfo, int) with reason DISCONTINUITY_REASON_SEEK instead.

@Override
public void onSeekProcessed() {
if (player != null) {
waitForSeekProcessed = false;
tryNotifyEndOfSeek();
if (initialSeekInProgress) {
initialSeekInProgress = false;
player.setPlayWhenReady(!isPaused);
// onStartPlayback();
videoLoaded();
}
}
}

Expand Down

0 comments on commit 687ebec

Please sign in to comment.