From 16688cef0f7e9acb1801bf6611329f1172453f90 Mon Sep 17 00:00:00 2001 From: sridhar Date: Fri, 24 Aug 2018 15:33:46 +0530 Subject: [PATCH 01/15] Youtube like video track selection 1. Loaded event will give the information about available video tracks 2. selectedVideoTrack prop will give the interface to select the video track. This prop will take the height of the video (Similar to youtube like 144p, 350p etc) and set the video track. If height is 0 then all video tracks will be added to list so that it will work like 'Auto' in youtube --- Video.js | 7 ++ .../exoplayer/ReactExoplayerView.java | 115 ++++++++++++++++-- .../exoplayer/ReactExoplayerViewManager.java | 17 +++ .../exoplayer/VideoEventEmitter.java | 4 +- .../brentvatne/react/ReactVideoPackage.java | 5 - 5 files changed, 129 insertions(+), 19 deletions(-) diff --git a/Video.js b/Video.js index 5c6cd1d3..a10c7dd4 100644 --- a/Video.js +++ b/Video.js @@ -323,6 +323,13 @@ Video.propTypes = { PropTypes.number ]) }), + selectedVideoTrack: 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/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java index e098c72a..bcac252f 100644 --- a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java +++ b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java @@ -46,6 +46,7 @@ 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.TrackGroup; import com.google.android.exoplayer2.source.dash.DashMediaSource; import com.google.android.exoplayer2.source.dash.DefaultDashChunkSource; import com.google.android.exoplayer2.source.hls.HlsMediaSource; @@ -121,6 +122,8 @@ class ReactExoplayerView extends FrameLayout implements private boolean repeat; private String audioTrackType; private Dynamic audioTrackValue; + private String videoTrackType; + private Dynamic videoTrackValue; private ReadableArray audioTracks; private String textTrackType; private Dynamic textTrackValue; @@ -512,12 +515,13 @@ class ReactExoplayerView extends FrameLayout implements if (loadVideoStarted) { loadVideoStarted = false; setSelectedAudioTrack(audioTrackType, audioTrackValue); + setSelectedVideoTrack(videoTrackType, videoTrackValue); 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, - getAudioTrackInfo(), getTextTrackInfo()); + getAudioTrackInfo(), getTextTrackInfo(), getVideoTrackInfo()); } } @@ -543,6 +547,40 @@ class ReactExoplayerView extends FrameLayout implements return audioTracks; } + private WritableArray getVideoTrackInfo() { + WritableArray videoTracks = Arguments.createArray(); + + MappingTrackSelector.MappedTrackInfo info = trackSelector.getCurrentMappedTrackInfo(); + int index = getTrackRendererIndex(C.TRACK_TYPE_VIDEO); + if (info == null || index == C.INDEX_UNSET) { + return videoTracks; + } + + TrackGroupArray groups = info.getTrackGroups(index); + for (int i = 0; i < groups.length; ++i) { + TrackGroup group = groups.get(i); + + for (int trackIndex = 0; trackIndex < group.length; trackIndex++) { + Format format = group.getFormat(trackIndex); + + WritableMap videoTrack = Arguments.createMap(); + + videoTrack.putString("width", + format.width == Format.NO_VALUE ? "" : format.width + ""); + videoTrack.putString("height", + format.height == Format.NO_VALUE ? "" : format.height + ""); + videoTrack.putString("bitrate", + format.bitrate == Format.NO_VALUE ? "" + : String.format(Locale.US, "%.2fMbps", format.bitrate / 1000000f)); + videoTrack.putString("trackid", format.id == null ? "" : "" + format.id + ""); + + videoTracks.pushMap(videoTrack); + } + + } + return videoTracks; + } + private WritableArray getTextTrackInfo() { WritableArray textTracks = Arguments.createArray(); @@ -758,6 +796,7 @@ class ReactExoplayerView extends FrameLayout implements } public void setSelectedTrack(int trackType, String type, Dynamic value) { + int rendererIndex = getTrackRendererIndex(trackType); if (rendererIndex == C.INDEX_UNSET) { return; @@ -768,7 +807,8 @@ class ReactExoplayerView extends FrameLayout implements } TrackGroupArray groups = info.getTrackGroups(rendererIndex); - int trackIndex = C.INDEX_UNSET; + int groupIndex = C.INDEX_UNSET; + int[] tracks = {0} ; if (TextUtils.isEmpty(type)) { type = "default"; @@ -786,7 +826,7 @@ class ReactExoplayerView extends FrameLayout implements for (int i = 0; i < groups.length; ++i) { Format format = groups.get(i).getFormat(0); if (format.language != null && format.language.equals(value.asString())) { - trackIndex = i; + groupIndex = i; break; } } @@ -794,13 +834,56 @@ class ReactExoplayerView extends FrameLayout implements for (int i = 0; i < groups.length; ++i) { Format format = groups.get(i).getFormat(0); if (format.id != null && format.id.equals(value.asString())) { - trackIndex = i; + groupIndex = i; break; } } } else if (type.equals("index")) { if (value.asInt() < groups.length) { - trackIndex = value.asInt(); + groupIndex = value.asInt(); + } + } else if (type.equals("videoHeight")) { + groupIndex = C.INDEX_UNSET; + + /*0 is auto mode. Add all tracks of group 0*/ + if (0 == value.asInt()) { + TrackGroup group = groups.get(0); + + tracks = new int[group.length]; + + groupIndex = 0; + + for (int j = 0; j < group.length; j++) { + tracks[j] = j; + } + } else { + /*Search for the exact video Height*/ + for (int i = 0; i < groups.length; ++i) { + TrackGroup group = groups.get(i); + + for (int j = 0; j < group.length; j++) { + Format format = group.getFormat(j); + + if (format.height == value.asInt()) { + groupIndex = i; + tracks[0] = j; + break; + } + } + } + + /*If exact height not found then make it auto. Add all tracks of group 0*/ + if (groupIndex == C.INDEX_UNSET) { + TrackGroup group = groups.get(0); + + tracks = new int[group.length]; + + groupIndex = 0; + + for (int j = 0; j < group.length; j++) { + tracks[j] = j; + } + } } } else { // default if (rendererIndex == C.TRACK_TYPE_TEXT && Util.SDK_INT > 18 && groups.length > 0) { @@ -808,14 +891,14 @@ class ReactExoplayerView extends FrameLayout implements CaptioningManager captioningManager = (CaptioningManager)themedReactContext.getSystemService(Context.CAPTIONING_SERVICE); if (captioningManager != null && captioningManager.isEnabled()) { - trackIndex = getTrackIndexForDefaultLocale(groups); + groupIndex = getGroupIndexForDefaultLocale(groups); } } else if (rendererIndex == C.TRACK_TYPE_AUDIO) { - trackIndex = getTrackIndexForDefaultLocale(groups); + groupIndex = getGroupIndexForDefaultLocale(groups); } } - if (trackIndex == C.INDEX_UNSET) { + if (groupIndex == C.INDEX_UNSET) { trackSelector.setParameters(disableParameters); return; } @@ -824,24 +907,30 @@ class ReactExoplayerView extends FrameLayout implements .buildUpon() .setRendererDisabled(rendererIndex, false) .setSelectionOverride(rendererIndex, groups, - new DefaultTrackSelector.SelectionOverride(trackIndex, 0)) + new DefaultTrackSelector.SelectionOverride(groupIndex, tracks)) .build(); trackSelector.setParameters(selectionParameters); } - private int getTrackIndexForDefaultLocale(TrackGroupArray groups) { - int trackIndex = 0; // default if no match + private int getGroupIndexForDefaultLocale(TrackGroupArray groups) { + int groupIndex = 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; + groupIndex = i; break; } } - return trackIndex; + return groupIndex; + } + + public void setSelectedVideoTrack(String type, Dynamic value) { + videoTrackType = type; + videoTrackValue = value; + setSelectedTrack(C.TRACK_TYPE_VIDEO, videoTrackType, videoTrackValue); } public void setSelectedAudioTrack(String type, Dynamic value) { 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 9ead70ce..f7510335 100644 --- a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java +++ b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java @@ -51,6 +51,9 @@ public class ReactExoplayerViewManager extends ViewGroupManager> createJSModules() { - return Collections.emptyList(); - } - @Override public List createViewManagers(ReactApplicationContext reactContext) { return Collections.singletonList(new ReactExoplayerViewManager()); From 4ea926e1375b14bf577b77d09a2da0d968799b66 Mon Sep 17 00:00:00 2001 From: sridhar Date: Sat, 25 Aug 2018 11:21:01 +0530 Subject: [PATCH 02/15] Bandwidth reporting To show the current bandwidth to user and for debugging purposes current bandwidth is required to be reported. This pull request adds the bandwidth estimate in the progress event. Also the bandwidth details are added in the audio track in load event. There is another pull request which reports the video track information --- .../java/com/brentvatne/exoplayer/ReactExoplayerView.java | 5 ++++- .../java/com/brentvatne/exoplayer/VideoEventEmitter.java | 4 +++- 2 files changed, 7 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 bcac252f..eb303e14 100644 --- a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java +++ b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java @@ -149,9 +149,10 @@ class ReactExoplayerView extends FrameLayout implements && player.getPlaybackState() == ExoPlayer.STATE_READY && player.getPlayWhenReady() ) { + long bitRateEstimate = BANDWIDTH_METER.getBitrateEstimate(); long pos = player.getCurrentPosition(); long bufferedDuration = player.getBufferedPercentage() * player.getDuration() / 100; - eventEmitter.progressChanged(pos, bufferedDuration, player.getDuration()); + eventEmitter.progressChanged(pos, bufferedDuration, player.getDuration(), bitRateEstimate); msg = obtainMessage(SHOW_PROGRESS); sendMessageDelayed(msg, Math.round(mProgressUpdateInterval)); } @@ -542,6 +543,8 @@ class ReactExoplayerView extends FrameLayout implements audioTrack.putString("title", format.id != null ? format.id : ""); audioTrack.putString("type", format.sampleMimeType); audioTrack.putString("language", format.language != null ? format.language : ""); + audioTrack.putString("bitrate", format.bitrate == Format.NO_VALUE ? "" + : String.format(Locale.US, "%.2fMbps", format.bitrate / 1000000f)); audioTracks.pushMap(audioTrack); } return audioTracks; diff --git a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/VideoEventEmitter.java b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/VideoEventEmitter.java index fca24062..a7fa2436 100644 --- a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/VideoEventEmitter.java +++ b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/VideoEventEmitter.java @@ -103,6 +103,7 @@ class VideoEventEmitter { private static final String EVENT_PROP_DURATION = "duration"; private static final String EVENT_PROP_PLAYABLE_DURATION = "playableDuration"; private static final String EVENT_PROP_SEEKABLE_DURATION = "seekableDuration"; + private static final String EVENT_PROP_BITRATE_ESTIMATE = "bitrateEstimate"; private static final String EVENT_PROP_CURRENT_TIME = "currentTime"; private static final String EVENT_PROP_SEEK_TIME = "seekTime"; private static final String EVENT_PROP_NATURAL_SIZE = "naturalSize"; @@ -163,11 +164,12 @@ class VideoEventEmitter { receiveEvent(EVENT_LOAD, event); } - void progressChanged(double currentPosition, double bufferedDuration, double seekableDuration) { + void progressChanged(double currentPosition, double bufferedDuration, double seekableDuration, double bitRateEstimate) { WritableMap event = Arguments.createMap(); event.putDouble(EVENT_PROP_CURRENT_TIME, currentPosition / 1000D); event.putDouble(EVENT_PROP_PLAYABLE_DURATION, bufferedDuration / 1000D); event.putDouble(EVENT_PROP_SEEKABLE_DURATION, seekableDuration / 1000D); + event.putDouble(EVENT_PROP_BITRATE_ESTIMATE, bitRateEstimate / 1000D); receiveEvent(EVENT_PROGRESS, event); } From ff31bd1772528d8ebd492e765dab63414501ca7c Mon Sep 17 00:00:00 2001 From: sridhar Date: Sat, 25 Aug 2018 11:24:08 +0530 Subject: [PATCH 03/15] reverted deprecated API reverted deprecated API --- .../main/java/com/brentvatne/react/ReactVideoPackage.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/android-exoplayer/src/main/java/com/brentvatne/react/ReactVideoPackage.java b/android-exoplayer/src/main/java/com/brentvatne/react/ReactVideoPackage.java index df618ccb..1e5c9284 100644 --- a/android-exoplayer/src/main/java/com/brentvatne/react/ReactVideoPackage.java +++ b/android-exoplayer/src/main/java/com/brentvatne/react/ReactVideoPackage.java @@ -17,6 +17,12 @@ public class ReactVideoPackage implements ReactPackage { return Collections.emptyList(); } + // Deprecated RN 0.47 + public List> createJSModules() { + return Collections.emptyList(); + } + + @Override public List createViewManagers(ReactApplicationContext reactContext) { return Collections.singletonList(new ReactExoplayerViewManager()); From 6480a6462b6c870ddbc03334db04fed25db96458 Mon Sep 17 00:00:00 2001 From: sridhar Date: Sat, 25 Aug 2018 21:53:11 +0530 Subject: [PATCH 04/15] Reporting estimatedBandwidth Reporting estimatedBandwidth --- Video.js | 10 +++++ .../exoplayer/ReactExoplayerView.java | 39 +++++++++++++++++-- .../exoplayer/ReactExoplayerViewManager.java | 12 ++++++ .../exoplayer/VideoEventEmitter.java | 15 +++++-- 4 files changed, 70 insertions(+), 6 deletions(-) diff --git a/Video.js b/Video.js index a10c7dd4..a0b7f35c 100644 --- a/Video.js +++ b/Video.js @@ -99,6 +99,12 @@ export default class Video extends Component { } }; + _onBandwidthUpdate = (event) => { + if (this.props.onBandwidthUpdate) { + this.props.onBandwidthUpdate(event.nativeEvent); + } + }; + _onSeek = (event) => { if (this.state.showPoster && !this.props.audioOnly) { this.setState({showPoster: false}); @@ -234,6 +240,7 @@ export default class Video extends Component { onVideoSeek: this._onSeek, onVideoEnd: this._onEnd, onVideoBuffer: this._onBuffer, + onBandwidthUpdate: this._onBandwidthUpdate, onTimedMetadata: this._onTimedMetadata, onVideoAudioBecomingNoisy: this._onAudioBecomingNoisy, onVideoFullscreenPlayerWillPresent: this._onFullscreenPlayerWillPresent, @@ -294,6 +301,7 @@ Video.propTypes = { onVideoBuffer: PropTypes.func, onVideoError: PropTypes.func, onVideoProgress: PropTypes.func, + onBandwidthUpdate: PropTypes.func, onVideoSeek: PropTypes.func, onVideoEnd: PropTypes.func, onTimedMetadata: PropTypes.func, @@ -363,6 +371,8 @@ Video.propTypes = { playInBackground: PropTypes.bool, playWhenInactive: PropTypes.bool, ignoreSilentSwitch: PropTypes.oneOf(['ignore', 'obey']), + reportBandwidth: PropTypes.bool, + bandwidthUpdateInterval: PropTypes.number, disableFocus: PropTypes.bool, controls: PropTypes.bool, audioOnly: PropTypes.bool, 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 eb303e14..308fc075 100644 --- a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java +++ b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java @@ -86,6 +86,7 @@ class ReactExoplayerView extends FrameLayout implements private static final DefaultBandwidthMeter BANDWIDTH_METER = new DefaultBandwidthMeter(); private static final CookieManager DEFAULT_COOKIE_MANAGER; private static final int SHOW_PROGRESS = 1; + private static final int REPORT_BANDWIDTH = 1; static { DEFAULT_COOKIE_MANAGER = new CookieManager(); @@ -133,6 +134,8 @@ class ReactExoplayerView extends FrameLayout implements private boolean playInBackground = false; private boolean useTextureView = false; private Map requestHeaders; + private float mBandwidthUpdateInterval = 250.0f; + private boolean mReportBandwidth = false; // \ End props // React @@ -149,10 +152,9 @@ class ReactExoplayerView extends FrameLayout implements && player.getPlaybackState() == ExoPlayer.STATE_READY && player.getPlayWhenReady() ) { - long bitRateEstimate = BANDWIDTH_METER.getBitrateEstimate(); long pos = player.getCurrentPosition(); long bufferedDuration = player.getBufferedPercentage() * player.getDuration() / 100; - eventEmitter.progressChanged(pos, bufferedDuration, player.getDuration(), bitRateEstimate); + eventEmitter.progressChanged(pos, bufferedDuration, player.getDuration()); msg = obtainMessage(SHOW_PROGRESS); sendMessageDelayed(msg, Math.round(mProgressUpdateInterval)); } @@ -161,6 +163,23 @@ class ReactExoplayerView extends FrameLayout implements } }; + private final Handler bandwidthReporter = new Handler() { + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case REPORT_BANDWIDTH: + if (player != null) { + long bitRateEstimate = BANDWIDTH_METER.getBitrateEstimate(); + + eventEmitter.bandwidthReport(bitRateEstimate); + msg = obtainMessage(REPORT_BANDWIDTH); + sendMessageDelayed(msg, Math.round(mBandwidthUpdateInterval)); + } + break; + } + } + }; + public ReactExoplayerView(ThemedReactContext context) { super(context); this.themedReactContext = context; @@ -338,6 +357,7 @@ class ReactExoplayerView extends FrameLayout implements player = null; trackSelector = null; } + bandwidthReporter.removeMessages(REPORT_BANDWIDTH); progressHandler.removeMessages(SHOW_PROGRESS); themedReactContext.removeLifecycleEventListener(this); audioBecomingNoisyReceiver.removeListener(); @@ -579,7 +599,6 @@ class ReactExoplayerView extends FrameLayout implements videoTracks.pushMap(videoTrack); } - } return videoTracks; } @@ -758,6 +777,20 @@ class ReactExoplayerView extends FrameLayout implements mProgressUpdateInterval = progressUpdateInterval; } + public void setBandwidthUpdateInterval(final float bandwidthUpdateInterval) { + mBandwidthUpdateInterval = bandwidthUpdateInterval; + } + + public void setReportBandwidthModifier(boolean reportBandwidth) { + mReportBandwidth = reportBandwidth; + if (mReportBandwidth) { + bandwidthReporter.removeMessages(REPORT_BANDWIDTH); + bandwidthReporter.sendEmptyMessage(REPORT_BANDWIDTH); + } else { + bandwidthReporter.removeMessages(REPORT_BANDWIDTH); + } + } + public void setRawSrc(final Uri uri, final String extension) { if (uri != null) { boolean isOriginalSourceNull = srcUri == null; 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 f7510335..7817520f 100644 --- a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java +++ b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java @@ -45,6 +45,8 @@ public class ReactExoplayerViewManager extends ViewGroupManager Date: Thu, 6 Sep 2018 14:25:44 +0530 Subject: [PATCH 05/15] named parameter added for exception. Otherwise this cannot be used in JS named parameter added for exception. Otherwise this cannot be used in JS --- .../main/java/com/brentvatne/exoplayer/VideoEventEmitter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/VideoEventEmitter.java b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/VideoEventEmitter.java index 1717e65d..6a4b4fd4 100644 --- a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/VideoEventEmitter.java +++ b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/VideoEventEmitter.java @@ -121,7 +121,7 @@ class VideoEventEmitter { private static final String EVENT_PROP_ERROR = "error"; private static final String EVENT_PROP_ERROR_STRING = "errorString"; - private static final String EVENT_PROP_ERROR_EXCEPTION = ""; + private static final String EVENT_PROP_ERROR_EXCEPTION = "errorException"; private static final String EVENT_PROP_TIMED_METADATA = "metadata"; From a1a0ca648c5e8ddf49da4f999edc6b35ffbde93a Mon Sep 17 00:00:00 2001 From: sridhar Date: Tue, 18 Sep 2018 20:09:32 +0530 Subject: [PATCH 06/15] bandwidth report for IOS bandwidth report for IOS --- ios/RCTVideo.m | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/ios/RCTVideo.m b/ios/RCTVideo.m index f5fc6125..2d5030ca 100644 --- a/ios/RCTVideo.m +++ b/ios/RCTVideo.m @@ -578,6 +578,22 @@ static int const RCTVideoUnset = -1; selector:@selector(playbackStalled:) name:AVPlayerItemPlaybackStalledNotification object:nil]; + + [[NSNotificationCenter defaultCenter] removeObserver:self + name:AVPlayerItemNewAccessLogEntryNotification + object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(handleAVPlayerAccess:) + name:AVPlayerItemNewAccessLogEntryNotification + object:nil]; + +} + +- (void)handleAVPlayerAccess:(NSNotification *)notification { + AVPlayerItemAccessLog *accessLog = [((AVPlayerItem *)notification.object) accessLog]; + AVPlayerItemAccessLogEvent *lastEvent = accessLog.events.lastObject; + float lastEventNumber = lastEvent.indicatedBitrate; + RCTLog(@"Switch indicatedBitrate from: %f to: %f", lastEvent.observedBitrate, lastEvent.indicatedBitrate); } - (void)playbackStalled:(NSNotification *)notification From b256f2d4d81b8b4c0288fd3e466af50838574fb2 Mon Sep 17 00:00:00 2001 From: sridhar Date: Wed, 19 Sep 2018 17:58:49 +0530 Subject: [PATCH 07/15] IOS bandwidth reporting IOS bandwidth reporting --- ios/RCTVideo.h | 1 + ios/RCTVideo.m | 6 ++++-- ios/RCTVideoManager.m | 1 + 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/ios/RCTVideo.h b/ios/RCTVideo.h index 1c471236..a63747ca 100644 --- a/ios/RCTVideo.h +++ b/ios/RCTVideo.h @@ -14,6 +14,7 @@ @property (nonatomic, copy) RCTBubblingEventBlock onVideoBuffer; @property (nonatomic, copy) RCTBubblingEventBlock onVideoError; @property (nonatomic, copy) RCTBubblingEventBlock onVideoProgress; +@property (nonatomic, copy) RCTBubblingEventBlock onBandwidthUpdate; @property (nonatomic, copy) RCTBubblingEventBlock onVideoSeek; @property (nonatomic, copy) RCTBubblingEventBlock onVideoEnd; @property (nonatomic, copy) RCTBubblingEventBlock onTimedMetadata; diff --git a/ios/RCTVideo.m b/ios/RCTVideo.m index 2d5030ca..a00fe7c8 100644 --- a/ios/RCTVideo.m +++ b/ios/RCTVideo.m @@ -592,8 +592,10 @@ static int const RCTVideoUnset = -1; - (void)handleAVPlayerAccess:(NSNotification *)notification { AVPlayerItemAccessLog *accessLog = [((AVPlayerItem *)notification.object) accessLog]; AVPlayerItemAccessLogEvent *lastEvent = accessLog.events.lastObject; - float lastEventNumber = lastEvent.indicatedBitrate; - RCTLog(@"Switch indicatedBitrate from: %f to: %f", lastEvent.observedBitrate, lastEvent.indicatedBitrate); + + if (self.onBandwidthUpdate) { + self.onBandwidthUpdate(@{@"bitrateEstimate": [NSNumber numberWithFloat:(lastEvent.observedBitrate/1000)]}); + } } - (void)playbackStalled:(NSNotification *)notification diff --git a/ios/RCTVideoManager.m b/ios/RCTVideoManager.m index e0e0162e..c3dfa4c2 100644 --- a/ios/RCTVideoManager.m +++ b/ios/RCTVideoManager.m @@ -44,6 +44,7 @@ RCT_EXPORT_VIEW_PROPERTY(onVideoLoad, RCTBubblingEventBlock); RCT_EXPORT_VIEW_PROPERTY(onVideoBuffer, RCTBubblingEventBlock); RCT_EXPORT_VIEW_PROPERTY(onVideoError, RCTBubblingEventBlock); RCT_EXPORT_VIEW_PROPERTY(onVideoProgress, RCTBubblingEventBlock); +RCT_EXPORT_VIEW_PROPERTY(onBandwidthUpdate, RCTBubblingEventBlock); RCT_EXPORT_VIEW_PROPERTY(onVideoSeek, RCTBubblingEventBlock); RCT_EXPORT_VIEW_PROPERTY(onVideoEnd, RCTBubblingEventBlock); RCT_EXPORT_VIEW_PROPERTY(onTimedMetadata, RCTBubblingEventBlock); From 41cbf073c77b16cd019691e0edea9cc44ddd1838 Mon Sep 17 00:00:00 2001 From: sridhar Date: Thu, 1 Nov 2018 15:18:59 +0530 Subject: [PATCH 08/15] Bandwidth is reported as enevts when download happens. Not by timer method Bandwidth is reported as enevts when download happens. Not by timer method --- android-exoplayer/build.gradle | 18 ++++++++----- .../exoplayer/ReactExoplayerView.java | 25 ++++++++++++++++++- 2 files changed, 36 insertions(+), 7 deletions(-) diff --git a/android-exoplayer/build.gradle b/android-exoplayer/build.gradle index 4546a597..1e93addd 100644 --- a/android-exoplayer/build.gradle +++ b/android-exoplayer/build.gradle @@ -18,18 +18,24 @@ android { dependencies { compileOnly "com.facebook.react:react-native:${safeExtGet('reactNativeVersion', '+')}" - implementation('com.google.android.exoplayer:exoplayer:2.9.0') { - exclude group: 'com.android.support' - } + // implementation('com.google.android.exoplayer:exoplayer:2.9.0') { + // exclude group: 'com.android.support' + // } + implementation project(':exoplayer-library-core') + implementation project(':exoplayer-library-dash') + implementation project(':exoplayer-library-ui') + implementation project(':exoplayer-library-smoothstreaming') + implementation project(':exoplayer-library-hls') + implementation project(':exoplayer-extension-okhttp') // All support libs must use the same version implementation "com.android.support:support-annotations:${safeExtGet('supportLibVersion', '+')}" implementation "com.android.support:support-compat:${safeExtGet('supportLibVersion', '+')}" implementation "com.android.support:support-media-compat:${safeExtGet('supportLibVersion', '+')}" - implementation('com.google.android.exoplayer:extension-okhttp:2.9.0') { - exclude group: 'com.squareup.okhttp3', module: 'okhttp' - } + // implementation('com.google.android.exoplayer:extension-okhttp:2.9.0') { + // exclude group: 'com.squareup.okhttp3', module: 'okhttp' + // } implementation 'com.squareup.okhttp3:okhttp:3.11.0' } 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 760fd6a8..531b64fa 100644 --- a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java +++ b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java @@ -60,6 +60,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.DefaultAllocator; +import com.google.android.exoplayer2.upstream.BandwidthMeter; import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter; import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.Util; @@ -83,7 +84,7 @@ class ReactExoplayerView extends FrameLayout implements private static final String TAG = "ReactExoplayerView"; - private static final DefaultBandwidthMeter BANDWIDTH_METER = new DefaultBandwidthMeter(); + private static DefaultBandwidthMeter BANDWIDTH_METER; // = new DefaultBandwidthMeter(); private static final CookieManager DEFAULT_COOKIE_MANAGER; private static final int SHOW_PROGRESS = 1; private static final int REPORT_BANDWIDTH = 1; @@ -183,6 +184,9 @@ class ReactExoplayerView extends FrameLayout implements public ReactExoplayerView(ThemedReactContext context) { super(context); this.themedReactContext = context; + + buildBandwidthMeter(); + createViews(); this.eventEmitter = new VideoEventEmitter(context); audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); @@ -261,6 +265,25 @@ class ReactExoplayerView extends FrameLayout implements // Internal methods + private void buildBandwidthMeter() { + BANDWIDTH_METER = new DefaultBandwidthMeter(new Handler(), new BandwidthMeter.EventListener() { + @Override + public void onBandwidthSample(int elapsedMs, long bytes, long bitrate) { + String bw = humanReadableByteCount(bitrate, true, true); + System.out.println("Debug::::In function onBandwidthSample, elapsedMs = " + elapsedMs + " bytes = " + bytes + " bitrate = " + bitrate); + } + + public String humanReadableByteCount(long bytes, boolean si, boolean isBits) { + int unit = !si ? 1000 : 1024; + if (bytes < unit) + return bytes + " KB"; + int exp = (int) (Math.log(bytes) / Math.log(unit)); + String pre = (si ? "kMGTPE" : "KMGTPE").charAt(exp - 1) + + (si ? "" : "i"); + return isBits ? String.format("%.1f %sb", bytes / Math.pow(unit, exp), pre) : String.format("%.1f %sB", bytes / Math.pow(unit, exp), pre); + } + }); + } private void initializePlayer() { if (player == null) { From 9dead2fefc06e2dcf544a3bf5185abb239aafee7 Mon Sep 17 00:00:00 2001 From: sridhar Date: Thu, 1 Nov 2018 16:58:27 +0530 Subject: [PATCH 09/15] Some log functions removed Some log functions removed --- .../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 531b64fa..cb8a3e2c 100644 --- a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java +++ b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java @@ -84,7 +84,7 @@ class ReactExoplayerView extends FrameLayout implements private static final String TAG = "ReactExoplayerView"; - private static DefaultBandwidthMeter BANDWIDTH_METER; // = new DefaultBandwidthMeter(); + private static DefaultBandwidthMeter BANDWIDTH_METER; private static final CookieManager DEFAULT_COOKIE_MANAGER; private static final int SHOW_PROGRESS = 1; private static final int REPORT_BANDWIDTH = 1; @@ -269,19 +269,8 @@ class ReactExoplayerView extends FrameLayout implements BANDWIDTH_METER = new DefaultBandwidthMeter(new Handler(), new BandwidthMeter.EventListener() { @Override public void onBandwidthSample(int elapsedMs, long bytes, long bitrate) { - String bw = humanReadableByteCount(bitrate, true, true); System.out.println("Debug::::In function onBandwidthSample, elapsedMs = " + elapsedMs + " bytes = " + bytes + " bitrate = " + bitrate); } - - public String humanReadableByteCount(long bytes, boolean si, boolean isBits) { - int unit = !si ? 1000 : 1024; - if (bytes < unit) - return bytes + " KB"; - int exp = (int) (Math.log(bytes) / Math.log(unit)); - String pre = (si ? "kMGTPE" : "KMGTPE").charAt(exp - 1) - + (si ? "" : "i"); - return isBits ? String.format("%.1f %sb", bytes / Math.pow(unit, exp), pre) : String.format("%.1f %sB", bytes / Math.pow(unit, exp), pre); - } }); } From 5dce3e216199ed26e1d9ae8f279155a14379cb9b Mon Sep 17 00:00:00 2001 From: sridhar Date: Thu, 1 Nov 2018 21:41:57 +0530 Subject: [PATCH 10/15] Code cleanup Code cleanup --- Video.js | 6 +- .../exoplayer/ReactExoplayerView.java | 60 +++++-------------- .../exoplayer/ReactExoplayerViewManager.java | 8 +-- .../exoplayer/VideoEventEmitter.java | 4 +- 4 files changed, 22 insertions(+), 56 deletions(-) diff --git a/Video.js b/Video.js index 65613443..db387db4 100644 --- a/Video.js +++ b/Video.js @@ -246,7 +246,7 @@ export default class Video extends Component { onVideoSeek: this._onSeek, onVideoEnd: this._onEnd, onVideoBuffer: this._onBuffer, - onBandwidthUpdate: this._onBandwidthUpdate, + onVideoBandwidthUpdate: this._onBandwidthUpdate, onTimedMetadata: this._onTimedMetadata, onVideoAudioBecomingNoisy: this._onAudioBecomingNoisy, onVideoExternalPlaybackChange: this._onExternalPlaybackChange, @@ -294,7 +294,7 @@ Video.propTypes = { onVideoBuffer: PropTypes.func, onVideoError: PropTypes.func, onVideoProgress: PropTypes.func, - onBandwidthUpdate: PropTypes.func, + onVideoBandwidthUpdate: PropTypes.func, onVideoSeek: PropTypes.func, onVideoEnd: PropTypes.func, onTimedMetadata: PropTypes.func, @@ -366,7 +366,6 @@ Video.propTypes = { playWhenInactive: PropTypes.bool, ignoreSilentSwitch: PropTypes.oneOf(['ignore', 'obey']), reportBandwidth: PropTypes.bool, - bandwidthUpdateInterval: PropTypes.number, disableFocus: PropTypes.bool, controls: PropTypes.bool, audioOnly: PropTypes.bool, @@ -379,6 +378,7 @@ Video.propTypes = { onBuffer: PropTypes.func, onError: PropTypes.func, onProgress: PropTypes.func, + onBandwidthUpdate: PropTypes.func, onSeek: PropTypes.func, onEnd: PropTypes.func, onFullscreenPlayerWillPresent: PropTypes.func, 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 cb8a3e2c..262d6240 100644 --- a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java +++ b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java @@ -78,13 +78,14 @@ import java.util.Locale; class ReactExoplayerView extends FrameLayout implements LifecycleEventListener, ExoPlayer.EventListener, + BandwidthMeter.EventListener, BecomingNoisyListener, AudioManager.OnAudioFocusChangeListener, MetadataRenderer.Output { private static final String TAG = "ReactExoplayerView"; - private static DefaultBandwidthMeter BANDWIDTH_METER; + private static final DefaultBandwidthMeter BANDWIDTH_METER = new DefaultBandwidthMeter(); private static final CookieManager DEFAULT_COOKIE_MANAGER; private static final int SHOW_PROGRESS = 1; private static final int REPORT_BANDWIDTH = 1; @@ -95,7 +96,7 @@ class ReactExoplayerView extends FrameLayout implements } private final VideoEventEmitter eventEmitter; - + private Handler mainHandler; private ExoPlayerView exoPlayerView; @@ -135,7 +136,6 @@ class ReactExoplayerView extends FrameLayout implements private boolean playInBackground = false; private boolean useTextureView = false; private Map requestHeaders; - private float mBandwidthUpdateInterval = 250.0f; private boolean mReportBandwidth = false; // \ End props @@ -164,31 +164,14 @@ class ReactExoplayerView extends FrameLayout implements } }; - private final Handler bandwidthReporter = new Handler() { - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case REPORT_BANDWIDTH: - if (player != null) { - long bitRateEstimate = BANDWIDTH_METER.getBitrateEstimate(); - - eventEmitter.bandwidthReport(bitRateEstimate); - msg = obtainMessage(REPORT_BANDWIDTH); - sendMessageDelayed(msg, Math.round(mBandwidthUpdateInterval)); - } - break; - } - } - }; - public ReactExoplayerView(ThemedReactContext context) { super(context); this.themedReactContext = context; - buildBandwidthMeter(); + this.eventEmitter = new VideoEventEmitter(context); createViews(); - this.eventEmitter = new VideoEventEmitter(context); + audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); themedReactContext.addLifecycleEventListener(this); audioBecomingNoisyReceiver = new AudioBecomingNoisyReceiver(themedReactContext); @@ -263,17 +246,15 @@ class ReactExoplayerView extends FrameLayout implements stopPlayback(); } - - // Internal methods - private void buildBandwidthMeter() { - BANDWIDTH_METER = new DefaultBandwidthMeter(new Handler(), new BandwidthMeter.EventListener() { - @Override - public void onBandwidthSample(int elapsedMs, long bytes, long bitrate) { - System.out.println("Debug::::In function onBandwidthSample, elapsedMs = " + elapsedMs + " bytes = " + bytes + " bitrate = " + bitrate); - } - }); + //BandwidthMeter.EventListener implementation + @Override + public void onBandwidthSample(int elapsedMs, long bytes, long bitrate) { + if (mReportBandwidth == true) { + eventEmitter.bandwidthReport(bitrate); + } } + // Internal methods private void initializePlayer() { if (player == null) { TrackSelection.Factory videoTrackSelectionFactory = new AdaptiveTrackSelection.Factory(BANDWIDTH_METER); @@ -285,6 +266,7 @@ class ReactExoplayerView extends FrameLayout implements player.setMetadataOutput(this); exoPlayerView.setPlayer(player); audioBecomingNoisyReceiver.setListener(this); + BANDWIDTH_METER.addEventListener(new Handler(), this); setPlayWhenReady(!isPaused); playerNeedsSource = true; @@ -372,10 +354,10 @@ class ReactExoplayerView extends FrameLayout implements player = null; trackSelector = null; } - bandwidthReporter.removeMessages(REPORT_BANDWIDTH); progressHandler.removeMessages(SHOW_PROGRESS); themedReactContext.removeLifecycleEventListener(this); audioBecomingNoisyReceiver.removeListener(); + BANDWIDTH_METER.removeEventListener(this); } private boolean requestAudioFocus() { @@ -792,19 +774,9 @@ class ReactExoplayerView extends FrameLayout implements mProgressUpdateInterval = progressUpdateInterval; } - public void setBandwidthUpdateInterval(final float bandwidthUpdateInterval) { - mBandwidthUpdateInterval = bandwidthUpdateInterval; - } - - public void setReportBandwidthModifier(boolean reportBandwidth) { + public void setReportBandwidth(boolean reportBandwidth) { mReportBandwidth = reportBandwidth; - if (mReportBandwidth) { - bandwidthReporter.removeMessages(REPORT_BANDWIDTH); - bandwidthReporter.sendEmptyMessage(REPORT_BANDWIDTH); - } else { - bandwidthReporter.removeMessages(REPORT_BANDWIDTH); - } - } + } public void setRawSrc(final Uri uri, final String extension) { if (uri != null) { 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 2bf8a2c3..52d0030b 100644 --- a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java +++ b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java @@ -45,7 +45,6 @@ public class ReactExoplayerViewManager extends ViewGroupManager Date: Thu, 20 Dec 2018 11:01:13 +0530 Subject: [PATCH 11/15] Defect fix Defect fix --- .../com/brentvatne/exoplayer/ReactExoplayerView.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 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 262d6240..691b7d8a 100644 --- a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java +++ b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java @@ -870,14 +870,16 @@ class ReactExoplayerView extends FrameLayout implements /*0 is auto mode. Add all tracks of group 0*/ if (0 == value.asInt()) { - TrackGroup group = groups.get(0); + if (groups.length > 0) { + TrackGroup group = groups.get(0); - tracks = new int[group.length]; + tracks = new int[group.length]; - groupIndex = 0; + groupIndex = 0; - for (int j = 0; j < group.length; j++) { - tracks[j] = j; + for (int j = 0; j < group.length; j++) { + tracks[j] = j; + } } } else { /*Search for the exact video Height*/ From d5168af211d2af1151d418493ffeb531f2721883 Mon Sep 17 00:00:00 2001 From: Hampton Maxwell Date: Mon, 31 Dec 2018 21:33:02 -0800 Subject: [PATCH 12/15] Cleanups to video track handling. This also fixes a bug that compared track type & renderer index --- .../exoplayer/ReactExoplayerView.java | 102 +++++++----------- 1 file changed, 36 insertions(+), 66 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 691b7d8a..d4b00102 100644 --- a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java +++ b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java @@ -249,7 +249,7 @@ class ReactExoplayerView extends FrameLayout implements //BandwidthMeter.EventListener implementation @Override public void onBandwidthSample(int elapsedMs, long bytes, long bitrate) { - if (mReportBandwidth == true) { + if (mReportBandwidth) { eventEmitter.bandwidthReport(bitrate); } } @@ -566,7 +566,6 @@ class ReactExoplayerView extends FrameLayout implements } return audioTracks; } - private WritableArray getVideoTrackInfo() { WritableArray videoTracks = Arguments.createArray(); @@ -582,18 +581,13 @@ class ReactExoplayerView extends FrameLayout implements for (int trackIndex = 0; trackIndex < group.length; trackIndex++) { Format format = group.getFormat(trackIndex); - WritableMap videoTrack = Arguments.createMap(); - - videoTrack.putString("width", - format.width == Format.NO_VALUE ? "" : format.width + ""); - videoTrack.putString("height", - format.height == Format.NO_VALUE ? "" : format.height + ""); - videoTrack.putString("bitrate", - format.bitrate == Format.NO_VALUE ? "" - : String.format(Locale.US, "%.2fMbps", format.bitrate / 1000000f)); - videoTrack.putString("trackid", format.id == null ? "" : "" + format.id + ""); - + videoTrack.putInt("width", format.width == Format.NO_VALUE ? 0 : format.width); + videoTrack.putInt("height",format.height == Format.NO_VALUE ? 0 : format.height); + videoTrack.putInt("bitrate", format.bitrate == Format.NO_VALUE ? 0 : format.bitrate); + videoTrack.putString("codecs", format.codecs != null ? format.codecs : ""); + videoTrack.putString("trackId", + format.id == null ? String.valueOf(trackIndex) : format.id); videoTracks.pushMap(videoTrack); } } @@ -819,7 +813,6 @@ class ReactExoplayerView extends FrameLayout implements } public void setSelectedTrack(int trackType, String type, Dynamic value) { - int rendererIndex = getTrackRendererIndex(trackType); if (rendererIndex == C.INDEX_UNSET) { return; @@ -865,65 +858,38 @@ class ReactExoplayerView extends FrameLayout implements if (value.asInt() < groups.length) { groupIndex = value.asInt(); } - } else if (type.equals("videoHeight")) { - groupIndex = C.INDEX_UNSET; - - /*0 is auto mode. Add all tracks of group 0*/ - if (0 == value.asInt()) { - if (groups.length > 0) { - TrackGroup group = groups.get(0); - - tracks = new int[group.length]; - - groupIndex = 0; - - for (int j = 0; j < group.length; j++) { - tracks[j] = j; - } - } - } else { - /*Search for the exact video Height*/ - for (int i = 0; i < groups.length; ++i) { - TrackGroup group = groups.get(i); - - for (int j = 0; j < group.length; j++) { - Format format = group.getFormat(j); - - if (format.height == value.asInt()) { - groupIndex = i; - tracks[0] = j; - break; - } - } - } - - /*If exact height not found then make it auto. Add all tracks of group 0*/ - if (groupIndex == C.INDEX_UNSET) { - TrackGroup group = groups.get(0); - - tracks = new int[group.length]; - - groupIndex = 0; - - for (int j = 0; j < group.length; j++) { - tracks[j] = j; + } else if (type.equals("resolution")) { + int height = value.asInt(); + for (int i = 0; i < groups.length; ++i) { // Search for the exact height + TrackGroup group = groups.get(i); + for (int j = 0; j < group.length; j++) { + Format format = group.getFormat(j); + if (format.height == value.asInt()) { + groupIndex = i; + tracks[0] = j; + break; } } } - } else { // default - if (rendererIndex == C.TRACK_TYPE_TEXT && Util.SDK_INT > 18 && groups.length > 0) { - // Use system settings if possible - CaptioningManager captioningManager - = (CaptioningManager)themedReactContext.getSystemService(Context.CAPTIONING_SERVICE); - if (captioningManager != null && captioningManager.isEnabled()) { - groupIndex = getGroupIndexForDefaultLocale(groups); - } - } else if (rendererIndex == C.TRACK_TYPE_AUDIO) { + } else if (rendererIndex == C.TRACK_TYPE_TEXT && Util.SDK_INT > 18) { // Text default + // Use system settings if possible + CaptioningManager captioningManager + = (CaptioningManager)themedReactContext.getSystemService(Context.CAPTIONING_SERVICE); + if (captioningManager != null && captioningManager.isEnabled()) { groupIndex = getGroupIndexForDefaultLocale(groups); } + } else if (rendererIndex == C.TRACK_TYPE_AUDIO) { // Audio default + groupIndex = getGroupIndexForDefaultLocale(groups); } - if (groupIndex == C.INDEX_UNSET) { + if (groupIndex == C.INDEX_UNSET && trackType == C.TRACK_TYPE_VIDEO) { // Video auto + TrackGroup group = groups.get(0); + tracks = new int[group.length]; + groupIndex = 0; + for (int j = 0; j < group.length; j++) { + tracks[j] = j; + } + } else if (groupIndex == C.INDEX_UNSET) { trackSelector.setParameters(disableParameters); return; } @@ -938,6 +904,10 @@ class ReactExoplayerView extends FrameLayout implements } private int getGroupIndexForDefaultLocale(TrackGroupArray groups) { + if (groups.length == 0){ + return C.INDEX_UNSET; + } + int groupIndex = 0; // default if no match String locale2 = Locale.getDefault().getLanguage(); // 2 letter code String locale3 = Locale.getDefault().getISO3Language(); // 3 letter code From d148c3f9f91e5c36d438064847b4e198549c1c3e Mon Sep 17 00:00:00 2001 From: Hampton Maxwell Date: Mon, 31 Dec 2018 21:35:15 -0800 Subject: [PATCH 13/15] Change field to bitrate for bandwidth update --- .../main/java/com/brentvatne/exoplayer/VideoEventEmitter.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/VideoEventEmitter.java b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/VideoEventEmitter.java index 6ed12532..b46b66d6 100644 --- a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/VideoEventEmitter.java +++ b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/VideoEventEmitter.java @@ -125,7 +125,7 @@ class VideoEventEmitter { private static final String EVENT_PROP_TIMED_METADATA = "metadata"; - private static final String EVENT_PROP_BITRATE_ESTIMATE = "bitrateEstimate"; + private static final String EVENT_PROP_BITRATE = "bitrate"; void setViewId(int viewId) { @@ -178,7 +178,7 @@ class VideoEventEmitter { void bandwidthReport(double bitRateEstimate) { WritableMap event = Arguments.createMap(); - event.putDouble(EVENT_PROP_BITRATE_ESTIMATE, bitRateEstimate / 1024D); + event.putDouble(EVENT_PROP_BITRATE, bitRate); receiveEvent(EVENT_BANDWIDTH, event); } From 7f2c4ab0ed1f258929d6abd79fada14e751ebd19 Mon Sep 17 00:00:00 2001 From: Hampton Maxwell Date: Mon, 31 Dec 2018 21:36:02 -0800 Subject: [PATCH 14/15] Reenable ExoPlayer exclusions --- android-exoplayer/build.gradle | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/android-exoplayer/build.gradle b/android-exoplayer/build.gradle index 1e93addd..9c467553 100644 --- a/android-exoplayer/build.gradle +++ b/android-exoplayer/build.gradle @@ -18,9 +18,9 @@ android { dependencies { compileOnly "com.facebook.react:react-native:${safeExtGet('reactNativeVersion', '+')}" - // implementation('com.google.android.exoplayer:exoplayer:2.9.0') { - // exclude group: 'com.android.support' - // } + implementation('com.google.android.exoplayer:exoplayer:2.9.0') { + exclude group: 'com.android.support' + } implementation project(':exoplayer-library-core') implementation project(':exoplayer-library-dash') implementation project(':exoplayer-library-ui') @@ -33,9 +33,9 @@ dependencies { implementation "com.android.support:support-compat:${safeExtGet('supportLibVersion', '+')}" implementation "com.android.support:support-media-compat:${safeExtGet('supportLibVersion', '+')}" - // implementation('com.google.android.exoplayer:extension-okhttp:2.9.0') { - // exclude group: 'com.squareup.okhttp3', module: 'okhttp' - // } + implementation('com.google.android.exoplayer:extension-okhttp:2.9.0') { + exclude group: 'com.squareup.okhttp3', module: 'okhttp' + } implementation 'com.squareup.okhttp3:okhttp:3.11.0' } From 72f896d6dfb2a7dda8d452e0b928f079ce7476b5 Mon Sep 17 00:00:00 2001 From: Hampton Maxwell Date: Mon, 31 Dec 2018 21:39:12 -0800 Subject: [PATCH 15/15] Don't format bandwidth update bitrate --- ios/Video/RCTVideo.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/Video/RCTVideo.m b/ios/Video/RCTVideo.m index 9b6f89c3..b71bbf28 100644 --- a/ios/Video/RCTVideo.m +++ b/ios/Video/RCTVideo.m @@ -720,7 +720,7 @@ static int const RCTVideoUnset = -1; AVPlayerItemAccessLogEvent *lastEvent = accessLog.events.lastObject; if (self.onBandwidthUpdate) { - self.onBandwidthUpdate(@{@"bitrateEstimate": [NSNumber numberWithFloat:(lastEvent.observedBitrate/1000)]}); + self.onBandwidthUpdate(@{@"bitrate": [NSNumber numberWithFloat:lastEvent.observedBitrate]}); } }