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
|
... // Various other settings go here
|
||||||
|
|
||||||
project.ext {
|
project.ext {
|
||||||
compileSdkVersion = 23
|
compileSdkVersion = 31
|
||||||
buildToolsVersion = "23.0.1"
|
buildToolsVersion = "30.0.2"
|
||||||
|
|
||||||
minSdkVersion = 16
|
minSdkVersion = 21
|
||||||
targetSdkVersion = 22
|
targetSdkVersion = 22
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
- Convert iOS implementation to Swift [#2527](https://github.com/react-native-video/react-native-video/pull/2527)
|
- 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)
|
- 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)
|
- 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)
|
- 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)
|
- 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)
|
- 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
|
... // Various other settings go here
|
||||||
|
|
||||||
project.ext {
|
project.ext {
|
||||||
compileSdkVersion = 23
|
compileSdkVersion = 31
|
||||||
buildToolsVersion = "23.0.1"
|
buildToolsVersion = "30.0.2"
|
||||||
|
|
||||||
minSdkVersion = 16
|
minSdkVersion = 21
|
||||||
targetSdkVersion = 22
|
targetSdkVersion = 22
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,8 +5,8 @@ def safeExtGet(prop, fallback) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion safeExtGet('compileSdkVersion', 28)
|
compileSdkVersion safeExtGet('compileSdkVersion', 31)
|
||||||
buildToolsVersion safeExtGet('buildToolsVersion', '28.0.3')
|
buildToolsVersion safeExtGet('buildToolsVersion', '30.0.2')
|
||||||
|
|
||||||
compileOptions {
|
compileOptions {
|
||||||
targetCompatibility JavaVersion.VERSION_1_8
|
targetCompatibility JavaVersion.VERSION_1_8
|
||||||
@ -14,7 +14,7 @@ android {
|
|||||||
}
|
}
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdkVersion safeExtGet('minSdkVersion', 16)
|
minSdkVersion safeExtGet('minSdkVersion', 21)
|
||||||
targetSdkVersion safeExtGet('targetSdkVersion', 28)
|
targetSdkVersion safeExtGet('targetSdkVersion', 28)
|
||||||
versionCode 1
|
versionCode 1
|
||||||
versionName "1.0"
|
versionName "1.0"
|
||||||
@ -33,7 +33,7 @@ repositories {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation "com.facebook.react:react-native:${safeExtGet('reactNativeVersion', '+')}"
|
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'
|
exclude group: 'com.android.support'
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,7 +42,7 @@ dependencies {
|
|||||||
implementation "androidx.core:core:1.1.0"
|
implementation "androidx.core:core:1.1.0"
|
||||||
implementation "androidx.media:media: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'
|
exclude group: 'com.squareup.okhttp3', module: 'okhttp'
|
||||||
}
|
}
|
||||||
implementation 'com.squareup.okhttp3:okhttp:${OKHTTP_VERSION}'
|
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.CookieJarContainer;
|
||||||
import com.facebook.react.modules.network.ForwardingCookieHandler;
|
import com.facebook.react.modules.network.ForwardingCookieHandler;
|
||||||
import com.facebook.react.modules.network.OkHttpClientProvider;
|
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.DataSource;
|
||||||
import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter;
|
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.upstream.HttpDataSource;
|
||||||
import com.google.android.exoplayer2.util.Util;
|
import com.google.android.exoplayer2.util.Util;
|
||||||
|
|
||||||
|
import okhttp3.Call;
|
||||||
import okhttp3.JavaNetCookieJar;
|
import okhttp3.JavaNetCookieJar;
|
||||||
import okhttp3.OkHttpClient;
|
import okhttp3.OkHttpClient;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -75,7 +76,7 @@ public class DataSourceUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static DataSource.Factory buildDataSourceFactory(ReactContext context, DefaultBandwidthMeter bandwidthMeter, Map<String, String> requestHeaders) {
|
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));
|
buildHttpDataSourceFactory(context, bandwidthMeter, requestHeaders));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,10 +85,12 @@ public class DataSourceUtil {
|
|||||||
CookieJarContainer container = (CookieJarContainer) client.cookieJar();
|
CookieJarContainer container = (CookieJarContainer) client.cookieJar();
|
||||||
ForwardingCookieHandler handler = new ForwardingCookieHandler(context);
|
ForwardingCookieHandler handler = new ForwardingCookieHandler(context);
|
||||||
container.setCookieJar(new JavaNetCookieJar(handler));
|
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)
|
if (requestHeaders != null)
|
||||||
okHttpDataSourceFactory.getDefaultRequestProperties().set(requestHeaders);
|
okHttpDataSourceFactory.setDefaultRequestProperties(requestHeaders);
|
||||||
|
|
||||||
return okHttpDataSourceFactory;
|
return okHttpDataSourceFactory;
|
||||||
}
|
}
|
||||||
|
@ -13,18 +13,16 @@ import android.view.ViewGroup;
|
|||||||
import android.widget.FrameLayout;
|
import android.widget.FrameLayout;
|
||||||
|
|
||||||
import com.google.android.exoplayer2.C;
|
import com.google.android.exoplayer2.C;
|
||||||
import com.google.android.exoplayer2.ExoPlaybackException;
|
import com.google.android.exoplayer2.PlaybackException;
|
||||||
import com.google.android.exoplayer2.ExoPlayer;
|
|
||||||
import com.google.android.exoplayer2.PlaybackParameters;
|
import com.google.android.exoplayer2.PlaybackParameters;
|
||||||
import com.google.android.exoplayer2.SimpleExoPlayer;
|
import com.google.android.exoplayer2.Player;
|
||||||
import com.google.android.exoplayer2.video.VideoListener;
|
import com.google.android.exoplayer2.ExoPlayer;
|
||||||
import com.google.android.exoplayer2.Timeline;
|
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.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.trackselection.TrackSelectionArray;
|
||||||
import com.google.android.exoplayer2.ui.SubtitleView;
|
import com.google.android.exoplayer2.ui.SubtitleView;
|
||||||
|
import com.google.android.exoplayer2.video.VideoSize;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -36,7 +34,7 @@ public final class ExoPlayerView extends FrameLayout {
|
|||||||
private final SubtitleView subtitleLayout;
|
private final SubtitleView subtitleLayout;
|
||||||
private final AspectRatioFrameLayout layout;
|
private final AspectRatioFrameLayout layout;
|
||||||
private final ComponentListener componentListener;
|
private final ComponentListener componentListener;
|
||||||
private SimpleExoPlayer player;
|
private ExoPlayer player;
|
||||||
private Context context;
|
private Context context;
|
||||||
private ViewGroup.LayoutParams layoutParams;
|
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
|
* Set the {@link ExoPlayer} to use. The {@link ExoPlayer#addListener} method of the
|
||||||
* {@link SimpleExoPlayer#addVideoListener} method of the player will be called and previous
|
* player will be called and previous
|
||||||
* assignments are overridden.
|
* 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) {
|
if (this.player == player) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this.player != null) {
|
if (this.player != null) {
|
||||||
this.player.removeTextOutput(componentListener);
|
|
||||||
this.player.removeVideoListener(componentListener);
|
|
||||||
this.player.removeListener(componentListener);
|
this.player.removeListener(componentListener);
|
||||||
clearVideoView();
|
clearVideoView();
|
||||||
}
|
}
|
||||||
@ -151,9 +147,7 @@ public final class ExoPlayerView extends FrameLayout {
|
|||||||
shutterView.setVisibility(this.hideShutterView ? View.INVISIBLE : View.VISIBLE);
|
shutterView.setVisibility(this.hideShutterView ? View.INVISIBLE : View.VISIBLE);
|
||||||
if (player != null) {
|
if (player != null) {
|
||||||
setVideoView();
|
setVideoView();
|
||||||
player.addVideoListener(componentListener);
|
|
||||||
player.addListener(componentListener);
|
player.addListener(componentListener);
|
||||||
player.addTextOutput(componentListener);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -230,8 +224,7 @@ public final class ExoPlayerView extends FrameLayout {
|
|||||||
layout.invalidateAspectRatio();
|
layout.invalidateAspectRatio();
|
||||||
}
|
}
|
||||||
|
|
||||||
private final class ComponentListener implements VideoListener,
|
private final class ComponentListener implements Player.Listener {
|
||||||
TextOutput, ExoPlayer.EventListener {
|
|
||||||
|
|
||||||
// TextRenderer.Output implementation
|
// TextRenderer.Output implementation
|
||||||
|
|
||||||
@ -240,12 +233,12 @@ public final class ExoPlayerView extends FrameLayout {
|
|||||||
subtitleLayout.onCues(cues);
|
subtitleLayout.onCues(cues);
|
||||||
}
|
}
|
||||||
|
|
||||||
// SimpleExoPlayer.VideoListener implementation
|
// ExoPlayer.VideoListener implementation
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees, float pixelWidthHeightRatio) {
|
public void onVideoSizeChanged(VideoSize videoSize) {
|
||||||
boolean isInitialRatio = layout.getAspectRatio() == 0;
|
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.
|
// React native workaround for measuring and layout on initial load.
|
||||||
if (isInitialRatio) {
|
if (isInitialRatio) {
|
||||||
@ -261,32 +254,37 @@ public final class ExoPlayerView extends FrameLayout {
|
|||||||
// ExoPlayer.EventListener implementation
|
// ExoPlayer.EventListener implementation
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onLoadingChanged(boolean isLoading) {
|
public void onIsLoadingChanged(boolean isLoading) {
|
||||||
// Do nothing.
|
// Do nothing.
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
|
public void onPlaybackStateChanged(int playbackState) {
|
||||||
// Do nothing.
|
// Do nothing.
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPlayerError(ExoPlaybackException e) {
|
public void onPlayWhenReadyChanged(boolean playWhenReady, int reason) {
|
||||||
// Do nothing.
|
// Do nothing.
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPositionDiscontinuity(int reason) {
|
public void onPlayerError(PlaybackException e) {
|
||||||
// Do nothing.
|
// Do nothing.
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTimelineChanged(Timeline timeline, Object manifest, int reason) {
|
public void onPositionDiscontinuity(Player.PositionInfo oldPosition, Player.PositionInfo newPosition, int reason) {
|
||||||
// Do nothing.
|
// Do nothing.
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {
|
public void onTimelineChanged(Timeline timeline, int reason) {
|
||||||
|
// Do nothing.
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTracksInfoChanged(TracksInfo tracksInfo) {
|
||||||
updateForCurrentTrackSelections();
|
updateForCurrentTrackSelections();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -295,11 +293,6 @@ public final class ExoPlayerView extends FrameLayout {
|
|||||||
// Do nothing
|
// Do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onSeekProcessed() {
|
|
||||||
// Do nothing.
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onShuffleModeEnabledChanged(boolean shuffleModeEnabled) {
|
public void onShuffleModeEnabledChanged(boolean shuffleModeEnabled) {
|
||||||
// Do nothing.
|
// Do nothing.
|
||||||
|
@ -35,16 +35,19 @@ import com.google.android.exoplayer2.DefaultRenderersFactory;
|
|||||||
import com.google.android.exoplayer2.ExoPlaybackException;
|
import com.google.android.exoplayer2.ExoPlaybackException;
|
||||||
import com.google.android.exoplayer2.drm.MediaDrmCallbackException;
|
import com.google.android.exoplayer2.drm.MediaDrmCallbackException;
|
||||||
import com.google.android.exoplayer2.drm.DrmSession.DrmSessionException;
|
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.Format;
|
||||||
|
import com.google.android.exoplayer2.MediaItem;
|
||||||
|
import com.google.android.exoplayer2.PlaybackException;
|
||||||
import com.google.android.exoplayer2.PlaybackParameters;
|
import com.google.android.exoplayer2.PlaybackParameters;
|
||||||
import com.google.android.exoplayer2.Player;
|
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.Timeline;
|
||||||
|
import com.google.android.exoplayer2.TracksInfo;
|
||||||
import com.google.android.exoplayer2.drm.DefaultDrmSessionManager;
|
import com.google.android.exoplayer2.drm.DefaultDrmSessionManager;
|
||||||
import com.google.android.exoplayer2.drm.DrmSessionEventListener;
|
import com.google.android.exoplayer2.drm.DrmSessionEventListener;
|
||||||
import com.google.android.exoplayer2.drm.DrmSessionManager;
|
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.FrameworkMediaDrm;
|
||||||
import com.google.android.exoplayer2.drm.HttpMediaDrmCallback;
|
import com.google.android.exoplayer2.drm.HttpMediaDrmCallback;
|
||||||
import com.google.android.exoplayer2.drm.MediaDrmCallbackException;
|
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.MediaCodecRenderer;
|
||||||
import com.google.android.exoplayer2.mediacodec.MediaCodecUtil;
|
import com.google.android.exoplayer2.mediacodec.MediaCodecUtil;
|
||||||
import com.google.android.exoplayer2.metadata.Metadata;
|
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.BehindLiveWindowException;
|
||||||
import com.google.android.exoplayer2.source.MediaSource;
|
import com.google.android.exoplayer2.source.MediaSource;
|
||||||
import com.google.android.exoplayer2.source.MergingMediaSource;
|
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.DefaultTrackSelector;
|
||||||
import com.google.android.exoplayer2.trackselection.MappingTrackSelector;
|
import com.google.android.exoplayer2.trackselection.MappingTrackSelector;
|
||||||
import com.google.android.exoplayer2.trackselection.ExoTrackSelection;
|
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.ui.PlayerControlView;
|
||||||
import com.google.android.exoplayer2.upstream.BandwidthMeter;
|
import com.google.android.exoplayer2.upstream.BandwidthMeter;
|
||||||
import com.google.android.exoplayer2.upstream.DataSource;
|
import com.google.android.exoplayer2.upstream.DataSource;
|
||||||
@ -91,6 +94,7 @@ import java.net.CookieHandler;
|
|||||||
import java.net.CookieManager;
|
import java.net.CookieManager;
|
||||||
import java.net.CookiePolicy;
|
import java.net.CookiePolicy;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -108,11 +112,10 @@ import java.lang.Integer;
|
|||||||
@SuppressLint("ViewConstructor")
|
@SuppressLint("ViewConstructor")
|
||||||
class ReactExoplayerView extends FrameLayout implements
|
class ReactExoplayerView extends FrameLayout implements
|
||||||
LifecycleEventListener,
|
LifecycleEventListener,
|
||||||
Player.EventListener,
|
Player.Listener,
|
||||||
BandwidthMeter.EventListener,
|
BandwidthMeter.EventListener,
|
||||||
BecomingNoisyListener,
|
BecomingNoisyListener,
|
||||||
AudioManager.OnAudioFocusChangeListener,
|
AudioManager.OnAudioFocusChangeListener,
|
||||||
MetadataOutput,
|
|
||||||
DrmSessionEventListener {
|
DrmSessionEventListener {
|
||||||
|
|
||||||
public static final double DEFAULT_MAX_HEAP_ALLOCATION_PERCENT = 1;
|
public static final double DEFAULT_MAX_HEAP_ALLOCATION_PERCENT = 1;
|
||||||
@ -134,12 +137,12 @@ class ReactExoplayerView extends FrameLayout implements
|
|||||||
private final DefaultBandwidthMeter bandwidthMeter;
|
private final DefaultBandwidthMeter bandwidthMeter;
|
||||||
private PlayerControlView playerControlView;
|
private PlayerControlView playerControlView;
|
||||||
private View playPauseControlContainer;
|
private View playPauseControlContainer;
|
||||||
private Player.EventListener eventListener;
|
private Player.Listener eventListener;
|
||||||
|
|
||||||
private ExoPlayerView exoPlayerView;
|
private ExoPlayerView exoPlayerView;
|
||||||
|
|
||||||
private DataSource.Factory mediaDataSourceFactory;
|
private DataSource.Factory mediaDataSourceFactory;
|
||||||
private SimpleExoPlayer player;
|
private ExoPlayer player;
|
||||||
private DefaultTrackSelector trackSelector;
|
private DefaultTrackSelector trackSelector;
|
||||||
private boolean playerNeedsSource;
|
private boolean playerNeedsSource;
|
||||||
|
|
||||||
@ -202,7 +205,7 @@ class ReactExoplayerView extends FrameLayout implements
|
|||||||
private final AudioManager audioManager;
|
private final AudioManager audioManager;
|
||||||
private final AudioBecomingNoisyReceiver audioBecomingNoisyReceiver;
|
private final AudioBecomingNoisyReceiver audioBecomingNoisyReceiver;
|
||||||
|
|
||||||
private final Handler progressHandler = new Handler() {
|
private final Handler progressHandler = new Handler(Looper.getMainLooper()) {
|
||||||
@Override
|
@Override
|
||||||
public void handleMessage(Message msg) {
|
public void handleMessage(Message msg) {
|
||||||
switch (msg.what) {
|
switch (msg.what) {
|
||||||
@ -225,7 +228,7 @@ class ReactExoplayerView extends FrameLayout implements
|
|||||||
public double getPositionInFirstPeriodMsForCurrentWindow(long currentPosition) {
|
public double getPositionInFirstPeriodMsForCurrentWindow(long currentPosition) {
|
||||||
Timeline.Window window = new Timeline.Window();
|
Timeline.Window window = new Timeline.Window();
|
||||||
if(!player.getCurrentTimeline().isEmpty()) {
|
if(!player.getCurrentTimeline().isEmpty()) {
|
||||||
player.getCurrentTimeline().getWindow(player.getCurrentWindowIndex(), window);
|
player.getCurrentTimeline().getWindow(player.getCurrentMediaItemIndex(), window);
|
||||||
}
|
}
|
||||||
return window.windowStartTimeMs + currentPosition;
|
return window.windowStartTimeMs + currentPosition;
|
||||||
}
|
}
|
||||||
@ -385,10 +388,17 @@ class ReactExoplayerView extends FrameLayout implements
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Invoking onPlayerStateChanged event for Player
|
// Invoking onPlaybackStateChanged and onPlayWhenReadyChanged events for Player
|
||||||
eventListener = new Player.EventListener() {
|
eventListener = new Player.Listener() {
|
||||||
@Override
|
@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);
|
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);
|
player.removeListener(eventListener);
|
||||||
@ -472,7 +482,7 @@ class ReactExoplayerView extends FrameLayout implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void startBufferCheckTimer() {
|
private void startBufferCheckTimer() {
|
||||||
SimpleExoPlayer player = this.player;
|
Player player = this.player;
|
||||||
VideoEventEmitter eventEmitter = this.eventEmitter;
|
VideoEventEmitter eventEmitter = this.eventEmitter;
|
||||||
Handler mainHandler = this.mainHandler;
|
Handler mainHandler = this.mainHandler;
|
||||||
|
|
||||||
@ -525,8 +535,6 @@ class ReactExoplayerView extends FrameLayout implements
|
|||||||
} else if (srcUri != null) {
|
} else if (srcUri != null) {
|
||||||
initializePlayerSource(self, null);
|
initializePlayerSource(self, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
self.playerNeedsSource = true;
|
self.playerNeedsSource = true;
|
||||||
Log.e("ExoPlayer Exception", "Failed to initialize Player!");
|
Log.e("ExoPlayer Exception", "Failed to initialize Player!");
|
||||||
@ -559,13 +567,12 @@ class ReactExoplayerView extends FrameLayout implements
|
|||||||
DefaultRenderersFactory renderersFactory =
|
DefaultRenderersFactory renderersFactory =
|
||||||
new DefaultRenderersFactory(getContext())
|
new DefaultRenderersFactory(getContext())
|
||||||
.setExtensionRendererMode(DefaultRenderersFactory.EXTENSION_RENDERER_MODE_OFF);
|
.setExtensionRendererMode(DefaultRenderersFactory.EXTENSION_RENDERER_MODE_OFF);
|
||||||
player = new SimpleExoPlayer.Builder(getContext(), renderersFactory)
|
player = new ExoPlayer.Builder(getContext(), renderersFactory)
|
||||||
.setTrackSelector(self.trackSelector)
|
.setTrackSelector(self.trackSelector)
|
||||||
.setBandwidthMeter(bandwidthMeter)
|
.setBandwidthMeter(bandwidthMeter)
|
||||||
.setLoadControl(loadControl)
|
.setLoadControl(loadControl)
|
||||||
.build();
|
.build();
|
||||||
player.addListener(self);
|
player.addListener(self);
|
||||||
player.addMetadataOutput(self);
|
|
||||||
exoPlayerView.setPlayer(player);
|
exoPlayerView.setPlayer(player);
|
||||||
audioBecomingNoisyReceiver.setListener(self);
|
audioBecomingNoisyReceiver.setListener(self);
|
||||||
bandwidthMeter.addEventListener(new Handler(), self);
|
bandwidthMeter.addEventListener(new Handler(), self);
|
||||||
@ -682,37 +689,47 @@ class ReactExoplayerView extends FrameLayout implements
|
|||||||
int type = Util.inferContentType(!TextUtils.isEmpty(overrideExtension) ? "." + overrideExtension
|
int type = Util.inferContentType(!TextUtils.isEmpty(overrideExtension) ? "." + overrideExtension
|
||||||
: uri.getLastPathSegment());
|
: uri.getLastPathSegment());
|
||||||
config.setDisableDisconnectError(this.disableDisconnectError);
|
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) {
|
switch (type) {
|
||||||
case C.TYPE_SS:
|
case C.TYPE_SS:
|
||||||
return new SsMediaSource.Factory(
|
return new SsMediaSource.Factory(
|
||||||
new DefaultSsChunkSource.Factory(mediaDataSourceFactory),
|
new DefaultSsChunkSource.Factory(mediaDataSourceFactory),
|
||||||
buildDataSourceFactory(false)
|
buildDataSourceFactory(false)
|
||||||
).setDrmSessionManager(drmSessionManager)
|
).setDrmSessionManagerProvider(drmProvider)
|
||||||
.setLoadErrorHandlingPolicy(
|
.setLoadErrorHandlingPolicy(
|
||||||
config.buildLoadErrorHandlingPolicy(minLoadRetryCount)
|
config.buildLoadErrorHandlingPolicy(minLoadRetryCount)
|
||||||
).createMediaSource(uri);
|
).createMediaSource(mediaItem);
|
||||||
case C.TYPE_DASH:
|
case C.TYPE_DASH:
|
||||||
return new DashMediaSource.Factory(
|
return new DashMediaSource.Factory(
|
||||||
new DefaultDashChunkSource.Factory(mediaDataSourceFactory),
|
new DefaultDashChunkSource.Factory(mediaDataSourceFactory),
|
||||||
buildDataSourceFactory(false)
|
buildDataSourceFactory(false)
|
||||||
).setDrmSessionManager(drmSessionManager)
|
).setDrmSessionManagerProvider(drmProvider)
|
||||||
.setLoadErrorHandlingPolicy(
|
.setLoadErrorHandlingPolicy(
|
||||||
config.buildLoadErrorHandlingPolicy(minLoadRetryCount)
|
config.buildLoadErrorHandlingPolicy(minLoadRetryCount)
|
||||||
).createMediaSource(uri);
|
).createMediaSource(mediaItem);
|
||||||
case C.TYPE_HLS:
|
case C.TYPE_HLS:
|
||||||
return new HlsMediaSource.Factory(
|
return new HlsMediaSource.Factory(
|
||||||
mediaDataSourceFactory
|
mediaDataSourceFactory
|
||||||
).setDrmSessionManager(drmSessionManager)
|
).setDrmSessionManagerProvider(drmProvider)
|
||||||
.setLoadErrorHandlingPolicy(
|
.setLoadErrorHandlingPolicy(
|
||||||
config.buildLoadErrorHandlingPolicy(minLoadRetryCount)
|
config.buildLoadErrorHandlingPolicy(minLoadRetryCount)
|
||||||
).createMediaSource(uri);
|
).createMediaSource(mediaItem);
|
||||||
case C.TYPE_OTHER:
|
case C.TYPE_OTHER:
|
||||||
return new ProgressiveMediaSource.Factory(
|
return new ProgressiveMediaSource.Factory(
|
||||||
mediaDataSourceFactory
|
mediaDataSourceFactory
|
||||||
).setDrmSessionManager(drmSessionManager)
|
).setDrmSessionManagerProvider(drmProvider)
|
||||||
.setLoadErrorHandlingPolicy(
|
.setLoadErrorHandlingPolicy(
|
||||||
config.buildLoadErrorHandlingPolicy(minLoadRetryCount)
|
config.buildLoadErrorHandlingPolicy(minLoadRetryCount)
|
||||||
).createMediaSource(uri);
|
).createMediaSource(mediaItem);
|
||||||
default: {
|
default: {
|
||||||
throw new IllegalStateException("Unsupported type: " + type);
|
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) {
|
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)
|
return new SingleSampleMediaSource.Factory(mediaDataSourceFactory)
|
||||||
.createMediaSource(uri, textFormat, C.TIME_UNSET);
|
.createMediaSource(subtitleConfiguration, C.TIME_UNSET);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void releasePlayer() {
|
private void releasePlayer() {
|
||||||
if (player != null) {
|
if (player != null) {
|
||||||
updateResumePosition();
|
updateResumePosition();
|
||||||
player.release();
|
player.release();
|
||||||
player.removeMetadataOutput(this);
|
player.removeListener(this);
|
||||||
trackSelector = null;
|
trackSelector = null;
|
||||||
player = null;
|
player = null;
|
||||||
}
|
}
|
||||||
@ -831,8 +854,8 @@ class ReactExoplayerView extends FrameLayout implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void updateResumePosition() {
|
private void updateResumePosition() {
|
||||||
resumeWindow = player.getCurrentWindowIndex();
|
resumeWindow = player.getCurrentMediaItemIndex();
|
||||||
resumePosition = player.isCurrentWindowSeekable() ? Math.max(0, player.getCurrentPosition())
|
resumePosition = player.isCurrentMediaItemSeekable() ? Math.max(0, player.getCurrentPosition())
|
||||||
: C.TIME_UNSET;
|
: C.TIME_UNSET;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -909,22 +932,25 @@ class ReactExoplayerView extends FrameLayout implements
|
|||||||
eventEmitter.audioBecomingNoisy();
|
eventEmitter.audioBecomingNoisy();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Player.EventListener implementation
|
// Player.Listener implementation
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onLoadingChanged(boolean isLoading) {
|
public void onIsLoadingChanged(boolean isLoading) {
|
||||||
// Do nothing.
|
// Do nothing.
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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=";
|
String text = "onStateChanged: playWhenReady=" + playWhenReady + ", playbackState=";
|
||||||
switch (playbackState) {
|
switch (playbackState) {
|
||||||
case Player.STATE_IDLE:
|
case Player.STATE_IDLE:
|
||||||
text += "idle";
|
text += "idle";
|
||||||
eventEmitter.idle();
|
eventEmitter.idle();
|
||||||
clearProgressMessageHandler();
|
clearProgressMessageHandler();
|
||||||
if (!playWhenReady) {
|
if (!player.getPlayWhenReady()) {
|
||||||
setKeepScreenOn(false);
|
setKeepScreenOn(false);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -960,7 +986,7 @@ class ReactExoplayerView extends FrameLayout implements
|
|||||||
text += "unknown";
|
text += "unknown";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Log.d(TAG, text);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void startProgressHandler() {
|
private void startProgressHandler() {
|
||||||
@ -1178,7 +1204,7 @@ class ReactExoplayerView extends FrameLayout implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPositionDiscontinuity(int reason) {
|
public void onPositionDiscontinuity(Player.PositionInfo oldPosition, Player.PositionInfo newPosition, int reason) {
|
||||||
if (playerNeedsSource) {
|
if (playerNeedsSource) {
|
||||||
// This will only occur if the user has performed a seek whilst in the error state. Update the
|
// 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
|
// 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
|
// When repeat is turned on, reaching the end of the video will not cause a state change
|
||||||
// so we need to explicitly detect it.
|
// 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) {
|
&& player.getRepeatMode() == Player.REPEAT_MODE_ONE) {
|
||||||
eventEmitter.end();
|
eventEmitter.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTimelineChanged(Timeline timeline, int reason) {
|
||||||
|
// Do nothing.
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPlaybackStateChanged(int playbackState) {
|
public void onPlaybackStateChanged(int playbackState) {
|
||||||
if (playbackState == Player.STATE_READY && seekTime != C.TIME_UNSET) {
|
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
|
@Override
|
||||||
public void onShuffleModeEnabledChanged(boolean shuffleModeEnabled) {
|
public void onShuffleModeEnabledChanged(boolean shuffleModeEnabled) {
|
||||||
// Do nothing.
|
// Do nothing.
|
||||||
@ -1227,8 +1253,8 @@ class ReactExoplayerView extends FrameLayout implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {
|
public void onTracksInfoChanged(TracksInfo tracksInfo) {
|
||||||
// Do Nothing.
|
// Do nothing.
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -1242,74 +1268,19 @@ class ReactExoplayerView extends FrameLayout implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPlayerError(ExoPlaybackException e) {
|
public void onPlayerError(PlaybackException e) {
|
||||||
String errorString = "ExoPlaybackException type : " + e.type;
|
if (e == null) {
|
||||||
String errorCode = "2001"; // Playback error code 2xxx (2001 - unknown playback exception)
|
return;
|
||||||
|
}
|
||||||
|
String errorString = "ExoPlaybackException: " + PlaybackException.getErrorCodeName(e.errorCode);
|
||||||
|
String errorCode = "2" + String.valueOf(e.errorCode);
|
||||||
boolean needsReInitialization = false;
|
boolean needsReInitialization = false;
|
||||||
Exception ex = e;
|
switch(e.errorCode) {
|
||||||
if (e.type == ExoPlaybackException.TYPE_RENDERER) {
|
case PlaybackException.ERROR_CODE_DRM_DEVICE_REVOKED:
|
||||||
Exception cause = e.getRendererException();
|
case PlaybackException.ERROR_CODE_DRM_LICENSE_ACQUISITION_FAILED:
|
||||||
if (cause instanceof MediaCodecRenderer.DecoderInitializationException) {
|
case PlaybackException.ERROR_CODE_DRM_PROVISIONING_FAILED:
|
||||||
// Special case for decoder initialization failures.
|
case PlaybackException.ERROR_CODE_DRM_SYSTEM_ERROR:
|
||||||
MediaCodecRenderer.DecoderInitializationException decoderInitializationException =
|
case PlaybackException.ERROR_CODE_DRM_UNSPECIFIED:
|
||||||
(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);
|
|
||||||
if (!hasDrmFailed) {
|
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;
|
hasDrmFailed = true;
|
||||||
@ -1319,10 +1290,11 @@ class ReactExoplayerView extends FrameLayout implements
|
|||||||
setPlayWhenReady(true);
|
setPlayWhenReady(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
eventEmitter.error(errorString, e, errorCode);
|
||||||
}
|
|
||||||
eventEmitter.error(errorString, ex, errorCode);
|
|
||||||
playerNeedsSource = true;
|
playerNeedsSource = true;
|
||||||
if (isBehindLiveWindow(e)) {
|
if (isBehindLiveWindow(e)) {
|
||||||
clearResumePosition();
|
clearResumePosition();
|
||||||
@ -1335,20 +1307,8 @@ class ReactExoplayerView extends FrameLayout implements
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isBehindLiveWindow(ExoPlaybackException e) {
|
private static boolean isBehindLiveWindow(PlaybackException e) {
|
||||||
Log.e("ExoPlayer Exception", e.toString());
|
return e.errorCode == PlaybackException.ERROR_CODE_BEHIND_LIVE_WINDOW;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getTrackRendererIndex(int trackType) {
|
public int getTrackRendererIndex(int trackType) {
|
||||||
@ -1389,7 +1349,8 @@ class ReactExoplayerView extends FrameLayout implements
|
|||||||
|
|
||||||
public void clearSrc() {
|
public void clearSrc() {
|
||||||
if (srcUri != null) {
|
if (srcUri != null) {
|
||||||
player.stop(true);
|
player.stop();
|
||||||
|
player.clearMediaItems();
|
||||||
this.srcUri = null;
|
this.srcUri = null;
|
||||||
this.extension = null;
|
this.extension = null;
|
||||||
this.requestHeaders = null;
|
this.requestHeaders = null;
|
||||||
@ -1466,7 +1427,8 @@ class ReactExoplayerView extends FrameLayout implements
|
|||||||
|
|
||||||
TrackGroupArray groups = info.getTrackGroups(rendererIndex);
|
TrackGroupArray groups = info.getTrackGroups(rendererIndex);
|
||||||
int groupIndex = C.INDEX_UNSET;
|
int groupIndex = C.INDEX_UNSET;
|
||||||
int[] tracks = {0} ;
|
List<Integer> tracks = new ArrayList<>();
|
||||||
|
tracks.add(0);
|
||||||
|
|
||||||
if (TextUtils.isEmpty(type)) {
|
if (TextUtils.isEmpty(type)) {
|
||||||
type = "default";
|
type = "default";
|
||||||
@ -1511,7 +1473,7 @@ class ReactExoplayerView extends FrameLayout implements
|
|||||||
Format format = group.getFormat(j);
|
Format format = group.getFormat(j);
|
||||||
if (format.height == height) {
|
if (format.height == height) {
|
||||||
groupIndex = i;
|
groupIndex = i;
|
||||||
tracks[0] = j;
|
tracks.set(0, j);
|
||||||
closestFormat = null;
|
closestFormat = null;
|
||||||
closestTrackIndex = -1;
|
closestTrackIndex = -1;
|
||||||
usingExactMatch = true;
|
usingExactMatch = true;
|
||||||
@ -1539,7 +1501,7 @@ class ReactExoplayerView extends FrameLayout implements
|
|||||||
if (format.height < minHeight) {
|
if (format.height < minHeight) {
|
||||||
minHeight = format.height;
|
minHeight = format.height;
|
||||||
groupIndex = i;
|
groupIndex = i;
|
||||||
tracks[0] = j;
|
tracks.set(0, j);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1547,7 +1509,7 @@ class ReactExoplayerView extends FrameLayout implements
|
|||||||
if (closestFormat != null && closestTrackIndex != -1) {
|
if (closestFormat != null && closestTrackIndex != -1) {
|
||||||
// We found the closest match instead of an exact one
|
// We found the closest match instead of an exact one
|
||||||
groupIndex = i;
|
groupIndex = i;
|
||||||
tracks[0] = closestTrackIndex;
|
tracks.set(0, closestTrackIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (trackType == C.TRACK_TYPE_TEXT && Util.SDK_INT > 18) { // Text default
|
} else if (trackType == C.TRACK_TYPE_TEXT && Util.SDK_INT > 18) { // Text default
|
||||||
@ -1564,34 +1526,32 @@ class ReactExoplayerView extends FrameLayout implements
|
|||||||
if (groupIndex == C.INDEX_UNSET && trackType == C.TRACK_TYPE_VIDEO && groups.length != 0) { // Video auto
|
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
|
// Add all tracks as valid options for ABR to choose from
|
||||||
TrackGroup group = groups.get(0);
|
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;
|
groupIndex = 0;
|
||||||
|
|
||||||
for (int j = 0; j < group.length; j++) {
|
for (int j = 0; j < group.length; j++) {
|
||||||
allTracks[j] = j;
|
allTracks.add(j);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Valiate list of all tracks and add only supported formats
|
// Valiate list of all tracks and add only supported formats
|
||||||
int supportedFormatLength = 0;
|
int supportedFormatLength = 0;
|
||||||
ArrayList<Integer> supportedTrackList = new ArrayList<Integer>();
|
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);
|
Format format = group.getFormat(g);
|
||||||
if (isFormatSupported(format)) {
|
if (isFormatSupported(format)) {
|
||||||
supportedFormatLength++;
|
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
|
// With only one tracks we can't remove any tracks so attempt to play it anyway
|
||||||
tracks = allTracks;
|
tracks = allTracks;
|
||||||
} else {
|
} else {
|
||||||
tracks = new int[supportedFormatLength + 1];
|
tracks = new ArrayList<>(supportedFormatLength + 1);
|
||||||
int o = 0;
|
for (int k = 0; k < allTracks.size(); k++) {
|
||||||
for (int k = 0; k < allTracks.length; k++) {
|
|
||||||
Format format = group.getFormat(k);
|
Format format = group.getFormat(k);
|
||||||
if (isFormatSupported(format)) {
|
if (isFormatSupported(format)) {
|
||||||
tracks[o] = allTracks[k];
|
tracks.add(allTracks.get(k));
|
||||||
supportedTrackList.add(allTracks[k]);
|
supportedTrackList.add(allTracks.get(k));
|
||||||
o++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1602,11 +1562,12 @@ class ReactExoplayerView extends FrameLayout implements
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TrackSelectionOverride selectionOverride = new TrackSelectionOverride(groups.get(groupIndex), tracks);
|
||||||
|
|
||||||
DefaultTrackSelector.Parameters selectionParameters = trackSelector.getParameters()
|
DefaultTrackSelector.Parameters selectionParameters = trackSelector.getParameters()
|
||||||
.buildUpon()
|
.buildUpon()
|
||||||
.setRendererDisabled(rendererIndex, false)
|
.setRendererDisabled(rendererIndex, false)
|
||||||
.setSelectionOverride(rendererIndex, groups,
|
.setTrackSelectionOverrides(new TrackSelectionOverrides.Builder().addOverride(selectionOverride).build())
|
||||||
new DefaultTrackSelector.SelectionOverride(groupIndex, tracks))
|
|
||||||
.build();
|
.build();
|
||||||
trackSelector.setParameters(selectionParameters);
|
trackSelector.setParameters(selectionParameters);
|
||||||
}
|
}
|
||||||
@ -1694,8 +1655,8 @@ class ReactExoplayerView extends FrameLayout implements
|
|||||||
|
|
||||||
public void seekTo(long positionMs) {
|
public void seekTo(long positionMs) {
|
||||||
if (player != null) {
|
if (player != null) {
|
||||||
seekTime = positionMs;
|
|
||||||
player.seekTo(positionMs);
|
player.seekTo(positionMs);
|
||||||
|
eventEmitter.seek(player.getCurrentPosition(), positionMs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,11 +5,11 @@ def safeExtGet(prop, fallback) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion safeExtGet('compileSdkVersion', 28)
|
compileSdkVersion safeExtGet('compileSdkVersion', 31)
|
||||||
buildToolsVersion safeExtGet('buildToolsVersion', '28.0.3')
|
buildToolsVersion safeExtGet('buildToolsVersion', '30.0.2')
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdkVersion safeExtGet('minSdkVersion', 16)
|
minSdkVersion safeExtGet('minSdkVersion', 21)
|
||||||
targetSdkVersion safeExtGet('targetSdkVersion', 28)
|
targetSdkVersion safeExtGet('targetSdkVersion', 28)
|
||||||
versionCode 1
|
versionCode 1
|
||||||
versionName "1.0"
|
versionName "1.0"
|
||||||
|
@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
buildscript {
|
buildscript {
|
||||||
ext {
|
ext {
|
||||||
buildToolsVersion = "29.0.2"
|
buildToolsVersion = "30.0.2"
|
||||||
minSdkVersion = 16
|
minSdkVersion = 21
|
||||||
compileSdkVersion = 29
|
compileSdkVersion = 31
|
||||||
targetSdkVersion = 29
|
targetSdkVersion = 29
|
||||||
}
|
}
|
||||||
repositories {
|
repositories {
|
||||||
|
@ -94,12 +94,12 @@ def enableSeparateBuildPerCPUArchitecture = false
|
|||||||
def enableProguardInReleaseBuilds = false
|
def enableProguardInReleaseBuilds = false
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 23
|
compileSdkVersion 31
|
||||||
buildToolsVersion "23.0.1"
|
buildToolsVersion "30.0.2"
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId "com.videocaching"
|
applicationId "com.videocaching"
|
||||||
minSdkVersion 16
|
minSdkVersion 21
|
||||||
targetSdkVersion 22
|
targetSdkVersion 22
|
||||||
versionCode 1
|
versionCode 1
|
||||||
versionName "1.0"
|
versionName "1.0"
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
|
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
|
||||||
|
|
||||||
<uses-sdk
|
<uses-sdk
|
||||||
android:minSdkVersion="16"
|
android:minSdkVersion="21"
|
||||||
android:targetSdkVersion="22" />
|
android:targetSdkVersion="22" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
|
Loading…
Reference in New Issue
Block a user