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