diff --git a/CHANGELOG.md b/CHANGELOG.md
index a0dd5543..88b60563 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,7 @@
### Next Version
* Basic fullscreen support for Android MediaPlayer [#1138](https://github.com/react-native-community/react-native-video/pull/1138)
+* Simplify default Android SDK code [#1145](https://github.com/react-native-community/react-native-video/pull/1145) [#1146](https://github.com/react-native-community/react-native-video/pull/1146)
* Support video cachging for iOS ([#955](https://github.com/react-native-community/react-native-video/pull/955))
### Version 3.1.0
diff --git a/README.md b/README.md
index dce6b6ec..af4df361 100644
--- a/README.md
+++ b/README.md
@@ -206,6 +206,10 @@ using System.Collections.Generic;
## Usage
```javascript
+// Load the module
+
+import Video from 'react-native-video';
+
// Within your render function, assuming you have a file called
// "background.mp4" in your project. You can include multiple videos
// on a single screen if you like.
@@ -245,6 +249,7 @@ var styles = StyleSheet.create({
* [rate](#rate)
* [repeat](#repeat)
* [resizeMode](#resizemode)
+* [selectedAudioTrack](#selectedaudiotrack)
* [selectedTextTrack](#selectedtexttrack)
* [stereoPan](#stereopan)
* [textTracks](#texttracks)
@@ -375,6 +380,36 @@ Determines how to resize the video when the frame doesn't match the raw video di
Platforms: Android ExoPlayer, Android MediaPlayer, iOS, Windows UWP
+#### selectedAudioTrack
+Configure which audio track, if any, is played.
+
+```
+selectedAudioTrack={{
+ type: Type,
+ value: Value
+}}
+```
+
+Example:
+```
+selectedAudioTrack={{
+ type: "title",
+ value: "Dubbing"
+}}
+```
+
+Type | Value | Description
+--- | --- | ---
+"system" (default) | N/A | Play the audio track that matches the system language. If none match, play the first track.
+"disabled" | N/A | Turn off audio
+"title" | string | Play the audio track with the title specified as the Value, e.g. "French"
+"language" | string | Play the audio track with the language specified as the Value, e.g. "fr"
+"index" | number | Play the audio track with the index specified as the value, e.g. 0
+
+If a track matching the specified Type (and Value if appropriate) is unavailable, the first audio track will be played. If multiple tracks match the criteria, the first match will be used.
+
+Platforms: Android ExoPlayer, iOS
+
#### selectedTextTrack
Configure which text track (caption or subtitle), if any, is shown.
@@ -517,7 +552,8 @@ 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 - 2 letter [ISO 639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) language code
* type - Mime type of track
+audioTracks | array | An array of audio 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) or 3 letter [ISO639-2](https://en.wikipedia.org/wiki/List_of_ISO_639-2_codes) 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) or 3 letter [ISO 639-2](https://en.wikipedia.org/wiki/List_of_ISO_639-2_codes) language code
* type - Mime type of track
Example:
```
@@ -535,6 +571,10 @@ Example:
orientation: 'landscape'
width: '1920'
},
+ audioTracks: [
+ { language: 'es', title: 'Spanish', type: 'audio/mpeg', index: 0 },
+ { language: 'en', title: 'English', type: 'audio/mpeg', index: 1 }
+ ],
textTracks: [
{ title: '#1 French', language: 'fr', index: 0, type: 'text/vtt' },
{ title: '#2 English CC', language: 'en', index: 1, type: 'text/vtt' },
diff --git a/Video.js b/Video.js
index dda530d3..f32725f3 100644
--- a/Video.js
+++ b/Video.js
@@ -316,6 +316,13 @@ Video.propTypes = {
posterResizeMode: Image.propTypes.resizeMode,
repeat: PropTypes.bool,
allowsExternalPlayback: PropTypes.bool,
+ selectedAudioTrack: PropTypes.shape({
+ type: PropTypes.string.isRequired,
+ value: PropTypes.oneOfType([
+ PropTypes.string,
+ PropTypes.number
+ ])
+ }),
selectedTextTrack: PropTypes.shape({
type: PropTypes.string.isRequired,
value: PropTypes.oneOfType([
diff --git a/android-exoplayer/build.gradle b/android-exoplayer/build.gradle
index a957dd62..4c1e9c32 100644
--- a/android-exoplayer/build.gradle
+++ b/android-exoplayer/build.gradle
@@ -1,20 +1,16 @@
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
+def safeExtGet(prop, fallback) {
+ rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
+}
android {
- compileSdkVersion _compileSdkVersion
- buildToolsVersion _buildToolsVersion
+ compileSdkVersion safeExtGet('compileSdkVersion', 27)
+ buildToolsVersion safeExtGet('buildToolsVersion', '27.0.3')
defaultConfig {
- minSdkVersion _minSdkVersion
- targetSdkVersion _targetSdkVersion
+ minSdkVersion safeExtGet('minSdkVersion', 16)
+ targetSdkVersion safeExtGet('targetSdkVersion', 27)
versionCode 1
versionName "1.0"
}
@@ -22,7 +18,7 @@ android {
dependencies {
//noinspection GradleDynamicVersion
- provided "com.facebook.react:react-native:${_reactNativeVersion}"
+ provided "com.facebook.react:react-native:${safeExtGet('reactNativeVersion', '+')}"
compile 'com.google.android.exoplayer:exoplayer:2.7.3'
compile('com.google.android.exoplayer:extension-okhttp:2.7.3') {
exclude group: 'com.squareup.okhttp3', module: 'okhttp'
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 9a036c25..487da343 100644
--- a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java
+++ b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java
@@ -113,6 +113,9 @@ class ReactExoplayerView extends FrameLayout implements
private Uri srcUri;
private String extension;
private boolean repeat;
+ private String audioTrackType;
+ private Dynamic audioTrackValue;
+ private ReadableArray audioTracks;
private String textTrackType;
private Dynamic textTrackValue;
private ReadableArray textTracks;
@@ -501,20 +504,43 @@ class ReactExoplayerView extends FrameLayout implements
private void videoLoaded() {
if (loadVideoStarted) {
loadVideoStarted = false;
+ setSelectedAudioTrack(audioTrackType, audioTrackValue);
setSelectedTextTrack(textTrackType, textTrackValue);
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,
- getTextTrackInfo());
+ getAudioTrackInfo(), getTextTrackInfo());
}
}
+ private WritableArray getAudioTrackInfo() {
+ WritableArray audioTracks = Arguments.createArray();
+
+ MappingTrackSelector.MappedTrackInfo info = trackSelector.getCurrentMappedTrackInfo();
+ int index = getTrackRendererIndex(C.TRACK_TYPE_AUDIO);
+ if (info == null || index == C.INDEX_UNSET) {
+ return audioTracks;
+ }
+
+ 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 != null ? format.id : "");
+ textTrack.putString("type", format.sampleMimeType);
+ textTrack.putString("language", format.language != null ? format.language : "");
+ audioTracks.pushMap(textTrack);
+ }
+ return audioTracks;
+ }
+
private WritableArray getTextTrackInfo() {
WritableArray textTracks = Arguments.createArray();
MappingTrackSelector.MappedTrackInfo info = trackSelector.getCurrentMappedTrackInfo();
- int index = getTextTrackRendererIndex();
+ int index = getTrackRendererIndex(C.TRACK_TYPE_TEXT);
if (info == null || index == C.INDEX_UNSET) {
return textTracks;
}
@@ -647,10 +673,10 @@ class ReactExoplayerView extends FrameLayout implements
return false;
}
- public int getTextTrackRendererIndex() {
+ public int getTrackRendererIndex(int trackType) {
int rendererCount = player.getRendererCount();
for (int rendererIndex = 0; rendererIndex < rendererCount; rendererIndex++) {
- if (player.getRendererType(rendererIndex) == C.TRACK_TYPE_TEXT) {
+ if (player.getRendererType(rendererIndex) == trackType) {
return rendererIndex;
}
}
@@ -724,12 +750,9 @@ class ReactExoplayerView extends FrameLayout implements
this.repeat = repeat;
}
- public void setSelectedTextTrack(String type, Dynamic value) {
- textTrackType = type;
- textTrackValue = value;
-
- int index = getTextTrackRendererIndex();
- if (index == C.INDEX_UNSET) {
+ public void setSelectedTrack(int trackType, String type, Dynamic value) {
+ int rendererIndex = getTrackRendererIndex(trackType);
+ if (rendererIndex == C.INDEX_UNSET) {
return;
}
MappingTrackSelector.MappedTrackInfo info = trackSelector.getCurrentMappedTrackInfo();
@@ -737,13 +760,15 @@ class ReactExoplayerView extends FrameLayout implements
return;
}
- TrackGroupArray groups = info.getTrackGroups(index);
+ TrackGroupArray groups = info.getTrackGroups(rendererIndex);
int trackIndex = C.INDEX_UNSET;
- trackSelector.setSelectionOverride(index, groups, null);
if (TextUtils.isEmpty(type)) {
- // Do nothing
- } else if (type.equals("disabled")) {
+ type = "default";
+ }
+
+ if (type.equals("disabled")) {
+ trackSelector.setSelectionOverride(rendererIndex, groups, null);
return;
} else if (type.equals("language")) {
for (int i = 0; i < groups.length; ++i) {
@@ -762,26 +787,25 @@ class ReactExoplayerView extends FrameLayout implements
}
}
} else if (type.equals("index")) {
- trackIndex = value.asInt();
- } else { // default. Use system settings if possible
- int sdk = android.os.Build.VERSION.SDK_INT;
- if (sdk>18 && groups.length>0) {
- CaptioningManager captioningManager = (CaptioningManager) themedReactContext.getSystemService(Context.CAPTIONING_SERVICE);
- if (captioningManager.isEnabled()) {
- // default is to take the first object
- trackIndex = 0;
-
- String locale = Locale.getDefault().getDisplayLanguage();
- for (int i = 0; i < groups.length; ++i) {
- Format format = groups.get(i).getFormat(0);
- if (format.language != null && format.language.equals(locale)) {
- trackIndex = i;
- break;
- }
+ if (value.asInt() < groups.length) {
+ trackIndex = value.asInt();
+ }
+ } else { // default
+ if (rendererIndex == C.TRACK_TYPE_TEXT) { // Use system settings if possible
+ int sdk = android.os.Build.VERSION.SDK_INT;
+ if (sdk > 18 && groups.length > 0) {
+ CaptioningManager captioningManager
+ = (CaptioningManager)themedReactContext.getSystemService(Context.CAPTIONING_SERVICE);
+ if (captioningManager != null && captioningManager.isEnabled()) {
+ trackIndex = getTrackIndexForDefaultLocale(groups);
}
+ } else {
+ trackSelector.setSelectionOverride(rendererIndex, groups, null);
+ return;
}
- } else return;
-
+ } else if (rendererIndex == C.TRACK_TYPE_AUDIO) {
+ trackIndex = getTrackIndexForDefaultLocale(groups);
+ }
}
if (trackIndex == C.INDEX_UNSET) {
@@ -791,8 +815,35 @@ class ReactExoplayerView extends FrameLayout implements
MappingTrackSelector.SelectionOverride override
= new MappingTrackSelector.SelectionOverride(
- new FixedTrackSelection.Factory(), trackIndex, 0);
- trackSelector.setSelectionOverride(index, groups, override);
+ new FixedTrackSelection.Factory(), trackIndex, 0);
+ trackSelector.setSelectionOverride(rendererIndex, groups, override);
+ }
+
+ private int getTrackIndexForDefaultLocale(TrackGroupArray groups) {
+ int trackIndex = 0; // default if no match
+ String locale2 = Locale.getDefault().getLanguage(); // 2 letter code
+ String locale3 = Locale.getDefault().getISO3Language(); // 3 letter code
+ for (int i = 0; i < groups.length; ++i) {
+ Format format = groups.get(i).getFormat(0);
+ String language = format.language;
+ if (language != null && (language.equals(locale2) || language.equals(locale3))) {
+ trackIndex = i;
+ break;
+ }
+ }
+ return trackIndex;
+ }
+
+ public void setSelectedAudioTrack(String type, Dynamic value) {
+ audioTrackType = type;
+ audioTrackValue = value;
+ setSelectedTrack(C.TRACK_TYPE_AUDIO, audioTrackType, audioTrackValue);
+ }
+
+ public void setSelectedTextTrack(String type, Dynamic value) {
+ textTrackType = type;
+ textTrackValue = value;
+ setSelectedTrack(C.TRACK_TYPE_TEXT, textTrackType, textTrackValue);
}
public void setPausedModifier(boolean paused) {
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 e3775a6e..fbc8a9ad 100644
--- a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java
+++ b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java
@@ -28,6 +28,9 @@ public class ReactExoplayerViewManager extends ViewGroupManager {
return (