Skip to content

Commit

Permalink
VEX-6778: Android: React Native video getVideoTrackInfoFromManifest c…
Browse files Browse the repository at this point in the history
…rash (#20)

JIRA: VEX-6778

Move video track info request logic entirely on a different thread, completely preventing ANRs in this section of code.
  • Loading branch information
armands-malejevs authored Mar 31, 2022
1 parent 39dee21 commit e39d87e
Showing 1 changed file with 34 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@
import java.util.concurrent.Executors;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.lang.Integer;

@SuppressLint("ViewConstructor")
Expand Down Expand Up @@ -943,8 +944,24 @@ private void videoLoaded() {
int width = videoFormat != null ? videoFormat.width : 0;
int height = videoFormat != null ? videoFormat.height : 0;
String trackId = videoFormat != null ? videoFormat.id : "-1";
eventEmitter.load(player.getDuration(), player.getCurrentPosition(), width, height,
getAudioTrackInfo(), getTextTrackInfo(), getVideoTrackInfo(), trackId);

// Properties that must be accessed on the main thread
long duration = player.getDuration();
long currentPosition = player.getCurrentPosition();
WritableArray audioTrackInfo = getAudioTrackInfo();
WritableArray textTrackInfo = getTextTrackInfo();
Timeline timelineRef = player.getCurrentTimeline();
int trackRendererIndex = getTrackRendererIndex(C.TRACK_TYPE_VIDEO);

ExecutorService es = Executors.newSingleThreadExecutor();
es.execute(new Runnable() {
@Override
public void run() {
// To prevent ANRs caused by getVideoTrackInfo we run this on a different thread and notify the player only when we're done
eventEmitter.load(duration, currentPosition, width, height,
audioTrackInfo, textTrackInfo, getVideoTrackInfo(timelineRef, trackRendererIndex), trackId);
}
});
}
}

Expand All @@ -971,9 +988,9 @@ private WritableArray getAudioTrackInfo() {
}
return audioTracks;
}
private WritableArray getVideoTrackInfo() {
private WritableArray getVideoTrackInfo(Timeline timelineRef, int trackRendererIndex) {

WritableArray contentVideoTracks = this.getVideoTrackInfoFromManifest();
WritableArray contentVideoTracks = this.getVideoTrackInfoFromManifest(timelineRef);
if (contentVideoTracks != null) {
isUsingContentResolution = true;
return contentVideoTracks;
Expand All @@ -982,12 +999,12 @@ private WritableArray getVideoTrackInfo() {
WritableArray videoTracks = Arguments.createArray();

MappingTrackSelector.MappedTrackInfo info = trackSelector.getCurrentMappedTrackInfo();
int index = getTrackRendererIndex(C.TRACK_TYPE_VIDEO);
if (info == null || index == C.INDEX_UNSET) {

if (info == null || trackRendererIndex == C.INDEX_UNSET) {
return videoTracks;
}

TrackGroupArray groups = info.getTrackGroups(index);
TrackGroupArray groups = info.getTrackGroups(trackRendererIndex);
for (int i = 0; i < groups.length; ++i) {
TrackGroup group = groups.get(i);

Expand All @@ -998,8 +1015,7 @@ private WritableArray getVideoTrackInfo() {
videoTrack.putInt("height",format.height == Format.NO_VALUE ? 0 : format.height);
videoTrack.putInt("bitrate", format.bitrate == Format.NO_VALUE ? 0 : format.bitrate);
videoTrack.putString("codecs", format.codecs != null ? format.codecs : "");
videoTrack.putString("trackId",
format.id == null ? String.valueOf(trackIndex) : format.id);
videoTrack.putString("trackId", format.id == null ? String.valueOf(trackIndex) : format.id);
if (isFormatSupported(format)) {
videoTracks.pushMap(videoTrack);
}
Expand All @@ -1009,11 +1025,14 @@ private WritableArray getVideoTrackInfo() {
return videoTracks;
}

private WritableArray getVideoTrackInfoFromManifest() {
private WritableArray getVideoTrackInfoFromManifest(Timeline timeline) {
return this.getVideoTrackInfoFromManifest(timeline, 0);
}

private WritableArray getVideoTrackInfoFromManifest(Timeline timelineRef, int retryCount) {
ExecutorService es = Executors.newSingleThreadExecutor();
final DataSource dataSource = this.mediaDataSourceFactory.createDataSource();
final Uri sourceUri = this.srcUri;
final Timeline timelineRef = this.player.getCurrentTimeline();
final long startTime = this.contentStartTime * 1000 - 100; // s -> ms with 100ms offset

Future<WritableArray> result = es.submit(new Callable<WritableArray>() {
Expand Down Expand Up @@ -1064,7 +1083,10 @@ public WritableArray call() throws Exception {
});

try {
WritableArray results = result.get();
WritableArray results = result.get(3000, TimeUnit.MILLISECONDS);
if (results == null && retryCount < 1) {
return this.getVideoTrackInfoFromManifest(timelineRef, ++retryCount);
}
es.shutdown();
return results;
} catch (Exception e) {}
Expand Down

0 comments on commit e39d87e

Please sign in to comment.