Revert formatting changes to keep diff cleaner

This commit is contained in:
Craig Martin 2023-08-22 23:30:01 -04:00
parent db6e73e035
commit 90a8eb245d
2 changed files with 208 additions and 260 deletions

View File

@ -269,8 +269,7 @@ class ReactExoplayerView extends FrameLayout implements
lastPos = pos; lastPos = pos;
lastBufferDuration = bufferedDuration; lastBufferDuration = bufferedDuration;
lastDuration = duration; lastDuration = duration;
eventEmitter.progressChanged(pos, bufferedDuration, player.getDuration(), eventEmitter.progressChanged(pos, bufferedDuration, player.getDuration(), getPositionInFirstPeriodMsForCurrentWindow(pos));
getPositionInFirstPeriodMsForCurrentWindow(pos));
} }
msg = obtainMessage(SHOW_PROGRESS); msg = obtainMessage(SHOW_PROGRESS);
sendMessageDelayed(msg, Math.round(mProgressUpdateInterval)); sendMessageDelayed(msg, Math.round(mProgressUpdateInterval));
@ -282,7 +281,7 @@ class ReactExoplayerView extends FrameLayout implements
public double getPositionInFirstPeriodMsForCurrentWindow(long currentPosition) { public double getPositionInFirstPeriodMsForCurrentWindow(long currentPosition) {
Timeline.Window window = new Timeline.Window(); Timeline.Window window = new Timeline.Window();
if (!player.getCurrentTimeline().isEmpty()) { if(!player.getCurrentTimeline().isEmpty()) {
player.getCurrentTimeline().getWindow(player.getCurrentMediaItemIndex(), window); player.getCurrentTimeline().getWindow(player.getCurrentMediaItemIndex(), window);
} }
return window.windowStartTimeMs + currentPosition; return window.windowStartTimeMs + currentPosition;
@ -342,8 +341,7 @@ class ReactExoplayerView extends FrameLayout implements
@Override @Override
protected void onDetachedFromWindow() { protected void onDetachedFromWindow() {
super.onDetachedFromWindow(); super.onDetachedFromWindow();
/* /* We want to be able to continue playing audio when switching tabs.
* We want to be able to continue playing audio when switching tabs.
* Leave this here in case it causes issues. * Leave this here in case it causes issues.
*/ */
// stopPlayback(); // stopPlayback();
@ -377,7 +375,7 @@ class ReactExoplayerView extends FrameLayout implements
stopPlayback(); stopPlayback();
} }
// BandwidthMeter.EventListener implementation //BandwidthMeter.EventListener implementation
@Override @Override
public void onBandwidthSample(int elapsedMs, long bytes, long bitrate) { public void onBandwidthSample(int elapsedMs, long bytes, long bitrate) {
if (mReportBandwidth) { if (mReportBandwidth) {
@ -399,7 +397,7 @@ class ReactExoplayerView extends FrameLayout implements
* Toggling the visibility of the player control view * Toggling the visibility of the player control view
*/ */
private void togglePlayerControlVisibility() { private void togglePlayerControlVisibility() {
if (player == null) if(player == null)
return; return;
reLayout(playerControlView); reLayout(playerControlView);
if (playerControlView.isVisible()) { if (playerControlView.isVisible()) {
@ -418,13 +416,12 @@ class ReactExoplayerView extends FrameLayout implements
} }
if (fullScreenPlayerView == null) { if (fullScreenPlayerView == null) {
fullScreenPlayerView = new FullScreenPlayerView(getContext(), exoPlayerView, playerControlView, fullScreenPlayerView = new FullScreenPlayerView(getContext(), exoPlayerView, playerControlView, new OnBackPressedCallback(true) {
new OnBackPressedCallback(true) { @Override
@Override public void handleOnBackPressed() {
public void handleOnBackPressed() { setFullscreen(false);
setFullscreen(false); }
} });
});
} }
// Setting the player for the playerControlView // Setting the player for the playerControlView
@ -441,7 +438,7 @@ class ReactExoplayerView extends FrameLayout implements
} }
}); });
// Handling the playButton click event //Handling the playButton click event
ImageButton playButton = playerControlView.findViewById(R.id.exo_play); ImageButton playButton = playerControlView.findViewById(R.id.exo_play);
playButton.setOnClickListener(new View.OnClickListener() { playButton.setOnClickListener(new View.OnClickListener() {
@Override @Override
@ -453,7 +450,7 @@ class ReactExoplayerView extends FrameLayout implements
} }
}); });
// Handling the pauseButton click event //Handling the pauseButton click event
ImageButton pauseButton = playerControlView.findViewById(R.id.exo_pause); ImageButton pauseButton = playerControlView.findViewById(R.id.exo_pause);
pauseButton.setOnClickListener(new View.OnClickListener() { pauseButton.setOnClickListener(new View.OnClickListener() {
@Override @Override
@ -462,7 +459,7 @@ class ReactExoplayerView extends FrameLayout implements
} }
}); });
// Handling the fullScreenButton click event //Handling the fullScreenButton click event
final ImageButton fullScreenButton = playerControlView.findViewById(R.id.exo_fullscreen); final ImageButton fullScreenButton = playerControlView.findViewById(R.id.exo_fullscreen);
fullScreenButton.setOnClickListener(v -> setFullscreen(!isFullscreen)); fullScreenButton.setOnClickListener(v -> setFullscreen(!isFullscreen));
updateFullScreenButtonVisbility(); updateFullScreenButtonVisbility();
@ -480,16 +477,14 @@ class ReactExoplayerView extends FrameLayout implements
pauseButton.setVisibility(INVISIBLE); pauseButton.setVisibility(INVISIBLE);
} }
reLayout(playPauseControlContainer); reLayout(playPauseControlContainer);
// Remove this eventListener once its executed. since UI will work fine once //Remove this eventListener once its executed. since UI will work fine once after the reLayout is done
// after the reLayout is done
player.removeListener(eventListener); player.removeListener(eventListener);
} }
@Override @Override
public void onPlayWhenReadyChanged(boolean playWhenReady, int reason) { public void onPlayWhenReadyChanged(boolean playWhenReady, int reason) {
reLayout(playPauseControlContainer); reLayout(playPauseControlContainer);
// Remove this eventListener once its executed. since UI will work fine once //Remove this eventListener once its executed. since UI will work fine once after the reLayout is done
// after the reLayout is done
player.removeListener(eventListener); player.removeListener(eventListener);
} }
}; };
@ -500,7 +495,7 @@ class ReactExoplayerView extends FrameLayout implements
* Adding Player control to the frame layout * Adding Player control to the frame layout
*/ */
private void addPlayerControl() { private void addPlayerControl() {
if (playerControlView == null) if(playerControlView == null)
return; return;
LayoutParams layoutParams = new LayoutParams( LayoutParams layoutParams = new LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
@ -516,15 +511,12 @@ class ReactExoplayerView extends FrameLayout implements
/** /**
* Update the layout * Update the layout
* * @param view view needs to update layout
* @param view view needs to update layout
* *
* This is a workaround for the open bug in react-native: * This is a workaround for the open bug in react-native: https://github.com/facebook/react-native/issues/17968
* https://github.com/facebook/react-native/issues/17968
*/ */
private void reLayout(View view) { private void reLayout(View view) {
if (view == null) if (view == null) return;
return;
view.measure(MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.EXACTLY), view.measure(MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.EXACTLY)); MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.EXACTLY));
view.layout(view.getLeft(), view.getTop(), view.getMeasuredWidth(), view.getMeasuredHeight()); view.layout(view.getLeft(), view.getTop(), view.getMeasuredWidth(), view.getMeasuredHeight());
@ -533,10 +525,7 @@ class ReactExoplayerView extends FrameLayout implements
private class RNVLoadControl extends DefaultLoadControl { private class RNVLoadControl extends DefaultLoadControl {
private int availableHeapInBytes = 0; private int availableHeapInBytes = 0;
private Runtime runtime; private Runtime runtime;
public RNVLoadControl(DefaultAllocator allocator, int minBufferMs, int maxBufferMs, int bufferForPlaybackMs, int bufferForPlaybackAfterRebufferMs, int targetBufferBytes, boolean prioritizeTimeOverSizeThresholds, int backBufferDurationMs, boolean retainBackBufferFromKeyframe) {
public RNVLoadControl(DefaultAllocator allocator, int minBufferMs, int maxBufferMs, int bufferForPlaybackMs,
int bufferForPlaybackAfterRebufferMs, int targetBufferBytes, boolean prioritizeTimeOverSizeThresholds,
int backBufferDurationMs, boolean retainBackBufferFromKeyframe) {
super(allocator, super(allocator,
minBufferMs, minBufferMs,
maxBufferMs, maxBufferMs,
@ -547,10 +536,8 @@ class ReactExoplayerView extends FrameLayout implements
backBufferDurationMs, backBufferDurationMs,
retainBackBufferFromKeyframe); retainBackBufferFromKeyframe);
runtime = Runtime.getRuntime(); runtime = Runtime.getRuntime();
ActivityManager activityManager = (ActivityManager) themedReactContext ActivityManager activityManager = (ActivityManager) themedReactContext.getSystemService(themedReactContext.ACTIVITY_SERVICE);
.getSystemService(themedReactContext.ACTIVITY_SERVICE); availableHeapInBytes = (int) Math.floor(activityManager.getMemoryClass() * maxHeapAllocationPercent * 1024 * 1024);
availableHeapInBytes = (int) Math
.floor(activityManager.getMemoryClass() * maxHeapAllocationPercent * 1024 * 1024);
} }
@Override @Override
@ -565,11 +552,10 @@ class ReactExoplayerView extends FrameLayout implements
} }
long usedMemory = runtime.totalMemory() - runtime.freeMemory(); long usedMemory = runtime.totalMemory() - runtime.freeMemory();
long freeMemory = runtime.maxMemory() - usedMemory; long freeMemory = runtime.maxMemory() - usedMemory;
long reserveMemory = (long) minBufferMemoryReservePercent * runtime.maxMemory(); long reserveMemory = (long)minBufferMemoryReservePercent * runtime.maxMemory();
long bufferedMs = bufferedDurationUs / (long) 1000; long bufferedMs = bufferedDurationUs / (long)1000;
if (reserveMemory > freeMemory && bufferedMs > 2000) { if (reserveMemory > freeMemory && bufferedMs > 2000) {
// We don't have enough memory in reserve so we stop buffering to allow other // We don't have enough memory in reserve so we stop buffering to allow other components to use it instead
// components to use it instead
return false; return false;
} }
if (runtime.freeMemory() == 0) { if (runtime.freeMemory() == 0) {
@ -602,8 +588,7 @@ class ReactExoplayerView extends FrameLayout implements
} }
if (playerNeedsSource && srcUri != null) { if (playerNeedsSource && srcUri != null) {
exoPlayerView.invalidateAspectRatio(); exoPlayerView.invalidateAspectRatio();
// DRM session manager creation must be done on a different thread to prevent // DRM session manager creation must be done on a different thread to prevent crashes so we start a new thread
// crashes so we start a new thread
ExecutorService es = Executors.newSingleThreadExecutor(); ExecutorService es = Executors.newSingleThreadExecutor();
es.execute(new Runnable() { es.execute(new Runnable() {
@Override @Override
@ -613,15 +598,14 @@ class ReactExoplayerView extends FrameLayout implements
if (drmSessionManager == null && self.drmUUID != null) { if (drmSessionManager == null && self.drmUUID != null) {
// Failed to intialize DRM session manager - cannot continue // Failed to intialize DRM session manager - cannot continue
Log.e("ExoPlayer Exception", "Failed to initialize DRM Session Manager Framework!"); Log.e("ExoPlayer Exception", "Failed to initialize DRM Session Manager Framework!");
eventEmitter.error("Failed to initialize DRM Session Manager Framework!", eventEmitter.error("Failed to initialize DRM Session Manager Framework!", new Exception("DRM Session Manager Framework failure!"), "3003");
new Exception("DRM Session Manager Framework failure!"), "3003");
return; return;
} }
if (activity == null) { if (activity == null) {
Log.e("ExoPlayer Exception", "Failed to initialize Player!"); Log.e("ExoPlayer Exception", "Failed to initialize Player!");
eventEmitter.error("Failed to initialize Player!", eventEmitter.error("Failed to initialize Player!", new Exception("Current Activity is null!"), "1001");
new Exception("Current Activity is null!"), "1001");
return; return;
} }
@ -671,22 +655,24 @@ class ReactExoplayerView extends FrameLayout implements
-1, -1,
true, true,
backBufferDurationMs, backBufferDurationMs,
DefaultLoadControl.DEFAULT_RETAIN_BACK_BUFFER_FROM_KEYFRAME); DefaultLoadControl.DEFAULT_RETAIN_BACK_BUFFER_FROM_KEYFRAME
DefaultRenderersFactory renderersFactory = new DefaultRenderersFactory(getContext()) );
.setExtensionRendererMode(DefaultRenderersFactory.EXTENSION_RENDERER_MODE_OFF); DefaultRenderersFactory renderersFactory =
new DefaultRenderersFactory(getContext())
.setExtensionRendererMode(DefaultRenderersFactory.EXTENSION_RENDERER_MODE_OFF);
// Create an AdsLoader. // Create an AdsLoader.
adsLoader = new ImaAdsLoader.Builder(themedReactContext).setAdEventListener(this).build(); adsLoader = new ImaAdsLoader.Builder(themedReactContext).setAdEventListener(this).build();
MediaSource.Factory mediaSourceFactory = new DefaultMediaSourceFactory(mediaDataSourceFactory) MediaSource.Factory mediaSourceFactory = new DefaultMediaSourceFactory(mediaDataSourceFactory)
.setLocalAdInsertionComponents(unusedAdTagUri -> adsLoader, exoPlayerView); .setLocalAdInsertionComponents(unusedAdTagUri -> adsLoader, exoPlayerView);
player = new ExoPlayer.Builder(getContext(), renderersFactory) player = new ExoPlayer.Builder(getContext(), renderersFactory)
.setTrackSelector(self.trackSelector) .setTrackSelector(self.trackSelector)
.setBandwidthMeter(bandwidthMeter) .setBandwidthMeter(bandwidthMeter)
.setLoadControl(loadControl) .setLoadControl(loadControl)
.setMediaSourceFactory(mediaSourceFactory) .setMediaSourceFactory(mediaSourceFactory)
.build(); .build();
player.addListener(self); player.addListener(self);
exoPlayerView.setPlayer(player); exoPlayerView.setPlayer(player);
if (adsLoader != null) { if (adsLoader != null) {
@ -711,8 +697,7 @@ class ReactExoplayerView extends FrameLayout implements
} catch (UnsupportedDrmException e) { } catch (UnsupportedDrmException e) {
int errorStringId = Util.SDK_INT < 18 ? R.string.error_drm_not_supported int errorStringId = Util.SDK_INT < 18 ? R.string.error_drm_not_supported
: (e.reason == UnsupportedDrmException.REASON_UNSUPPORTED_SCHEME : (e.reason == UnsupportedDrmException.REASON_UNSUPPORTED_SCHEME
? R.string.error_drm_unsupported_scheme ? R.string.error_drm_unsupported_scheme : R.string.error_drm_unknown);
: R.string.error_drm_unknown);
eventEmitter.error(getResources().getString(errorStringId), e, "3003"); eventEmitter.error(getResources().getString(errorStringId), e, "3003");
return null; return null;
} }
@ -722,15 +707,13 @@ class ReactExoplayerView extends FrameLayout implements
private void initializePlayerSource(ReactExoplayerView self, DrmSessionManager drmSessionManager) { private void initializePlayerSource(ReactExoplayerView self, DrmSessionManager drmSessionManager) {
ArrayList<MediaSource> mediaSourceList = buildTextSources(); ArrayList<MediaSource> mediaSourceList = buildTextSources();
MediaSource videoSource = buildMediaSource(self.srcUri, self.extension, drmSessionManager, startTimeMs, MediaSource videoSource = buildMediaSource(self.srcUri, self.extension, drmSessionManager, startTimeMs, endTimeMs);
endTimeMs);
MediaSource mediaSourceWithAds = null; MediaSource mediaSourceWithAds = null;
if (adTagUrl != null) { if (adTagUrl != null) {
MediaSource.Factory mediaSourceFactory = new DefaultMediaSourceFactory(mediaDataSourceFactory) MediaSource.Factory mediaSourceFactory = new DefaultMediaSourceFactory(mediaDataSourceFactory)
.setLocalAdInsertionComponents(unusedAdTagUri -> adsLoader, exoPlayerView); .setLocalAdInsertionComponents(unusedAdTagUri -> adsLoader, exoPlayerView);
DataSpec adTagDataSpec = new DataSpec(adTagUrl); DataSpec adTagDataSpec = new DataSpec(adTagUrl);
mediaSourceWithAds = new AdsMediaSource(videoSource, adTagDataSpec, ImmutableList.of(srcUri, adTagUrl), mediaSourceWithAds = new AdsMediaSource(videoSource, adTagDataSpec, ImmutableList.of(srcUri, adTagUrl), mediaSourceFactory, adsLoader, exoPlayerView);
mediaSourceFactory, adsLoader, exoPlayerView);
} }
MediaSource mediaSource; MediaSource mediaSource;
if (mediaSourceList.size() == 0) { if (mediaSourceList.size() == 0) {
@ -746,7 +729,8 @@ class ReactExoplayerView extends FrameLayout implements
mediaSourceList.add(0, videoSource); mediaSourceList.add(0, videoSource);
} }
MediaSource[] textSourceArray = mediaSourceList.toArray( MediaSource[] textSourceArray = mediaSourceList.toArray(
new MediaSource[mediaSourceList.size()]); new MediaSource[mediaSourceList.size()]
);
mediaSource = new MergingMediaSource(textSourceArray); mediaSource = new MergingMediaSource(textSourceArray);
} }
@ -782,16 +766,15 @@ class ReactExoplayerView extends FrameLayout implements
startBufferCheckTimer(); startBufferCheckTimer();
} }
private DrmSessionManager buildDrmSessionManager(UUID uuid, String licenseUrl, String[] keyRequestPropertiesArray) private DrmSessionManager buildDrmSessionManager(UUID uuid, String licenseUrl, String[] keyRequestPropertiesArray) throws UnsupportedDrmException {
throws UnsupportedDrmException {
return buildDrmSessionManager(uuid, licenseUrl, keyRequestPropertiesArray, 0); return buildDrmSessionManager(uuid, licenseUrl, keyRequestPropertiesArray, 0);
} }
private DrmSessionManager buildDrmSessionManager(UUID uuid, String licenseUrl, String[] keyRequestPropertiesArray, private DrmSessionManager buildDrmSessionManager(UUID uuid, String licenseUrl, String[] keyRequestPropertiesArray, int retryCount) throws UnsupportedDrmException {
int retryCount) throws UnsupportedDrmException {
if (Util.SDK_INT < 18) { if (Util.SDK_INT < 18) {
return null; return null;
} }
try { try {
HttpMediaDrmCallback drmCallback = new HttpMediaDrmCallback(licenseUrl, HttpMediaDrmCallback drmCallback = new HttpMediaDrmCallback(licenseUrl,
buildHttpDataSourceFactory(false)); buildHttpDataSourceFactory(false));
@ -806,13 +789,12 @@ class ReactExoplayerView extends FrameLayout implements
mediaDrm.setPropertyString("securityLevel", "L3"); mediaDrm.setPropertyString("securityLevel", "L3");
} }
return new DefaultDrmSessionManager(uuid, mediaDrm, drmCallback, null, false, 3); return new DefaultDrmSessionManager(uuid, mediaDrm, drmCallback, null, false, 3);
} catch (UnsupportedDrmException ex) { } catch(UnsupportedDrmException ex) {
// Unsupported DRM exceptions are handled by the calling method // Unsupported DRM exceptions are handled by the calling method
throw ex; throw ex;
} catch (Exception ex) { } catch (Exception ex) {
if (retryCount < 3) { if (retryCount < 3) {
// Attempt retry 3 times in case where the OS Media DRM Framework fails for // Attempt retry 3 times in case where the OS Media DRM Framework fails for whatever reason
// whatever reason
return buildDrmSessionManager(uuid, licenseUrl, keyRequestPropertiesArray, ++retryCount); return buildDrmSessionManager(uuid, licenseUrl, keyRequestPropertiesArray, ++retryCount);
} }
// Handle the unknow exception and emit to JS // Handle the unknow exception and emit to JS
@ -821,8 +803,7 @@ class ReactExoplayerView extends FrameLayout implements
} }
} }
private MediaSource buildMediaSource(Uri uri, String overrideExtension, DrmSessionManager drmSessionManager, private MediaSource buildMediaSource(Uri uri, String overrideExtension, DrmSessionManager drmSessionManager, long startTimeMs, long endTimeMs) {
long startTimeMs, long endTimeMs) {
if (uri == null) { if (uri == null) {
throw new IllegalStateException("Invalid video uri"); throw new IllegalStateException("Invalid video uri");
} }
@ -834,7 +815,8 @@ class ReactExoplayerView extends FrameLayout implements
if (adTagUrl != null) { if (adTagUrl != null) {
mediaItemBuilder.setAdsConfiguration( mediaItemBuilder.setAdsConfiguration(
new MediaItem.AdsConfiguration.Builder(adTagUrl).build()); new MediaItem.AdsConfiguration.Builder(adTagUrl).build()
);
} }
MediaItem mediaItem = mediaItemBuilder.build(); MediaItem mediaItem = mediaItemBuilder.build();
@ -854,39 +836,44 @@ class ReactExoplayerView extends FrameLayout implements
case CONTENT_TYPE_SS: case CONTENT_TYPE_SS:
mediaSource = new SsMediaSource.Factory( mediaSource = new SsMediaSource.Factory(
new DefaultSsChunkSource.Factory(mediaDataSourceFactory), new DefaultSsChunkSource.Factory(mediaDataSourceFactory),
buildDataSourceFactory(false)).setDrmSessionManagerProvider(drmProvider) buildDataSourceFactory(false)
.setLoadErrorHandlingPolicy( ).setDrmSessionManagerProvider(drmProvider)
config.buildLoadErrorHandlingPolicy(minLoadRetryCount)) .setLoadErrorHandlingPolicy(
.createMediaSource(mediaItem); config.buildLoadErrorHandlingPolicy(minLoadRetryCount)
).createMediaSource(mediaItem);
break; break;
case CONTENT_TYPE_DASH: case CONTENT_TYPE_DASH:
mediaSource = new DashMediaSource.Factory( mediaSource = new DashMediaSource.Factory(
new DefaultDashChunkSource.Factory(mediaDataSourceFactory), new DefaultDashChunkSource.Factory(mediaDataSourceFactory),
buildDataSourceFactory(false)).setDrmSessionManagerProvider(drmProvider) buildDataSourceFactory(false)
.setLoadErrorHandlingPolicy( ).setDrmSessionManagerProvider(drmProvider)
config.buildLoadErrorHandlingPolicy(minLoadRetryCount)) .setLoadErrorHandlingPolicy(
.createMediaSource(mediaItem); config.buildLoadErrorHandlingPolicy(minLoadRetryCount)
).createMediaSource(mediaItem);
break; break;
case CONTENT_TYPE_HLS: case CONTENT_TYPE_HLS:
mediaSource = new HlsMediaSource.Factory( mediaSource = new HlsMediaSource.Factory(
mediaDataSourceFactory).setDrmSessionManagerProvider(drmProvider) mediaDataSourceFactory
.setLoadErrorHandlingPolicy( ).setDrmSessionManagerProvider(drmProvider)
config.buildLoadErrorHandlingPolicy(minLoadRetryCount)) .setLoadErrorHandlingPolicy(
.createMediaSource(mediaItem); config.buildLoadErrorHandlingPolicy(minLoadRetryCount)
).createMediaSource(mediaItem);
break; break;
case CONTENT_TYPE_OTHER: case CONTENT_TYPE_OTHER:
mediaSource = new ProgressiveMediaSource.Factory( mediaSource = new ProgressiveMediaSource.Factory(
mediaDataSourceFactory).setDrmSessionManagerProvider(drmProvider) mediaDataSourceFactory
.setLoadErrorHandlingPolicy( ).setDrmSessionManagerProvider(drmProvider)
config.buildLoadErrorHandlingPolicy(minLoadRetryCount)) .setLoadErrorHandlingPolicy(
.createMediaSource(mediaItem); config.buildLoadErrorHandlingPolicy(minLoadRetryCount)
).createMediaSource(mediaItem);
break; break;
default: { default: {
throw new IllegalStateException("Unsupported type: " + type); throw new IllegalStateException("Unsupported type: " + type);
} }
} }
if (startTimeMs >= 0 && endTimeMs >= 0) { if (startTimeMs >= 0 && endTimeMs >= 0)
{
return new ClippingMediaSource(mediaSource, startTimeMs * 1000, endTimeMs * 1000); return new ClippingMediaSource(mediaSource, startTimeMs * 1000, endTimeMs * 1000);
} else if (startTimeMs >= 0) { } else if (startTimeMs >= 0) {
return new ClippingMediaSource(mediaSource, startTimeMs * 1000, TIME_END_OF_SOURCE); return new ClippingMediaSource(mediaSource, startTimeMs * 1000, TIME_END_OF_SOURCE);
@ -907,8 +894,7 @@ class ReactExoplayerView extends FrameLayout implements
ReadableMap textTrack = textTracks.getMap(i); ReadableMap textTrack = textTracks.getMap(i);
String language = textTrack.getString("language"); String language = textTrack.getString("language");
String title = textTrack.hasKey("title") String title = textTrack.hasKey("title")
? textTrack.getString("title") ? textTrack.getString("title") : language + " " + i;
: language + " " + i;
Uri uri = Uri.parse(textTrack.getString("uri")); Uri uri = Uri.parse(textTrack.getString("uri"));
MediaSource textSource = buildTextSource(title, uri, textTrack.getString("type"), MediaSource textSource = buildTextSource(title, uri, textTrack.getString("type"),
language); language);
@ -1082,8 +1068,7 @@ class ReactExoplayerView extends FrameLayout implements
/** /**
* Returns a new DataSource factory. * Returns a new DataSource factory.
* *
* @param useBandwidthMeter Whether to set {@link #bandwidthMeter} as a listener * @param useBandwidthMeter Whether to set {@link #bandwidthMeter} as a listener to the new
* to the new
* DataSource factory. * DataSource factory.
* @return A new DataSource factory. * @return A new DataSource factory.
*/ */
@ -1095,16 +1080,16 @@ class ReactExoplayerView extends FrameLayout implements
/** /**
* Returns a new HttpDataSource factory. * Returns a new HttpDataSource factory.
* *
* @param useBandwidthMeter Whether to set {@link #bandwidthMeter} as a listener * @param useBandwidthMeter Whether to set {@link #bandwidthMeter} as a listener to the new
* to the new * DataSource factory.
* DataSource factory.
* @return A new HttpDataSource factory. * @return A new HttpDataSource factory.
*/ */
private HttpDataSource.Factory buildHttpDataSourceFactory(boolean useBandwidthMeter) { private HttpDataSource.Factory buildHttpDataSourceFactory(boolean useBandwidthMeter) {
return DataSourceUtil.getDefaultHttpDataSourceFactory(this.themedReactContext, return DataSourceUtil.getDefaultHttpDataSourceFactory(this.themedReactContext, useBandwidthMeter ? bandwidthMeter : null, requestHeaders);
useBandwidthMeter ? bandwidthMeter : null, requestHeaders);
} }
// AudioBecomingNoisyListener implementation // AudioBecomingNoisyListener implementation
@Override @Override
@ -1121,8 +1106,7 @@ class ReactExoplayerView extends FrameLayout implements
@Override @Override
public void onEvents(Player player, Player.Events events) { public void onEvents(Player player, Player.Events events) {
if (events.contains(Player.EVENT_PLAYBACK_STATE_CHANGED) if (events.contains(Player.EVENT_PLAYBACK_STATE_CHANGED) || events.contains(Player.EVENT_PLAY_WHEN_READY_CHANGED)) {
|| events.contains(Player.EVENT_PLAY_WHEN_READY_CHANGED)) {
int playbackState = player.getPlaybackState(); int playbackState = player.getPlaybackState();
boolean playWhenReady = player.getPlayWhenReady(); boolean playWhenReady = player.getPlayWhenReady();
String text = "onStateChanged: playWhenReady=" + playWhenReady + ", playbackState="; String text = "onStateChanged: playWhenReady=" + playWhenReady + ", playbackState=";
@ -1136,38 +1120,38 @@ class ReactExoplayerView extends FrameLayout implements
setKeepScreenOn(false); setKeepScreenOn(false);
} }
break; break;
case Player.STATE_BUFFERING: case Player.STATE_BUFFERING:
text += "buffering"; text += "buffering";
onBuffering(true); onBuffering(true);
clearProgressMessageHandler(); clearProgressMessageHandler();
setKeepScreenOn(preventsDisplaySleepDuringVideoPlayback); setKeepScreenOn(preventsDisplaySleepDuringVideoPlayback);
break; break;
case Player.STATE_READY: case Player.STATE_READY:
text += "ready"; text += "ready";
eventEmitter.ready(); eventEmitter.ready();
onBuffering(false); onBuffering(false);
clearProgressMessageHandler(); // ensure there is no other message clearProgressMessageHandler(); // ensure there is no other message
startProgressHandler(); startProgressHandler();
videoLoaded(); videoLoaded();
if (selectTrackWhenReady && isUsingContentResolution) { if (selectTrackWhenReady && isUsingContentResolution) {
selectTrackWhenReady = false; selectTrackWhenReady = false;
setSelectedTrack(C.TRACK_TYPE_VIDEO, videoTrackType, videoTrackValue); setSelectedTrack(C.TRACK_TYPE_VIDEO, videoTrackType, videoTrackValue);
} }
// Setting the visibility for the playerControlView // Setting the visibility for the playerControlView
if (playerControlView != null) { if (playerControlView != null) {
playerControlView.show(); playerControlView.show();
} }
setKeepScreenOn(preventsDisplaySleepDuringVideoPlayback); setKeepScreenOn(preventsDisplaySleepDuringVideoPlayback);
break; break;
case Player.STATE_ENDED: case Player.STATE_ENDED:
text += "ended"; text += "ended";
eventEmitter.end(); eventEmitter.end();
onStopPlayback(); onStopPlayback();
setKeepScreenOn(false); setKeepScreenOn(false);
break; break;
default: default:
text += "unknown"; text += "unknown";
break; break;
} }
} }
} }
@ -1177,14 +1161,12 @@ class ReactExoplayerView extends FrameLayout implements
} }
/* /*
* The progress message handler will duplicate recursions of the The progress message handler will duplicate recursions of the onProgressMessage handler
* onProgressMessage handler on change of player state from any state to STATE_READY with playWhenReady is true (when
* on change of player state from any state to STATE_READY with playWhenReady is the video is not paused). This clears all existing messages.
* true (when
* the video is not paused). This clears all existing messages.
*/ */
private void clearProgressMessageHandler() { private void clearProgressMessageHandler() {
progressHandler.removeMessages(SHOW_PROGRESS); progressHandler.removeMessages(SHOW_PROGRESS);
} }
private void videoLoaded() { private void videoLoaded() {
@ -1208,21 +1190,20 @@ class ReactExoplayerView extends FrameLayout implements
long duration = player.getDuration(); long duration = player.getDuration();
long currentPosition = player.getCurrentPosition(); long currentPosition = player.getCurrentPosition();
ArrayList<Track> audioTracks = getAudioTrackInfo(); ArrayList<Track> audioTracks = getAudioTrackInfo();
ArrayList<Track> textTracks = getTextTrackInfo(); ArrayList<Track> textTracks = getTextTrackInfo();
if (this.contentStartTime != -1L) { 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 // To prevent ANRs caused by getVideoTrackInfo we run this on a different thread and notify the player only when we're done
// and notify the player only when we're done
ArrayList<VideoTrack> videoTracks = getVideoTrackInfoFromManifest(); ArrayList<VideoTrack> videoTracks = getVideoTrackInfoFromManifest();
if (videoTracks != null) { if (videoTracks != null) {
isUsingContentResolution = true; isUsingContentResolution = true;
} }
eventEmitter.load(duration, currentPosition, width, height, eventEmitter.load(duration, currentPosition, width, height,
audioTracks, textTracks, videoTracks, trackId); audioTracks, textTracks, videoTracks, trackId );
} }
}); });
@ -1237,10 +1218,11 @@ class ReactExoplayerView extends FrameLayout implements
} }
private static boolean isTrackSelected(TrackSelection selection, TrackGroup group, private static boolean isTrackSelected(TrackSelection selection, TrackGroup group,
int trackIndex) { int trackIndex){
return selection != null && selection.getTrackGroup() == group return selection != null && selection.getTrackGroup() == group
&& selection.indexOf(trackIndex) != C.INDEX_UNSET; && selection.indexOf( trackIndex ) != C.INDEX_UNSET;
} }
private ArrayList<Track> getAudioTrackInfo() { private ArrayList<Track> getAudioTrackInfo() {
ArrayList<Track> audioTracks = new ArrayList<>(); ArrayList<Track> audioTracks = new ArrayList<>();
@ -1256,7 +1238,7 @@ class ReactExoplayerView extends FrameLayout implements
} }
TrackGroupArray groups = info.getTrackGroups(index); TrackGroupArray groups = info.getTrackGroups(index);
TrackSelectionArray selectionArray = player.getCurrentTrackSelections(); TrackSelectionArray selectionArray = player.getCurrentTrackSelections();
TrackSelection selection = selectionArray.get(C.TRACK_TYPE_AUDIO); TrackSelection selection = selectionArray.get( C.TRACK_TYPE_AUDIO );
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);
@ -1267,7 +1249,7 @@ class ReactExoplayerView extends FrameLayout implements
audioTrack.m_mimeType = format.sampleMimeType; audioTrack.m_mimeType = format.sampleMimeType;
audioTrack.m_language = format.language != null ? format.language : ""; audioTrack.m_language = format.language != null ? format.language : "";
audioTrack.m_bitrate = format.bitrate == Format.NO_VALUE ? 0 : format.bitrate; audioTrack.m_bitrate = format.bitrate == Format.NO_VALUE ? 0 : format.bitrate;
audioTrack.m_isSelected = isTrackSelected(selection, group, 0); audioTrack.m_isSelected = isTrackSelected(selection, group, 0 );
audioTracks.add(audioTrack); audioTracks.add(audioTrack);
} }
return audioTracks; return audioTracks;
@ -1309,8 +1291,7 @@ class ReactExoplayerView extends FrameLayout implements
return this.getVideoTrackInfoFromManifest(0); return this.getVideoTrackInfoFromManifest(0);
} }
// We need retry count to in case where minefest request fails from poor network // We need retry count to in case where minefest request fails from poor network conditions
// conditions
@WorkerThread @WorkerThread
private ArrayList<VideoTrack> getVideoTrackInfoFromManifest(int retryCount) { private ArrayList<VideoTrack> getVideoTrackInfoFromManifest(int retryCount) {
ExecutorService es = Executors.newSingleThreadExecutor(); ExecutorService es = Executors.newSingleThreadExecutor();
@ -1325,20 +1306,18 @@ class ReactExoplayerView extends FrameLayout implements
public ArrayList<VideoTrack> call() throws Exception { public ArrayList<VideoTrack> call() throws Exception {
ArrayList<VideoTrack> videoTracks = new ArrayList<>(); 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();
for (int i = 0; i < periodCount; i++) { for (int i = 0; i < periodCount; i++) {
Period period = manifest.getPeriod(i); Period period = manifest.getPeriod(i);
for (int adaptationIndex = 0; adaptationIndex < period.adaptationSets for (int adaptationIndex = 0; adaptationIndex < period.adaptationSets.size(); adaptationIndex++) {
.size(); adaptationIndex++) {
AdaptationSet adaptation = period.adaptationSets.get(adaptationIndex); AdaptationSet adaptation = period.adaptationSets.get(adaptationIndex);
if (adaptation.type != C.TRACK_TYPE_VIDEO) { if (adaptation.type != C.TRACK_TYPE_VIDEO) {
continue; continue;
} }
boolean hasFoundContentPeriod = false; boolean hasFoundContentPeriod = false;
for (int representationIndex = 0; representationIndex < adaptation.representations for (int representationIndex = 0; representationIndex < adaptation.representations.size(); representationIndex++) {
.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 (isFormatSupported(format)) {
@ -1351,8 +1330,7 @@ class ReactExoplayerView extends FrameLayout implements
videoTrack.m_height = format.height == Format.NO_VALUE ? 0 : format.height; videoTrack.m_height = format.height == Format.NO_VALUE ? 0 : format.height;
videoTrack.m_bitrate = format.bitrate == Format.NO_VALUE ? 0 : format.bitrate; videoTrack.m_bitrate = format.bitrate == Format.NO_VALUE ? 0 : format.bitrate;
videoTrack.m_codecs = format.codecs != null ? format.codecs : ""; videoTrack.m_codecs = format.codecs != null ? format.codecs : "";
videoTrack.m_trackId = format.id == null ? String.valueOf(representationIndex) videoTrack.m_trackId = format.id == null ? String.valueOf(representationIndex) : format.id;
: format.id;
videoTracks.add(videoTrack); videoTracks.add(videoTrack);
} }
} }
@ -1361,8 +1339,7 @@ class ReactExoplayerView extends FrameLayout implements
} }
} }
} }
} catch (Exception e) { } catch (Exception e) {}
}
return null; return null;
} }
}); });
@ -1374,8 +1351,7 @@ class ReactExoplayerView extends FrameLayout implements
} }
es.shutdown(); es.shutdown();
return results; return results;
} catch (Exception e) { } catch (Exception e) {}
}
return null; return null;
} }
@ -1391,7 +1367,7 @@ class ReactExoplayerView extends FrameLayout implements
return textTracks; return textTracks;
} }
TrackSelectionArray selectionArray = player.getCurrentTrackSelections(); TrackSelectionArray selectionArray = player.getCurrentTrackSelections();
TrackSelection selection = selectionArray.get(C.TRACK_TYPE_VIDEO); 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) {
@ -1403,7 +1379,7 @@ class ReactExoplayerView extends FrameLayout implements
textTrack.m_title = format.id != null ? format.id : ""; textTrack.m_title = format.id != null ? format.id : "";
textTrack.m_mimeType = format.sampleMimeType; textTrack.m_mimeType = format.sampleMimeType;
textTrack.m_language = format.language != null ? format.language : ""; textTrack.m_language = format.language != null ? format.language : "";
textTrack.m_isSelected = isTrackSelected(selection, group, 0); textTrack.m_isSelected = isTrackSelected(selection, group, 0 );
textTracks.add(textTrack); textTracks.add(textTrack);
} }
return textTracks; return textTracks;
@ -1425,21 +1401,17 @@ class ReactExoplayerView extends FrameLayout implements
@Override @Override
public void onPositionDiscontinuity(Player.PositionInfo oldPosition, Player.PositionInfo newPosition, int reason) { public void onPositionDiscontinuity(Player.PositionInfo oldPosition, Player.PositionInfo newPosition, int reason) {
if (playerNeedsSource) { if (playerNeedsSource) {
// This will only occur if the user has performed a seek whilst in the error // This will only occur if the user has performed a seek whilst in the error state. Update the
// state. Update the // resume position so that if the user then retries, playback will resume from the position to
// resume position so that if the user then retries, playback will resume from
// the position to
// which they seeked. // which they seeked.
updateResumePosition(); updateResumePosition();
} }
if (isUsingContentResolution) { if (isUsingContentResolution) {
// Discontinuity events might have a different track list so we update the // Discontinuity events might have a different track list so we update the selected track
// selected track
setSelectedTrack(C.TRACK_TYPE_VIDEO, videoTrackType, videoTrackValue); setSelectedTrack(C.TRACK_TYPE_VIDEO, videoTrackType, videoTrackValue);
selectTrackWhenReady = true; selectTrackWhenReady = true;
} }
// When repeat is turned on, reaching the end of the video will not cause a // When repeat is turned on, reaching the end of the video will not cause a state change
// state change
// so we need to explicitly detect it. // so we need to explicitly detect it.
if (reason == Player.DISCONTINUITY_REASON_AUTO_TRANSITION if (reason == Player.DISCONTINUITY_REASON_AUTO_TRANSITION
&& player.getRepeatMode() == Player.REPEAT_MODE_ONE) { && player.getRepeatMode() == Player.REPEAT_MODE_ONE) {
@ -1459,8 +1431,7 @@ class ReactExoplayerView extends FrameLayout implements
eventEmitter.seek(player.getCurrentPosition(), seekTime); eventEmitter.seek(player.getCurrentPosition(), seekTime);
seekTime = C.TIME_UNSET; seekTime = C.TIME_UNSET;
if (isUsingContentResolution) { if (isUsingContentResolution) {
// We need to update the selected track to make sure that it still matches user // We need to update the selected track to make sure that it still matches user selection if track list has changed in this period
// selection if track list has changed in this period
setSelectedTrack(C.TRACK_TYPE_VIDEO, videoTrackType, videoTrackValue); setSelectedTrack(C.TRACK_TYPE_VIDEO, videoTrackType, videoTrackValue);
} }
} }
@ -1501,15 +1472,14 @@ class ReactExoplayerView extends FrameLayout implements
String errorString = "ExoPlaybackException: " + PlaybackException.getErrorCodeName(e.errorCode); String errorString = "ExoPlaybackException: " + PlaybackException.getErrorCodeName(e.errorCode);
String errorCode = "2" + String.valueOf(e.errorCode); String errorCode = "2" + String.valueOf(e.errorCode);
boolean needsReInitialization = false; boolean needsReInitialization = false;
switch (e.errorCode) { switch(e.errorCode) {
case PlaybackException.ERROR_CODE_DRM_DEVICE_REVOKED: case PlaybackException.ERROR_CODE_DRM_DEVICE_REVOKED:
case PlaybackException.ERROR_CODE_DRM_LICENSE_ACQUISITION_FAILED: case PlaybackException.ERROR_CODE_DRM_LICENSE_ACQUISITION_FAILED:
case PlaybackException.ERROR_CODE_DRM_PROVISIONING_FAILED: case PlaybackException.ERROR_CODE_DRM_PROVISIONING_FAILED:
case PlaybackException.ERROR_CODE_DRM_SYSTEM_ERROR: case PlaybackException.ERROR_CODE_DRM_SYSTEM_ERROR:
case PlaybackException.ERROR_CODE_DRM_UNSPECIFIED: case PlaybackException.ERROR_CODE_DRM_UNSPECIFIED:
if (!hasDrmFailed) { if (!hasDrmFailed) {
// When DRM fails to reach the app level certificate server it will fail with a // When DRM fails to reach the app level certificate server it will fail with a source error so we assume that it is DRM related and try one more time
// source error so we assume that it is DRM related and try one more time
hasDrmFailed = true; hasDrmFailed = true;
playerNeedsSource = true; playerNeedsSource = true;
updateResumePosition(); updateResumePosition();
@ -1557,20 +1527,19 @@ class ReactExoplayerView extends FrameLayout implements
// ReactExoplayerViewManager public api // ReactExoplayerViewManager public api
public void setSrc(final Uri uri, final long startTimeMs, final long endTimeMs, final String extension, public void setSrc(final Uri uri, final long startTimeMs, final long endTimeMs, final String extension, Map<String, String> headers) {
Map<String, String> headers) {
if (uri != null) { if (uri != null) {
boolean isSourceEqual = uri.equals(srcUri) && startTimeMs == this.startTimeMs boolean isSourceEqual = uri.equals(srcUri) && startTimeMs == this.startTimeMs && endTimeMs == this.endTimeMs;
&& endTimeMs == this.endTimeMs;
hasDrmFailed = false; hasDrmFailed = false;
this.srcUri = uri; this.srcUri = uri;
this.startTimeMs = startTimeMs; this.startTimeMs = startTimeMs;
this.endTimeMs = endTimeMs; this.endTimeMs = endTimeMs;
this.extension = extension; this.extension = extension;
this.requestHeaders = headers; this.requestHeaders = headers;
this.mediaDataSourceFactory = DataSourceUtil.getDefaultDataSourceFactory(this.themedReactContext, this.mediaDataSourceFactory =
bandwidthMeter, DataSourceUtil.getDefaultDataSourceFactory(this.themedReactContext, bandwidthMeter,
this.requestHeaders); this.requestHeaders);
if (!isSourceEqual) { if (!isSourceEqual) {
reloadSource(); reloadSource();
@ -1660,8 +1629,7 @@ class ReactExoplayerView extends FrameLayout implements
} }
public void setSelectedTrack(int trackType, String type, Dynamic value) { public void setSelectedTrack(int trackType, String type, Dynamic value) {
if (player == null) if (player == null) return;
return;
int rendererIndex = getTrackRendererIndex(trackType); int rendererIndex = getTrackRendererIndex(trackType);
if (rendererIndex == C.INDEX_UNSET) { if (rendererIndex == C.INDEX_UNSET) {
return; return;
@ -1720,23 +1688,20 @@ class ReactExoplayerView extends FrameLayout implements
usingExactMatch = true; usingExactMatch = true;
break; break;
} else if (isUsingContentResolution) { } else if (isUsingContentResolution) {
// When using content resolution rather than ads, we need to try and find the // When using content resolution rather than ads, we need to try and find the closest match if there is no exact match
// closest match if there is no exact match
if (closestFormat != null) { if (closestFormat != null) {
if ((format.bitrate > closestFormat.bitrate || format.height > closestFormat.height) if ((format.bitrate > closestFormat.bitrate || format.height > closestFormat.height) && format.height < height) {
&& format.height < height) {
// Higher quality match // Higher quality match
closestFormat = format; closestFormat = format;
closestTrackIndex = j; closestTrackIndex = j;
} }
} else if (format.height < height) { } else if(format.height < height) {
closestFormat = format; closestFormat = format;
closestTrackIndex = j; closestTrackIndex = j;
} }
} }
} }
// This is a fallback if the new period contains only higher resolutions than // This is a fallback if the new period contains only higher resolutions than the user has selected
// the user has selected
if (closestFormat == null && isUsingContentResolution && !usingExactMatch) { if (closestFormat == null && isUsingContentResolution && !usingExactMatch) {
// No close match found - so we pick the lowest quality // No close match found - so we pick the lowest quality
int minHeight = Integer.MAX_VALUE; int minHeight = Integer.MAX_VALUE;
@ -1758,8 +1723,8 @@ class ReactExoplayerView extends FrameLayout implements
} }
} else if (trackType == C.TRACK_TYPE_TEXT && Util.SDK_INT > 18) { // Text default } else if (trackType == C.TRACK_TYPE_TEXT && Util.SDK_INT > 18) { // Text default
// Use system settings if possible // Use system settings if possible
CaptioningManager captioningManager = (CaptioningManager) themedReactContext CaptioningManager captioningManager
.getSystemService(Context.CAPTIONING_SERVICE); = (CaptioningManager)themedReactContext.getSystemService(Context.CAPTIONING_SERVICE);
if (captioningManager != null && captioningManager.isEnabled()) { if (captioningManager != null && captioningManager.isEnabled()) {
groupIndex = getGroupIndexForDefaultLocale(groups); groupIndex = getGroupIndexForDefaultLocale(groups);
} }
@ -1790,7 +1755,7 @@ class ReactExoplayerView extends FrameLayout implements
// With only one tracks we can't remove any tracks so attempt to play it anyway // With only one tracks we can't remove any tracks so attempt to play it anyway
tracks = allTracks; tracks = allTracks;
} else { } else {
tracks = new ArrayList<>(supportedFormatLength + 1); tracks = new ArrayList<>(supportedFormatLength + 1);
for (int k = 0; k < allTracks.size(); k++) { for (int k = 0; k < allTracks.size(); k++) {
Format format = group.getFormat(k); Format format = group.getFormat(k);
if (isFormatSupported(format)) { if (isFormatSupported(format)) {
@ -1809,11 +1774,11 @@ class ReactExoplayerView extends FrameLayout implements
TrackSelectionOverride selectionOverride = new TrackSelectionOverride(groups.get(groupIndex), tracks); TrackSelectionOverride selectionOverride = new TrackSelectionOverride(groups.get(groupIndex), tracks);
DefaultTrackSelector.Parameters selectionParameters = trackSelector.getParameters() DefaultTrackSelector.Parameters selectionParameters = trackSelector.getParameters()
.buildUpon() .buildUpon()
.setRendererDisabled(rendererIndex, false) .setRendererDisabled(rendererIndex, false)
.clearOverridesOfType(selectionOverride.getType()) .clearOverridesOfType(selectionOverride.getType())
.addOverride(selectionOverride) .addOverride(selectionOverride)
.build(); .build();
trackSelector.setParameters(selectionParameters); trackSelector.setParameters(selectionParameters);
} }
@ -1837,7 +1802,7 @@ class ReactExoplayerView extends FrameLayout implements
} }
private int getGroupIndexForDefaultLocale(TrackGroupArray groups) { private int getGroupIndexForDefaultLocale(TrackGroupArray groups) {
if (groups.length == 0) { if (groups.length == 0){
return C.INDEX_UNSET; return C.INDEX_UNSET;
} }
@ -1968,11 +1933,10 @@ class ReactExoplayerView extends FrameLayout implements
Runtime runtime = Runtime.getRuntime(); Runtime runtime = Runtime.getRuntime();
long usedMemory = runtime.totalMemory() - runtime.freeMemory(); long usedMemory = runtime.totalMemory() - runtime.freeMemory();
long freeMemory = runtime.maxMemory() - usedMemory; long freeMemory = runtime.maxMemory() - usedMemory;
long reserveMemory = (long) minBackBufferMemoryReservePercent * runtime.maxMemory(); long reserveMemory = (long)minBackBufferMemoryReservePercent * runtime.maxMemory();
if (reserveMemory > freeMemory) { if (reserveMemory > freeMemory) {
// We don't have enough memory in reserve so we will // We don't have enough memory in reserve so we will
Log.w("ExoPlayer Warning", Log.w("ExoPlayer Warning", "Not enough reserve memory, setting back buffer to 0ms to reduce memory pressure!");
"Not enough reserve memory, setting back buffer to 0ms to reduce memory pressure!");
this.backBufferDurationMs = 0; this.backBufferDurationMs = 0;
return; return;
} }
@ -1980,7 +1944,7 @@ class ReactExoplayerView extends FrameLayout implements
} }
public void setContentStartTime(int contentStartTime) { public void setContentStartTime(int contentStartTime) {
this.contentStartTime = (long) contentStartTime; this.contentStartTime = (long)contentStartTime;
} }
public void setDisableBuffering(boolean disableBuffering) { public void setDisableBuffering(boolean disableBuffering) {
@ -1991,7 +1955,7 @@ class ReactExoplayerView extends FrameLayout implements
if (playerControlView != null) { if (playerControlView != null) {
final ImageButton fullScreenButton = playerControlView.findViewById(R.id.exo_fullscreen); final ImageButton fullScreenButton = playerControlView.findViewById(R.id.exo_fullscreen);
if (controls) { if (controls) {
// Handling the fullScreenButton click event //Handling the fullScreenButton click event
if (isFullscreen && fullScreenPlayerView != null && !fullScreenPlayerView.isShowing()) { if (isFullscreen && fullScreenPlayerView != null && !fullScreenPlayerView.isShowing()) {
fullScreenButton.setVisibility(GONE); fullScreenButton.setVisibility(GONE);
} else { } else {
@ -2050,8 +2014,7 @@ class ReactExoplayerView extends FrameLayout implements
eventEmitter.fullscreenDidDismiss(); eventEmitter.fullscreenDidDismiss();
}); });
} }
// need to be done at the end to avoid hiding fullscreen control button when // need to be done at the end to avoid hiding fullscreen control button when fullScreenPlayerView is shown
// fullScreenPlayerView is shown
updateFullScreenButtonVisbility(); updateFullScreenButtonVisbility();
} }
@ -2068,9 +2031,7 @@ class ReactExoplayerView extends FrameLayout implements
exoPlayerView.setHideShutterView(hideShutterView); exoPlayerView.setHideShutterView(hideShutterView);
} }
public void setBufferConfig(int newMinBufferMs, int newMaxBufferMs, int newBufferForPlaybackMs, public void setBufferConfig(int newMinBufferMs, int newMaxBufferMs, int newBufferForPlaybackMs, int newBufferForPlaybackAfterRebufferMs, double newMaxHeapAllocationPercent, double newMinBackBufferMemoryReservePercent, double newMinBufferMemoryReservePercent) {
int newBufferForPlaybackAfterRebufferMs, double newMaxHeapAllocationPercent,
double newMinBackBufferMemoryReservePercent, double newMinBufferMemoryReservePercent) {
minBufferMs = newMinBufferMs; minBufferMs = newMinBufferMs;
maxBufferMs = newMaxBufferMs; maxBufferMs = newMaxBufferMs;
bufferForPlaybackMs = newBufferForPlaybackMs; bufferForPlaybackMs = newBufferForPlaybackMs;
@ -2086,14 +2047,15 @@ class ReactExoplayerView extends FrameLayout implements
this.drmUUID = drmType; this.drmUUID = drmType;
} }
public void setDrmLicenseUrl(String licenseUrl) { public void setDrmLicenseUrl(String licenseUrl){
this.drmLicenseUrl = licenseUrl; this.drmLicenseUrl = licenseUrl;
} }
public void setDrmLicenseHeader(String[] header) { public void setDrmLicenseHeader(String[] header){
this.drmLicenseHeader = header; this.drmLicenseHeader = header;
} }
@Override @Override
public void onDrmKeysLoaded(int windowIndex, MediaSource.MediaPeriodId mediaPeriodId) { public void onDrmKeysLoaded(int windowIndex, MediaSource.MediaPeriodId mediaPeriodId) {
Log.d("DRM Info", "onDrmKeysLoaded"); Log.d("DRM Info", "onDrmKeysLoaded");
@ -2118,7 +2080,7 @@ class ReactExoplayerView extends FrameLayout implements
/** /**
* Handling controls prop * Handling controls prop
* *
* @param controls Controls prop, if true enable controls, if false disable them * @param controls Controls prop, if true enable controls, if false disable them
*/ */
public void setControls(boolean controls) { public void setControls(boolean controls) {
this.controls = controls; this.controls = controls;

View File

@ -120,7 +120,8 @@ public class ReactExoplayerViewManager extends ViewGroupManager<ReactExoplayerVi
"ScaleNone", Integer.toString(ResizeMode.RESIZE_MODE_FIT), "ScaleNone", Integer.toString(ResizeMode.RESIZE_MODE_FIT),
"ScaleAspectFit", Integer.toString(ResizeMode.RESIZE_MODE_FIT), "ScaleAspectFit", Integer.toString(ResizeMode.RESIZE_MODE_FIT),
"ScaleToFill", Integer.toString(ResizeMode.RESIZE_MODE_FILL), "ScaleToFill", Integer.toString(ResizeMode.RESIZE_MODE_FILL),
"ScaleAspectFill", Integer.toString(ResizeMode.RESIZE_MODE_CENTER_CROP)); "ScaleAspectFill", Integer.toString(ResizeMode.RESIZE_MODE_CENTER_CROP)
);
} }
@ReactProp(name = PROP_DRM) @ReactProp(name = PROP_DRM)
@ -170,14 +171,16 @@ public class ReactExoplayerViewManager extends ViewGroupManager<ReactExoplayerVi
} }
} else { } else {
int identifier = context.getResources().getIdentifier( int identifier = context.getResources().getIdentifier(
uriString, uriString,
"drawable", "drawable",
context.getPackageName()); context.getPackageName()
);
if (identifier == 0) { if (identifier == 0) {
identifier = context.getResources().getIdentifier( identifier = context.getResources().getIdentifier(
uriString, uriString,
"raw", "raw",
context.getPackageName()); context.getPackageName()
);
} }
if (identifier > 0) { if (identifier > 0) {
Uri srcUri = RawResourceDataSource.buildRawResourceUri(identifier); Uri srcUri = RawResourceDataSource.buildRawResourceUri(identifier);
@ -201,6 +204,7 @@ public class ReactExoplayerViewManager extends ViewGroupManager<ReactExoplayerVi
videoView.setAdTagUrl(adTagUrl); videoView.setAdTagUrl(adTagUrl);
} }
@ReactProp(name = PROP_RESIZE_MODE) @ReactProp(name = PROP_RESIZE_MODE)
public void setResizeMode(final ReactExoplayerView videoView, final String resizeModeOrdinalString) { public void setResizeMode(final ReactExoplayerView videoView, final String resizeModeOrdinalString) {
videoView.setResizeModeModifier(convertToIntDef(resizeModeOrdinalString)); videoView.setResizeModeModifier(convertToIntDef(resizeModeOrdinalString));
@ -212,62 +216,55 @@ public class ReactExoplayerViewManager extends ViewGroupManager<ReactExoplayerVi
} }
@ReactProp(name = PROP_PREVENTS_DISPLAY_SLEEP_DURING_VIDEO_PLAYBACK, defaultBoolean = false) @ReactProp(name = PROP_PREVENTS_DISPLAY_SLEEP_DURING_VIDEO_PLAYBACK, defaultBoolean = false)
public void setPreventsDisplaySleepDuringVideoPlayback(final ReactExoplayerView videoView, public void setPreventsDisplaySleepDuringVideoPlayback(final ReactExoplayerView videoView, final boolean preventsSleep) {
final boolean preventsSleep) {
videoView.setPreventsDisplaySleepDuringVideoPlayback(preventsSleep); videoView.setPreventsDisplaySleepDuringVideoPlayback(preventsSleep);
} }
@ReactProp(name = PROP_SELECTED_VIDEO_TRACK) @ReactProp(name = PROP_SELECTED_VIDEO_TRACK)
public void setSelectedVideoTrack(final ReactExoplayerView videoView, public void setSelectedVideoTrack(final ReactExoplayerView videoView,
@Nullable ReadableMap selectedVideoTrack) { @Nullable ReadableMap selectedVideoTrack) {
String typeString = null; String typeString = null;
Dynamic value = null; Dynamic value = null;
if (selectedVideoTrack != null) { if (selectedVideoTrack != null) {
typeString = selectedVideoTrack.hasKey(PROP_SELECTED_VIDEO_TRACK_TYPE) typeString = selectedVideoTrack.hasKey(PROP_SELECTED_VIDEO_TRACK_TYPE)
? selectedVideoTrack.getString(PROP_SELECTED_VIDEO_TRACK_TYPE) ? selectedVideoTrack.getString(PROP_SELECTED_VIDEO_TRACK_TYPE) : null;
: null;
value = selectedVideoTrack.hasKey(PROP_SELECTED_VIDEO_TRACK_VALUE) value = selectedVideoTrack.hasKey(PROP_SELECTED_VIDEO_TRACK_VALUE)
? selectedVideoTrack.getDynamic(PROP_SELECTED_VIDEO_TRACK_VALUE) ? selectedVideoTrack.getDynamic(PROP_SELECTED_VIDEO_TRACK_VALUE) : null;
: null;
} }
videoView.setSelectedVideoTrack(typeString, value); videoView.setSelectedVideoTrack(typeString, value);
} }
@ReactProp(name = PROP_SELECTED_AUDIO_TRACK) @ReactProp(name = PROP_SELECTED_AUDIO_TRACK)
public void setSelectedAudioTrack(final ReactExoplayerView videoView, public void setSelectedAudioTrack(final ReactExoplayerView videoView,
@Nullable ReadableMap selectedAudioTrack) { @Nullable ReadableMap selectedAudioTrack) {
String typeString = null; String typeString = null;
Dynamic value = null; Dynamic value = null;
if (selectedAudioTrack != null) { if (selectedAudioTrack != null) {
typeString = selectedAudioTrack.hasKey(PROP_SELECTED_AUDIO_TRACK_TYPE) typeString = selectedAudioTrack.hasKey(PROP_SELECTED_AUDIO_TRACK_TYPE)
? selectedAudioTrack.getString(PROP_SELECTED_AUDIO_TRACK_TYPE) ? selectedAudioTrack.getString(PROP_SELECTED_AUDIO_TRACK_TYPE) : null;
: null;
value = selectedAudioTrack.hasKey(PROP_SELECTED_AUDIO_TRACK_VALUE) value = selectedAudioTrack.hasKey(PROP_SELECTED_AUDIO_TRACK_VALUE)
? selectedAudioTrack.getDynamic(PROP_SELECTED_AUDIO_TRACK_VALUE) ? selectedAudioTrack.getDynamic(PROP_SELECTED_AUDIO_TRACK_VALUE) : null;
: null;
} }
videoView.setSelectedAudioTrack(typeString, value); videoView.setSelectedAudioTrack(typeString, value);
} }
@ReactProp(name = PROP_SELECTED_TEXT_TRACK) @ReactProp(name = PROP_SELECTED_TEXT_TRACK)
public void setSelectedTextTrack(final ReactExoplayerView videoView, public void setSelectedTextTrack(final ReactExoplayerView videoView,
@Nullable ReadableMap selectedTextTrack) { @Nullable ReadableMap selectedTextTrack) {
String typeString = null; String typeString = null;
Dynamic value = null; Dynamic value = null;
if (selectedTextTrack != null) { if (selectedTextTrack != null) {
typeString = selectedTextTrack.hasKey(PROP_SELECTED_TEXT_TRACK_TYPE) typeString = selectedTextTrack.hasKey(PROP_SELECTED_TEXT_TRACK_TYPE)
? selectedTextTrack.getString(PROP_SELECTED_TEXT_TRACK_TYPE) ? selectedTextTrack.getString(PROP_SELECTED_TEXT_TRACK_TYPE) : null;
: null;
value = selectedTextTrack.hasKey(PROP_SELECTED_TEXT_TRACK_VALUE) value = selectedTextTrack.hasKey(PROP_SELECTED_TEXT_TRACK_VALUE)
? selectedTextTrack.getDynamic(PROP_SELECTED_TEXT_TRACK_VALUE) ? selectedTextTrack.getDynamic(PROP_SELECTED_TEXT_TRACK_VALUE) : null;
: null;
} }
videoView.setSelectedTextTrack(typeString, value); videoView.setSelectedTextTrack(typeString, value);
} }
@ReactProp(name = PROP_TEXT_TRACKS) @ReactProp(name = PROP_TEXT_TRACKS)
public void setPropTextTracks(final ReactExoplayerView videoView, public void setPropTextTracks(final ReactExoplayerView videoView,
@Nullable ReadableArray textTracks) { @Nullable ReadableArray textTracks) {
videoView.setTextTracks(textTracks); videoView.setTextTracks(textTracks);
} }
@ -403,30 +400,20 @@ public class ReactExoplayerViewManager extends ViewGroupManager<ReactExoplayerVi
if (bufferConfig != null) { if (bufferConfig != null) {
minBufferMs = bufferConfig.hasKey(PROP_BUFFER_CONFIG_MIN_BUFFER_MS) minBufferMs = bufferConfig.hasKey(PROP_BUFFER_CONFIG_MIN_BUFFER_MS)
? bufferConfig.getInt(PROP_BUFFER_CONFIG_MIN_BUFFER_MS) ? bufferConfig.getInt(PROP_BUFFER_CONFIG_MIN_BUFFER_MS) : minBufferMs;
: minBufferMs;
maxBufferMs = bufferConfig.hasKey(PROP_BUFFER_CONFIG_MAX_BUFFER_MS) maxBufferMs = bufferConfig.hasKey(PROP_BUFFER_CONFIG_MAX_BUFFER_MS)
? bufferConfig.getInt(PROP_BUFFER_CONFIG_MAX_BUFFER_MS) ? bufferConfig.getInt(PROP_BUFFER_CONFIG_MAX_BUFFER_MS) : maxBufferMs;
: maxBufferMs;
bufferForPlaybackMs = bufferConfig.hasKey(PROP_BUFFER_CONFIG_BUFFER_FOR_PLAYBACK_MS) bufferForPlaybackMs = bufferConfig.hasKey(PROP_BUFFER_CONFIG_BUFFER_FOR_PLAYBACK_MS)
? bufferConfig.getInt(PROP_BUFFER_CONFIG_BUFFER_FOR_PLAYBACK_MS) ? bufferConfig.getInt(PROP_BUFFER_CONFIG_BUFFER_FOR_PLAYBACK_MS) : bufferForPlaybackMs;
: bufferForPlaybackMs; bufferForPlaybackAfterRebufferMs = bufferConfig.hasKey(PROP_BUFFER_CONFIG_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS)
bufferForPlaybackAfterRebufferMs = bufferConfig ? bufferConfig.getInt(PROP_BUFFER_CONFIG_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS) : bufferForPlaybackAfterRebufferMs;
.hasKey(PROP_BUFFER_CONFIG_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS)
? bufferConfig.getInt(PROP_BUFFER_CONFIG_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS)
: bufferForPlaybackAfterRebufferMs;
maxHeapAllocationPercent = bufferConfig.hasKey(PROP_BUFFER_CONFIG_MAX_HEAP_ALLOCATION_PERCENT) maxHeapAllocationPercent = bufferConfig.hasKey(PROP_BUFFER_CONFIG_MAX_HEAP_ALLOCATION_PERCENT)
? bufferConfig.getDouble(PROP_BUFFER_CONFIG_MAX_HEAP_ALLOCATION_PERCENT) ? bufferConfig.getDouble(PROP_BUFFER_CONFIG_MAX_HEAP_ALLOCATION_PERCENT) : maxHeapAllocationPercent;
: maxHeapAllocationPercent; minBackBufferMemoryReservePercent = bufferConfig.hasKey(PROP_BUFFER_CONFIG_MIN_BACK_BUFFER_MEMORY_RESERVE_PERCENT)
minBackBufferMemoryReservePercent = bufferConfig ? bufferConfig.getDouble(PROP_BUFFER_CONFIG_MIN_BACK_BUFFER_MEMORY_RESERVE_PERCENT) : minBackBufferMemoryReservePercent;
.hasKey(PROP_BUFFER_CONFIG_MIN_BACK_BUFFER_MEMORY_RESERVE_PERCENT)
? bufferConfig.getDouble(PROP_BUFFER_CONFIG_MIN_BACK_BUFFER_MEMORY_RESERVE_PERCENT)
: minBackBufferMemoryReservePercent;
minBufferMemoryReservePercent = bufferConfig.hasKey(PROP_BUFFER_CONFIG_MIN_BUFFER_MEMORY_RESERVE_PERCENT) minBufferMemoryReservePercent = bufferConfig.hasKey(PROP_BUFFER_CONFIG_MIN_BUFFER_MEMORY_RESERVE_PERCENT)
? bufferConfig.getDouble(PROP_BUFFER_CONFIG_MIN_BUFFER_MEMORY_RESERVE_PERCENT) ? bufferConfig.getDouble(PROP_BUFFER_CONFIG_MIN_BUFFER_MEMORY_RESERVE_PERCENT) : minBufferMemoryReservePercent;
: minBufferMemoryReservePercent; videoView.setBufferConfig(minBufferMs, maxBufferMs, bufferForPlaybackMs, bufferForPlaybackAfterRebufferMs, maxHeapAllocationPercent, minBackBufferMemoryReservePercent, minBufferMemoryReservePercent);
videoView.setBufferConfig(minBufferMs, maxBufferMs, bufferForPlaybackMs, bufferForPlaybackAfterRebufferMs,
maxHeapAllocationPercent, minBackBufferMemoryReservePercent, minBufferMemoryReservePercent);
} }
} }
@ -452,8 +439,7 @@ public class ReactExoplayerViewManager extends ViewGroupManager<ReactExoplayerVi
* *
* @param readableMap The ReadableMap to be conveted. * @param readableMap The ReadableMap to be conveted.
* @return A HashMap containing the data that was in the ReadableMap. * @return A HashMap containing the data that was in the ReadableMap.
* @see 'Adapted from * @see 'Adapted from https://github.com/artemyarulin/react-native-eval/blob/master/android/src/main/java/com/evaluator/react/ConversionUtil.java'
* https://github.com/artemyarulin/react-native-eval/blob/master/android/src/main/java/com/evaluator/react/ConversionUtil.java'
*/ */
public static Map<String, String> toStringMap(@Nullable ReadableMap readableMap) { public static Map<String, String> toStringMap(@Nullable ReadableMap readableMap) {
if (readableMap == null) if (readableMap == null)