feat: upgrade exoplayer to v2.17.1 (#2498)
Describe the changes Upgrade ExoPlayer to version 2.17.1 Provide an example of how to test the change Tested with a forked of react-native-video-test * Update exoplayer to v2.15.1 * feat: upgrade ExoPlayer to version 2.17.1 * chore: update CHANGELOG * remove ExoPlayerFullscreenVideoActivity * Fix build issues * Fix build & runtime issues Co-authored-by: Eran Hammer <eran@hammer.io> Co-authored-by: Armands Malejev <armands.malejevs@gmail.com>
This commit is contained in:
parent
33930c8b9c
commit
daf5e595ec
6
API.md
6
API.md
@ -1519,10 +1519,10 @@ allprojects {
|
||||
... // Various other settings go here
|
||||
|
||||
project.ext {
|
||||
compileSdkVersion = 23
|
||||
buildToolsVersion = "23.0.1"
|
||||
compileSdkVersion = 31
|
||||
buildToolsVersion = "30.0.2"
|
||||
|
||||
minSdkVersion = 16
|
||||
minSdkVersion = 21
|
||||
targetSdkVersion = 22
|
||||
}
|
||||
}
|
||||
|
@ -32,6 +32,7 @@
|
||||
- Convert iOS implementation to Swift [#2527](https://github.com/react-native-video/react-native-video/pull/2527)
|
||||
- Add iOS support for decoding offline sources [#2527](https://github.com/react-native-video/react-native-video/pull/2527)
|
||||
- Update basic example applications (React Native 0.63.4) [#2527](https://github.com/react-native-video/react-native-video/pull/2527)
|
||||
- Upgrade ExoPlayer to 2.17.1 [#2498](https://github.com/react-native-video/react-native-video/pull/2498)
|
||||
- Fix volume reset issue in exoPlayer [#2371](https://github.com/react-native-video/react-native-video/pull/2371)
|
||||
- Change WindowsTargetPlatformVersion to 10.0 [#2706](https://github.com/react-native-video/react-native-video/pull/2706)
|
||||
- Fixed Android seeking bug [#2712](https://github.com/react-native-video/react-native-video/pull/2712)
|
||||
|
@ -1598,10 +1598,10 @@ allprojects {
|
||||
... // Various other settings go here
|
||||
|
||||
project.ext {
|
||||
compileSdkVersion = 23
|
||||
buildToolsVersion = "23.0.1"
|
||||
compileSdkVersion = 31
|
||||
buildToolsVersion = "30.0.2"
|
||||
|
||||
minSdkVersion = 16
|
||||
minSdkVersion = 21
|
||||
targetSdkVersion = 22
|
||||
}
|
||||
}
|
||||
|
@ -5,8 +5,8 @@ def safeExtGet(prop, fallback) {
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion safeExtGet('compileSdkVersion', 28)
|
||||
buildToolsVersion safeExtGet('buildToolsVersion', '28.0.3')
|
||||
compileSdkVersion safeExtGet('compileSdkVersion', 31)
|
||||
buildToolsVersion safeExtGet('buildToolsVersion', '30.0.2')
|
||||
|
||||
compileOptions {
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
@ -14,7 +14,7 @@ android {
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion safeExtGet('minSdkVersion', 16)
|
||||
minSdkVersion safeExtGet('minSdkVersion', 21)
|
||||
targetSdkVersion safeExtGet('targetSdkVersion', 28)
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
@ -33,7 +33,7 @@ repositories {
|
||||
|
||||
dependencies {
|
||||
implementation "com.facebook.react:react-native:${safeExtGet('reactNativeVersion', '+')}"
|
||||
implementation('com.google.android.exoplayer:exoplayer:2.13.3') {
|
||||
implementation('com.google.android.exoplayer:exoplayer:2.17.1') {
|
||||
exclude group: 'com.android.support'
|
||||
}
|
||||
|
||||
@ -42,7 +42,7 @@ dependencies {
|
||||
implementation "androidx.core:core:1.1.0"
|
||||
implementation "androidx.media:media:1.1.0"
|
||||
|
||||
implementation('com.google.android.exoplayer:extension-okhttp:2.13.3') {
|
||||
implementation('com.google.android.exoplayer:extension-okhttp:2.17.1') {
|
||||
exclude group: 'com.squareup.okhttp3', module: 'okhttp'
|
||||
}
|
||||
implementation 'com.squareup.okhttp3:okhttp:${OKHTTP_VERSION}'
|
||||
|
@ -4,13 +4,14 @@ import com.facebook.react.bridge.ReactContext;
|
||||
import com.facebook.react.modules.network.CookieJarContainer;
|
||||
import com.facebook.react.modules.network.ForwardingCookieHandler;
|
||||
import com.facebook.react.modules.network.OkHttpClientProvider;
|
||||
import com.google.android.exoplayer2.ext.okhttp.OkHttpDataSourceFactory;
|
||||
import com.google.android.exoplayer2.ext.okhttp.OkHttpDataSource;
|
||||
import com.google.android.exoplayer2.upstream.DataSource;
|
||||
import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter;
|
||||
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
|
||||
import com.google.android.exoplayer2.upstream.DefaultDataSource;
|
||||
import com.google.android.exoplayer2.upstream.HttpDataSource;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
|
||||
import okhttp3.Call;
|
||||
import okhttp3.JavaNetCookieJar;
|
||||
import okhttp3.OkHttpClient;
|
||||
import java.util.Map;
|
||||
@ -75,7 +76,7 @@ public class DataSourceUtil {
|
||||
}
|
||||
|
||||
private static DataSource.Factory buildDataSourceFactory(ReactContext context, DefaultBandwidthMeter bandwidthMeter, Map<String, String> requestHeaders) {
|
||||
return new DefaultDataSourceFactory(context, bandwidthMeter,
|
||||
return new DefaultDataSource.Factory(context,
|
||||
buildHttpDataSourceFactory(context, bandwidthMeter, requestHeaders));
|
||||
}
|
||||
|
||||
@ -84,10 +85,12 @@ public class DataSourceUtil {
|
||||
CookieJarContainer container = (CookieJarContainer) client.cookieJar();
|
||||
ForwardingCookieHandler handler = new ForwardingCookieHandler(context);
|
||||
container.setCookieJar(new JavaNetCookieJar(handler));
|
||||
OkHttpDataSourceFactory okHttpDataSourceFactory = new OkHttpDataSourceFactory(client, getUserAgent(context), bandwidthMeter);
|
||||
OkHttpDataSource.Factory okHttpDataSourceFactory = new OkHttpDataSource.Factory((Call.Factory) client)
|
||||
.setUserAgent(getUserAgent(context))
|
||||
.setTransferListener(bandwidthMeter);
|
||||
|
||||
if (requestHeaders != null)
|
||||
okHttpDataSourceFactory.getDefaultRequestProperties().set(requestHeaders);
|
||||
okHttpDataSourceFactory.setDefaultRequestProperties(requestHeaders);
|
||||
|
||||
return okHttpDataSourceFactory;
|
||||
}
|
||||
|
@ -13,18 +13,16 @@ import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.ExoPlaybackException;
|
||||
import com.google.android.exoplayer2.ExoPlayer;
|
||||
import com.google.android.exoplayer2.PlaybackException;
|
||||
import com.google.android.exoplayer2.PlaybackParameters;
|
||||
import com.google.android.exoplayer2.SimpleExoPlayer;
|
||||
import com.google.android.exoplayer2.video.VideoListener;
|
||||
import com.google.android.exoplayer2.Player;
|
||||
import com.google.android.exoplayer2.ExoPlayer;
|
||||
import com.google.android.exoplayer2.Timeline;
|
||||
import com.google.android.exoplayer2.source.TrackGroupArray;
|
||||
import com.google.android.exoplayer2.TracksInfo;
|
||||
import com.google.android.exoplayer2.text.Cue;
|
||||
import com.google.android.exoplayer2.text.TextRenderer;
|
||||
import com.google.android.exoplayer2.text.TextOutput;
|
||||
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
|
||||
import com.google.android.exoplayer2.ui.SubtitleView;
|
||||
import com.google.android.exoplayer2.video.VideoSize;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@ -36,7 +34,7 @@ public final class ExoPlayerView extends FrameLayout {
|
||||
private final SubtitleView subtitleLayout;
|
||||
private final AspectRatioFrameLayout layout;
|
||||
private final ComponentListener componentListener;
|
||||
private SimpleExoPlayer player;
|
||||
private ExoPlayer player;
|
||||
private Context context;
|
||||
private ViewGroup.LayoutParams layoutParams;
|
||||
|
||||
@ -131,19 +129,17 @@ public final class ExoPlayerView extends FrameLayout {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link SimpleExoPlayer} to use. The {@link SimpleExoPlayer#addTextOutput} and
|
||||
* {@link SimpleExoPlayer#addVideoListener} method of the player will be called and previous
|
||||
* Set the {@link ExoPlayer} to use. The {@link ExoPlayer#addListener} method of the
|
||||
* player will be called and previous
|
||||
* assignments are overridden.
|
||||
*
|
||||
* @param player The {@link SimpleExoPlayer} to use.
|
||||
* @param player The {@link ExoPlayer} to use.
|
||||
*/
|
||||
public void setPlayer(SimpleExoPlayer player) {
|
||||
public void setPlayer(ExoPlayer player) {
|
||||
if (this.player == player) {
|
||||
return;
|
||||
}
|
||||
if (this.player != null) {
|
||||
this.player.removeTextOutput(componentListener);
|
||||
this.player.removeVideoListener(componentListener);
|
||||
this.player.removeListener(componentListener);
|
||||
clearVideoView();
|
||||
}
|
||||
@ -151,9 +147,7 @@ public final class ExoPlayerView extends FrameLayout {
|
||||
shutterView.setVisibility(this.hideShutterView ? View.INVISIBLE : View.VISIBLE);
|
||||
if (player != null) {
|
||||
setVideoView();
|
||||
player.addVideoListener(componentListener);
|
||||
player.addListener(componentListener);
|
||||
player.addTextOutput(componentListener);
|
||||
}
|
||||
}
|
||||
|
||||
@ -230,8 +224,7 @@ public final class ExoPlayerView extends FrameLayout {
|
||||
layout.invalidateAspectRatio();
|
||||
}
|
||||
|
||||
private final class ComponentListener implements VideoListener,
|
||||
TextOutput, ExoPlayer.EventListener {
|
||||
private final class ComponentListener implements Player.Listener {
|
||||
|
||||
// TextRenderer.Output implementation
|
||||
|
||||
@ -240,12 +233,12 @@ public final class ExoPlayerView extends FrameLayout {
|
||||
subtitleLayout.onCues(cues);
|
||||
}
|
||||
|
||||
// SimpleExoPlayer.VideoListener implementation
|
||||
// ExoPlayer.VideoListener implementation
|
||||
|
||||
@Override
|
||||
public void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees, float pixelWidthHeightRatio) {
|
||||
public void onVideoSizeChanged(VideoSize videoSize) {
|
||||
boolean isInitialRatio = layout.getAspectRatio() == 0;
|
||||
layout.setAspectRatio(height == 0 ? 1 : (width * pixelWidthHeightRatio) / height);
|
||||
layout.setAspectRatio(videoSize.height == 0 ? 1 : (videoSize.width * videoSize.pixelWidthHeightRatio) / videoSize.height);
|
||||
|
||||
// React native workaround for measuring and layout on initial load.
|
||||
if (isInitialRatio) {
|
||||
@ -261,32 +254,37 @@ public final class ExoPlayerView extends FrameLayout {
|
||||
// ExoPlayer.EventListener implementation
|
||||
|
||||
@Override
|
||||
public void onLoadingChanged(boolean isLoading) {
|
||||
public void onIsLoadingChanged(boolean isLoading) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
|
||||
public void onPlaybackStateChanged(int playbackState) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlayerError(ExoPlaybackException e) {
|
||||
public void onPlayWhenReadyChanged(boolean playWhenReady, int reason) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPositionDiscontinuity(int reason) {
|
||||
public void onPlayerError(PlaybackException e) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTimelineChanged(Timeline timeline, Object manifest, int reason) {
|
||||
public void onPositionDiscontinuity(Player.PositionInfo oldPosition, Player.PositionInfo newPosition, int reason) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {
|
||||
public void onTimelineChanged(Timeline timeline, int reason) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTracksInfoChanged(TracksInfo tracksInfo) {
|
||||
updateForCurrentTrackSelections();
|
||||
}
|
||||
|
||||
@ -295,11 +293,6 @@ public final class ExoPlayerView extends FrameLayout {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSeekProcessed() {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onShuffleModeEnabledChanged(boolean shuffleModeEnabled) {
|
||||
// Do nothing.
|
||||
|
@ -35,16 +35,19 @@ import com.google.android.exoplayer2.DefaultRenderersFactory;
|
||||
import com.google.android.exoplayer2.ExoPlaybackException;
|
||||
import com.google.android.exoplayer2.drm.MediaDrmCallbackException;
|
||||
import com.google.android.exoplayer2.drm.DrmSession.DrmSessionException;
|
||||
import com.google.android.exoplayer2.ExoPlayerFactory;
|
||||
import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.MediaItem;
|
||||
import com.google.android.exoplayer2.PlaybackException;
|
||||
import com.google.android.exoplayer2.PlaybackParameters;
|
||||
import com.google.android.exoplayer2.Player;
|
||||
import com.google.android.exoplayer2.SimpleExoPlayer;
|
||||
import com.google.android.exoplayer2.ExoPlayer;
|
||||
import com.google.android.exoplayer2.Timeline;
|
||||
import com.google.android.exoplayer2.TracksInfo;
|
||||
import com.google.android.exoplayer2.drm.DefaultDrmSessionManager;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionEventListener;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionManager;
|
||||
import com.google.android.exoplayer2.drm.FrameworkMediaCrypto;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionManagerProvider;
|
||||
import com.google.android.exoplayer2.drm.ExoMediaDrm;
|
||||
import com.google.android.exoplayer2.drm.FrameworkMediaDrm;
|
||||
import com.google.android.exoplayer2.drm.HttpMediaDrmCallback;
|
||||
import com.google.android.exoplayer2.drm.MediaDrmCallbackException;
|
||||
@ -53,7 +56,6 @@ import com.google.android.exoplayer2.mediacodec.MediaCodecInfo;
|
||||
import com.google.android.exoplayer2.mediacodec.MediaCodecRenderer;
|
||||
import com.google.android.exoplayer2.mediacodec.MediaCodecUtil;
|
||||
import com.google.android.exoplayer2.metadata.Metadata;
|
||||
import com.google.android.exoplayer2.metadata.MetadataOutput;
|
||||
import com.google.android.exoplayer2.source.BehindLiveWindowException;
|
||||
import com.google.android.exoplayer2.source.MediaSource;
|
||||
import com.google.android.exoplayer2.source.MergingMediaSource;
|
||||
@ -70,7 +72,8 @@ import com.google.android.exoplayer2.trackselection.AdaptiveTrackSelection;
|
||||
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.ui.PlayerControlView;
|
||||
import com.google.android.exoplayer2.upstream.BandwidthMeter;
|
||||
import com.google.android.exoplayer2.upstream.DataSource;
|
||||
@ -91,6 +94,7 @@ import java.net.CookieHandler;
|
||||
import java.net.CookieManager;
|
||||
import java.net.CookiePolicy;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.UUID;
|
||||
import java.util.Map;
|
||||
@ -108,11 +112,10 @@ import java.lang.Integer;
|
||||
@SuppressLint("ViewConstructor")
|
||||
class ReactExoplayerView extends FrameLayout implements
|
||||
LifecycleEventListener,
|
||||
Player.EventListener,
|
||||
Player.Listener,
|
||||
BandwidthMeter.EventListener,
|
||||
BecomingNoisyListener,
|
||||
AudioManager.OnAudioFocusChangeListener,
|
||||
MetadataOutput,
|
||||
DrmSessionEventListener {
|
||||
|
||||
public static final double DEFAULT_MAX_HEAP_ALLOCATION_PERCENT = 1;
|
||||
@ -134,12 +137,12 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
private final DefaultBandwidthMeter bandwidthMeter;
|
||||
private PlayerControlView playerControlView;
|
||||
private View playPauseControlContainer;
|
||||
private Player.EventListener eventListener;
|
||||
private Player.Listener eventListener;
|
||||
|
||||
private ExoPlayerView exoPlayerView;
|
||||
|
||||
private DataSource.Factory mediaDataSourceFactory;
|
||||
private SimpleExoPlayer player;
|
||||
private ExoPlayer player;
|
||||
private DefaultTrackSelector trackSelector;
|
||||
private boolean playerNeedsSource;
|
||||
|
||||
@ -202,7 +205,7 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
private final AudioManager audioManager;
|
||||
private final AudioBecomingNoisyReceiver audioBecomingNoisyReceiver;
|
||||
|
||||
private final Handler progressHandler = new Handler() {
|
||||
private final Handler progressHandler = new Handler(Looper.getMainLooper()) {
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
switch (msg.what) {
|
||||
@ -225,7 +228,7 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
public double getPositionInFirstPeriodMsForCurrentWindow(long currentPosition) {
|
||||
Timeline.Window window = new Timeline.Window();
|
||||
if(!player.getCurrentTimeline().isEmpty()) {
|
||||
player.getCurrentTimeline().getWindow(player.getCurrentWindowIndex(), window);
|
||||
player.getCurrentTimeline().getWindow(player.getCurrentMediaItemIndex(), window);
|
||||
}
|
||||
return window.windowStartTimeMs + currentPosition;
|
||||
}
|
||||
@ -385,10 +388,17 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
}
|
||||
});
|
||||
|
||||
// Invoking onPlayerStateChanged event for Player
|
||||
eventListener = new Player.EventListener() {
|
||||
// Invoking onPlaybackStateChanged and onPlayWhenReadyChanged events for Player
|
||||
eventListener = new Player.Listener() {
|
||||
@Override
|
||||
public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
|
||||
public void onPlaybackStateChanged(int playbackState) {
|
||||
reLayout(playPauseControlContainer);
|
||||
//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
|
||||
player.removeListener(eventListener);
|
||||
@ -472,7 +482,7 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
}
|
||||
|
||||
private void startBufferCheckTimer() {
|
||||
SimpleExoPlayer player = this.player;
|
||||
Player player = this.player;
|
||||
VideoEventEmitter eventEmitter = this.eventEmitter;
|
||||
Handler mainHandler = this.mainHandler;
|
||||
|
||||
@ -525,8 +535,6 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
} else if (srcUri != null) {
|
||||
initializePlayerSource(self, null);
|
||||
}
|
||||
|
||||
|
||||
} catch (Exception ex) {
|
||||
self.playerNeedsSource = true;
|
||||
Log.e("ExoPlayer Exception", "Failed to initialize Player!");
|
||||
@ -559,13 +567,12 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
DefaultRenderersFactory renderersFactory =
|
||||
new DefaultRenderersFactory(getContext())
|
||||
.setExtensionRendererMode(DefaultRenderersFactory.EXTENSION_RENDERER_MODE_OFF);
|
||||
player = new SimpleExoPlayer.Builder(getContext(), renderersFactory)
|
||||
player = new ExoPlayer.Builder(getContext(), renderersFactory)
|
||||
.setTrackSelector(self.trackSelector)
|
||||
.setBandwidthMeter(bandwidthMeter)
|
||||
.setLoadControl(loadControl)
|
||||
.build();
|
||||
player.addListener(self);
|
||||
player.addMetadataOutput(self);
|
||||
exoPlayerView.setPlayer(player);
|
||||
audioBecomingNoisyReceiver.setListener(self);
|
||||
bandwidthMeter.addEventListener(new Handler(), self);
|
||||
@ -682,37 +689,47 @@ 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();
|
||||
DrmSessionManagerProvider drmProvider = null;
|
||||
if (drmSessionManager != null) {
|
||||
drmProvider = new DrmSessionManagerProvider() {
|
||||
@Override
|
||||
public DrmSessionManager get(MediaItem mediaItem) {
|
||||
return drmSessionManager;
|
||||
}
|
||||
};
|
||||
}
|
||||
switch (type) {
|
||||
case C.TYPE_SS:
|
||||
return new SsMediaSource.Factory(
|
||||
new DefaultSsChunkSource.Factory(mediaDataSourceFactory),
|
||||
buildDataSourceFactory(false)
|
||||
).setDrmSessionManager(drmSessionManager)
|
||||
).setDrmSessionManagerProvider(drmProvider)
|
||||
.setLoadErrorHandlingPolicy(
|
||||
config.buildLoadErrorHandlingPolicy(minLoadRetryCount)
|
||||
).createMediaSource(uri);
|
||||
).createMediaSource(mediaItem);
|
||||
case C.TYPE_DASH:
|
||||
return new DashMediaSource.Factory(
|
||||
new DefaultDashChunkSource.Factory(mediaDataSourceFactory),
|
||||
buildDataSourceFactory(false)
|
||||
).setDrmSessionManager(drmSessionManager)
|
||||
).setDrmSessionManagerProvider(drmProvider)
|
||||
.setLoadErrorHandlingPolicy(
|
||||
config.buildLoadErrorHandlingPolicy(minLoadRetryCount)
|
||||
).createMediaSource(uri);
|
||||
).createMediaSource(mediaItem);
|
||||
case C.TYPE_HLS:
|
||||
return new HlsMediaSource.Factory(
|
||||
mediaDataSourceFactory
|
||||
).setDrmSessionManager(drmSessionManager)
|
||||
).setDrmSessionManagerProvider(drmProvider)
|
||||
.setLoadErrorHandlingPolicy(
|
||||
config.buildLoadErrorHandlingPolicy(minLoadRetryCount)
|
||||
).createMediaSource(uri);
|
||||
).createMediaSource(mediaItem);
|
||||
case C.TYPE_OTHER:
|
||||
return new ProgressiveMediaSource.Factory(
|
||||
mediaDataSourceFactory
|
||||
).setDrmSessionManager(drmSessionManager)
|
||||
).setDrmSessionManagerProvider(drmProvider)
|
||||
.setLoadErrorHandlingPolicy(
|
||||
config.buildLoadErrorHandlingPolicy(minLoadRetryCount)
|
||||
).createMediaSource(uri);
|
||||
).createMediaSource(mediaItem);
|
||||
default: {
|
||||
throw new IllegalStateException("Unsupported type: " + type);
|
||||
}
|
||||
@ -741,16 +758,22 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
}
|
||||
|
||||
private MediaSource buildTextSource(String title, Uri uri, String mimeType, String language) {
|
||||
Format textFormat = Format.createTextSampleFormat(title, mimeType, Format.NO_VALUE, language);
|
||||
MediaItem.SubtitleConfiguration subtitleConfiguration = new MediaItem.SubtitleConfiguration.Builder(uri)
|
||||
.setMimeType(mimeType)
|
||||
.setLanguage(language)
|
||||
.setSelectionFlags(C.SELECTION_FLAG_DEFAULT)
|
||||
.setRoleFlags(C.ROLE_FLAG_SUBTITLE)
|
||||
.setLabel(title)
|
||||
.build();
|
||||
return new SingleSampleMediaSource.Factory(mediaDataSourceFactory)
|
||||
.createMediaSource(uri, textFormat, C.TIME_UNSET);
|
||||
.createMediaSource(subtitleConfiguration, C.TIME_UNSET);
|
||||
}
|
||||
|
||||
private void releasePlayer() {
|
||||
if (player != null) {
|
||||
updateResumePosition();
|
||||
player.release();
|
||||
player.removeMetadataOutput(this);
|
||||
player.removeListener(this);
|
||||
trackSelector = null;
|
||||
player = null;
|
||||
}
|
||||
@ -831,8 +854,8 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
}
|
||||
|
||||
private void updateResumePosition() {
|
||||
resumeWindow = player.getCurrentWindowIndex();
|
||||
resumePosition = player.isCurrentWindowSeekable() ? Math.max(0, player.getCurrentPosition())
|
||||
resumeWindow = player.getCurrentMediaItemIndex();
|
||||
resumePosition = player.isCurrentMediaItemSeekable() ? Math.max(0, player.getCurrentPosition())
|
||||
: C.TIME_UNSET;
|
||||
}
|
||||
|
||||
@ -909,22 +932,25 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
eventEmitter.audioBecomingNoisy();
|
||||
}
|
||||
|
||||
// Player.EventListener implementation
|
||||
// Player.Listener implementation
|
||||
|
||||
@Override
|
||||
public void onLoadingChanged(boolean isLoading) {
|
||||
public void onIsLoadingChanged(boolean isLoading) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
|
||||
public void onEvents(Player player, Player.Events events) {
|
||||
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=";
|
||||
switch (playbackState) {
|
||||
case Player.STATE_IDLE:
|
||||
text += "idle";
|
||||
eventEmitter.idle();
|
||||
clearProgressMessageHandler();
|
||||
if (!playWhenReady) {
|
||||
if (!player.getPlayWhenReady()) {
|
||||
setKeepScreenOn(false);
|
||||
}
|
||||
break;
|
||||
@ -960,7 +986,7 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
text += "unknown";
|
||||
break;
|
||||
}
|
||||
Log.d(TAG, text);
|
||||
}
|
||||
}
|
||||
|
||||
private void startProgressHandler() {
|
||||
@ -1178,7 +1204,7 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPositionDiscontinuity(int reason) {
|
||||
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
|
||||
@ -1192,13 +1218,18 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
}
|
||||
// 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_PERIOD_TRANSITION
|
||||
if (reason == Player.DISCONTINUITY_REASON_AUTO_TRANSITION
|
||||
&& player.getRepeatMode() == Player.REPEAT_MODE_ONE) {
|
||||
eventEmitter.end();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTimelineChanged(Timeline timeline, int reason) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlaybackStateChanged(int playbackState) {
|
||||
if (playbackState == Player.STATE_READY && seekTime != C.TIME_UNSET) {
|
||||
@ -1211,11 +1242,6 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTimelineChanged(Timeline timeline, Object manifest, int reason) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onShuffleModeEnabledChanged(boolean shuffleModeEnabled) {
|
||||
// Do nothing.
|
||||
@ -1227,8 +1253,8 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {
|
||||
// Do Nothing.
|
||||
public void onTracksInfoChanged(TracksInfo tracksInfo) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -1242,74 +1268,19 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlayerError(ExoPlaybackException e) {
|
||||
String errorString = "ExoPlaybackException type : " + e.type;
|
||||
String errorCode = "2001"; // Playback error code 2xxx (2001 - unknown playback exception)
|
||||
public void onPlayerError(PlaybackException e) {
|
||||
if (e == null) {
|
||||
return;
|
||||
}
|
||||
String errorString = "ExoPlaybackException: " + PlaybackException.getErrorCodeName(e.errorCode);
|
||||
String errorCode = "2" + String.valueOf(e.errorCode);
|
||||
boolean needsReInitialization = false;
|
||||
Exception ex = e;
|
||||
if (e.type == ExoPlaybackException.TYPE_RENDERER) {
|
||||
Exception cause = e.getRendererException();
|
||||
if (cause instanceof MediaCodecRenderer.DecoderInitializationException) {
|
||||
// Special case for decoder initialization failures.
|
||||
MediaCodecRenderer.DecoderInitializationException decoderInitializationException =
|
||||
(MediaCodecRenderer.DecoderInitializationException) cause;
|
||||
if (decoderInitializationException.codecInfo == null
|
||||
|| decoderInitializationException.codecInfo.name == null) {
|
||||
if (decoderInitializationException.getCause() instanceof MediaCodecUtil.DecoderQueryException) {
|
||||
errorCode = "2011";
|
||||
errorString = getResources().getString(R.string.error_querying_decoders);
|
||||
} else if (decoderInitializationException.secureDecoderRequired) {
|
||||
errorCode = "2012";
|
||||
errorString = getResources().getString(R.string.error_no_secure_decoder,
|
||||
decoderInitializationException.mimeType);
|
||||
} else {
|
||||
errorCode = "2013";
|
||||
errorString = getResources().getString(R.string.error_no_decoder,
|
||||
decoderInitializationException.mimeType);
|
||||
}
|
||||
} else {
|
||||
errorCode = "2014";
|
||||
errorString = getResources().getString(R.string.error_instantiating_decoder,
|
||||
decoderInitializationException.codecInfo.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (e.type == ExoPlaybackException.TYPE_SOURCE) {
|
||||
// Re-initialization improves recovery speed and properly resumes
|
||||
needsReInitialization = true;
|
||||
errorString = getResources().getString(R.string.unrecognized_media_format);
|
||||
Exception cause = e.getSourceException();
|
||||
if (cause instanceof DefaultDrmSessionManager.MissingSchemeDataException) {
|
||||
errorCode = "3004";
|
||||
errorString = getResources().getString(R.string.unrecognized_media_format);
|
||||
} else if(cause instanceof MediaDrmCallbackException || cause instanceof DrmSessionException) {
|
||||
errorCode = "3005";
|
||||
errorString = getResources().getString(R.string.unrecognized_media_format);
|
||||
// DrmSessionExceptions can be caused by a lot internal reasons for failure, in most cases they can be safely retried and playback will recover
|
||||
if (!hasDrmFailed || cause instanceof DrmSessionException) {
|
||||
// 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();
|
||||
initializePlayer();
|
||||
setPlayWhenReady(true);
|
||||
return;
|
||||
}
|
||||
} else if (cause instanceof HttpDataSource.HttpDataSourceException) {
|
||||
// this exception happens when connectivity is lost
|
||||
updateResumePosition();
|
||||
initializePlayer();
|
||||
setPlayWhenReady(true);
|
||||
return;
|
||||
} else {
|
||||
errorCode = "2021";
|
||||
errorString = getResources().getString(R.string.unrecognized_media_format);
|
||||
}
|
||||
if (cause != null) {
|
||||
Throwable rootCause = cause.getCause();
|
||||
if (rootCause instanceof MediaDrmCallbackException) {
|
||||
errorCode = "3005";
|
||||
errorString = getResources().getString(R.string.unrecognized_media_format);
|
||||
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
|
||||
hasDrmFailed = true;
|
||||
@ -1319,10 +1290,11 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
setPlayWhenReady(true);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
eventEmitter.error(errorString, ex, errorCode);
|
||||
eventEmitter.error(errorString, e, errorCode);
|
||||
playerNeedsSource = true;
|
||||
if (isBehindLiveWindow(e)) {
|
||||
clearResumePosition();
|
||||
@ -1335,20 +1307,8 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isBehindLiveWindow(ExoPlaybackException e) {
|
||||
Log.e("ExoPlayer Exception", e.toString());
|
||||
if (e.type != ExoPlaybackException.TYPE_SOURCE) {
|
||||
return false;
|
||||
}
|
||||
Throwable cause = e.getSourceException();
|
||||
while (cause != null) {
|
||||
if (cause instanceof BehindLiveWindowException ||
|
||||
cause instanceof HttpDataSource.HttpDataSourceException) {
|
||||
return true;
|
||||
}
|
||||
cause = cause.getCause();
|
||||
}
|
||||
return false;
|
||||
private static boolean isBehindLiveWindow(PlaybackException e) {
|
||||
return e.errorCode == PlaybackException.ERROR_CODE_BEHIND_LIVE_WINDOW;
|
||||
}
|
||||
|
||||
public int getTrackRendererIndex(int trackType) {
|
||||
@ -1389,7 +1349,8 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
|
||||
public void clearSrc() {
|
||||
if (srcUri != null) {
|
||||
player.stop(true);
|
||||
player.stop();
|
||||
player.clearMediaItems();
|
||||
this.srcUri = null;
|
||||
this.extension = null;
|
||||
this.requestHeaders = null;
|
||||
@ -1466,7 +1427,8 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
|
||||
TrackGroupArray groups = info.getTrackGroups(rendererIndex);
|
||||
int groupIndex = C.INDEX_UNSET;
|
||||
int[] tracks = {0} ;
|
||||
List<Integer> tracks = new ArrayList<>();
|
||||
tracks.add(0);
|
||||
|
||||
if (TextUtils.isEmpty(type)) {
|
||||
type = "default";
|
||||
@ -1511,7 +1473,7 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
Format format = group.getFormat(j);
|
||||
if (format.height == height) {
|
||||
groupIndex = i;
|
||||
tracks[0] = j;
|
||||
tracks.set(0, j);
|
||||
closestFormat = null;
|
||||
closestTrackIndex = -1;
|
||||
usingExactMatch = true;
|
||||
@ -1539,7 +1501,7 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
if (format.height < minHeight) {
|
||||
minHeight = format.height;
|
||||
groupIndex = i;
|
||||
tracks[0] = j;
|
||||
tracks.set(0, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1547,7 +1509,7 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
if (closestFormat != null && closestTrackIndex != -1) {
|
||||
// We found the closest match instead of an exact one
|
||||
groupIndex = i;
|
||||
tracks[0] = closestTrackIndex;
|
||||
tracks.set(0, closestTrackIndex);
|
||||
}
|
||||
}
|
||||
} else if (trackType == C.TRACK_TYPE_TEXT && Util.SDK_INT > 18) { // Text default
|
||||
@ -1564,34 +1526,32 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
if (groupIndex == C.INDEX_UNSET && trackType == C.TRACK_TYPE_VIDEO && groups.length != 0) { // Video auto
|
||||
// Add all tracks as valid options for ABR to choose from
|
||||
TrackGroup group = groups.get(0);
|
||||
int[] allTracks = new int[group.length];
|
||||
tracks = new ArrayList<Integer>(group.length);
|
||||
ArrayList<Integer> allTracks = new ArrayList<Integer>(group.length);
|
||||
groupIndex = 0;
|
||||
|
||||
for (int j = 0; j < group.length; j++) {
|
||||
allTracks[j] = j;
|
||||
allTracks.add(j);
|
||||
}
|
||||
|
||||
// Valiate list of all tracks and add only supported formats
|
||||
int supportedFormatLength = 0;
|
||||
ArrayList<Integer> supportedTrackList = new ArrayList<Integer>();
|
||||
for (int g = 0; g < allTracks.length; g++) {
|
||||
for (int g = 0; g < allTracks.size(); g++) {
|
||||
Format format = group.getFormat(g);
|
||||
if (isFormatSupported(format)) {
|
||||
supportedFormatLength++;
|
||||
}
|
||||
}
|
||||
if (allTracks.length == 1) {
|
||||
if (allTracks.size() == 1) {
|
||||
// With only one tracks we can't remove any tracks so attempt to play it anyway
|
||||
tracks = allTracks;
|
||||
} else {
|
||||
tracks = new int[supportedFormatLength + 1];
|
||||
int o = 0;
|
||||
for (int k = 0; k < allTracks.length; k++) {
|
||||
tracks = new ArrayList<>(supportedFormatLength + 1);
|
||||
for (int k = 0; k < allTracks.size(); k++) {
|
||||
Format format = group.getFormat(k);
|
||||
if (isFormatSupported(format)) {
|
||||
tracks[o] = allTracks[k];
|
||||
supportedTrackList.add(allTracks[k]);
|
||||
o++;
|
||||
tracks.add(allTracks.get(k));
|
||||
supportedTrackList.add(allTracks.get(k));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1602,11 +1562,12 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
return;
|
||||
}
|
||||
|
||||
TrackSelectionOverride selectionOverride = new TrackSelectionOverride(groups.get(groupIndex), tracks);
|
||||
|
||||
DefaultTrackSelector.Parameters selectionParameters = trackSelector.getParameters()
|
||||
.buildUpon()
|
||||
.setRendererDisabled(rendererIndex, false)
|
||||
.setSelectionOverride(rendererIndex, groups,
|
||||
new DefaultTrackSelector.SelectionOverride(groupIndex, tracks))
|
||||
.setTrackSelectionOverrides(new TrackSelectionOverrides.Builder().addOverride(selectionOverride).build())
|
||||
.build();
|
||||
trackSelector.setParameters(selectionParameters);
|
||||
}
|
||||
@ -1694,8 +1655,8 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
|
||||
public void seekTo(long positionMs) {
|
||||
if (player != null) {
|
||||
seekTime = positionMs;
|
||||
player.seekTo(positionMs);
|
||||
eventEmitter.seek(player.getCurrentPosition(), positionMs);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,11 +5,11 @@ def safeExtGet(prop, fallback) {
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion safeExtGet('compileSdkVersion', 28)
|
||||
buildToolsVersion safeExtGet('buildToolsVersion', '28.0.3')
|
||||
compileSdkVersion safeExtGet('compileSdkVersion', 31)
|
||||
buildToolsVersion safeExtGet('buildToolsVersion', '30.0.2')
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion safeExtGet('minSdkVersion', 16)
|
||||
minSdkVersion safeExtGet('minSdkVersion', 21)
|
||||
targetSdkVersion safeExtGet('targetSdkVersion', 28)
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
|
@ -2,9 +2,9 @@
|
||||
|
||||
buildscript {
|
||||
ext {
|
||||
buildToolsVersion = "29.0.2"
|
||||
minSdkVersion = 16
|
||||
compileSdkVersion = 29
|
||||
buildToolsVersion = "30.0.2"
|
||||
minSdkVersion = 21
|
||||
compileSdkVersion = 31
|
||||
targetSdkVersion = 29
|
||||
}
|
||||
repositories {
|
||||
|
@ -94,12 +94,12 @@ def enableSeparateBuildPerCPUArchitecture = false
|
||||
def enableProguardInReleaseBuilds = false
|
||||
|
||||
android {
|
||||
compileSdkVersion 23
|
||||
buildToolsVersion "23.0.1"
|
||||
compileSdkVersion 31
|
||||
buildToolsVersion "30.0.2"
|
||||
|
||||
defaultConfig {
|
||||
applicationId "com.videocaching"
|
||||
minSdkVersion 16
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 22
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
|
@ -7,7 +7,7 @@
|
||||
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
|
||||
|
||||
<uses-sdk
|
||||
android:minSdkVersion="16"
|
||||
android:minSdkVersion="21"
|
||||
android:targetSdkVersion="22" />
|
||||
|
||||
<application
|
||||
|
Loading…
Reference in New Issue
Block a user