From f7b7f2666a206bc92faa94028b26d65b45a7300c Mon Sep 17 00:00:00 2001 From: Marc-Olivier Duval Date: Tue, 24 Oct 2017 21:49:46 -0400 Subject: [PATCH 01/50] Apply fix in playInBackground props --- .../java/com/brentvatne/exoplayer/ReactExoplayerView.java | 6 +++--- 1 file changed, 3 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 52bf24e6..c12b2a48 100644 --- a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java +++ b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java @@ -167,6 +167,9 @@ class ReactExoplayerView extends FrameLayout implements @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); + if (playInBackground) { + return; + } stopPlayback(); } @@ -174,9 +177,6 @@ class ReactExoplayerView extends FrameLayout implements @Override public void onHostResume() { - if (playInBackground) { - return; - } setPlayWhenReady(!isPaused); } From ee5818b6ff4e39b1d5bdc5d59616f0f5f255ad7c Mon Sep 17 00:00:00 2001 From: Marc-Olivier Duval Date: Tue, 24 Oct 2017 22:42:41 -0400 Subject: [PATCH 02/50] Fix bug with playInBackground --- .../java/com/brentvatne/exoplayer/ReactExoplayerView.java | 7 +++---- 1 file changed, 3 insertions(+), 4 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 c12b2a48..34df0031 100644 --- a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java +++ b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java @@ -167,9 +167,6 @@ class ReactExoplayerView extends FrameLayout implements @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); - if (playInBackground) { - return; - } stopPlayback(); } @@ -209,12 +206,14 @@ class ReactExoplayerView extends FrameLayout implements player.setMetadataOutput(this); exoPlayerView.setPlayer(player); audioBecomingNoisyReceiver.setListener(this); - setPlayWhenReady(!isPaused); playerNeedsSource = true; PlaybackParameters params = new PlaybackParameters(rate, 1f); player.setPlaybackParameters(params); } + + setPlayWhenReady(!isPaused); + if (playerNeedsSource && srcUri != null) { MediaSource mediaSource = buildMediaSource(srcUri, extension); mediaSource = repeat ? new LoopingMediaSource(mediaSource) : mediaSource; From 0fe621a26db4f9e091649b0304a5715d4d8b2947 Mon Sep 17 00:00:00 2001 From: Marc-Olivier Duval Date: Tue, 24 Oct 2017 22:42:51 -0400 Subject: [PATCH 03/50] Updated exoplayer readme --- android-exoplayer/README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/android-exoplayer/README.md b/android-exoplayer/README.md index e2d4f9fa..9396763b 100644 --- a/android-exoplayer/README.md +++ b/android-exoplayer/README.md @@ -42,6 +42,5 @@ https://github.com/google/ExoPlayer ## Unimplemented props -- `playInBackground={true}` -- `rate={1.0}` - Expansion file - `source={{ mainVer: 1, patchVer: 0 }}` + From 3e293407e8b15cb97b9ed475a0d65e40b079c466 Mon Sep 17 00:00:00 2001 From: Marc-Olivier Duval Date: Tue, 24 Oct 2017 22:50:20 -0400 Subject: [PATCH 04/50] updated readme to with a guid to setup exoplayer --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index 597b71ec..89e46a2f 100644 --- a/README.md +++ b/README.md @@ -269,6 +269,16 @@ Toggles a fullscreen player. Access using a ref to the component. - [Lumpen Radio](https://github.com/jhabdas/lumpen-radio) contains another example integration using local files and full screen background video. +## Use ExoPlayer on Android + +To use ExoPlayer instead of the default player, you have to change android to android-exoplayer in settings.gradle + +**android/settings.gradle** + +```gradle +project(':react-native-video').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-video/android-exoplayer') +``` + ## TODOS - [ ] Add support for captions From 4e85d3a1c4abe789c1406acf380a0983584c56b9 Mon Sep 17 00:00:00 2001 From: Rayron Victor Date: Tue, 24 Apr 2018 14:51:07 -0300 Subject: [PATCH 05/50] Using SDK Version variables from root project Instead of assuming the `compileSdkVersion`, `targetSdkVersion`, etc, read it from the root project. Default `compileSdkVersion` and `targetSdkVersion` to the latest versions. Android Target API Level 26 will be required in August 2018. https://android-developers.googleblog.com/2017/12/improving-app-security-and-performance.html And the React Native team is already working on this: facebook/react-native#17741 facebook/react-native#18095 --- android-exoplayer/build.gradle | 21 ++++++++++++++++----- android/build.gradle | 18 +++++++++++++----- 2 files changed, 29 insertions(+), 10 deletions(-) diff --git a/android-exoplayer/build.gradle b/android-exoplayer/build.gradle index b25b8164..9f01ea73 100644 --- a/android-exoplayer/build.gradle +++ b/android-exoplayer/build.gradle @@ -1,17 +1,28 @@ apply plugin: 'com.android.library' +def _ext = rootProject.ext + +def _reactNativeVersion = _ext.has('reactNative') ? _ext.reactNative : '+' +def _compileSdkVersion = _ext.has('compileSdkVersion') ? _ext.compileSdkVersion : 27 +def _buildToolsVersion = _ext.has('buildToolsVersion') ? _ext.buildToolsVersion : '27.0.3' +def _minSdkVersion = _ext.has('minSdkVersion') ? _ext.minSdkVersion : 16 +def _targetSdkVersion = _ext.has('targetSdkVersion') ? _ext.targetSdkVersion : 27 + android { - compileSdkVersion 23 - buildToolsVersion "25.0.2" + compileSdkVersion _compileSdkVersion + buildToolsVersion _buildToolsVersion defaultConfig { - minSdkVersion 16 - targetSdkVersion 23 + minSdkVersion _minSdkVersion + targetSdkVersion _targetSdkVersion + versionCode 1 + versionName "1.0" } } dependencies { - provided 'com.facebook.react:react-native:+' + //noinspection GradleDynamicVersion + provided "com.facebook.react:react-native:${_reactNativeVersion}" compile 'com.google.android.exoplayer:exoplayer:r2.4.0' compile('com.google.android.exoplayer:extension-okhttp:r2.4.0') { exclude group: 'com.squareup.okhttp3', module: 'okhttp' diff --git a/android/build.gradle b/android/build.gradle index 922bd9e3..789f4345 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,12 +1,20 @@ apply plugin: 'com.android.library' +def _ext = rootProject.ext + +def _reactNativeVersion = _ext.has('reactNative') ? _ext.reactNative : '+' +def _compileSdkVersion = _ext.has('compileSdkVersion') ? _ext.compileSdkVersion : 27 +def _buildToolsVersion = _ext.has('buildToolsVersion') ? _ext.buildToolsVersion : '27.0.3' +def _minSdkVersion = _ext.has('minSdkVersion') ? _ext.minSdkVersion : 16 +def _targetSdkVersion = _ext.has('targetSdkVersion') ? _ext.targetSdkVersion : 27 + android { - compileSdkVersion 25 - buildToolsVersion "25.0.2" + compileSdkVersion _compileSdkVersion + buildToolsVersion _buildToolsVersion defaultConfig { - minSdkVersion 16 - targetSdkVersion 25 + minSdkVersion _minSdkVersion + targetSdkVersion _targetSdkVersion versionCode 1 versionName "1.0" ndk { @@ -17,6 +25,6 @@ android { dependencies { //noinspection GradleDynamicVersion - provided 'com.facebook.react:react-native:+' + provided "com.facebook.react:react-native:${_reactNativeVersion}" compile 'com.yqritc:android-scalablevideoview:1.0.4' } From fc6244e4404026c582d15e62aa7f33289b424c76 Mon Sep 17 00:00:00 2001 From: Shlok Amin Date: Tue, 29 May 2018 15:59:21 -0400 Subject: [PATCH 06/50] adds audioOnly option that always displays poster image (if provided) on top of player --- README.md | 1 + Video.js | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0a3afb03..cbfeb068 100644 --- a/README.md +++ b/README.md @@ -187,6 +187,7 @@ using System.Collections.Generic; }} // Store reference rate={1.0} // 0 is paused, 1 is normal. volume={1.0} // 0 is muted, 1 is normal. + audioOnly={true|false} // Always displays poster image over player if provided. Default false muted={true|false} // Mutes the audio entirely. Default false paused={true|false} // Pauses playback entirely. Default false resizeMode="cover" // Fill the whole screen at aspect ratio.* diff --git a/Video.js b/Video.js index feb79861..25e86d71 100644 --- a/Video.js +++ b/Video.js @@ -65,7 +65,7 @@ export default class Video extends Component { }; _onSeek = (event) => { - if (this.state.showPoster) { + if (this.state.showPoster && !this.props.audioOnly) { this.setState({showPoster: false}); } @@ -129,7 +129,7 @@ export default class Video extends Component { }; _onPlaybackRateChange = (event) => { - if (this.state.showPoster && (event.nativeEvent.playbackRate !== 0)) { + if (this.state.showPoster && (event.nativeEvent.playbackRate !== 0) && (!this.props.audioOnly)) { this.setState({showPoster: false}); } From e79e447375f26027510f3aaa84b2f916e2c45b3c Mon Sep 17 00:00:00 2001 From: LeoGeng Date: Wed, 6 Jun 2018 09:40:12 +0800 Subject: [PATCH 07/50] Add allowsExternalPlayback property to control external playback --- ios/RCTVideo.m | 9 +++++++++ ios/RCTVideoManager.m | 1 + 2 files changed, 10 insertions(+) diff --git a/ios/RCTVideo.m b/ios/RCTVideo.m index 25beee6e..d80ba934 100644 --- a/ios/RCTVideo.m +++ b/ios/RCTVideo.m @@ -40,6 +40,7 @@ static NSString *const timedMetadata = @"timedMetadata"; BOOL _muted; BOOL _paused; BOOL _repeat; + BOOL _allowsExternalPlayback; BOOL _playbackStalled; BOOL _playInBackground; BOOL _playWhenInactive; @@ -66,6 +67,7 @@ static NSString *const timedMetadata = @"timedMetadata"; _controls = NO; _playerBufferEmpty = YES; _playInBackground = false; + _allowsExternalPlayback = YES; _playWhenInactive = false; _ignoreSilentSwitch = @"inherit"; // inherit, ignore, obey @@ -522,6 +524,12 @@ static NSString *const timedMetadata = @"timedMetadata"; _playInBackground = playInBackground; } +- (void)setAllowsExternalPlayback:(BOOL)allowsExternalPlayback +{ + _allowsExternalPlayback = allowsExternalPlayback; + _player.allowsExternalPlayback = _allowsExternalPlayback; +} + - (void)setPlayWhenInactive:(BOOL)playWhenInactive { _playWhenInactive = playWhenInactive; @@ -633,6 +641,7 @@ static NSString *const timedMetadata = @"timedMetadata"; [self setRepeat:_repeat]; [self setPaused:_paused]; [self setControls:_controls]; + [self setAllowsExternalPlayback:_allowsExternalPlayback]; } - (void)setRepeat:(BOOL)repeat { diff --git a/ios/RCTVideoManager.m b/ios/RCTVideoManager.m index c1edb9b7..4fa1a1f1 100644 --- a/ios/RCTVideoManager.m +++ b/ios/RCTVideoManager.m @@ -22,6 +22,7 @@ RCT_EXPORT_MODULE(); RCT_EXPORT_VIEW_PROPERTY(src, NSDictionary); RCT_EXPORT_VIEW_PROPERTY(resizeMode, NSString); RCT_EXPORT_VIEW_PROPERTY(repeat, BOOL); +RCT_EXPORT_VIEW_PROPERTY(allowsExternalPlayback, BOOL); RCT_EXPORT_VIEW_PROPERTY(paused, BOOL); RCT_EXPORT_VIEW_PROPERTY(muted, BOOL); RCT_EXPORT_VIEW_PROPERTY(controls, BOOL); From b83fda983898e7a5dbdd8e585bdaf6a2400a16ff Mon Sep 17 00:00:00 2001 From: LeoGeng Date: Wed, 6 Jun 2018 10:22:19 +0800 Subject: [PATCH 08/50] Add allowsExternalPlayback to video for ios --- Video.js | 1 + 1 file changed, 1 insertion(+) diff --git a/Video.js b/Video.js index aced6e55..80187e95 100644 --- a/Video.js +++ b/Video.js @@ -274,6 +274,7 @@ Video.propTypes = { poster: PropTypes.string, posterResizeMode: Image.propTypes.resizeMode, repeat: PropTypes.bool, + allowsExternalPlayback: PropTypes.bool, paused: PropTypes.bool, muted: PropTypes.bool, volume: PropTypes.number, From d0de96da27045a289e5b9a1b69bb6d6d0538d74d Mon Sep 17 00:00:00 2001 From: Hampton Maxwell Date: Sat, 9 Jun 2018 16:08:34 -0700 Subject: [PATCH 09/50] Remove extra ExoPlayer instructions This is covered already in the Android install instructions --- README.md | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/README.md b/README.md index 89e46a2f..597b71ec 100644 --- a/README.md +++ b/README.md @@ -269,16 +269,6 @@ Toggles a fullscreen player. Access using a ref to the component. - [Lumpen Radio](https://github.com/jhabdas/lumpen-radio) contains another example integration using local files and full screen background video. -## Use ExoPlayer on Android - -To use ExoPlayer instead of the default player, you have to change android to android-exoplayer in settings.gradle - -**android/settings.gradle** - -```gradle -project(':react-native-video').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-video/android-exoplayer') -``` - ## TODOS - [ ] Add support for captions From d3bda4a204aeeded04b8f4146e2f8200d9a4f843 Mon Sep 17 00:00:00 2001 From: Hampton Maxwell Date: Sat, 9 Jun 2018 16:11:18 -0700 Subject: [PATCH 10/50] Don't affect pause status after playing in the background --- .../java/com/brentvatne/exoplayer/ReactExoplayerView.java | 7 ++++++- 1 file changed, 6 insertions(+), 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 34df0031..7ccb255d 100644 --- a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java +++ b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java @@ -85,6 +85,7 @@ class ReactExoplayerView extends FrameLayout implements private int resumeWindow; private long resumePosition; private boolean loadVideoStarted; + private boolean isInBackground; private boolean isPaused = true; private boolean isBuffering; private float rate = 1f; @@ -174,11 +175,15 @@ class ReactExoplayerView extends FrameLayout implements @Override public void onHostResume() { - setPlayWhenReady(!isPaused); + if (!playInBackground || !isInBackground) { + setPlayWhenReady(!isPaused); + } + isInBackground = false; } @Override public void onHostPause() { + isInBackground = true; if (playInBackground) { return; } From da7bd43011ad84f4b913bac6e2f22ae32d159e94 Mon Sep 17 00:00:00 2001 From: Hampton Maxwell Date: Sat, 9 Jun 2018 16:13:58 -0700 Subject: [PATCH 11/50] Revert setPlayWhenReady change --- .../java/com/brentvatne/exoplayer/ReactExoplayerView.java | 4 +--- 1 file changed, 1 insertion(+), 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 17979427..eefd3f61 100644 --- a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java +++ b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java @@ -223,14 +223,12 @@ class ReactExoplayerView extends FrameLayout implements player.setMetadataOutput(this); exoPlayerView.setPlayer(player); audioBecomingNoisyReceiver.setListener(this); + setPlayWhenReady(!isPaused); playerNeedsSource = true; PlaybackParameters params = new PlaybackParameters(rate, 1f); player.setPlaybackParameters(params); } - - setPlayWhenReady(!isPaused); - if (playerNeedsSource && srcUri != null) { MediaSource mediaSource = buildMediaSource(srcUri, extension); mediaSource = repeat ? new LoopingMediaSource(mediaSource) : mediaSource; From d67b35329de1847ccd06867401b3f2fd5d929d9e Mon Sep 17 00:00:00 2001 From: Hampton Maxwell Date: Sat, 9 Jun 2018 16:27:52 -0700 Subject: [PATCH 12/50] Entry for ExoPlayer starts paused when playInBackground set --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e5aab04..47e054d5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ ## Changelog +### Next Version +* Fix bug that caused ExoPlayer to start paused if playInBackground was set [#833](https://github.com/react-native-community/react-native-video/pull/833) + ### Version 2.2.0 * Text track selection support for iOS & ExoPlayer [#1049](https://github.com/react-native-community/react-native-video/pull/1049) * Support outputting to a TextureView on Android ExoPlayer [#1058](https://github.com/react-native-community/react-native-video/pull/1058) From 9be83b19e7fb8a2a81aa0f90140ac7d7c1452962 Mon Sep 17 00:00:00 2001 From: Hampton Maxwell Date: Sat, 9 Jun 2018 16:49:21 -0700 Subject: [PATCH 13/50] Entry for inherit Android SDK & build tools version from root project --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 47e054d5..4177e051 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ ## Changelog ### Next Version +* Inherit Android buildtools and SDK version from the root project [#999](https://github.com/react-native-community/react-native-video/pull/999) * Fix bug that caused ExoPlayer to start paused if playInBackground was set [#833](https://github.com/react-native-community/react-native-video/pull/833) ### Version 2.2.0 From a0066675a9181023a336456d5979ea0d9d6f1b54 Mon Sep 17 00:00:00 2001 From: Hampton Maxwell Date: Sat, 9 Jun 2018 17:13:14 -0700 Subject: [PATCH 14/50] Remove the LoopingMediaSource since we repeat with other means --- .../main/java/com/brentvatne/exoplayer/ReactExoplayerView.java | 2 -- 1 file changed, 2 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 eefd3f61..22f14759 100644 --- a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java +++ b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java @@ -36,7 +36,6 @@ import com.google.android.exoplayer2.metadata.Metadata; import com.google.android.exoplayer2.metadata.MetadataRenderer; import com.google.android.exoplayer2.source.BehindLiveWindowException; import com.google.android.exoplayer2.source.ExtractorMediaSource; -import com.google.android.exoplayer2.source.LoopingMediaSource; import com.google.android.exoplayer2.source.MediaSource; import com.google.android.exoplayer2.source.TrackGroupArray; import com.google.android.exoplayer2.source.dash.DashMediaSource; @@ -231,7 +230,6 @@ class ReactExoplayerView extends FrameLayout implements } if (playerNeedsSource && srcUri != null) { MediaSource mediaSource = buildMediaSource(srcUri, extension); - mediaSource = repeat ? new LoopingMediaSource(mediaSource) : mediaSource; boolean haveResumePosition = resumeWindow != C.INDEX_UNSET; if (haveResumePosition) { player.seekTo(resumeWindow, resumePosition); From 6f5211f2c4250afc156d2a310ec72f326e1d6a80 Mon Sep 17 00:00:00 2001 From: genglei01 Date: Mon, 11 Jun 2018 00:04:13 +0800 Subject: [PATCH 15/50] remove indentation remove indentation --- ios/RCTVideo.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/RCTVideo.m b/ios/RCTVideo.m index 17afef68..253f48da 100644 --- a/ios/RCTVideo.m +++ b/ios/RCTVideo.m @@ -68,7 +68,7 @@ static NSString *const timedMetadata = @"timedMetadata"; _controls = NO; _playerBufferEmpty = YES; _playInBackground = false; - _allowsExternalPlayback = YES; + _allowsExternalPlayback = YES; _playWhenInactive = false; _ignoreSilentSwitch = @"inherit"; // inherit, ignore, obey From 187158be34dbe2f3f19bebc1833268990887febf Mon Sep 17 00:00:00 2001 From: LeoGeng Date: Mon, 11 Jun 2018 00:31:22 +0800 Subject: [PATCH 16/50] add an entry in the README for allowsExternalPlayback property --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index b1ee113e..936504fb 100644 --- a/README.md +++ b/README.md @@ -232,6 +232,7 @@ var styles = StyleSheet.create({ * [resizeMode](#resizemode) * [selectedTextTrack](#selectedtexttrack) * [volume](#volume) +* [allowsExternalPlayback](#allowsExternalPlayback) #### ignoreSilentSwitch Controls the iOS silent switch behavior @@ -345,6 +346,12 @@ Adjust the volume. Platforms: all +#### allowsExternalPlayback +A Boolean value that indicates whether the player allows switching to external playback mode. +* **true (default)** - allow switching to external playback mode +* **false** - Don't allow switching to external playback mode +Platforms: iOS + ### Additional props To see the full list of available props, you can check the [propTypes](https://github.com/react-native-community/react-native-video/blob/master/Video.js#L246) of the Video.js component. From 36dffa694cb9e6907f69b89b964332fcf6397fec Mon Sep 17 00:00:00 2001 From: Hampton Maxwell Date: Sun, 10 Jun 2018 10:48:32 -0700 Subject: [PATCH 17/50] Reorder allowsExternalPlayback alphabetically --- README.md | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 936504fb..ee5d6d8e 100644 --- a/README.md +++ b/README.md @@ -221,6 +221,7 @@ var styles = StyleSheet.create({ ``` ### Configurable props +* [allowsExternalPlayback](#allowsexternalplayback) * [ignoreSilentSwitch](#ignoresilentswitch) * [muted](#muted) * [paused](#paused) @@ -232,7 +233,13 @@ var styles = StyleSheet.create({ * [resizeMode](#resizemode) * [selectedTextTrack](#selectedtexttrack) * [volume](#volume) -* [allowsExternalPlayback](#allowsExternalPlayback) + +#### allowsExternalPlayback +Indicates whether the player allows switching to external playback mode such as AirPlay or HDMI. +* **true (default)** - allow switching to external playback mode +* **false** - Don't allow switching to external playback mode + +Platforms: iOS #### ignoreSilentSwitch Controls the iOS silent switch behavior @@ -346,12 +353,6 @@ Adjust the volume. Platforms: all -#### allowsExternalPlayback -A Boolean value that indicates whether the player allows switching to external playback mode. -* **true (default)** - allow switching to external playback mode -* **false** - Don't allow switching to external playback mode -Platforms: iOS - ### Additional props To see the full list of available props, you can check the [propTypes](https://github.com/react-native-community/react-native-video/blob/master/Video.js#L246) of the Video.js component. From 1522644f7060cfe9e48d438a815a427ccc235aae Mon Sep 17 00:00:00 2001 From: Hampton Maxwell Date: Sun, 10 Jun 2018 11:05:43 -0700 Subject: [PATCH 18/50] Support allowsExternalPlayback on iOS --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4177e051..e9641003 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ ## Changelog ### Next Version +* Support allowsExternalPlayback on iOS [#1057](https://github.com/react-native-community/react-native-video/pull/1057) * Inherit Android buildtools and SDK version from the root project [#999](https://github.com/react-native-community/react-native-video/pull/999) * Fix bug that caused ExoPlayer to start paused if playInBackground was set [#833](https://github.com/react-native-community/react-native-video/pull/833) From 361b771371cf56004691aa6683e595735f91f3f3 Mon Sep 17 00:00:00 2001 From: Hampton Maxwell Date: Mon, 11 Jun 2018 11:05:26 -0700 Subject: [PATCH 19/50] Make ExoPlayer the default Android library --- package.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 9a906357..31df96b8 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "license": "MIT", "author": "Brent Vatne (https://github.com/brentvatne)", "contributors": [ - { + { "name": "Isaiah Grey", "email": "isaiahgrey@gmail.com" }, @@ -40,5 +40,10 @@ }, "scripts": { "test": "node_modules/.bin/eslint *.js" + }, + "rnpm": { + "android": { + "sourceDir": "./android-exoplayer" + } } } From 8aac3dd9057125340b598ecbc2e694d29e2d6302 Mon Sep 17 00:00:00 2001 From: Hampton Maxwell Date: Mon, 11 Jun 2018 15:23:43 -0700 Subject: [PATCH 20/50] Testing sideloaded text tracks --- .../exoplayer/ReactExoplayerView.java | 43 ++++++++++++++++++- 1 file changed, 42 insertions(+), 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 22f14759..c80cf8da 100644 --- a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java +++ b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java @@ -37,6 +37,8 @@ import com.google.android.exoplayer2.metadata.MetadataRenderer; import com.google.android.exoplayer2.source.BehindLiveWindowException; import com.google.android.exoplayer2.source.ExtractorMediaSource; import com.google.android.exoplayer2.source.MediaSource; +import com.google.android.exoplayer2.source.MergingMediaSource; +import com.google.android.exoplayer2.source.SingleSampleMediaSource; import com.google.android.exoplayer2.source.TrackGroupArray; import com.google.android.exoplayer2.source.dash.DashMediaSource; import com.google.android.exoplayer2.source.dash.DefaultDashChunkSource; @@ -51,6 +53,7 @@ import com.google.android.exoplayer2.trackselection.TrackSelection; import com.google.android.exoplayer2.trackselection.TrackSelectionArray; import com.google.android.exoplayer2.upstream.DataSource; import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter; +import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.Util; import java.net.CookieHandler; @@ -58,6 +61,8 @@ import java.net.CookieManager; import java.net.CookiePolicy; import java.lang.Math; import java.lang.Object; +import java.util.ArrayList; +import java.util.Arrays; @SuppressLint("ViewConstructor") class ReactExoplayerView extends FrameLayout implements @@ -229,7 +234,27 @@ class ReactExoplayerView extends FrameLayout implements player.setPlaybackParameters(params); } if (playerNeedsSource && srcUri != null) { - MediaSource mediaSource = buildMediaSource(srcUri, extension); + ArrayList mediaSources = new ArrayList<>(); + mediaSources.add(buildMediaSource(srcUri, extension)); // video source + MediaSource text0 = buildTextSource( + "ES VTT", + Uri.parse("https://bitdash-a.akamaihd.net/content/sintel/subtitles/subtitles_es.vtt"), + "vtt", + "es" + ); + if (text0 != null) { + mediaSources.add(text0); + } + MediaSource mediaSource; + if (mediaSources.size() > 1) { + MediaSource[] textSourceArray = mediaSources.toArray( + new MediaSource[mediaSources.size()] + ); + mediaSource = new MergingMediaSource(textSourceArray); + } else { + mediaSource = mediaSources.get(0); + } + boolean haveResumePosition = resumeWindow != C.INDEX_UNSET; if (haveResumePosition) { player.seekTo(resumeWindow, resumePosition); @@ -263,6 +288,22 @@ class ReactExoplayerView extends FrameLayout implements } } + private MediaSource buildTextSource(String title, Uri uri, String mimeType, String language) { + String sampleType; + switch (mimeType) { + case "srt": + sampleType = MimeTypes.APPLICATION_SUBRIP; + break; + case "vtt": + sampleType = MimeTypes.TEXT_VTT; + break; + default: + return null; + } + Format textFormat = Format.createTextSampleFormat(title, sampleType, Format.NO_VALUE, language); + return new SingleSampleMediaSource(uri, mediaDataSourceFactory, textFormat, C.TIME_UNSET); + } + private void releasePlayer() { if (player != null) { isPaused = player.getPlayWhenReady(); From a1a4e0c44bb2b3d7a71d1f602dfc7d64ccef5c1a Mon Sep 17 00:00:00 2001 From: Hampton Maxwell Date: Mon, 11 Jun 2018 20:55:23 -0700 Subject: [PATCH 21/50] Report textTracks in onLoad --- ios/RCTVideo.m | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/ios/RCTVideo.m b/ios/RCTVideo.m index 253f48da..d2cc3114 100644 --- a/ios/RCTVideo.m +++ b/ios/RCTVideo.m @@ -415,6 +415,7 @@ static NSString *const timedMetadata = @"timedMetadata"; @"height": height, @"orientation": orientation }, + @"textTracks": [self getTextTrackInfo], @"target": self.reactTag}); } @@ -694,6 +695,26 @@ static NSString *const timedMetadata = @"timedMetadata"; [_player.currentItem selectMediaOption:option inMediaSelectionGroup:group]; } +- (NSArray *)getTextTrackInfo +{ + NSMutableArray *textTracks = [[NSMutableArray alloc] init]; + AVMediaSelectionGroup *group = [_player.currentItem.asset + mediaSelectionGroupForMediaCharacteristic:AVMediaCharacteristicLegible]; + for (int i = 0; i < group.options.count; ++i) { + AVMediaSelectionOption *currentOption = [group.options objectAtIndex:i]; + NSString *title = [[[currentOption commonMetadata] + valueForKey:@"value"] + objectAtIndex:0]; + NSDictionary *textTrack = @{ + @"index": [NSNumber numberWithInt:i], + @"title": title, + @"language": [currentOption extendedLanguageTag] + }; + [textTracks addObject:textTrack]; + } + return textTracks; +} + - (BOOL)getFullscreen { return _fullscreenPlayerPresented; From e2ea849d9e6dcca6d4215ed6013398f0b51bf7f3 Mon Sep 17 00:00:00 2001 From: Hampton Maxwell Date: Mon, 11 Jun 2018 21:25:58 -0700 Subject: [PATCH 22/50] Add ability to sideload text tracks and report them in onLoad --- .../exoplayer/ReactExoplayerView.java | 82 +++++++++++++++---- .../exoplayer/ReactExoplayerViewManager.java | 8 ++ .../exoplayer/VideoEventEmitter.java | 6 +- 3 files changed, 77 insertions(+), 19 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 c80cf8da..d659025e 100644 --- a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java +++ b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java @@ -16,8 +16,13 @@ import android.widget.FrameLayout; import com.brentvatne.react.R; import com.brentvatne.receiver.AudioBecomingNoisyReceiver; import com.brentvatne.receiver.BecomingNoisyListener; +import com.facebook.react.bridge.Arguments; import com.facebook.react.bridge.Dynamic; import com.facebook.react.bridge.LifecycleEventListener; +import com.facebook.react.bridge.ReadableArray; +import com.facebook.react.bridge.ReadableMap; +import com.facebook.react.bridge.WritableArray; +import com.facebook.react.bridge.WritableMap; import com.facebook.react.uimanager.ThemedReactContext; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.DefaultLoadControl; @@ -62,7 +67,6 @@ import java.net.CookiePolicy; import java.lang.Math; import java.lang.Object; import java.util.ArrayList; -import java.util.Arrays; @SuppressLint("ViewConstructor") class ReactExoplayerView extends FrameLayout implements @@ -108,6 +112,7 @@ class ReactExoplayerView extends FrameLayout implements private boolean repeat; private String textTrackType; private Dynamic textTrackValue; + private ReadableArray textTracks; private boolean disableFocus; private float mProgressUpdateInterval = 250.0f; private boolean playInBackground = false; @@ -234,25 +239,17 @@ class ReactExoplayerView extends FrameLayout implements player.setPlaybackParameters(params); } if (playerNeedsSource && srcUri != null) { - ArrayList mediaSources = new ArrayList<>(); - mediaSources.add(buildMediaSource(srcUri, extension)); // video source - MediaSource text0 = buildTextSource( - "ES VTT", - Uri.parse("https://bitdash-a.akamaihd.net/content/sintel/subtitles/subtitles_es.vtt"), - "vtt", - "es" - ); - if (text0 != null) { - mediaSources.add(text0); - } + ArrayList mediaSourceList = buildTextSources(); + MediaSource videoSource = buildMediaSource(srcUri, extension); MediaSource mediaSource; - if (mediaSources.size() > 1) { - MediaSource[] textSourceArray = mediaSources.toArray( - new MediaSource[mediaSources.size()] + if (mediaSourceList.size() == 0) { + mediaSource = videoSource; + } else { + mediaSourceList.add(0, videoSource); + MediaSource[] textSourceArray = mediaSourceList.toArray( + new MediaSource[mediaSourceList.size()] ); mediaSource = new MergingMediaSource(textSourceArray); - } else { - mediaSource = mediaSources.get(0); } boolean haveResumePosition = resumeWindow != C.INDEX_UNSET; @@ -288,6 +285,27 @@ class ReactExoplayerView extends FrameLayout implements } } + private ArrayList buildTextSources() { + ArrayList textSources = new ArrayList<>(); + if (textTracks == null) { + return textSources; + } + + for (int i = 0; i < textTracks.size(); ++i) { + ReadableMap textTrack = textTracks.getMap(i); + String language = textTrack.getString("language"); + String title = textTrack.hasKey("title") + ? textTrack.getString("title") : language + " " + i; + Uri uri = Uri.parse(textTrack.getString("uri")); + MediaSource textSource = buildTextSource(title, uri, textTrack.getString("type"), + language); + if (textSource != null) { + textSources.add(textSource); + } + } + return textSources; + } + private MediaSource buildTextSource(String title, Uri uri, String mimeType, String language) { String sampleType; switch (mimeType) { @@ -494,10 +512,33 @@ class ReactExoplayerView extends FrameLayout implements Format videoFormat = player.getVideoFormat(); int width = videoFormat != null ? videoFormat.width : 0; int height = videoFormat != null ? videoFormat.height : 0; - eventEmitter.load(player.getDuration(), player.getCurrentPosition(), width, height); + eventEmitter.load(player.getDuration(), player.getCurrentPosition(), width, height, + getTextTrackInfo()); } } + private WritableArray getTextTrackInfo() { + WritableArray textTracks = Arguments.createArray(); + + MappingTrackSelector.MappedTrackInfo info = trackSelector.getCurrentMappedTrackInfo(); + int index = getTextTrackRendererIndex(); + if (info == null || index == C.INDEX_UNSET) { + return textTracks; + } + + TrackGroupArray groups = info.getTrackGroups(index); + for (int i = 0; i < groups.length; ++i) { + Format format = groups.get(i).getFormat(0); + WritableMap textTrack = Arguments.createMap(); + textTrack.putInt("index", i); + textTrack.putString("title", format.id); + textTrack.putString("type", format.sampleMimeType); + textTrack.putString("language", format.language); + textTracks.pushMap(textTrack); + } + return textTracks; + } + private void onBuffering(boolean buffering) { if (isBuffering == buffering) { return; @@ -664,6 +705,11 @@ class ReactExoplayerView extends FrameLayout implements } } + public void setTextTracks(ReadableArray textTracks) { + this.textTracks = textTracks; + reloadSource(); + } + private void reloadSource() { playerNeedsSource = true; initializePlayer(); diff --git a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java index 4611c078..e204a4e7 100644 --- a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java +++ b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java @@ -5,6 +5,7 @@ import android.net.Uri; import android.text.TextUtils; import com.facebook.react.bridge.Dynamic; +import com.facebook.react.bridge.ReadableArray; import com.facebook.react.bridge.ReadableMap; import com.facebook.react.common.MapBuilder; import com.facebook.react.uimanager.ThemedReactContext; @@ -28,6 +29,7 @@ public class ReactExoplayerViewManager extends ViewGroupManager Date: Tue, 12 Jun 2018 20:57:30 -0700 Subject: [PATCH 23/50] Specify the text track type without any conversion --- .../brentvatne/exoplayer/ReactExoplayerView.java | 13 +------------ 1 file changed, 1 insertion(+), 12 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 d659025e..04c4bb2c 100644 --- a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java +++ b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java @@ -307,18 +307,7 @@ class ReactExoplayerView extends FrameLayout implements } private MediaSource buildTextSource(String title, Uri uri, String mimeType, String language) { - String sampleType; - switch (mimeType) { - case "srt": - sampleType = MimeTypes.APPLICATION_SUBRIP; - break; - case "vtt": - sampleType = MimeTypes.TEXT_VTT; - break; - default: - return null; - } - Format textFormat = Format.createTextSampleFormat(title, sampleType, Format.NO_VALUE, language); + Format textFormat = Format.createTextSampleFormat(title, mimeType, Format.NO_VALUE, language); return new SingleSampleMediaSource(uri, mediaDataSourceFactory, textFormat, C.TIME_UNSET); } From 659ca8fad9f61e508b4b9c81044b74e0c47e01d7 Mon Sep 17 00:00:00 2001 From: Hampton Maxwell Date: Tue, 12 Jun 2018 21:03:55 -0700 Subject: [PATCH 24/50] Document onLoad, onLoadStart & textTracks --- README.md | 105 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 102 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 9aac6495..caf69cf3 100644 --- a/README.md +++ b/README.md @@ -191,8 +191,6 @@ using System.Collections.Generic; onFullscreenPlayerDidPresent={this.fullScreenPlayerDidPresent} // Callback after fullscreen started onFullscreenPlayerWillDismiss={this.fullScreenPlayerWillDismiss} // Callback before fullscreen stops onFullscreenPlayerDidDismiss={this.fullScreenPlayerDidDismiss} // Callback after fullscreen stopped - onLoadStart={this.loadStart} // Callback when video starts to load - onLoad={this.setDuration} // Callback when video loads onProgress={this.setTime} // Callback every ~250ms with currentTime onTimedMetadata={this.onTimedMetadata} // Callback when the stream receive some metadata style={styles.backgroundVideo} /> @@ -233,9 +231,14 @@ var styles = StyleSheet.create({ * [resizeMode](#resizemode) * [selectedTextTrack](#selectedtexttrack) * [stereoPan](#stereopan) +* [textTracks](#texttracks) * [useTextureView](#usetextureview) * [volume](#volume) +### Event props +* [onLoad](#onload) +* [onLoadStart](#onloadstart) + #### allowsExternalPlayback Indicates whether the player allows switching to external playback mode such as AirPlay or HDMI. * **true (default)** - allow switching to external playback mode @@ -359,7 +362,7 @@ Type | Value | Description "language" | string | Display the text track with the language specified as the Value, e.g. "fr" "index" | number | Display the text track with the index specified as the value, e.g. 0 -Both iOS & Android offer Settings to enable Captions for hearing impaired people. If "system" is selected and the Captions Setting is enabled, iOS/Android will look for a caption that matches that customer's language and display it. +Both iOS & Android (only 4.4 and higher) offer Settings to enable Captions for hearing impaired people. If "system" is selected and the Captions Setting is enabled, iOS/Android will look for a caption that matches that customer's language and display it. If a track matching the specified Type (and Value if appropriate) is unavailable, no text track will be displayed. If multiple tracks match the criteria, the first match will be used. @@ -373,6 +376,40 @@ Adjust the balance of the left and right audio channels. Any value between –1 Platforms: Android MediaPlayer +#### textTracks +Load one or more "sidecar" text tracks. This takes an array of objects representing each track. Each object should have the format: + +Property | Description +--- | --- +title | Descriptive name for the track +language | 2 character [ISO 639-1 code](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) representing the language +type | Mime type of the track
* TextTrackType.SRT - .srt SubRip Subtitle
* TextTrackType.TTML - .ttml TTML
* TextTrackType.VTT - .vtt WebVTT +uri | URL for the text track. Currently, only tracks hosted on a webserver are supported + +Example: +``` +import { TextTrackType }, Video from 'react-native-video'; + +textTracks={[ + { + title: "English CC", + language: "en", + type: "text/vtt", TextTrackType.VTT, + uri: "https://bitdash-a.akamaihd.net/content/sintel/subtitles/subtitles_en.vtt" + }, + { + title: "Spanish Subtitles", + language: "es", + type: "application/x-subrip", TextTrackType.SRT, + uri: "https://durian.blender.org/wp-content/content/subtitles/sintel_es.srt" + } +]} +``` + +This isn't support on iOS because AVPlayer doesn't support it. Text tracks must be loaded as part of an HLS playlist. + +Platforms: Android ExoPlayer + #### useTextureView Output to a TextureView instead of the default SurfaceView. In general, you will want to use SurfaceView because it is more efficient and provides better performance. However, SurfaceViews has two limitations: * It can't be animated, transformed or scaled @@ -393,6 +430,68 @@ Adjust the volume. Platforms: all +### Event props + +#### onLoad +Callback function that is called when the media is loaded and ready to play. + +Payload: + +Property | Description +--- | --- +currentPosition | Time in seconds where the media will start +duration | Length of the media in seconds +naturalSize | * width - Width in pixels that the video was encoding at
* height - Height in pixels that the video was encoding at
* orientation - "portrait" or "landscape" +textTracks | An array with info about the text tracks
* index - Index number
* title - Description of the track
* language - IOS 639-1 2 letter language code
* type - Mime type of track + +Example: +``` +{ + canPlaySlowForward: true, + canPlayReverse: false, + canPlaySlowReverse: false, + canPlayFastForward: false, + canStepForward: false, + canStepBackward: false, + currentTime: 0, + duration: 5910.208984375, + naturalSize: { + height: 1080 + orientation: 'landscape' + width: '1920' + }, + textTracks: [ + { title: '#1 French', language: 'fr', index: 0, type: 'text/vtt' }, + { title: '#2 English CC', language: 'en', index: 1, type: 'text/vtt' }, + { title: '#3 English Director Commentary', language: 'en', index: 2, type: 'text/vtt' } + ] +} +``` + +Platforms: all + +#### onLoadStart +Callback function that is called when the media starts loading. + +Payload: + +Property | Description +--- | --- +isNetwork | Boolean indicating if the media is being loaded from the network +type | Type of the media. Not available on Windows +uri | URI for the media source. Not available on Windows + +Example: +``` +{ + isNetwork: true, + type: '', + uri: 'https://bitdash-a.akamaihd.net/content/sintel/hls/playlist.m3u8' +} +``` + +Platforms: all + ### Additional props To see the full list of available props, you can check the [propTypes](https://github.com/react-native-community/react-native-video/blob/master/Video.js#L246) of the Video.js component. From fdf34c50fe274f84ff5a3c0cf29aa024430aba76 Mon Sep 17 00:00:00 2001 From: Hampton Maxwell Date: Tue, 12 Jun 2018 21:04:00 -0700 Subject: [PATCH 25/50] Initial commit --- TextTrackType.js | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 TextTrackType.js diff --git a/TextTrackType.js b/TextTrackType.js new file mode 100644 index 00000000..caff65a9 --- /dev/null +++ b/TextTrackType.js @@ -0,0 +1,7 @@ +import keyMirror from 'keymirror'; + +export default { + SRT: 'application/x-subrip', + TTML: 'application/ttml+xml', + VTT: 'text/vtt' +}; From 7793e00e9f2a761313bae842b5d45218b1cff86c Mon Sep 17 00:00:00 2001 From: Hampton Maxwell Date: Tue, 12 Jun 2018 21:04:15 -0700 Subject: [PATCH 26/50] Add TextTrackType export and textTracks prop --- Video.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Video.js b/Video.js index 5d11936c..ddee232a 100644 --- a/Video.js +++ b/Video.js @@ -2,6 +2,7 @@ import React, {Component} from 'react'; import PropTypes from 'prop-types'; import {StyleSheet, requireNativeComponent, NativeModules, View, ViewPropTypes, Image} from 'react-native'; import resolveAssetSource from 'react-native/Libraries/Image/resolveAssetSource'; +import TextTrackType from './TextTrackType'; import VideoResizeMode from './VideoResizeMode.js'; const styles = StyleSheet.create({ @@ -10,6 +11,8 @@ const styles = StyleSheet.create({ }, }); +export { TextTrackType }; + export default class Video extends Component { constructor(props) { @@ -282,6 +285,18 @@ Video.propTypes = { PropTypes.number ]) }), + textTracks: PropTypes.arrayOf( + PropTypes.shape({ + title: PropTypes.string, + uri: PropTypes.string.isRequired, + type: PropTypes.oneOf([ + TextTrackType.SRT, + TextTrackType.TTML, + TextTrackType.VTT, + ]), + language: PropTypes.string.isRequired + }) + ), paused: PropTypes.bool, muted: PropTypes.bool, volume: PropTypes.number, From 146cbe3183481ef7f291101b1b726020c9e3df0a Mon Sep 17 00:00:00 2001 From: Hampton Maxwell Date: Tue, 12 Jun 2018 21:17:47 -0700 Subject: [PATCH 27/50] Clean up onLoad info --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index caf69cf3..dc5ae17f 100644 --- a/README.md +++ b/README.md @@ -437,12 +437,12 @@ Callback function that is called when the media is loaded and ready to play. Payload: -Property | Description ---- | --- -currentPosition | Time in seconds where the media will start -duration | Length of the media in seconds -naturalSize | * width - Width in pixels that the video was encoding at
* height - Height in pixels that the video was encoding at
* orientation - "portrait" or "landscape" -textTracks | An array with info about the text tracks
* index - Index number
* title - Description of the track
* language - IOS 639-1 2 letter language code
* type - Mime type of track +Property | Type | Description +--- | --- | --- +currentPosition | number | Time in seconds where the media will start +duration | number | Length of the media in seconds +naturalSize | object | Properties:
* width - Width in pixels that the video was encoded at
* height - Height in pixels that the video was encoded at
* orientation - "portrait" or "landscape" +textTracks | array | An array of text track info objects with the following properties:
* index - Index number
* title - Description of the track
* language - IOS 639-1 2 letter language code
* type - Mime type of track Example: ``` From 3da2489484a715fa6f028dd284648fe47b8addcd Mon Sep 17 00:00:00 2001 From: Hampton Maxwell Date: Tue, 12 Jun 2018 21:21:04 -0700 Subject: [PATCH 28/50] Fix type in ISO name --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index dc5ae17f..98898b9a 100644 --- a/README.md +++ b/README.md @@ -382,7 +382,7 @@ Load one or more "sidecar" text tracks. This takes an array of objects represent Property | Description --- | --- title | Descriptive name for the track -language | 2 character [ISO 639-1 code](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) representing the language +language | 2 letter [ISO 639-1 code](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) representing the language type | Mime type of the track
* TextTrackType.SRT - .srt SubRip Subtitle
* TextTrackType.TTML - .ttml TTML
* TextTrackType.VTT - .vtt WebVTT uri | URL for the text track. Currently, only tracks hosted on a webserver are supported @@ -442,7 +442,7 @@ Property | Type | Description currentPosition | number | Time in seconds where the media will start duration | number | Length of the media in seconds naturalSize | object | Properties:
* width - Width in pixels that the video was encoded at
* height - Height in pixels that the video was encoded at
* orientation - "portrait" or "landscape" -textTracks | array | An array of text track info objects with the following properties:
* index - Index number
* title - Description of the track
* language - IOS 639-1 2 letter language code
* type - Mime type of track +textTracks | array | An array of text track info objects with the following properties:
* index - Index number
* title - Description of the track
* language - 2 letter [ISO 639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) language code
* type - Mime type of track Example: ``` From 9ad11dd5698c256b913ca5d7ec4086e427659610 Mon Sep 17 00:00:00 2001 From: Hampton Maxwell Date: Wed, 20 Jun 2018 15:26:24 -0700 Subject: [PATCH 29/50] Avoid crash when text track doesn't have a title or language --- ios/RCTVideo.m | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/ios/RCTVideo.m b/ios/RCTVideo.m index d2cc3114..5fd921cd 100644 --- a/ios/RCTVideo.m +++ b/ios/RCTVideo.m @@ -702,13 +702,16 @@ static NSString *const timedMetadata = @"timedMetadata"; mediaSelectionGroupForMediaCharacteristic:AVMediaCharacteristicLegible]; for (int i = 0; i < group.options.count; ++i) { AVMediaSelectionOption *currentOption = [group.options objectAtIndex:i]; - NSString *title = [[[currentOption commonMetadata] - valueForKey:@"value"] - objectAtIndex:0]; + NSString *title = @""; + NSArray *values = [[currentOption commonMetadata] valueForKey:@"value"]; + if (values.count > 0) { + title = [values objectAtIndex:0]; + } + NSString *language = [currentOption extendedLanguageTag] ? [currentOption extendedLanguageTag] : @""; NSDictionary *textTrack = @{ @"index": [NSNumber numberWithInt:i], @"title": title, - @"language": [currentOption extendedLanguageTag] + @"language": language }; [textTracks addObject:textTrack]; } From e684ba65b6bbad65a4472c535b758ebfed57a628 Mon Sep 17 00:00:00 2001 From: Hampton Maxwell Date: Wed, 20 Jun 2018 15:34:36 -0700 Subject: [PATCH 30/50] Fix crash when selectedTextTrack is null or undefined --- .../exoplayer/ReactExoplayerViewManager.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java index e204a4e7..7c41db58 100644 --- a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java +++ b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java @@ -126,10 +126,14 @@ public class ReactExoplayerViewManager extends ViewGroupManager Date: Wed, 20 Jun 2018 15:46:04 -0700 Subject: [PATCH 31/50] Return empty string instead of null if text track title or language are not set --- .../java/com/brentvatne/exoplayer/ReactExoplayerView.java | 4 ++-- 1 file changed, 2 insertions(+), 2 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 04c4bb2c..3d4702fb 100644 --- a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java +++ b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java @@ -520,9 +520,9 @@ class ReactExoplayerView extends FrameLayout implements Format format = groups.get(i).getFormat(0); WritableMap textTrack = Arguments.createMap(); textTrack.putInt("index", i); - textTrack.putString("title", format.id); + textTrack.putString("title", format.id != null ? format.id : ""); textTrack.putString("type", format.sampleMimeType); - textTrack.putString("language", format.language); + textTrack.putString("language", format.language != null ? format.language : ""); textTracks.pushMap(textTrack); } return textTracks; From 026afabe8b9f73754db9aa347adcecd8bb8008d2 Mon Sep 17 00:00:00 2001 From: Hampton Maxwell Date: Wed, 20 Jun 2018 16:33:50 -0700 Subject: [PATCH 32/50] Only allow the player layer observer to be cleared if it's set (#907) --- ios/RCTVideo.m | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ios/RCTVideo.m b/ios/RCTVideo.m index 5fd921cd..a9734f7d 100644 --- a/ios/RCTVideo.m +++ b/ios/RCTVideo.m @@ -18,6 +18,7 @@ static NSString *const timedMetadata = @"timedMetadata"; BOOL _playerItemObserversSet; BOOL _playerBufferEmpty; AVPlayerLayer *_playerLayer; + BOOL _playerLayerObserverSet; AVPlayerViewController *_playerViewController; NSURL *_videoURL; @@ -794,6 +795,7 @@ static NSString *const timedMetadata = @"timedMetadata"; // resize mode must be set before layer is added [self setResizeMode:_resizeMode]; [_playerLayer addObserver:self forKeyPath:readyForDisplayKeyPath options:NSKeyValueObservingOptionNew context:nil]; + _playerLayerObserverSet = YES; [self.layer addSublayer:_playerLayer]; self.layer.needsDisplayOnBoundsChange = YES; @@ -832,7 +834,10 @@ static NSString *const timedMetadata = @"timedMetadata"; - (void)removePlayerLayer { [_playerLayer removeFromSuperlayer]; - [_playerLayer removeObserver:self forKeyPath:readyForDisplayKeyPath]; + if (_playerLayerObserverSet) { + [_playerLayer removeObserver:self forKeyPath:readyForDisplayKeyPath]; + _playerLayerObserverSet = NO; + } _playerLayer = nil; } From a6808eea6b3b6bba17707495fc7aa9f819fadd43 Mon Sep 17 00:00:00 2001 From: Hampton Maxwell Date: Wed, 20 Jun 2018 16:46:39 -0700 Subject: [PATCH 33/50] Fix for removePlayerLayer observer not being set --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e9641003..ffcd847b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ * Support allowsExternalPlayback on iOS [#1057](https://github.com/react-native-community/react-native-video/pull/1057) * Inherit Android buildtools and SDK version from the root project [#999](https://github.com/react-native-community/react-native-video/pull/999) * Fix bug that caused ExoPlayer to start paused if playInBackground was set [#833](https://github.com/react-native-community/react-native-video/pull/833) +* Fix crash if clearing an observer on iOS that was already cleared [#1075](https://github.com/react-native-community/react-native-video/pull/1075) ### Version 2.2.0 * Text track selection support for iOS & ExoPlayer [#1049](https://github.com/react-native-community/react-native-video/pull/1049) From b785060b3000e83c496e275b2729464623fcbaa5 Mon Sep 17 00:00:00 2001 From: Hampton Maxwell Date: Wed, 20 Jun 2018 16:52:48 -0700 Subject: [PATCH 34/50] Add prop type for audioOnly --- Video.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Video.js b/Video.js index 25e86d71..da29efb8 100644 --- a/Video.js +++ b/Video.js @@ -129,7 +129,7 @@ export default class Video extends Component { }; _onPlaybackRateChange = (event) => { - if (this.state.showPoster && (event.nativeEvent.playbackRate !== 0) && (!this.props.audioOnly)) { + if (this.state.showPoster && event.nativeEvent.playbackRate !== 0 && !this.props.audioOnly) { this.setState({showPoster: false}); } @@ -282,6 +282,7 @@ Video.propTypes = { ignoreSilentSwitch: PropTypes.oneOf(['ignore', 'obey']), disableFocus: PropTypes.bool, controls: PropTypes.bool, + audioOnly: PropTypes.bool, currentTime: PropTypes.number, progressUpdateInterval: PropTypes.number, onLoadStart: PropTypes.func, From dc4c180cd4f15b52085e03d6ad12cb5bb263e36f Mon Sep 17 00:00:00 2001 From: Hampton Maxwell Date: Wed, 20 Jun 2018 17:52:21 -0700 Subject: [PATCH 35/50] Add audioOnly prop --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ffcd847b..a4cabd0d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ * Inherit Android buildtools and SDK version from the root project [#999](https://github.com/react-native-community/react-native-video/pull/999) * Fix bug that caused ExoPlayer to start paused if playInBackground was set [#833](https://github.com/react-native-community/react-native-video/pull/833) * Fix crash if clearing an observer on iOS that was already cleared [#1075](https://github.com/react-native-community/react-native-video/pull/1075) +* Add audioOnly prop for music files [#1039](https://github.com/react-native-community/react-native-video/pull/1039) ### Version 2.2.0 * Text track selection support for iOS & ExoPlayer [#1049](https://github.com/react-native-community/react-native-video/pull/1049) From 3f243b1583f80f9a7515f95a7df3f5131018170f Mon Sep 17 00:00:00 2001 From: Hampton Maxwell Date: Wed, 20 Jun 2018 22:09:05 -0700 Subject: [PATCH 36/50] Document the seek() method --- README.md | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/README.md b/README.md index 4bfbb9d5..60ac25be 100644 --- a/README.md +++ b/README.md @@ -240,6 +240,11 @@ var styles = StyleSheet.create({ * [onLoad](#onload) * [onLoadStart](#onloadstart) +### Methods +* [seek](#seek) + +### Configurable props + #### allowsExternalPlayback Indicates whether the player allows switching to external playback mode such as AirPlay or HDMI. * **true (default)** - allow switching to external playback mode @@ -502,6 +507,45 @@ Example: Platforms: all +### Methods +Methods operate on a ref to the Video element. You can create a ref using code like: +``` +return ( +