Merge branch 'master' of https://github.com/react-native-video/react-native-video into feat/add_new_events_on_tracks_changed
# Conflicts: # API.md # android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java # android/src/main/java/com/brentvatne/exoplayer/VideoEventEmitter.java # examples/basic/yarn.lock
This commit is contained in:
@@ -1,5 +1,10 @@
|
||||
package com.brentvatne.exoplayer;
|
||||
|
||||
import static com.google.android.exoplayer2.C.CONTENT_TYPE_DASH;
|
||||
import static com.google.android.exoplayer2.C.CONTENT_TYPE_HLS;
|
||||
import static com.google.android.exoplayer2.C.CONTENT_TYPE_OTHER;
|
||||
import static com.google.android.exoplayer2.C.CONTENT_TYPE_SS;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.app.ActivityManager;
|
||||
@@ -30,6 +35,7 @@ import com.facebook.react.bridge.LifecycleEventListener;
|
||||
import com.facebook.react.bridge.ReadableArray;
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
import com.facebook.react.uimanager.ThemedReactContext;
|
||||
import com.google.ads.interactivemedia.v3.api.AdEvent;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.DefaultLoadControl;
|
||||
import com.google.android.exoplayer2.DefaultRenderersFactory;
|
||||
@@ -68,11 +74,11 @@ import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
|
||||
import com.google.android.exoplayer2.trackselection.MappingTrackSelector;
|
||||
import com.google.android.exoplayer2.trackselection.ExoTrackSelection;
|
||||
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
|
||||
import com.google.android.exoplayer2.trackselection.TrackSelectionOverrides;
|
||||
import com.google.android.exoplayer2.trackselection.TrackSelectionOverrides.TrackSelectionOverride;
|
||||
import com.google.android.exoplayer2.trackselection.TrackSelectionOverride;
|
||||
import com.google.android.exoplayer2.ui.PlayerControlView;
|
||||
import com.google.android.exoplayer2.upstream.BandwidthMeter;
|
||||
import com.google.android.exoplayer2.upstream.DataSource;
|
||||
import com.google.android.exoplayer2.upstream.DataSpec;
|
||||
import com.google.android.exoplayer2.upstream.DefaultAllocator;
|
||||
import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter;
|
||||
import com.google.android.exoplayer2.upstream.HttpDataSource;
|
||||
@@ -84,6 +90,11 @@ import com.google.android.exoplayer2.source.dash.manifest.Period;
|
||||
import com.google.android.exoplayer2.source.dash.manifest.AdaptationSet;
|
||||
import com.google.android.exoplayer2.source.dash.manifest.Representation;
|
||||
|
||||
import com.google.android.exoplayer2.ext.ima.ImaAdsLoader;
|
||||
import com.google.android.exoplayer2.source.ads.AdsMediaSource;
|
||||
import com.google.android.exoplayer2.source.DefaultMediaSourceFactory;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import java.net.CookieHandler;
|
||||
import java.net.CookieManager;
|
||||
import java.net.CookiePolicy;
|
||||
@@ -107,7 +118,8 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
BandwidthMeter.EventListener,
|
||||
BecomingNoisyListener,
|
||||
AudioManager.OnAudioFocusChangeListener,
|
||||
DrmSessionEventListener {
|
||||
DrmSessionEventListener,
|
||||
AdEvent.AdEventListener {
|
||||
|
||||
public static final double DEFAULT_MAX_HEAP_ALLOCATION_PERCENT = 1;
|
||||
public static final double DEFAULT_MIN_BACK_BUFFER_MEMORY_RESERVE = 0;
|
||||
@@ -132,6 +144,7 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
|
||||
private ExoPlayerView exoPlayerView;
|
||||
private FullScreenPlayerView fullScreenPlayerView;
|
||||
private ImaAdsLoader adsLoader;
|
||||
|
||||
private DataSource.Factory mediaDataSourceFactory;
|
||||
private ExoPlayer player;
|
||||
@@ -191,6 +204,7 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
private String drmLicenseUrl = null;
|
||||
private String[] drmLicenseHeader = null;
|
||||
private boolean controls;
|
||||
private Uri adTagUrl;
|
||||
// \ End props
|
||||
|
||||
// React
|
||||
@@ -209,6 +223,9 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
switch (msg.what) {
|
||||
case SHOW_PROGRESS:
|
||||
if (player != null) {
|
||||
if (playerControlView != null && isPlayingAd() && controls) {
|
||||
playerControlView.hide();
|
||||
}
|
||||
long pos = player.getCurrentPosition();
|
||||
long bufferedDuration = player.getBufferedPercentage() * player.getDuration() / 100;
|
||||
long duration = player.getDuration();
|
||||
@@ -251,6 +268,9 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
audioBecomingNoisyReceiver = new AudioBecomingNoisyReceiver(themedReactContext);
|
||||
}
|
||||
|
||||
private boolean isPlayingAd() {
|
||||
return player != null && player.isPlayingAd();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setId(int id) {
|
||||
@@ -360,6 +380,15 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
playerControlView = new PlayerControlView(getContext());
|
||||
}
|
||||
|
||||
if (fullScreenPlayerView == null) {
|
||||
fullScreenPlayerView = new FullScreenPlayerView(getContext(), exoPlayerView, playerControlView, new OnBackPressedCallback(true) {
|
||||
@Override
|
||||
public void handleOnBackPressed() {
|
||||
setFullscreen(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Setting the player for the playerControlView
|
||||
playerControlView.setPlayer(player);
|
||||
playPauseControlContainer = playerControlView.findViewById(R.id.exo_play_pause_container);
|
||||
@@ -368,7 +397,9 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
exoPlayerView.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
togglePlayerControlVisibility();
|
||||
if (!isPlayingAd()) {
|
||||
togglePlayerControlVisibility();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -394,8 +425,9 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
});
|
||||
|
||||
//Handling the fullScreenButton click event
|
||||
ImageButton fullScreenButton = playerControlView.findViewById(R.id.exo_fullscreen);
|
||||
final ImageButton fullScreenButton = playerControlView.findViewById(R.id.exo_fullscreen);
|
||||
fullScreenButton.setOnClickListener(v -> setFullscreen(!isFullscreen));
|
||||
updateFullScreenButtonVisbility();
|
||||
|
||||
// Invoking onPlaybackStateChanged and onPlayWhenReadyChanged events for Player
|
||||
eventListener = new Player.Listener() {
|
||||
@@ -409,7 +441,6 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
if (pauseButton != null && pauseButton.getVisibility() == GONE) {
|
||||
pauseButton.setVisibility(INVISIBLE);
|
||||
}
|
||||
|
||||
reLayout(playPauseControlContainer);
|
||||
//Remove this eventListener once its executed. since UI will work fine once after the reLayout is done
|
||||
player.removeListener(eventListener);
|
||||
@@ -429,7 +460,7 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
* Adding Player control to the frame layout
|
||||
*/
|
||||
private void addPlayerControl() {
|
||||
if(player == null) return;
|
||||
if(playerControlView == null) return;
|
||||
LayoutParams layoutParams = new LayoutParams(
|
||||
LayoutParams.MATCH_PARENT,
|
||||
LayoutParams.MATCH_PARENT);
|
||||
@@ -534,6 +565,12 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
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");
|
||||
return;
|
||||
}
|
||||
|
||||
// Initialize handler to run on the main thread
|
||||
activity.runOnUiThread(new Runnable() {
|
||||
@@ -586,13 +623,22 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
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);
|
||||
|
||||
player = new ExoPlayer.Builder(getContext(), renderersFactory)
|
||||
.setTrackSelector(self.trackSelector)
|
||||
.setBandwidthMeter(bandwidthMeter)
|
||||
.setLoadControl(loadControl)
|
||||
.setMediaSourceFactory(mediaSourceFactory)
|
||||
.build();
|
||||
player.addListener(self);
|
||||
exoPlayerView.setPlayer(player);
|
||||
adsLoader.setPlayer(player);
|
||||
audioBecomingNoisyReceiver.setListener(self);
|
||||
bandwidthMeter.addEventListener(new Handler(), self);
|
||||
setPlayWhenReady(!isPaused);
|
||||
@@ -622,11 +668,26 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
private void initializePlayerSource(ReactExoplayerView self, DrmSessionManager drmSessionManager) {
|
||||
ArrayList<MediaSource> mediaSourceList = buildTextSources();
|
||||
MediaSource videoSource = buildMediaSource(self.srcUri, self.extension, drmSessionManager);
|
||||
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);
|
||||
}
|
||||
MediaSource mediaSource;
|
||||
if (mediaSourceList.size() == 0) {
|
||||
mediaSource = videoSource;
|
||||
if (mediaSourceWithAds != null) {
|
||||
mediaSource = mediaSourceWithAds;
|
||||
} else {
|
||||
mediaSource = videoSource;
|
||||
}
|
||||
} else {
|
||||
mediaSourceList.add(0, videoSource);
|
||||
if (mediaSourceWithAds != null) {
|
||||
mediaSourceList.add(0, mediaSourceWithAds);
|
||||
} else {
|
||||
mediaSourceList.add(0, videoSource);
|
||||
}
|
||||
MediaSource[] textSourceArray = mediaSourceList.toArray(
|
||||
new MediaSource[mediaSourceList.size()]
|
||||
);
|
||||
@@ -663,12 +724,6 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
setControls(controls);
|
||||
applyModifiers();
|
||||
startBufferCheckTimer();
|
||||
fullScreenPlayerView = new FullScreenPlayerView(getContext(), exoPlayerView, playerControlView, new OnBackPressedCallback(true) {
|
||||
@Override
|
||||
public void handleOnBackPressed() {
|
||||
setFullscreen(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private DrmSessionManager buildDrmSessionManager(UUID uuid, String licenseUrl, String[] keyRequestPropertiesArray) throws UnsupportedDrmException {
|
||||
@@ -714,7 +769,17 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
int type = Util.inferContentType(!TextUtils.isEmpty(overrideExtension) ? "." + overrideExtension
|
||||
: uri.getLastPathSegment());
|
||||
config.setDisableDisconnectError(this.disableDisconnectError);
|
||||
MediaItem mediaItem = new MediaItem.Builder().setUri(uri).build();
|
||||
|
||||
MediaItem.Builder mediaItemBuilder = new MediaItem.Builder().setUri(uri);
|
||||
|
||||
if (adTagUrl != null) {
|
||||
mediaItemBuilder.setAdsConfiguration(
|
||||
new MediaItem.AdsConfiguration.Builder(adTagUrl).build()
|
||||
);
|
||||
}
|
||||
|
||||
MediaItem mediaItem = mediaItemBuilder.build();
|
||||
|
||||
DrmSessionManagerProvider drmProvider = null;
|
||||
if (drmSessionManager != null) {
|
||||
drmProvider = new DrmSessionManagerProvider() {
|
||||
@@ -727,7 +792,7 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
drmProvider = new DefaultDrmSessionManagerProvider();
|
||||
}
|
||||
switch (type) {
|
||||
case C.TYPE_SS:
|
||||
case CONTENT_TYPE_SS:
|
||||
return new SsMediaSource.Factory(
|
||||
new DefaultSsChunkSource.Factory(mediaDataSourceFactory),
|
||||
buildDataSourceFactory(false)
|
||||
@@ -735,7 +800,7 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
.setLoadErrorHandlingPolicy(
|
||||
config.buildLoadErrorHandlingPolicy(minLoadRetryCount)
|
||||
).createMediaSource(mediaItem);
|
||||
case C.TYPE_DASH:
|
||||
case CONTENT_TYPE_DASH:
|
||||
return new DashMediaSource.Factory(
|
||||
new DefaultDashChunkSource.Factory(mediaDataSourceFactory),
|
||||
buildDataSourceFactory(false)
|
||||
@@ -743,14 +808,14 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
.setLoadErrorHandlingPolicy(
|
||||
config.buildLoadErrorHandlingPolicy(minLoadRetryCount)
|
||||
).createMediaSource(mediaItem);
|
||||
case C.TYPE_HLS:
|
||||
case CONTENT_TYPE_HLS:
|
||||
return new HlsMediaSource.Factory(
|
||||
mediaDataSourceFactory
|
||||
).setDrmSessionManagerProvider(drmProvider)
|
||||
.setLoadErrorHandlingPolicy(
|
||||
config.buildLoadErrorHandlingPolicy(minLoadRetryCount)
|
||||
).createMediaSource(mediaItem);
|
||||
case C.TYPE_OTHER:
|
||||
case CONTENT_TYPE_OTHER:
|
||||
return new ProgressiveMediaSource.Factory(
|
||||
mediaDataSourceFactory
|
||||
).setDrmSessionManagerProvider(drmProvider)
|
||||
@@ -798,12 +863,15 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
|
||||
private void releasePlayer() {
|
||||
if (player != null) {
|
||||
adsLoader.setPlayer(null);
|
||||
updateResumePosition();
|
||||
player.release();
|
||||
player.removeListener(this);
|
||||
trackSelector = null;
|
||||
player = null;
|
||||
}
|
||||
adsLoader.release();
|
||||
adsLoader = null;
|
||||
progressHandler.removeMessages(SHOW_PROGRESS);
|
||||
themedReactContext.removeLifecycleEventListener(this);
|
||||
audioBecomingNoisyReceiver.removeListener();
|
||||
@@ -995,6 +1063,7 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
text += "ready";
|
||||
eventEmitter.ready();
|
||||
onBuffering(false);
|
||||
clearProgressMessageHandler(); // ensure there is no other message
|
||||
startProgressHandler();
|
||||
videoLoaded();
|
||||
if (selectTrackWhenReady && isUsingContentResolution) {
|
||||
@@ -1034,7 +1103,7 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
}
|
||||
|
||||
private void videoLoaded() {
|
||||
if (loadVideoStarted) {
|
||||
if (!player.isPlayingAd() && loadVideoStarted) {
|
||||
loadVideoStarted = false;
|
||||
if (audioTrackType != null) {
|
||||
setSelectedAudioTrack(audioTrackType, audioTrackValue);
|
||||
@@ -1427,6 +1496,10 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
mReportBandwidth = reportBandwidth;
|
||||
}
|
||||
|
||||
public void setAdTagUrl(final Uri uri) {
|
||||
adTagUrl = uri;
|
||||
}
|
||||
|
||||
public void setRawSrc(final Uri uri, final String extension) {
|
||||
if (uri != null) {
|
||||
boolean isSourceEqual = uri.equals(srcUri);
|
||||
@@ -1778,6 +1851,22 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
this.disableBuffering = disableBuffering;
|
||||
}
|
||||
|
||||
private void updateFullScreenButtonVisbility() {
|
||||
if (playerControlView != null) {
|
||||
final ImageButton fullScreenButton = playerControlView.findViewById(R.id.exo_fullscreen);
|
||||
if (controls) {
|
||||
//Handling the fullScreenButton click event
|
||||
if (isFullscreen && fullScreenPlayerView != null && !fullScreenPlayerView.isShowing()) {
|
||||
fullScreenButton.setVisibility(GONE);
|
||||
} else {
|
||||
fullScreenButton.setVisibility(VISIBLE);
|
||||
}
|
||||
} else {
|
||||
fullScreenButton.setVisibility(GONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setDisableDisconnectError(boolean disableDisconnectError) {
|
||||
this.disableDisconnectError = disableDisconnectError;
|
||||
}
|
||||
@@ -1793,15 +1882,6 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
return;
|
||||
}
|
||||
|
||||
if (fullScreenPlayerView == null) {
|
||||
fullScreenPlayerView = new FullScreenPlayerView(getContext(), exoPlayerView, playerControlView, new OnBackPressedCallback(true) {
|
||||
@Override
|
||||
public void handleOnBackPressed() {
|
||||
setFullscreen(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Window window = activity.getWindow();
|
||||
View decorView = window.getDecorView();
|
||||
int uiOptions;
|
||||
@@ -1815,7 +1895,7 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
| SYSTEM_UI_FLAG_FULLSCREEN;
|
||||
}
|
||||
eventEmitter.fullscreenWillPresent();
|
||||
if (controls) {
|
||||
if (controls && fullScreenPlayerView != null) {
|
||||
fullScreenPlayerView.show();
|
||||
}
|
||||
post(() -> {
|
||||
@@ -1825,7 +1905,7 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
} else {
|
||||
uiOptions = View.SYSTEM_UI_FLAG_VISIBLE;
|
||||
eventEmitter.fullscreenWillDismiss();
|
||||
if (controls) {
|
||||
if (controls && fullScreenPlayerView != null) {
|
||||
fullScreenPlayerView.dismiss();
|
||||
reLayout(exoPlayerView);
|
||||
}
|
||||
@@ -1834,6 +1914,8 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
eventEmitter.fullscreenDidDismiss();
|
||||
});
|
||||
}
|
||||
// need to be done at the end to avoid hiding fullscreen control button when fullScreenPlayerView is shown
|
||||
updateFullScreenButtonVisbility();
|
||||
}
|
||||
|
||||
public void setUseTextureView(boolean useTextureView) {
|
||||
@@ -1902,9 +1984,9 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
*/
|
||||
public void setControls(boolean controls) {
|
||||
this.controls = controls;
|
||||
if (player == null || exoPlayerView == null) return;
|
||||
if (controls) {
|
||||
addPlayerControl();
|
||||
updateFullScreenButtonVisbility();
|
||||
} else {
|
||||
int indexOfPC = indexOfChild(playerControlView);
|
||||
if (indexOfPC != -1) {
|
||||
@@ -1916,4 +1998,9 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
public void setSubtitleStyle(SubtitleStyle style) {
|
||||
exoPlayerView.setSubtitleStyle(style);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAdEvent(AdEvent adEvent) {
|
||||
eventEmitter.receiveAdEvent(adEvent.getType().name());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user