feat(android): add new events for audioTrack, textTracks and videoTracks
This commit is contained in:
parent
62ce3df461
commit
63008ced42
94
API.md
94
API.md
@ -316,6 +316,7 @@ var styles = StyleSheet.create({
|
|||||||
| Name |Plateforms Support |
|
| Name |Plateforms Support |
|
||||||
|--|--|
|
|--|--|
|
||||||
|[onAudioBecomingNoisy](#onaudiobecomingnoisy)|Android, iOS|
|
|[onAudioBecomingNoisy](#onaudiobecomingnoisy)|Android, iOS|
|
||||||
|
|[onAudioTracks](#onAudioTracks)|Android|
|
||||||
|[onBandwidthUpdate](#onbandwidthupdate)|Android|
|
|[onBandwidthUpdate](#onbandwidthupdate)|Android|
|
||||||
|[onBuffer](#onbuffer)|Android, iOS|
|
|[onBuffer](#onbuffer)|Android, iOS|
|
||||||
|[onEnd](#onend)|All|
|
|[onEnd](#onend)|All|
|
||||||
@ -333,6 +334,8 @@ var styles = StyleSheet.create({
|
|||||||
|[onSeek](#onseek)|Android, iOS, Windows UWP|
|
|[onSeek](#onseek)|Android, iOS, Windows UWP|
|
||||||
|[onRestoreUserInterfaceForPictureInPictureStop](#onrestoreuserinterfaceforpictureinpicturestop)|iOS|
|
|[onRestoreUserInterfaceForPictureInPictureStop](#onrestoreuserinterfaceforpictureinpicturestop)|iOS|
|
||||||
|[onTimedMetadata](#ontimedmetadata)|Android, iOS|
|
|[onTimedMetadata](#ontimedmetadata)|Android, iOS|
|
||||||
|
|[onTextTracks](#onTextTracks)|Android|
|
||||||
|
|[onVideoTracks](#onVideoTracks)|Android|
|
||||||
|
|
||||||
|
|
||||||
### Methods
|
### Methods
|
||||||
@ -652,6 +655,34 @@ Determine whether to repeat the video when the end is reached
|
|||||||
|
|
||||||
Platforms: all
|
Platforms: all
|
||||||
|
|
||||||
|
|
||||||
|
#### onAudioTracks
|
||||||
|
Callback function that is called when audio tracks change
|
||||||
|
|
||||||
|
Payload:
|
||||||
|
|
||||||
|
Property | Type | Description
|
||||||
|
--- | --- | ---
|
||||||
|
index | number | Internal track ID
|
||||||
|
title | string | Descriptive name for the track
|
||||||
|
language | string | 2 letter [ISO 639-1 code](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) representing the language
|
||||||
|
bitrate | number | bitrate of track
|
||||||
|
type | string | Mime type of track
|
||||||
|
selected | boolean | true if track is playing
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```
|
||||||
|
{
|
||||||
|
audioTracks: [
|
||||||
|
{ language: 'es', title: 'Spanish', type: 'audio/mpeg', index: 0, selected: true },
|
||||||
|
{ language: 'en', title: 'English', type: 'audio/mpeg', index: 1 }
|
||||||
|
],
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
Platforms: Android
|
||||||
|
|
||||||
#### reportBandwidth
|
#### reportBandwidth
|
||||||
Determine whether to generate onBandwidthUpdate events. This is needed due to the high frequency of these events on ExoPlayer.
|
Determine whether to generate onBandwidthUpdate events. This is needed due to the high frequency of these events on ExoPlayer.
|
||||||
|
|
||||||
@ -1228,6 +1259,69 @@ Example:
|
|||||||
|
|
||||||
Platforms: Android, iOS
|
Platforms: Android, iOS
|
||||||
|
|
||||||
|
#### onTextTracks
|
||||||
|
Callback function that is called when text tracks change
|
||||||
|
|
||||||
|
Payload:
|
||||||
|
|
||||||
|
Property | Type | Description
|
||||||
|
--- | --- | ---
|
||||||
|
index | number | Internal track ID
|
||||||
|
title | string | Descriptive name for the track
|
||||||
|
language | string | 2 letter [ISO 639-1 code](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) representing the language
|
||||||
|
type | string | Mime type of the track<br> * TextTrackType.SRT - SubRip (.srt)<br> * TextTrackType.TTML - TTML (.ttml)<br> * TextTrackType.VTT - WebVTT (.vtt)<br>iOS only supports VTT, Android supports all 3
|
||||||
|
selected | boolean | true if track is playing
|
||||||
|
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```
|
||||||
|
{
|
||||||
|
textTracks: [
|
||||||
|
{
|
||||||
|
index: 0,
|
||||||
|
title: 'Any Time You Like',
|
||||||
|
type: 'srt',
|
||||||
|
selected: true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Platforms: Android
|
||||||
|
|
||||||
|
#### onVideoTracks
|
||||||
|
Callback function that is called when video tracks change
|
||||||
|
|
||||||
|
Payload:
|
||||||
|
|
||||||
|
Property | Type | Description
|
||||||
|
--- | --- | ---
|
||||||
|
trackId | number | Internal track ID
|
||||||
|
codecs | string | MimeType of codec used for this track
|
||||||
|
width | number | Track width
|
||||||
|
height | number | Track height
|
||||||
|
bitrate | number | Bitrate in bps
|
||||||
|
selected | boolean | true if track is selected for playing
|
||||||
|
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```
|
||||||
|
{
|
||||||
|
videoTracks: [
|
||||||
|
{
|
||||||
|
trackId: 0,
|
||||||
|
codecs: 'video/mp4',
|
||||||
|
width: 1920,
|
||||||
|
height: 1080,
|
||||||
|
bitrate: 10000,
|
||||||
|
selected: true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Platforms: Android
|
||||||
|
|
||||||
### Methods
|
### Methods
|
||||||
Methods operate on a ref to the Video element. You can create a ref using code like:
|
Methods operate on a ref to the Video element. You can create a ref using code like:
|
||||||
```
|
```
|
||||||
|
24
Video.js
24
Video.js
@ -116,6 +116,24 @@ export default class Video extends Component {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
_onAudioTracks = (event) => {
|
||||||
|
if (this.props.onAudioTracks) {
|
||||||
|
this.props.onAudioTracks(event.nativeEvent);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
_onTextTracks = (event) => {
|
||||||
|
if (this.props.onTextTracks) {
|
||||||
|
this.props.onTextTracks(event.nativeEvent);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
_onVideoTracks = (event) => {
|
||||||
|
if (this.props.onVideoTracks) {
|
||||||
|
this.props.onVideoTracks(event.nativeEvent);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
_onError = (event) => {
|
_onError = (event) => {
|
||||||
if (this.props.onError) {
|
if (this.props.onError) {
|
||||||
this.props.onError(event.nativeEvent);
|
this.props.onError(event.nativeEvent);
|
||||||
@ -316,6 +334,9 @@ export default class Video extends Component {
|
|||||||
onVideoLoadStart: this._onLoadStart,
|
onVideoLoadStart: this._onLoadStart,
|
||||||
onVideoPlaybackStateChanged: this._onPlaybackStateChanged,
|
onVideoPlaybackStateChanged: this._onPlaybackStateChanged,
|
||||||
onVideoLoad: this._onLoad,
|
onVideoLoad: this._onLoad,
|
||||||
|
onAudioTracks: this._onAudioTracks,
|
||||||
|
onTextTracks: this._onTextTracks,
|
||||||
|
onVideoTracks: this._onVideoTracks,
|
||||||
onVideoError: this._onError,
|
onVideoError: this._onError,
|
||||||
onVideoProgress: this._onProgress,
|
onVideoProgress: this._onProgress,
|
||||||
onVideoSeek: this._onSeek,
|
onVideoSeek: this._onSeek,
|
||||||
@ -495,6 +516,9 @@ Video.propTypes = {
|
|||||||
onLoadStart: PropTypes.func,
|
onLoadStart: PropTypes.func,
|
||||||
onPlaybackStateChanged: PropTypes.func,
|
onPlaybackStateChanged: PropTypes.func,
|
||||||
onLoad: PropTypes.func,
|
onLoad: PropTypes.func,
|
||||||
|
onAudioTracks: PropTypes.func,
|
||||||
|
onTextTracks: PropTypes.func,
|
||||||
|
onVideoTracks: PropTypes.func,
|
||||||
onBuffer: PropTypes.func,
|
onBuffer: PropTypes.func,
|
||||||
onError: PropTypes.func,
|
onError: PropTypes.func,
|
||||||
onProgress: PropTypes.func,
|
onProgress: PropTypes.func,
|
||||||
|
13
android/src/main/java/com/brentvatne/common/Track.java
Normal file
13
android/src/main/java/com/brentvatne/common/Track.java
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
package com.brentvatne.common;
|
||||||
|
import android.net.Uri;
|
||||||
|
|
||||||
|
public class Track
|
||||||
|
{
|
||||||
|
public String m_title;
|
||||||
|
public Uri m_uri;
|
||||||
|
public String m_mimeType;
|
||||||
|
public String m_language;
|
||||||
|
public boolean m_isSelected;
|
||||||
|
public int m_bitrate;
|
||||||
|
public int m_index;
|
||||||
|
}
|
12
android/src/main/java/com/brentvatne/common/VideoTrack.java
Normal file
12
android/src/main/java/com/brentvatne/common/VideoTrack.java
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
package com.brentvatne.common;
|
||||||
|
|
||||||
|
public class VideoTrack
|
||||||
|
{
|
||||||
|
public int m_width = 0;
|
||||||
|
public int m_height = 0;
|
||||||
|
public int m_bitrate = 0;
|
||||||
|
public String m_codecs = "";
|
||||||
|
public int m_id = -1;
|
||||||
|
public String m_trackId = "";
|
||||||
|
public boolean m_isSelected = false;
|
||||||
|
}
|
@ -17,24 +17,21 @@ import android.view.accessibility.CaptioningManager;
|
|||||||
import android.widget.FrameLayout;
|
import android.widget.FrameLayout;
|
||||||
import android.widget.ImageButton;
|
import android.widget.ImageButton;
|
||||||
|
|
||||||
|
import androidx.annotation.WorkerThread;
|
||||||
|
|
||||||
|
import com.brentvatne.common.Track;
|
||||||
|
import com.brentvatne.common.VideoTrack;
|
||||||
import com.brentvatne.react.R;
|
import com.brentvatne.react.R;
|
||||||
import com.brentvatne.receiver.AudioBecomingNoisyReceiver;
|
import com.brentvatne.receiver.AudioBecomingNoisyReceiver;
|
||||||
import com.brentvatne.receiver.BecomingNoisyListener;
|
import com.brentvatne.receiver.BecomingNoisyListener;
|
||||||
import com.facebook.react.bridge.Arguments;
|
|
||||||
import com.facebook.react.bridge.Dynamic;
|
import com.facebook.react.bridge.Dynamic;
|
||||||
import com.facebook.react.bridge.LifecycleEventListener;
|
import com.facebook.react.bridge.LifecycleEventListener;
|
||||||
import com.facebook.react.bridge.ReadableArray;
|
import com.facebook.react.bridge.ReadableArray;
|
||||||
import com.facebook.react.bridge.ReadableMap;
|
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.facebook.react.uimanager.ThemedReactContext;
|
||||||
import com.facebook.react.util.RNLog;
|
|
||||||
import com.google.android.exoplayer2.C;
|
import com.google.android.exoplayer2.C;
|
||||||
import com.google.android.exoplayer2.DefaultLoadControl;
|
import com.google.android.exoplayer2.DefaultLoadControl;
|
||||||
import com.google.android.exoplayer2.DefaultRenderersFactory;
|
import com.google.android.exoplayer2.DefaultRenderersFactory;
|
||||||
import com.google.android.exoplayer2.ExoPlaybackException;
|
|
||||||
import com.google.android.exoplayer2.drm.MediaDrmCallbackException;
|
|
||||||
import com.google.android.exoplayer2.drm.DrmSession.DrmSessionException;
|
|
||||||
import com.google.android.exoplayer2.Format;
|
import com.google.android.exoplayer2.Format;
|
||||||
import com.google.android.exoplayer2.MediaItem;
|
import com.google.android.exoplayer2.MediaItem;
|
||||||
import com.google.android.exoplayer2.PlaybackException;
|
import com.google.android.exoplayer2.PlaybackException;
|
||||||
@ -47,16 +44,12 @@ import com.google.android.exoplayer2.drm.DefaultDrmSessionManager;
|
|||||||
import com.google.android.exoplayer2.drm.DrmSessionEventListener;
|
import com.google.android.exoplayer2.drm.DrmSessionEventListener;
|
||||||
import com.google.android.exoplayer2.drm.DrmSessionManager;
|
import com.google.android.exoplayer2.drm.DrmSessionManager;
|
||||||
import com.google.android.exoplayer2.drm.DrmSessionManagerProvider;
|
import com.google.android.exoplayer2.drm.DrmSessionManagerProvider;
|
||||||
import com.google.android.exoplayer2.drm.ExoMediaDrm;
|
|
||||||
import com.google.android.exoplayer2.drm.FrameworkMediaDrm;
|
import com.google.android.exoplayer2.drm.FrameworkMediaDrm;
|
||||||
import com.google.android.exoplayer2.drm.HttpMediaDrmCallback;
|
import com.google.android.exoplayer2.drm.HttpMediaDrmCallback;
|
||||||
import com.google.android.exoplayer2.drm.MediaDrmCallbackException;
|
|
||||||
import com.google.android.exoplayer2.drm.UnsupportedDrmException;
|
import com.google.android.exoplayer2.drm.UnsupportedDrmException;
|
||||||
import com.google.android.exoplayer2.mediacodec.MediaCodecInfo;
|
import com.google.android.exoplayer2.mediacodec.MediaCodecInfo;
|
||||||
import com.google.android.exoplayer2.mediacodec.MediaCodecRenderer;
|
|
||||||
import com.google.android.exoplayer2.mediacodec.MediaCodecUtil;
|
import com.google.android.exoplayer2.mediacodec.MediaCodecUtil;
|
||||||
import com.google.android.exoplayer2.metadata.Metadata;
|
import com.google.android.exoplayer2.metadata.Metadata;
|
||||||
import com.google.android.exoplayer2.source.BehindLiveWindowException;
|
|
||||||
import com.google.android.exoplayer2.source.MediaSource;
|
import com.google.android.exoplayer2.source.MediaSource;
|
||||||
import com.google.android.exoplayer2.source.MergingMediaSource;
|
import com.google.android.exoplayer2.source.MergingMediaSource;
|
||||||
import com.google.android.exoplayer2.source.ProgressiveMediaSource;
|
import com.google.android.exoplayer2.source.ProgressiveMediaSource;
|
||||||
@ -72,6 +65,7 @@ import com.google.android.exoplayer2.trackselection.AdaptiveTrackSelection;
|
|||||||
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
|
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
|
||||||
import com.google.android.exoplayer2.trackselection.MappingTrackSelector;
|
import com.google.android.exoplayer2.trackselection.MappingTrackSelector;
|
||||||
import com.google.android.exoplayer2.trackselection.ExoTrackSelection;
|
import com.google.android.exoplayer2.trackselection.ExoTrackSelection;
|
||||||
|
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
|
||||||
import com.google.android.exoplayer2.trackselection.TrackSelectionOverrides;
|
import com.google.android.exoplayer2.trackselection.TrackSelectionOverrides;
|
||||||
import com.google.android.exoplayer2.trackselection.TrackSelectionOverrides.TrackSelectionOverride;
|
import com.google.android.exoplayer2.trackselection.TrackSelectionOverrides.TrackSelectionOverride;
|
||||||
import com.google.android.exoplayer2.ui.PlayerControlView;
|
import com.google.android.exoplayer2.ui.PlayerControlView;
|
||||||
@ -80,7 +74,6 @@ import com.google.android.exoplayer2.upstream.DataSource;
|
|||||||
import com.google.android.exoplayer2.upstream.DefaultAllocator;
|
import com.google.android.exoplayer2.upstream.DefaultAllocator;
|
||||||
import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter;
|
import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter;
|
||||||
import com.google.android.exoplayer2.upstream.HttpDataSource;
|
import com.google.android.exoplayer2.upstream.HttpDataSource;
|
||||||
import com.google.android.exoplayer2.util.Assertions;
|
|
||||||
import com.google.android.exoplayer2.util.Util;
|
import com.google.android.exoplayer2.util.Util;
|
||||||
import com.google.android.exoplayer2.trackselection.TrackSelection;
|
import com.google.android.exoplayer2.trackselection.TrackSelection;
|
||||||
import com.google.android.exoplayer2.source.dash.DashUtil;
|
import com.google.android.exoplayer2.source.dash.DashUtil;
|
||||||
@ -88,7 +81,6 @@ import com.google.android.exoplayer2.source.dash.manifest.DashManifest;
|
|||||||
import com.google.android.exoplayer2.source.dash.manifest.Period;
|
import com.google.android.exoplayer2.source.dash.manifest.Period;
|
||||||
import com.google.android.exoplayer2.source.dash.manifest.AdaptationSet;
|
import com.google.android.exoplayer2.source.dash.manifest.AdaptationSet;
|
||||||
import com.google.android.exoplayer2.source.dash.manifest.Representation;
|
import com.google.android.exoplayer2.source.dash.manifest.Representation;
|
||||||
import com.google.android.exoplayer2.source.dash.manifest.Descriptor;
|
|
||||||
|
|
||||||
import java.net.CookieHandler;
|
import java.net.CookieHandler;
|
||||||
import java.net.CookieManager;
|
import java.net.CookieManager;
|
||||||
@ -98,9 +90,6 @@ import java.util.List;
|
|||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Timer;
|
|
||||||
import java.util.TimerTask;
|
|
||||||
import java.util.List;
|
|
||||||
import java.lang.Thread;
|
import java.lang.Thread;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
@ -1043,25 +1032,42 @@ class ReactExoplayerView extends FrameLayout implements
|
|||||||
// Properties that must be accessed on the main thread
|
// Properties that must be accessed on the main thread
|
||||||
long duration = player.getDuration();
|
long duration = player.getDuration();
|
||||||
long currentPosition = player.getCurrentPosition();
|
long currentPosition = player.getCurrentPosition();
|
||||||
WritableArray audioTrackInfo = getAudioTrackInfo();
|
ArrayList<Track> audioTracks = getAudioTrackInfo();
|
||||||
WritableArray textTrackInfo = getTextTrackInfo();
|
ArrayList<Track> textTracks = getTextTrackInfo();
|
||||||
int trackRendererIndex = getTrackRendererIndex(C.TRACK_TYPE_VIDEO);
|
|
||||||
|
|
||||||
|
if (this.contentStartTime != -1L) {
|
||||||
ExecutorService es = Executors.newSingleThreadExecutor();
|
ExecutorService es = Executors.newSingleThreadExecutor();
|
||||||
es.execute(new Runnable() {
|
es.execute(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
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
|
// To prevent ANRs caused by getVideoTrackInfo we run this on a different thread and notify the player only when we're done
|
||||||
|
ArrayList<VideoTrack> videoTracks = getVideoTrackInfoFromManifest();
|
||||||
|
if (videoTracks != null) {
|
||||||
|
isUsingContentResolution = true;
|
||||||
|
}
|
||||||
eventEmitter.load(duration, currentPosition, width, height,
|
eventEmitter.load(duration, currentPosition, width, height,
|
||||||
audioTrackInfo, textTrackInfo, getVideoTrackInfo(trackRendererIndex), trackId);
|
audioTracks, textTracks, videoTracks, trackId );
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayList<VideoTrack> videoTracks = getVideoTrackInfo();
|
||||||
|
|
||||||
|
eventEmitter.load(duration, currentPosition, width, height,
|
||||||
|
audioTracks, textTracks, videoTracks, trackId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private WritableArray getAudioTrackInfo() {
|
private static boolean isTrackSelected(TrackSelection selection, TrackGroup group,
|
||||||
WritableArray audioTracks = Arguments.createArray();
|
int trackIndex){
|
||||||
|
return selection != null && selection.getTrackGroup() == group
|
||||||
|
&& selection.indexOf( trackIndex ) != C.INDEX_UNSET;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ArrayList<Track> getAudioTrackInfo() {
|
||||||
|
ArrayList<Track> audioTracks = new ArrayList<>();
|
||||||
if (trackSelector == null) {
|
if (trackSelector == null) {
|
||||||
// Likely player is unmounting so no audio tracks are available anymore
|
// Likely player is unmounting so no audio tracks are available anymore
|
||||||
return audioTracks;
|
return audioTracks;
|
||||||
@ -1072,78 +1078,76 @@ class ReactExoplayerView extends FrameLayout implements
|
|||||||
if (info == null || index == C.INDEX_UNSET) {
|
if (info == null || index == C.INDEX_UNSET) {
|
||||||
return audioTracks;
|
return audioTracks;
|
||||||
}
|
}
|
||||||
|
|
||||||
TrackGroupArray groups = info.getTrackGroups(index);
|
TrackGroupArray groups = info.getTrackGroups(index);
|
||||||
|
TrackSelectionArray selectionArray = player.getCurrentTrackSelections();
|
||||||
|
TrackSelection selection = selectionArray.get( C.TRACK_TYPE_AUDIO );
|
||||||
|
|
||||||
for (int i = 0; i < groups.length; ++i) {
|
for (int i = 0; i < groups.length; ++i) {
|
||||||
Format format = groups.get(i).getFormat(0);
|
TrackGroup group = groups.get(i);
|
||||||
WritableMap audioTrack = Arguments.createMap();
|
Format format = group.getFormat(0);
|
||||||
audioTrack.putInt("index", i);
|
Track audioTrack = new Track();
|
||||||
audioTrack.putString("title", format.id != null ? format.id : "");
|
audioTrack.m_index = i;
|
||||||
audioTrack.putString("type", format.sampleMimeType);
|
audioTrack.m_title = format.id != null ? format.id : "";
|
||||||
audioTrack.putString("language", format.language != null ? format.language : "");
|
audioTrack.m_mimeType = format.sampleMimeType;
|
||||||
audioTrack.putString("bitrate", format.bitrate == Format.NO_VALUE ? ""
|
audioTrack.m_language = format.language != null ? format.language : "";
|
||||||
: String.format(Locale.US, "%.2fMbps", format.bitrate / 1000000f));
|
audioTrack.m_bitrate = format.bitrate == Format.NO_VALUE ? 0 : format.bitrate;
|
||||||
audioTracks.pushMap(audioTrack);
|
audioTrack.m_isSelected = isTrackSelected(selection, group, 0 );
|
||||||
|
audioTracks.add(audioTrack);
|
||||||
}
|
}
|
||||||
return audioTracks;
|
return audioTracks;
|
||||||
}
|
}
|
||||||
private WritableArray getVideoTrackInfo(int trackRendererIndex) {
|
|
||||||
|
|
||||||
if (this.contentStartTime != -1L) {
|
private ArrayList<VideoTrack> getVideoTrackInfo() {
|
||||||
WritableArray contentVideoTracks = this.getVideoTrackInfoFromManifest();
|
ArrayList<VideoTrack> videoTracks = new ArrayList<>();
|
||||||
if (contentVideoTracks != null) {
|
if (trackSelector == null) {
|
||||||
isUsingContentResolution = true;
|
// Likely player is unmounting so no audio tracks are available anymore
|
||||||
return contentVideoTracks;
|
return videoTracks;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
WritableArray videoTracks = Arguments.createArray();
|
|
||||||
|
|
||||||
MappingTrackSelector.MappedTrackInfo info = trackSelector.getCurrentMappedTrackInfo();
|
MappingTrackSelector.MappedTrackInfo info = trackSelector.getCurrentMappedTrackInfo();
|
||||||
|
int index = getTrackRendererIndex(C.TRACK_TYPE_VIDEO);
|
||||||
if (info == null || trackRendererIndex == C.INDEX_UNSET) {
|
if (info == null || index == C.INDEX_UNSET) {
|
||||||
return videoTracks;
|
return videoTracks;
|
||||||
}
|
}
|
||||||
|
|
||||||
TrackGroupArray groups = info.getTrackGroups(trackRendererIndex);
|
TrackGroupArray groups = info.getTrackGroups(index);
|
||||||
for (int i = 0; i < groups.length; ++i) {
|
for (int i = 0; i < groups.length; ++i) {
|
||||||
TrackGroup group = groups.get(i);
|
TrackGroup group = groups.get(i);
|
||||||
|
|
||||||
for (int trackIndex = 0; trackIndex < group.length; trackIndex++) {
|
for (int trackIndex = 0; trackIndex < group.length; trackIndex++) {
|
||||||
Format format = group.getFormat(trackIndex);
|
Format format = group.getFormat(trackIndex);
|
||||||
if (isFormatSupported(format)) {
|
if (isFormatSupported(format)) {
|
||||||
WritableMap videoTrack = Arguments.createMap();
|
VideoTrack videoTrack = new VideoTrack();
|
||||||
videoTrack.putInt("width", format.width == Format.NO_VALUE ? 0 : format.width);
|
videoTrack.m_width = format.width == Format.NO_VALUE ? 0 : format.width;
|
||||||
videoTrack.putInt("height",format.height == Format.NO_VALUE ? 0 : format.height);
|
videoTrack.m_height = format.height == Format.NO_VALUE ? 0 : format.height;
|
||||||
videoTrack.putInt("bitrate", format.bitrate == Format.NO_VALUE ? 0 : format.bitrate);
|
videoTrack.m_bitrate = format.bitrate == Format.NO_VALUE ? 0 : format.bitrate;
|
||||||
videoTrack.putString("codecs", format.codecs != null ? format.codecs : "");
|
videoTrack.m_codecs = format.codecs != null ? format.codecs : "";
|
||||||
videoTrack.putString("trackId", format.id == null ? String.valueOf(trackIndex) : format.id);
|
videoTrack.m_trackId = format.id == null ? String.valueOf(trackIndex) : format.id;
|
||||||
videoTracks.pushMap(videoTrack);
|
videoTracks.add(videoTrack);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return videoTracks;
|
return videoTracks;
|
||||||
}
|
}
|
||||||
|
|
||||||
private WritableArray getVideoTrackInfoFromManifest() {
|
private ArrayList<VideoTrack> getVideoTrackInfoFromManifest() {
|
||||||
return this.getVideoTrackInfoFromManifest(0);
|
return this.getVideoTrackInfoFromManifest(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// We need retry count to in case where minefest request fails from poor network conditions
|
// We need retry count to in case where minefest request fails from poor network conditions
|
||||||
private WritableArray getVideoTrackInfoFromManifest(int retryCount) {
|
@WorkerThread
|
||||||
|
private ArrayList<VideoTrack> getVideoTrackInfoFromManifest(int retryCount) {
|
||||||
ExecutorService es = Executors.newSingleThreadExecutor();
|
ExecutorService es = Executors.newSingleThreadExecutor();
|
||||||
final DataSource dataSource = this.mediaDataSourceFactory.createDataSource();
|
final DataSource dataSource = this.mediaDataSourceFactory.createDataSource();
|
||||||
final Uri sourceUri = this.srcUri;
|
final Uri sourceUri = this.srcUri;
|
||||||
final long startTime = this.contentStartTime * 1000 - 100; // s -> ms with 100ms offset
|
final long startTime = this.contentStartTime * 1000 - 100; // s -> ms with 100ms offset
|
||||||
|
|
||||||
Future<WritableArray> result = es.submit(new Callable<WritableArray>() {
|
Future<ArrayList<VideoTrack>> result = es.submit(new Callable<ArrayList<VideoTrack>>() {
|
||||||
DataSource ds = dataSource;
|
DataSource ds = dataSource;
|
||||||
Uri uri = sourceUri;
|
Uri uri = sourceUri;
|
||||||
long startTimeUs = startTime * 1000; // ms -> us
|
long startTimeUs = startTime * 1000; // ms -> us
|
||||||
|
|
||||||
public WritableArray call() throws Exception {
|
public ArrayList<VideoTrack> call() throws Exception {
|
||||||
WritableArray videoTracks = Arguments.createArray();
|
ArrayList<VideoTrack> videoTracks = new ArrayList<>();
|
||||||
try {
|
try {
|
||||||
DashManifest manifest = DashUtil.loadManifest(this.ds, this.uri);
|
DashManifest manifest = DashUtil.loadManifest(this.ds, this.uri);
|
||||||
int periodCount = manifest.getPeriodCount();
|
int periodCount = manifest.getPeriodCount();
|
||||||
@ -1158,19 +1162,18 @@ class ReactExoplayerView extends FrameLayout implements
|
|||||||
for (int representationIndex = 0; representationIndex < adaptation.representations.size(); representationIndex++) {
|
for (int representationIndex = 0; representationIndex < adaptation.representations.size(); representationIndex++) {
|
||||||
Representation representation = adaptation.representations.get(representationIndex);
|
Representation representation = adaptation.representations.get(representationIndex);
|
||||||
Format format = representation.format;
|
Format format = representation.format;
|
||||||
|
if (isFormatSupported(format)) {
|
||||||
if (representation.presentationTimeOffsetUs <= startTimeUs) {
|
if (representation.presentationTimeOffsetUs <= startTimeUs) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
hasFoundContentPeriod = true;
|
hasFoundContentPeriod = true;
|
||||||
WritableMap videoTrack = Arguments.createMap();
|
VideoTrack videoTrack = new VideoTrack();
|
||||||
videoTrack.putInt("width", format.width == Format.NO_VALUE ? 0 : format.width);
|
videoTrack.m_width = format.width == Format.NO_VALUE ? 0 : format.width;
|
||||||
videoTrack.putInt("height",format.height == Format.NO_VALUE ? 0 : format.height);
|
videoTrack.m_height = format.height == Format.NO_VALUE ? 0 : format.height;
|
||||||
videoTrack.putInt("bitrate", format.bitrate == Format.NO_VALUE ? 0 : format.bitrate);
|
videoTrack.m_bitrate = format.bitrate == Format.NO_VALUE ? 0 : format.bitrate;
|
||||||
videoTrack.putString("codecs", format.codecs != null ? format.codecs : "");
|
videoTrack.m_codecs = format.codecs != null ? format.codecs : "";
|
||||||
videoTrack.putString("trackId",
|
videoTrack.m_trackId = format.id == null ? String.valueOf(representationIndex) : format.id;
|
||||||
format.id == null ? String.valueOf(representationIndex) : format.id);
|
videoTracks.add(videoTrack);
|
||||||
if (isFormatSupported(format)) {
|
|
||||||
videoTracks.pushMap(videoTrack);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (hasFoundContentPeriod) {
|
if (hasFoundContentPeriod) {
|
||||||
@ -1184,7 +1187,7 @@ class ReactExoplayerView extends FrameLayout implements
|
|||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
WritableArray results = result.get(3000, TimeUnit.MILLISECONDS);
|
ArrayList<VideoTrack> results = result.get(3000, TimeUnit.MILLISECONDS);
|
||||||
if (results == null && retryCount < 1) {
|
if (results == null && retryCount < 1) {
|
||||||
return this.getVideoTrackInfoFromManifest(++retryCount);
|
return this.getVideoTrackInfoFromManifest(++retryCount);
|
||||||
}
|
}
|
||||||
@ -1195,24 +1198,31 @@ class ReactExoplayerView extends FrameLayout implements
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private WritableArray getTextTrackInfo() {
|
private ArrayList<Track> getTextTrackInfo() {
|
||||||
WritableArray textTracks = Arguments.createArray();
|
ArrayList<Track> textTracks = new ArrayList<>();
|
||||||
|
if (trackSelector == null) {
|
||||||
|
return textTracks;
|
||||||
|
}
|
||||||
MappingTrackSelector.MappedTrackInfo info = trackSelector.getCurrentMappedTrackInfo();
|
MappingTrackSelector.MappedTrackInfo info = trackSelector.getCurrentMappedTrackInfo();
|
||||||
int index = getTrackRendererIndex(C.TRACK_TYPE_TEXT);
|
int index = getTrackRendererIndex(C.TRACK_TYPE_TEXT);
|
||||||
if (info == null || index == C.INDEX_UNSET) {
|
if (info == null || index == C.INDEX_UNSET) {
|
||||||
return textTracks;
|
return textTracks;
|
||||||
}
|
}
|
||||||
|
TrackSelectionArray selectionArray = player.getCurrentTrackSelections();
|
||||||
|
TrackSelection selection = selectionArray.get( C.TRACK_TYPE_VIDEO );
|
||||||
TrackGroupArray groups = info.getTrackGroups(index);
|
TrackGroupArray groups = info.getTrackGroups(index);
|
||||||
|
|
||||||
for (int i = 0; i < groups.length; ++i) {
|
for (int i = 0; i < groups.length; ++i) {
|
||||||
Format format = groups.get(i).getFormat(0);
|
TrackGroup group = groups.get(i);
|
||||||
WritableMap textTrack = Arguments.createMap();
|
Format format = group.getFormat(0);
|
||||||
textTrack.putInt("index", i);
|
|
||||||
textTrack.putString("title", format.id != null ? format.id : "");
|
Track textTrack = new Track();
|
||||||
textTrack.putString("type", format.sampleMimeType);
|
textTrack.m_index = i;
|
||||||
textTrack.putString("language", format.language != null ? format.language : "");
|
textTrack.m_title = format.id != null ? format.id : "";
|
||||||
textTracks.pushMap(textTrack);
|
textTrack.m_mimeType = format.sampleMimeType;
|
||||||
|
textTrack.m_language = format.language != null ? format.language : "";
|
||||||
|
textTrack.m_isSelected = isTrackSelected(selection, group, 0 );
|
||||||
|
textTracks.add(textTrack);
|
||||||
}
|
}
|
||||||
return textTracks;
|
return textTracks;
|
||||||
}
|
}
|
||||||
@ -1281,7 +1291,10 @@ class ReactExoplayerView extends FrameLayout implements
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTracksInfoChanged(TracksInfo tracksInfo) {
|
public void onTracksInfoChanged(TracksInfo tracksInfo) {
|
||||||
// Do nothing.
|
eventEmitter.textTracks(getTextTrackInfo());
|
||||||
|
eventEmitter.audioTracks(getAudioTrackInfo());
|
||||||
|
eventEmitter.videoTracks(getVideoTrackInfo());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -3,6 +3,8 @@ package com.brentvatne.exoplayer;
|
|||||||
import androidx.annotation.StringDef;
|
import androidx.annotation.StringDef;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
|
import com.brentvatne.common.Track;
|
||||||
|
import com.brentvatne.common.VideoTrack;
|
||||||
import com.facebook.react.bridge.Arguments;
|
import com.facebook.react.bridge.Arguments;
|
||||||
import com.facebook.react.bridge.ReactContext;
|
import com.facebook.react.bridge.ReactContext;
|
||||||
import com.facebook.react.bridge.WritableArray;
|
import com.facebook.react.bridge.WritableArray;
|
||||||
@ -17,6 +19,7 @@ import java.lang.annotation.Retention;
|
|||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
import java.io.StringWriter;
|
import java.io.StringWriter;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
class VideoEventEmitter {
|
class VideoEventEmitter {
|
||||||
|
|
||||||
@ -50,6 +53,9 @@ class VideoEventEmitter {
|
|||||||
private static final String EVENT_AUDIO_BECOMING_NOISY = "onVideoAudioBecomingNoisy";
|
private static final String EVENT_AUDIO_BECOMING_NOISY = "onVideoAudioBecomingNoisy";
|
||||||
private static final String EVENT_AUDIO_FOCUS_CHANGE = "onAudioFocusChanged";
|
private static final String EVENT_AUDIO_FOCUS_CHANGE = "onAudioFocusChanged";
|
||||||
private static final String EVENT_PLAYBACK_RATE_CHANGE = "onPlaybackRateChange";
|
private static final String EVENT_PLAYBACK_RATE_CHANGE = "onPlaybackRateChange";
|
||||||
|
private static final String EVENT_AUDIO_TRACKS = "onAudioTracks";
|
||||||
|
private static final String EVENT_TEXT_TRACKS = "onTextTracks";
|
||||||
|
private static final String EVENT_VIDEO_TRACKS = "onVideoTracks";
|
||||||
|
|
||||||
static final String[] Events = {
|
static final String[] Events = {
|
||||||
EVENT_LOAD_START,
|
EVENT_LOAD_START,
|
||||||
@ -72,6 +78,9 @@ class VideoEventEmitter {
|
|||||||
EVENT_AUDIO_BECOMING_NOISY,
|
EVENT_AUDIO_BECOMING_NOISY,
|
||||||
EVENT_AUDIO_FOCUS_CHANGE,
|
EVENT_AUDIO_FOCUS_CHANGE,
|
||||||
EVENT_PLAYBACK_RATE_CHANGE,
|
EVENT_PLAYBACK_RATE_CHANGE,
|
||||||
|
EVENT_AUDIO_TRACKS,
|
||||||
|
EVENT_TEXT_TRACKS,
|
||||||
|
EVENT_VIDEO_TRACKS,
|
||||||
EVENT_BANDWIDTH,
|
EVENT_BANDWIDTH,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -97,6 +106,9 @@ class VideoEventEmitter {
|
|||||||
EVENT_AUDIO_BECOMING_NOISY,
|
EVENT_AUDIO_BECOMING_NOISY,
|
||||||
EVENT_AUDIO_FOCUS_CHANGE,
|
EVENT_AUDIO_FOCUS_CHANGE,
|
||||||
EVENT_PLAYBACK_RATE_CHANGE,
|
EVENT_PLAYBACK_RATE_CHANGE,
|
||||||
|
EVENT_AUDIO_TRACKS,
|
||||||
|
EVENT_TEXT_TRACKS,
|
||||||
|
EVENT_VIDEO_TRACKS,
|
||||||
EVENT_BANDWIDTH,
|
EVENT_BANDWIDTH,
|
||||||
})
|
})
|
||||||
@interface VideoEvents {
|
@interface VideoEvents {
|
||||||
@ -149,12 +161,7 @@ class VideoEventEmitter {
|
|||||||
receiveEvent(EVENT_LOAD_START, null);
|
receiveEvent(EVENT_LOAD_START, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
void load(double duration, double currentPosition, int videoWidth, int videoHeight,
|
WritableMap aspectRatioToNaturalSize(int videoWidth, int videoHeight) {
|
||||||
WritableArray audioTracks, WritableArray textTracks, WritableArray videoTracks, String trackId) {
|
|
||||||
WritableMap event = Arguments.createMap();
|
|
||||||
event.putDouble(EVENT_PROP_DURATION, duration / 1000D);
|
|
||||||
event.putDouble(EVENT_PROP_CURRENT_TIME, currentPosition / 1000D);
|
|
||||||
|
|
||||||
WritableMap naturalSize = Arguments.createMap();
|
WritableMap naturalSize = Arguments.createMap();
|
||||||
naturalSize.putInt(EVENT_PROP_WIDTH, videoWidth);
|
naturalSize.putInt(EVENT_PROP_WIDTH, videoWidth);
|
||||||
naturalSize.putInt(EVENT_PROP_HEIGHT, videoHeight);
|
naturalSize.putInt(EVENT_PROP_HEIGHT, videoHeight);
|
||||||
@ -165,7 +172,79 @@ class VideoEventEmitter {
|
|||||||
} else {
|
} else {
|
||||||
naturalSize.putString(EVENT_PROP_ORIENTATION, "square");
|
naturalSize.putString(EVENT_PROP_ORIENTATION, "square");
|
||||||
}
|
}
|
||||||
|
return naturalSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WritableArray audioTracksToArray(ArrayList<Track> audioTracks) {
|
||||||
|
WritableArray waAudioTracks = Arguments.createArray();
|
||||||
|
if( audioTracks != null ){
|
||||||
|
for (int i = 0; i < audioTracks.size(); ++i) {
|
||||||
|
Track format = audioTracks.get(i);
|
||||||
|
WritableMap audioTrack = Arguments.createMap();
|
||||||
|
audioTrack.putInt("index", i);
|
||||||
|
audioTrack.putString("title", format.m_title != null ? format.m_title : "");
|
||||||
|
audioTrack.putString("type", format.m_mimeType != null ? format.m_mimeType : "");
|
||||||
|
audioTrack.putString("language", format.m_language != null ? format.m_language : "");
|
||||||
|
audioTrack.putInt("bitrate", format.m_bitrate);
|
||||||
|
audioTrack.putBoolean("selected", format.m_isSelected);
|
||||||
|
waAudioTracks.pushMap(audioTrack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return waAudioTracks;
|
||||||
|
}
|
||||||
|
|
||||||
|
WritableArray videoTracksToArray(ArrayList<VideoTrack> videoTracks) {
|
||||||
|
WritableArray waVideoTracks = Arguments.createArray();
|
||||||
|
if( videoTracks != null ){
|
||||||
|
for (int i = 0; i < videoTracks.size(); ++i) {
|
||||||
|
VideoTrack vTrack = videoTracks.get(i);
|
||||||
|
WritableMap videoTrack = Arguments.createMap();
|
||||||
|
videoTrack.putInt("width", vTrack.m_width);
|
||||||
|
videoTrack.putInt("height",vTrack.m_height);
|
||||||
|
videoTrack.putInt("bitrate", vTrack.m_bitrate);
|
||||||
|
videoTrack.putString("codecs", vTrack.m_codecs);
|
||||||
|
videoTrack.putInt("trackId",vTrack.m_id);
|
||||||
|
videoTrack.putBoolean("selected", vTrack.m_isSelected);
|
||||||
|
waVideoTracks.pushMap(videoTrack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return waVideoTracks;
|
||||||
|
}
|
||||||
|
|
||||||
|
WritableArray textTracksToArray(ArrayList<Track> textTracks) {
|
||||||
|
WritableArray waTextTracks = Arguments.createArray();
|
||||||
|
if (textTracks != null) {
|
||||||
|
for (int i = 0; i < textTracks.size(); ++i) {
|
||||||
|
Track format = textTracks.get(i);
|
||||||
|
WritableMap textTrack = Arguments.createMap();
|
||||||
|
textTrack.putInt("index", i);
|
||||||
|
textTrack.putString("title", format.m_title != null ? format.m_title : "");
|
||||||
|
textTrack.putString("type", format.m_mimeType != null ? format.m_mimeType : "");
|
||||||
|
textTrack.putString("language", format.m_language != null ? format.m_language : "");
|
||||||
|
textTrack.putBoolean("selected", format.m_isSelected);
|
||||||
|
waTextTracks.pushMap(textTrack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return waTextTracks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void load(double duration, double currentPosition, int videoWidth, int videoHeight,
|
||||||
|
ArrayList<Track> audioTracks, ArrayList<Track> textTracks, ArrayList<VideoTrack> videoTracks, String trackId){
|
||||||
|
WritableArray waAudioTracks = audioTracksToArray(audioTracks);
|
||||||
|
WritableArray waVideoTracks = videoTracksToArray(videoTracks);
|
||||||
|
WritableArray waTextTracks = textTracksToArray(textTracks);
|
||||||
|
|
||||||
|
load( duration, currentPosition, videoWidth, videoHeight, waAudioTracks, waTextTracks, waVideoTracks, trackId);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void load(double duration, double currentPosition, int videoWidth, int videoHeight,
|
||||||
|
WritableArray audioTracks, WritableArray textTracks, WritableArray videoTracks, String trackId) {
|
||||||
|
WritableMap event = Arguments.createMap();
|
||||||
|
event.putDouble(EVENT_PROP_DURATION, duration / 1000D);
|
||||||
|
event.putDouble(EVENT_PROP_CURRENT_TIME, currentPosition / 1000D);
|
||||||
|
|
||||||
|
WritableMap naturalSize = aspectRatioToNaturalSize(videoWidth, videoHeight);
|
||||||
event.putMap(EVENT_PROP_NATURAL_SIZE, naturalSize);
|
event.putMap(EVENT_PROP_NATURAL_SIZE, naturalSize);
|
||||||
event.putString(EVENT_PROP_TRACK_ID, trackId);
|
event.putString(EVENT_PROP_TRACK_ID, trackId);
|
||||||
event.putArray(EVENT_PROP_VIDEO_TRACKS, videoTracks);
|
event.putArray(EVENT_PROP_VIDEO_TRACKS, videoTracks);
|
||||||
@ -184,6 +263,26 @@ class VideoEventEmitter {
|
|||||||
receiveEvent(EVENT_LOAD, event);
|
receiveEvent(EVENT_LOAD, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
WritableMap arrayToObject(String field, WritableArray array) {
|
||||||
|
WritableMap event = Arguments.createMap();
|
||||||
|
event.putArray(field, array);
|
||||||
|
return event;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void audioTracks(ArrayList<Track> audioTracks){
|
||||||
|
receiveEvent(EVENT_AUDIO_TRACKS, arrayToObject(EVENT_PROP_AUDIO_TRACKS, audioTracksToArray(audioTracks)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void textTracks(ArrayList<Track> textTracks){
|
||||||
|
receiveEvent(EVENT_TEXT_TRACKS, arrayToObject(EVENT_PROP_TEXT_TRACKS, textTracksToArray(textTracks)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void videoTracks(ArrayList<VideoTrack> videoTracks){
|
||||||
|
receiveEvent(EVENT_VIDEO_TRACKS, arrayToObject(EVENT_PROP_VIDEO_TRACKS, videoTracksToArray(videoTracks)));
|
||||||
|
}
|
||||||
|
|
||||||
void progressChanged(double currentPosition, double bufferedDuration, double seekableDuration, double currentPlaybackTime) {
|
void progressChanged(double currentPosition, double bufferedDuration, double seekableDuration, double currentPlaybackTime) {
|
||||||
WritableMap event = Arguments.createMap();
|
WritableMap event = Arguments.createMap();
|
||||||
event.putDouble(EVENT_PROP_CURRENT_TIME, currentPosition / 1000D);
|
event.putDouble(EVENT_PROP_CURRENT_TIME, currentPosition / 1000D);
|
||||||
|
Loading…
Reference in New Issue
Block a user