From 466c00483708a89bbf8c70436ab9a0982c102a80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marin=CC=83o?= Date: Sun, 7 Jul 2019 10:21:23 +0200 Subject: [PATCH 1/5] handle racing conditions when props are setted on exoplayer --- CHANGELOG.md | 3 + .../exoplayer/ReactExoplayerView.java | 97 ++++++++++--------- 2 files changed, 56 insertions(+), 44 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8668a915..5ceaa234 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ ## Changelog +### next +* Handle racing conditions when props are setted on exoplayer + ### Version 4.4.2 * Change compileOnly to implementation on gradle (for newer gradle versions and react-native 0.59 support) [#1592](https://github.com/react-native-community/react-native-video/pull/1592) * Replaced RCTBubblingEventBlock events by RCTDirectEventBlock to avoid event name collisions [#1625](https://github.com/react-native-community/react-native-video/pull/1625) 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 175ef84f..97b2d428 100644 --- a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java +++ b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java @@ -333,53 +333,60 @@ class ReactExoplayerView extends FrameLayout implements } private void initializePlayer() { - if (player == null) { - TrackSelection.Factory videoTrackSelectionFactory = new AdaptiveTrackSelection.Factory(BANDWIDTH_METER); - trackSelector = new DefaultTrackSelector(videoTrackSelectionFactory); - trackSelector.setParameters(trackSelector.buildUponParameters() + ReactExoplayerView self = this; + + new Handler().postDelayed(new Runnable() { + @Override + public void run() { + if (player == null) { + TrackSelection.Factory videoTrackSelectionFactory = new AdaptiveTrackSelection.Factory(BANDWIDTH_METER); + trackSelector = new DefaultTrackSelector(videoTrackSelectionFactory); + trackSelector.setParameters(trackSelector.buildUponParameters() .setMaxVideoBitrate(maxBitRate == 0 ? Integer.MAX_VALUE : maxBitRate)); - DefaultAllocator allocator = new DefaultAllocator(true, C.DEFAULT_BUFFER_SEGMENT_SIZE); - DefaultLoadControl defaultLoadControl = new DefaultLoadControl(allocator, minBufferMs, maxBufferMs, bufferForPlaybackMs, bufferForPlaybackAfterRebufferMs, -1, true); - player = ExoPlayerFactory.newSimpleInstance(getContext(), trackSelector, defaultLoadControl); - player.addListener(this); - player.setMetadataOutput(this); - exoPlayerView.setPlayer(player); - audioBecomingNoisyReceiver.setListener(this); - BANDWIDTH_METER.addEventListener(new Handler(), this); - setPlayWhenReady(!isPaused); - playerNeedsSource = true; + DefaultAllocator allocator = new DefaultAllocator(true, C.DEFAULT_BUFFER_SEGMENT_SIZE); + DefaultLoadControl defaultLoadControl = new DefaultLoadControl(allocator, minBufferMs, maxBufferMs, bufferForPlaybackMs, bufferForPlaybackAfterRebufferMs, -1, true); + player = ExoPlayerFactory.newSimpleInstance(getContext(), trackSelector, defaultLoadControl); + player.addListener(self); + player.setMetadataOutput(self); + exoPlayerView.setPlayer(player); + audioBecomingNoisyReceiver.setListener(self); + BANDWIDTH_METER.addEventListener(new Handler(), self); + setPlayWhenReady(!isPaused); + playerNeedsSource = true; - PlaybackParameters params = new PlaybackParameters(rate, 1f); - player.setPlaybackParameters(params); - } - if (playerNeedsSource && srcUri != null) { - ArrayList mediaSourceList = buildTextSources(); - MediaSource videoSource = buildMediaSource(srcUri, extension); - MediaSource mediaSource; - if (mediaSourceList.size() == 0) { - mediaSource = videoSource; - } else { - mediaSourceList.add(0, videoSource); - MediaSource[] textSourceArray = mediaSourceList.toArray( - new MediaSource[mediaSourceList.size()] - ); - mediaSource = new MergingMediaSource(textSourceArray); + PlaybackParameters params = new PlaybackParameters(rate, 1f); + player.setPlaybackParameters(params); + } + if (playerNeedsSource && srcUri != null) { + ArrayList mediaSourceList = buildTextSources(); + MediaSource videoSource = buildMediaSource(srcUri, extension); + MediaSource mediaSource; + if (mediaSourceList.size() == 0) { + mediaSource = videoSource; + } else { + mediaSourceList.add(0, videoSource); + MediaSource[] textSourceArray = mediaSourceList.toArray( + new MediaSource[mediaSourceList.size()] + ); + mediaSource = new MergingMediaSource(textSourceArray); + } + + boolean haveResumePosition = resumeWindow != C.INDEX_UNSET; + if (haveResumePosition) { + player.seekTo(resumeWindow, resumePosition); + } + player.prepare(mediaSource, !haveResumePosition, false); + playerNeedsSource = false; + + eventEmitter.loadStart(); + loadVideoStarted = true; + } + + // Initializing the playerControlView + initializePlayerControl(); } - - boolean haveResumePosition = resumeWindow != C.INDEX_UNSET; - if (haveResumePosition) { - player.seekTo(resumeWindow, resumePosition); - } - player.prepare(mediaSource, !haveResumePosition, false); - playerNeedsSource = false; - - eventEmitter.loadStart(); - loadVideoStarted = true; - } - - // Initializing the playerControlView - initializePlayerControl(); + }, 1); } private MediaSource buildMediaSource(Uri uri, String overrideExtension) { @@ -439,8 +446,9 @@ class ReactExoplayerView extends FrameLayout implements updateResumePosition(); player.release(); player.setMetadataOutput(null); - player = null; trackSelector = null; + player = null; + } progressHandler.removeMessages(SHOW_PROGRESS); themedReactContext.removeLifecycleEventListener(this); @@ -906,6 +914,7 @@ class ReactExoplayerView extends FrameLayout implements } public void setSelectedTrack(int trackType, String type, Dynamic value) { + if (player == null) return; int rendererIndex = getTrackRendererIndex(trackType); if (rendererIndex == C.INDEX_UNSET) { return; From 40c7371b3e8955ffae516dbda1a8783952c14381 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marin=CC=83o?= Date: Sun, 7 Jul 2019 22:17:15 +0200 Subject: [PATCH 2/5] fix for setControls --- .../exoplayer/ReactExoplayerView.java | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) 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 97b2d428..fad34bcf 100644 --- a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java +++ b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java @@ -144,6 +144,7 @@ class ReactExoplayerView extends FrameLayout implements private boolean playInBackground = false; private Map requestHeaders; private boolean mReportBandwidth = false; + private boolean controls; // \ End props // React @@ -267,6 +268,7 @@ class ReactExoplayerView extends FrameLayout implements * Toggling the visibility of the player control view */ private void togglePlayerControlVisibility() { + if(player == null) return; reLayout(playerControlView); if (playerControlView.isVisible()) { playerControlView.hide(); @@ -312,10 +314,15 @@ class ReactExoplayerView extends FrameLayout implements * Adding Player control to the frame layout */ private void addPlayerControl() { + if(player == null) return; LayoutParams layoutParams = new LayoutParams( LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); playerControlView.setLayoutParams(layoutParams); + int indexOfPC = indexOfChild(playerControlView); + if (indexOfPC != -1) { + removeViewAt(indexOfPC); + } addView(playerControlView, 1, layoutParams); } @@ -385,6 +392,7 @@ class ReactExoplayerView extends FrameLayout implements // Initializing the playerControlView initializePlayerControl(); + setControls(controls); } }, 1); } @@ -1165,10 +1173,15 @@ class ReactExoplayerView extends FrameLayout implements * @param controls Controls prop, if true enable controls, if false disable them */ public void setControls(boolean controls) { - if (controls && exoPlayerView != null) { + this.controls = controls; + if (player == null || exoPlayerView == null) return; + if (controls) { addPlayerControl(); - } else if (getChildAt(1) instanceof PlayerControlView && exoPlayerView != null) { - removeViewAt(1); + } else { + int indexOfPC = indexOfChild(playerControlView); + if (indexOfPC != -1) { + removeViewAt(indexOfPC); + } } } } From cb3cff777211667539291bf1f1e6cfeb507ed47d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marin=CC=83o?= Date: Mon, 8 Jul 2019 12:47:05 +0200 Subject: [PATCH 3/5] fix repeat --- .../java/com/brentvatne/exoplayer/ReactExoplayerView.java | 5 +++++ 1 file changed, 5 insertions(+) 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 fad34bcf..898e4eee 100644 --- a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java +++ b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java @@ -393,6 +393,7 @@ class ReactExoplayerView extends FrameLayout implements // Initializing the playerControlView initializePlayerControl(); setControls(controls); + applyModifiers(); } }, 1); } @@ -910,6 +911,10 @@ class ReactExoplayerView extends FrameLayout implements exoPlayerView.setResizeMode(resizeMode); } + private void applyModifiers() { + setRepeatModifier(repeat); + } + public void setRepeatModifier(boolean repeat) { if (player != null) { if (repeat) { From f60aff79896bfd5abd6212768e21e074a2c147dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marin=CC=83o?= Date: Tue, 9 Jul 2019 11:40:23 +0200 Subject: [PATCH 4/5] comment why postDelayed --- .../main/java/com/brentvatne/exoplayer/ReactExoplayerView.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 ed874e9e..9a86fcd8 100644 --- a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java +++ b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java @@ -341,7 +341,7 @@ class ReactExoplayerView extends FrameLayout implements private void initializePlayer() { ReactExoplayerView self = this; - + // This ensures all props have been setted, to avoid async racing conditions. new Handler().postDelayed(new Runnable() { @Override public void run() { From f58ae349e8745f629860d9d5cce4c969c2a12bfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marin=CC=83o?= Date: Tue, 9 Jul 2019 11:41:03 +0200 Subject: [PATCH 5/5] remove extra whitespace --- .../main/java/com/brentvatne/exoplayer/ReactExoplayerView.java | 1 - 1 file changed, 1 deletion(-) 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 9a86fcd8..1edb8c7a 100644 --- a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java +++ b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java @@ -457,7 +457,6 @@ class ReactExoplayerView extends FrameLayout implements player.setMetadataOutput(null); trackSelector = null; player = null; - } progressHandler.removeMessages(SHOW_PROGRESS); themedReactContext.removeLifecycleEventListener(this);