This commit is contained in:
Tuan Luong 2021-07-04 15:18:38 +07:00
commit 4951c2e13c
5 changed files with 72 additions and 47 deletions

View File

@ -1,5 +1,7 @@
## Changelog ## Changelog
- Fix Android AudioFocus bug that could cause player to not respond to play/pause in some instances [#2311](https://github.com/react-native-video/react-native-video/pull/2311)
### Version 5.1.0-alpha9 ### Version 5.1.0-alpha9
- Add ARM64 support for windows [#2137](https://github.com/react-native-community/react-native-video/pull/2137) - Add ARM64 support for windows [#2137](https://github.com/react-native-community/react-native-video/pull/2137)

View File

@ -28,7 +28,7 @@ android {
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.11.4') { implementation('com.google.android.exoplayer:exoplayer:2.13.2') {
exclude group: 'com.android.support' exclude group: 'com.android.support'
} }
@ -37,7 +37,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.11.4') { implementation('com.google.android.exoplayer:extension-okhttp:2.13.2') {
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}'

View File

@ -17,6 +17,7 @@ import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.ExoPlayer; 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.SimpleExoPlayer;
import com.google.android.exoplayer2.video.VideoListener;
import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.source.TrackGroupArray; import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.android.exoplayer2.text.Cue; import com.google.android.exoplayer2.text.Cue;
@ -85,6 +86,14 @@ public final class ExoPlayerView extends FrameLayout {
addViewInLayout(layout, 0, aspectRatioParams); addViewInLayout(layout, 0, aspectRatioParams);
} }
private void clearVideoView() {
if (surfaceView instanceof TextureView) {
player.clearVideoTextureView((TextureView) surfaceView);
} else if (surfaceView instanceof SurfaceView) {
player.clearVideoSurfaceView((SurfaceView) surfaceView);
}
}
private void setVideoView() { private void setVideoView() {
if (surfaceView instanceof TextureView) { if (surfaceView instanceof TextureView) {
player.setVideoTextureView((TextureView) surfaceView); player.setVideoTextureView((TextureView) surfaceView);
@ -113,26 +122,26 @@ public final class ExoPlayerView extends FrameLayout {
} }
/** /**
* Set the {@link SimpleExoPlayer} to use. The {@link SimpleExoPlayer#setTextOutput} and * Set the {@link SimpleExoPlayer} to use. The {@link SimpleExoPlayer#addTextOutput} and
* {@link SimpleExoPlayer#setVideoListener} method of the player will be called and previous * {@link SimpleExoPlayer#addVideoListener} method of the player will be called and previous
* assignments are overridden. * assignments are overridden.
* *
* @param player The {@link SimpleExoPlayer} to use. * @param player The {@link SimpleExoPlayer} to use.
*/ */
public void setPlayer(SimpleExoPlayer player) { public void setPlayer(SimpleExoPlayer player) {
if (this.player != null) { if (this.player != null) {
this.player.setTextOutput(null); this.player.removeTextOutput(componentListener);
this.player.setVideoListener(null); this.player.removeVideoListener(componentListener);
this.player.removeListener(componentListener); this.player.removeListener(componentListener);
this.player.setVideoSurface(null); clearVideoView();
} }
this.player = player; this.player = player;
shutterView.setVisibility(VISIBLE); shutterView.setVisibility(VISIBLE);
if (player != null) { if (player != null) {
setVideoView(); setVideoView();
player.setVideoListener(componentListener); player.addVideoListener(componentListener);
player.addListener(componentListener); player.addListener(componentListener);
player.setTextOutput(componentListener); player.addTextOutput(componentListener);
} }
} }
@ -202,7 +211,7 @@ public final class ExoPlayerView extends FrameLayout {
layout.invalidateAspectRatio(); layout.invalidateAspectRatio();
} }
private final class ComponentListener implements SimpleExoPlayer.VideoListener, private final class ComponentListener implements VideoListener,
TextOutput, ExoPlayer.EventListener { TextOutput, ExoPlayer.EventListener {
// TextRenderer.Output implementation // TextRenderer.Output implementation

View File

@ -36,7 +36,7 @@ import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.SimpleExoPlayer; import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.drm.DefaultDrmSessionManager; import com.google.android.exoplayer2.drm.DefaultDrmSessionManager;
import com.google.android.exoplayer2.drm.DefaultDrmSessionEventListener; 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.FrameworkMediaCrypto;
import com.google.android.exoplayer2.drm.FrameworkMediaDrm; import com.google.android.exoplayer2.drm.FrameworkMediaDrm;
@ -61,7 +61,7 @@ import com.google.android.exoplayer2.source.smoothstreaming.SsMediaSource;
import com.google.android.exoplayer2.trackselection.AdaptiveTrackSelection; 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.TrackSelection; import com.google.android.exoplayer2.trackselection.ExoTrackSelection;
import com.google.android.exoplayer2.trackselection.TrackSelectionArray; import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
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;
@ -88,7 +88,7 @@ class ReactExoplayerView extends FrameLayout implements
BecomingNoisyListener, BecomingNoisyListener,
AudioManager.OnAudioFocusChangeListener, AudioManager.OnAudioFocusChangeListener,
MetadataOutput, MetadataOutput,
DefaultDrmSessionEventListener { DrmSessionEventListener {
private static final String TAG = "ReactExoplayerView"; private static final String TAG = "ReactExoplayerView";
@ -129,6 +129,7 @@ class ReactExoplayerView extends FrameLayout implements
private boolean isPaused; private boolean isPaused;
private boolean isBuffering; private boolean isBuffering;
private boolean muted = false; private boolean muted = false;
private boolean hasAudioFocus = false;
private float rate = 1f; private float rate = 1f;
private float audioVolume = 1f; private float audioVolume = 1f;
private int minLoadRetryCount = 3; private int minLoadRetryCount = 3;
@ -443,7 +444,7 @@ class ReactExoplayerView extends FrameLayout implements
@Override @Override
public void run() { public void run() {
if (player == null) { if (player == null) {
TrackSelection.Factory videoTrackSelectionFactory = new AdaptiveTrackSelection.Factory(); ExoTrackSelection.Factory videoTrackSelectionFactory = new AdaptiveTrackSelection.Factory();
trackSelector = new DefaultTrackSelector(videoTrackSelectionFactory); trackSelector = new DefaultTrackSelector(videoTrackSelectionFactory);
trackSelector.setParameters(trackSelector.buildUponParameters() trackSelector.setParameters(trackSelector.buildUponParameters()
.setMaxVideoBitrate(maxBitRate == 0 ? Integer.MAX_VALUE : maxBitRate)); .setMaxVideoBitrate(maxBitRate == 0 ? Integer.MAX_VALUE : maxBitRate));
@ -458,23 +459,11 @@ 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);
// DRM player = new SimpleExoPlayer.Builder(getContext(), renderersFactory)
DrmSessionManager<FrameworkMediaCrypto> drmSessionManager = null; .setTrackSelector(trackSelector)
if (self.drmUUID != null) { .setBandwidthMeter(bandwidthMeter)
try { .setLoadControl(defaultLoadControl)
drmSessionManager = buildDrmSessionManager(self.drmUUID, self.drmLicenseUrl, .build();
self.drmLicenseHeader);
} catch (UnsupportedDrmException e) {
int errorStringId = Util.SDK_INT < 18 ? R.string.error_drm_not_supported
: (e.reason == UnsupportedDrmException.REASON_UNSUPPORTED_SCHEME
? R.string.error_drm_unsupported_scheme : R.string.error_drm_unknown);
eventEmitter.error(getResources().getString(errorStringId), e);
return;
}
}
// End DRM
player = ExoPlayerFactory.newSimpleInstance(getContext(), renderersFactory,
trackSelector, defaultLoadControl, drmSessionManager, bandwidthMeter);
player.addListener(self); player.addListener(self);
player.addMetadataOutput(self); player.addMetadataOutput(self);
exoPlayerView.setPlayer(player); exoPlayerView.setPlayer(player);
@ -489,8 +478,24 @@ class ReactExoplayerView extends FrameLayout implements
if (playerNeedsSource && srcUri != null) { if (playerNeedsSource && srcUri != null) {
exoPlayerView.invalidateAspectRatio(); exoPlayerView.invalidateAspectRatio();
// DRM
DrmSessionManager drmSessionManager = null;
if (self.drmUUID != null) {
try {
drmSessionManager = buildDrmSessionManager(self.drmUUID, self.drmLicenseUrl,
self.drmLicenseHeader);
} catch (UnsupportedDrmException e) {
int errorStringId = Util.SDK_INT < 18 ? R.string.error_drm_not_supported
: (e.reason == UnsupportedDrmException.REASON_UNSUPPORTED_SCHEME
? R.string.error_drm_unsupported_scheme : R.string.error_drm_unknown);
eventEmitter.error(getResources().getString(errorStringId), e);
return;
}
}
// End DRM
ArrayList<MediaSource> mediaSourceList = buildTextSources(); ArrayList<MediaSource> mediaSourceList = buildTextSources();
MediaSource videoSource = buildMediaSource(srcUri, extension); MediaSource videoSource = buildMediaSource(srcUri, extension, drmSessionManager);
MediaSource mediaSource; MediaSource mediaSource;
if (mediaSourceList.size() == 0) { if (mediaSourceList.size() == 0) {
mediaSource = videoSource; mediaSource = videoSource;
@ -521,7 +526,7 @@ class ReactExoplayerView extends FrameLayout implements
}, 1); }, 1);
} }
private DrmSessionManager<FrameworkMediaCrypto> buildDrmSessionManager(UUID uuid, private DrmSessionManager buildDrmSessionManager(UUID uuid,
String licenseUrl, String[] keyRequestPropertiesArray) throws UnsupportedDrmException { String licenseUrl, String[] keyRequestPropertiesArray) throws UnsupportedDrmException {
if (Util.SDK_INT < 18) { if (Util.SDK_INT < 18) {
return null; return null;
@ -534,11 +539,11 @@ class ReactExoplayerView extends FrameLayout implements
keyRequestPropertiesArray[i + 1]); keyRequestPropertiesArray[i + 1]);
} }
} }
return new DefaultDrmSessionManager<>(uuid, return new DefaultDrmSessionManager(uuid,
FrameworkMediaDrm.newInstance(uuid), drmCallback, null, false, 3); FrameworkMediaDrm.newInstance(uuid), drmCallback, null, false, 3);
} }
private MediaSource buildMediaSource(Uri uri, String overrideExtension) { private MediaSource buildMediaSource(Uri uri, String overrideExtension, DrmSessionManager drmSessionManager) {
int type = Util.inferContentType(!TextUtils.isEmpty(overrideExtension) ? "." + overrideExtension int type = Util.inferContentType(!TextUtils.isEmpty(overrideExtension) ? "." + overrideExtension
: uri.getLastPathSegment()); : uri.getLastPathSegment());
switch (type) { switch (type) {
@ -546,26 +551,30 @@ class ReactExoplayerView extends FrameLayout implements
return new SsMediaSource.Factory( return new SsMediaSource.Factory(
new DefaultSsChunkSource.Factory(mediaDataSourceFactory), new DefaultSsChunkSource.Factory(mediaDataSourceFactory),
buildDataSourceFactory(false) buildDataSourceFactory(false)
).setLoadErrorHandlingPolicy( ).setDrmSessionManager(drmSessionManager)
.setLoadErrorHandlingPolicy(
config.buildLoadErrorHandlingPolicy(minLoadRetryCount) config.buildLoadErrorHandlingPolicy(minLoadRetryCount)
).createMediaSource(uri); ).createMediaSource(uri);
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)
).setLoadErrorHandlingPolicy( ).setDrmSessionManager(drmSessionManager)
.setLoadErrorHandlingPolicy(
config.buildLoadErrorHandlingPolicy(minLoadRetryCount) config.buildLoadErrorHandlingPolicy(minLoadRetryCount)
).createMediaSource(uri); ).createMediaSource(uri);
case C.TYPE_HLS: case C.TYPE_HLS:
return new HlsMediaSource.Factory( return new HlsMediaSource.Factory(
mediaDataSourceFactory mediaDataSourceFactory
).setLoadErrorHandlingPolicy( ).setDrmSessionManager(drmSessionManager)
.setLoadErrorHandlingPolicy(
config.buildLoadErrorHandlingPolicy(minLoadRetryCount) config.buildLoadErrorHandlingPolicy(minLoadRetryCount)
).createMediaSource(uri); ).createMediaSource(uri);
case C.TYPE_OTHER: case C.TYPE_OTHER:
return new ProgressiveMediaSource.Factory( return new ProgressiveMediaSource.Factory(
mediaDataSourceFactory mediaDataSourceFactory
).setLoadErrorHandlingPolicy( ).setDrmSessionManager(drmSessionManager)
.setLoadErrorHandlingPolicy(
config.buildLoadErrorHandlingPolicy(minLoadRetryCount) config.buildLoadErrorHandlingPolicy(minLoadRetryCount)
).createMediaSource(uri); ).createMediaSource(uri);
default: { default: {
@ -616,7 +625,7 @@ class ReactExoplayerView extends FrameLayout implements
} }
private boolean requestAudioFocus() { private boolean requestAudioFocus() {
if (disableFocus || srcUri == null) { if (disableFocus || srcUri == null || this.hasAudioFocus) {
return true; return true;
} }
int result = audioManager.requestAudioFocus(this, int result = audioManager.requestAudioFocus(this,
@ -631,8 +640,8 @@ class ReactExoplayerView extends FrameLayout implements
} }
if (playWhenReady) { if (playWhenReady) {
boolean hasAudioFocus = requestAudioFocus(); this.hasAudioFocus = requestAudioFocus();
if (hasAudioFocus) { if (this.hasAudioFocus) {
player.setPlayWhenReady(true); player.setPlayWhenReady(true);
} }
} else { } else {
@ -724,6 +733,7 @@ class ReactExoplayerView extends FrameLayout implements
public void onAudioFocusChange(int focusChange) { public void onAudioFocusChange(int focusChange) {
switch (focusChange) { switch (focusChange) {
case AudioManager.AUDIOFOCUS_LOSS: case AudioManager.AUDIOFOCUS_LOSS:
this.hasAudioFocus = false;
eventEmitter.audioFocusChanged(false); eventEmitter.audioFocusChanged(false);
pausePlayback(); pausePlayback();
audioManager.abandonAudioFocus(this); audioManager.abandonAudioFocus(this);
@ -732,6 +742,7 @@ class ReactExoplayerView extends FrameLayout implements
eventEmitter.audioFocusChanged(false); eventEmitter.audioFocusChanged(false);
break; break;
case AudioManager.AUDIOFOCUS_GAIN: case AudioManager.AUDIOFOCUS_GAIN:
this.hasAudioFocus = true;
eventEmitter.audioFocusChanged(true); eventEmitter.audioFocusChanged(true);
break; break;
default: default:
@ -1371,23 +1382,23 @@ class ReactExoplayerView extends FrameLayout implements
@Override @Override
public void onDrmKeysLoaded() { public void onDrmKeysLoaded(int windowIndex, MediaSource.MediaPeriodId mediaPeriodId) {
Log.d("DRM Info", "onDrmKeysLoaded"); Log.d("DRM Info", "onDrmKeysLoaded");
} }
@Override @Override
public void onDrmSessionManagerError(Exception e) { public void onDrmSessionManagerError(int windowIndex, MediaSource.MediaPeriodId mediaPeriodId, Exception e) {
Log.d("DRM Info", "onDrmSessionManagerError"); Log.d("DRM Info", "onDrmSessionManagerError");
eventEmitter.error("onDrmSessionManagerError", e); eventEmitter.error("onDrmSessionManagerError", e);
} }
@Override @Override
public void onDrmKeysRestored() { public void onDrmKeysRestored(int windowIndex, MediaSource.MediaPeriodId mediaPeriodId) {
Log.d("DRM Info", "onDrmKeysRestored"); Log.d("DRM Info", "onDrmKeysRestored");
} }
@Override @Override
public void onDrmKeysRemoved() { public void onDrmKeysRemoved(int windowIndex, MediaSource.MediaPeriodId mediaPeriodId) {
Log.d("DRM Info", "onDrmKeysRemoved"); Log.d("DRM Info", "onDrmKeysRemoved");
} }

View File

@ -718,7 +718,10 @@ static int const RCTVideoUnset = -1;
} }
} else if (object == _player) { } else if (object == _player) {
if([keyPath isEqualToString:playbackRate]) { if([keyPath isEqualToString:playbackRate]) {
if(self.onPlaybackRateChange) { if (_player.rate > 0 && _rate > 0 && _player.rate != _rate) {
// Playback is resuming, apply rate modifer.
[_player setRate:_rate];
} else if(self.onPlaybackRateChange) {
self.onPlaybackRateChange(@{@"playbackRate": [NSNumber numberWithFloat:_player.rate], self.onPlaybackRateChange(@{@"playbackRate": [NSNumber numberWithFloat:_player.rate],
@"target": self.reactTag}); @"target": self.reactTag});
} }