From e4da5c97734862e6a3585d06088b7aed336166e8 Mon Sep 17 00:00:00 2001 From: benlime Date: Sun, 30 Apr 2017 13:43:01 +0200 Subject: [PATCH 001/189] adds resizeMode to poster image --- Video.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Video.js b/Video.js index 4d69b333..ed55b7fc 100644 --- a/Video.js +++ b/Video.js @@ -217,7 +217,6 @@ export default class Video extends Component { top: 0, right: 0, bottom: 0, - resizeMode: 'contain', }; return ( @@ -229,6 +228,7 @@ export default class Video extends Component { ); @@ -271,6 +271,7 @@ Video.propTypes = { ]), resizeMode: PropTypes.string, poster: PropTypes.string, + posterResizeMode: Image.propTypes.resizeMode, repeat: PropTypes.bool, paused: PropTypes.bool, muted: PropTypes.bool, From b6afaa3378fed72d6bd356f9a76dce965e350cf7 Mon Sep 17 00:00:00 2001 From: Nicolas Ngomai Date: Thu, 11 May 2017 13:46:04 +0200 Subject: [PATCH 002/189] Add link to propTypes Some props are missing in the documentation, the propTypes provides a full list of those. I think it would help a lot of developers to add a link here. --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index e473a766..11819fb2 100644 --- a/README.md +++ b/README.md @@ -170,6 +170,8 @@ var styles = StyleSheet.create({ - * *For iOS you also need to specify muted for this to work* +To see full list of available props, you can check [the propTypes](https://github.com/react-native-community/react-native-video/blob/master/Video.js#L246) of the Video.js component. + ## Android Expansion File Usage ```javascript From a4ada46b3069ee300df2b68d89ef2ecbde7f0469 Mon Sep 17 00:00:00 2001 From: Landon Sherwood Date: Tue, 29 Aug 2017 16:39:18 -0500 Subject: [PATCH 003/189] Show iOS controls if not fullscreen Show controls without calling the present full screen method. --- ios/RCTVideo.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/RCTVideo.m b/ios/RCTVideo.m index 16174add..134cc0ae 100644 --- a/ios/RCTVideo.m +++ b/ios/RCTVideo.m @@ -90,7 +90,7 @@ static NSString *const timedMetadata = @"timedMetadata"; - (AVPlayerViewController*)createPlayerViewController:(AVPlayer*)player withPlayerItem:(AVPlayerItem*)playerItem { RCTVideoPlayerViewController* playerLayer= [[RCTVideoPlayerViewController alloc] init]; - playerLayer.showsPlaybackControls = NO; + playerLayer.showsPlaybackControls = YES; playerLayer.rctDelegate = self; playerLayer.view.frame = self.bounds; playerLayer.player = _player; From 451f8d0919e94e44d7b294b187ac527533d06b82 Mon Sep 17 00:00:00 2001 From: Alex Fox Date: Thu, 7 Sep 2017 13:16:44 +0100 Subject: [PATCH 004/189] Fixed rate not being respected after seeking Referenced in issue => https://github.com/react-native-community/react-native-video/issues/763 --- ios/RCTVideo.m | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ios/RCTVideo.m b/ios/RCTVideo.m index 9962c2bb..097e16c8 100644 --- a/ios/RCTVideo.m +++ b/ios/RCTVideo.m @@ -561,7 +561,9 @@ static NSString *const timedMetadata = @"timedMetadata"; if (CMTimeCompare(current, cmSeekTime) != 0) { if (!wasPaused) [_player pause]; [_player seekToTime:cmSeekTime toleranceBefore:tolerance toleranceAfter:tolerance completionHandler:^(BOOL finished) { - if (!wasPaused) [_player play]; + if (!wasPaused) { + [self setPaused:false]; + } if(self.onVideoSeek) { self.onVideoSeek(@{@"currentTime": [NSNumber numberWithFloat:CMTimeGetSeconds(item.currentTime)], @"seekTime": [NSNumber numberWithFloat:seekTime], From 1bdd8720fbc08b2a04edf2b59e8e03063ed41c48 Mon Sep 17 00:00:00 2001 From: Anne Glines Date: Mon, 11 Sep 2017 22:30:17 -0700 Subject: [PATCH 005/189] Reseting isCompleted flag on source change --- android/src/main/java/com/brentvatne/react/ReactVideoView.java | 1 + 1 file changed, 1 insertion(+) diff --git a/android/src/main/java/com/brentvatne/react/ReactVideoView.java b/android/src/main/java/com/brentvatne/react/ReactVideoView.java index 94a25a0e..f426c30e 100644 --- a/android/src/main/java/com/brentvatne/react/ReactVideoView.java +++ b/android/src/main/java/com/brentvatne/react/ReactVideoView.java @@ -297,6 +297,7 @@ public class ReactVideoView extends ScalableVideoView implements MediaPlayer.OnP WritableMap event = Arguments.createMap(); event.putMap(ReactVideoViewManager.PROP_SRC, src); mEventEmitter.receiveEvent(getId(), Events.EVENT_LOAD_START.toString(), event); + isCompleted = false; try { prepareAsync(this); From 3e0f084c621e7af0a60a13c701cb94cd3b211041 Mon Sep 17 00:00:00 2001 From: Louis Capitanchik Date: Wed, 27 Sep 2017 16:13:29 +0100 Subject: [PATCH 006/189] Implement 'rate' prop for android devices - Version locked to 6.0+ because that is the version that introduced setPlaybackParams - Ignores rate prop as before on android versions lower than 6.0 --- .../main/java/com/brentvatne/react/ReactVideoView.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/android/src/main/java/com/brentvatne/react/ReactVideoView.java b/android/src/main/java/com/brentvatne/react/ReactVideoView.java index 94a25a0e..099bec33 100644 --- a/android/src/main/java/com/brentvatne/react/ReactVideoView.java +++ b/android/src/main/java/com/brentvatne/react/ReactVideoView.java @@ -5,6 +5,7 @@ import android.content.res.AssetFileDescriptor; import android.graphics.Matrix; import android.media.MediaPlayer; import android.net.Uri; +import android.os.Build; import android.os.Handler; import android.util.Log; import android.view.MotionEvent; @@ -377,8 +378,11 @@ public class ReactVideoView extends ScalableVideoView implements MediaPlayer.OnP mRate = rate; if (mMediaPlayerValid) { - // TODO: Implement this. - Log.e(ReactVideoViewManager.REACT_CLASS, "Setting playback rate is not yet supported on Android"); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + mMediaPlayer.setPlaybackParams(mMediaPlayer.getPlaybackParams().setSpeed(rate)); + } else { + Log.e(ReactVideoViewManager.REACT_CLASS, "Setting playback rate is not yet supported on Android versions below 6.0"); + } } } @@ -388,7 +392,7 @@ public class ReactVideoView extends ScalableVideoView implements MediaPlayer.OnP setPausedModifier(mPaused); setMutedModifier(mMuted); setProgressUpdateInterval(mProgressUpdateInterval); -// setRateModifier(mRate); + setRateModifier(mRate); } public void setPlayInBackground(final boolean playInBackground) { From 435669a944430fa51b8bbd640c6bf66c7756a1ce Mon Sep 17 00:00:00 2001 From: Dan Hodos Date: Thu, 28 Sep 2017 21:37:26 -0400 Subject: [PATCH 007/189] Extract method to add observer for progress update --- ios/RCTVideo.m | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/ios/RCTVideo.m b/ios/RCTVideo.m index 9962c2bb..88f3a640 100644 --- a/ios/RCTVideo.m +++ b/ios/RCTVideo.m @@ -124,6 +124,16 @@ static NSString *const timedMetadata = @"timedMetadata"; return (kCMTimeRangeZero); } +-(void)addPlayerTimeObserver +{ + const Float64 progressUpdateIntervalMS = _progressUpdateInterval / 1000; + // @see endScrubbing in AVPlayerDemoPlaybackViewController.m of https://developer.apple.com/library/ios/samplecode/AVPlayerDemo/Introduction/Intro.html + __weak RCTVideo *weakSelf = self; + _timeObserver = [_player addPeriodicTimeObserverForInterval:CMTimeMakeWithSeconds(progressUpdateIntervalMS, NSEC_PER_SEC) + queue:NULL + usingBlock:^(CMTime time) { [weakSelf sendProgressUpdate]; } + ]; +} /* Cancels the previously registered time observer. */ -(void)removePlayerTimeObserver @@ -283,13 +293,7 @@ static NSString *const timedMetadata = @"timedMetadata"; [_player addObserver:self forKeyPath:playbackRate options:0 context:nil]; _playbackRateObserverRegistered = YES; - const Float64 progressUpdateIntervalMS = _progressUpdateInterval / 1000; - // @see endScrubbing in AVPlayerDemoPlaybackViewController.m of https://developer.apple.com/library/ios/samplecode/AVPlayerDemo/Introduction/Intro.html - __weak RCTVideo *weakSelf = self; - _timeObserver = [_player addPeriodicTimeObserverForInterval:CMTimeMakeWithSeconds(progressUpdateIntervalMS, NSEC_PER_SEC) - queue:NULL - usingBlock:^(CMTime time) { [weakSelf sendProgressUpdate]; } - ]; + [self addPlayerTimeObserver]; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ //Perform on next run loop, otherwise onVideoLoadStart is nil From 10cba5ad5c545a1ea6a6e7d53020f834466aa72e Mon Sep 17 00:00:00 2001 From: Dan Hodos Date: Thu, 28 Sep 2017 21:37:52 -0400 Subject: [PATCH 008/189] Reset progress observer on update interval changes --- ios/RCTVideo.m | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ios/RCTVideo.m b/ios/RCTVideo.m index 88f3a640..68e52e31 100644 --- a/ios/RCTVideo.m +++ b/ios/RCTVideo.m @@ -725,6 +725,11 @@ static NSString *const timedMetadata = @"timedMetadata"; - (void)setProgressUpdateInterval:(float)progressUpdateInterval { _progressUpdateInterval = progressUpdateInterval; + + if (_timeObserver) { + [self removePlayerTimeObserver]; + [self addPlayerTimeObserver]; + } } - (void)removePlayerLayer From 270fdfb657bb298a2c381aa5ff0e455cb2a95423 Mon Sep 17 00:00:00 2001 From: Emrah Kaya Date: Mon, 2 Oct 2017 20:11:41 +0200 Subject: [PATCH 009/189] added optional request headers for remote assests (android & ios) --- Video.js | 11 +++++ .../brentvatne/exoplayer/DataSourceUtil.java | 25 +++++++--- .../exoplayer/ReactExoplayerView.java | 10 ++-- .../exoplayer/ReactExoplayerViewManager.java | 30 +++++++++++- .../com/brentvatne/react/ReactVideoView.java | 48 +++++++++++++++++-- .../react/ReactVideoViewManager.java | 7 ++- ios/RCTVideo.m | 7 ++- 7 files changed, 119 insertions(+), 19 deletions(-) diff --git a/Video.js b/Video.js index b90c030e..b835664d 100644 --- a/Video.js +++ b/Video.js @@ -24,6 +24,16 @@ export default class Video extends Component { this._root.setNativeProps(nativeProps); } + stringsOnlyObject(obj) { + const strObj = {}; + + Object.keys(obj).forEach(x => { + strObj[x] = obj[x].toString(); + }); + + return strObj; + } + seek = (time) => { this.setNativeProps({ seek: time }); }; @@ -190,6 +200,7 @@ export default class Video extends Component { type: source.type || '', mainVer: source.mainVer || 0, patchVer: source.patchVer || 0, + requestHeaders: source.headers ? this.stringsOnlyObject(source.headers) : {} }, onVideoLoadStart: this._onLoadStart, onVideoLoad: this._onLoad, diff --git a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/DataSourceUtil.java b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/DataSourceUtil.java index 0077c3b0..2c3af708 100644 --- a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/DataSourceUtil.java +++ b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/DataSourceUtil.java @@ -1,7 +1,10 @@ package com.brentvatne.exoplayer; import android.content.Context; +import android.util.ArrayMap; +import com.facebook.react.bridge.ReadableMap; +import com.facebook.react.bridge.ReadableNativeMap; import com.facebook.react.modules.network.OkHttpClientProvider; import com.google.android.exoplayer2.ext.okhttp.OkHttpDataSourceFactory; import com.google.android.exoplayer2.upstream.DataSource; @@ -10,6 +13,10 @@ import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory; import com.google.android.exoplayer2.upstream.HttpDataSource; import com.google.android.exoplayer2.util.Util; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + public class DataSourceUtil { private DataSourceUtil() { @@ -41,9 +48,9 @@ public class DataSourceUtil { DataSourceUtil.rawDataSourceFactory = factory; } - public static DataSource.Factory getDefaultDataSourceFactory(Context context, DefaultBandwidthMeter bandwidthMeter) { + public static DataSource.Factory getDefaultDataSourceFactory(Context context, DefaultBandwidthMeter bandwidthMeter, Map requestHeaders) { if (defaultDataSourceFactory == null) { - defaultDataSourceFactory = buildDataSourceFactory(context, bandwidthMeter); + defaultDataSourceFactory = buildDataSourceFactory(context, bandwidthMeter, requestHeaders); } return defaultDataSourceFactory; } @@ -56,14 +63,18 @@ public class DataSourceUtil { return new RawResourceDataSourceFactory(context.getApplicationContext()); } - private static DataSource.Factory buildDataSourceFactory(Context context, DefaultBandwidthMeter bandwidthMeter) { + private static DataSource.Factory buildDataSourceFactory(Context context, DefaultBandwidthMeter bandwidthMeter, Map requestHeaders) { Context appContext = context.getApplicationContext(); return new DefaultDataSourceFactory(appContext, bandwidthMeter, - buildHttpDataSourceFactory(appContext, bandwidthMeter)); + buildHttpDataSourceFactory(appContext, bandwidthMeter, requestHeaders)); } - private static HttpDataSource.Factory buildHttpDataSourceFactory(Context context, DefaultBandwidthMeter bandwidthMeter) { - return new OkHttpDataSourceFactory(OkHttpClientProvider.getOkHttpClient(), getUserAgent(context), bandwidthMeter); - } + private static HttpDataSource.Factory buildHttpDataSourceFactory(Context context, DefaultBandwidthMeter bandwidthMeter, Map requestHeaders) { + OkHttpDataSourceFactory okHttpDataSourceFactory = new OkHttpDataSourceFactory(OkHttpClientProvider.getOkHttpClient(), getUserAgent(context), bandwidthMeter); + if (requestHeaders != null) + okHttpDataSourceFactory.getDefaultRequestProperties().set(requestHeaders); + + return okHttpDataSourceFactory; + } } diff --git a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java index 52bf24e6..dc48de31 100644 --- a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java +++ b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java @@ -14,6 +14,7 @@ import com.brentvatne.react.R; import com.brentvatne.receiver.AudioBecomingNoisyReceiver; import com.brentvatne.receiver.BecomingNoisyListener; import com.facebook.react.bridge.LifecycleEventListener; +import com.facebook.react.bridge.ReadableMap; import com.facebook.react.uimanager.ThemedReactContext; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.DefaultLoadControl; @@ -52,6 +53,7 @@ import java.net.CookieHandler; import java.net.CookieManager; import java.net.CookiePolicy; import java.lang.Math; +import java.util.Map; @SuppressLint("ViewConstructor") class ReactExoplayerView extends FrameLayout implements @@ -96,6 +98,7 @@ class ReactExoplayerView extends FrameLayout implements private boolean disableFocus; private float mProgressUpdateInterval = 250.0f; private boolean playInBackground = false; + private Map requestHeaders; // \ End props // React @@ -353,7 +356,7 @@ class ReactExoplayerView extends FrameLayout implements * @return A new DataSource factory. */ private DataSource.Factory buildDataSourceFactory(boolean useBandwidthMeter) { - return DataSourceUtil.getDefaultDataSourceFactory(getContext(), useBandwidthMeter ? BANDWIDTH_METER : null); + return DataSourceUtil.getDefaultDataSourceFactory(getContext(), useBandwidthMeter ? BANDWIDTH_METER : null, requestHeaders); } // AudioManager.OnAudioFocusChangeListener implementation @@ -537,14 +540,15 @@ class ReactExoplayerView extends FrameLayout implements // ReactExoplayerViewManager public api - public void setSrc(final Uri uri, final String extension) { + public void setSrc(final Uri uri, final String extension, Map headers) { if (uri != null) { boolean isOriginalSourceNull = srcUri == null; boolean isSourceEqual = uri.equals(srcUri); this.srcUri = uri; this.extension = extension; - this.mediaDataSourceFactory = DataSourceUtil.getDefaultDataSourceFactory(getContext(), BANDWIDTH_METER); + this.requestHeaders = headers; + this.mediaDataSourceFactory = DataSourceUtil.getDefaultDataSourceFactory(getContext(), BANDWIDTH_METER, requestHeaders); if (!isOriginalSourceNull && !isSourceEqual) { reloadSource(); diff --git a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java index dda8d000..cc0bee64 100644 --- a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java +++ b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java @@ -11,6 +11,7 @@ import com.facebook.react.uimanager.ViewGroupManager; import com.facebook.react.uimanager.annotations.ReactProp; import com.google.android.exoplayer2.upstream.RawResourceDataSource; +import java.util.HashMap; import java.util.Map; import javax.annotation.Nullable; @@ -22,6 +23,7 @@ public class ReactExoplayerViewManager extends ViewGroupManager headers = src.hasKey(PROP_SRC_HEADERS) ? toStringMap(src.getMap(PROP_SRC_HEADERS)) : null; + if (TextUtils.isEmpty(uriString)) { return; @@ -81,7 +85,7 @@ public class ReactExoplayerViewManager extends ViewGroupManager toStringMap(@Nullable ReadableMap readableMap) { + if (readableMap == null) + return null; + + com.facebook.react.bridge.ReadableMapKeySetIterator iterator = readableMap.keySetIterator(); + if (!iterator.hasNextKey()) + return null; + + Map result = new HashMap<>(); + while (iterator.hasNextKey()) { + String key = iterator.nextKey(); + result.put(key, readableMap.getString(key)); + } + + return result; + } } diff --git a/android/src/main/java/com/brentvatne/react/ReactVideoView.java b/android/src/main/java/com/brentvatne/react/ReactVideoView.java index 94a25a0e..17a8fbb0 100644 --- a/android/src/main/java/com/brentvatne/react/ReactVideoView.java +++ b/android/src/main/java/com/brentvatne/react/ReactVideoView.java @@ -15,6 +15,7 @@ import com.android.vending.expansion.zipfile.APKExpansionSupport; import com.android.vending.expansion.zipfile.ZipResourceFile; import com.facebook.react.bridge.Arguments; import com.facebook.react.bridge.LifecycleEventListener; +import com.facebook.react.bridge.ReadableMap; import com.facebook.react.bridge.WritableMap; import com.facebook.react.uimanager.ThemedReactContext; import com.facebook.react.uimanager.events.RCTEventEmitter; @@ -28,6 +29,8 @@ import java.util.HashMap; import java.util.Map; import java.lang.Math; +import javax.annotation.Nullable; + @SuppressLint("ViewConstructor") public class ReactVideoView extends ScalableVideoView implements MediaPlayer.OnPreparedListener, MediaPlayer .OnErrorListener, MediaPlayer.OnBufferingUpdateListener, MediaPlayer.OnCompletionListener, MediaPlayer.OnInfoListener, LifecycleEventListener, MediaController.MediaPlayerControl { @@ -86,6 +89,7 @@ public class ReactVideoView extends ScalableVideoView implements MediaPlayer.OnP private String mSrcUriString = null; private String mSrcType = "mp4"; + private ReadableMap mRequestHeaders = null; private boolean mSrcIsNetwork = false; private boolean mSrcIsAsset = false; private ScalableType mResizeMode = ScalableType.LEFT_TOP; @@ -201,16 +205,17 @@ public class ReactVideoView extends ScalableVideoView implements MediaPlayer.OnP } } - public void setSrc(final String uriString, final String type, final boolean isNetwork, final boolean isAsset) { - setSrc(uriString,type,isNetwork,isAsset,0,0); + public void setSrc(final String uriString, final String type, final boolean isNetwork, final boolean isAsset, final ReadableMap requestHeaders) { + setSrc(uriString, type, isNetwork, isAsset, requestHeaders, 0, 0); } - public void setSrc(final String uriString, final String type, final boolean isNetwork, final boolean isAsset, final int expansionMainVersion, final int expansionPatchVersion) { + public void setSrc(final String uriString, final String type, final boolean isNetwork, final boolean isAsset, final ReadableMap requestHeaders, final int expansionMainVersion, final int expansionPatchVersion) { mSrcUriString = uriString; mSrcType = type; mSrcIsNetwork = isNetwork; mSrcIsAsset = isAsset; + mRequestHeaders = requestHeaders; mMainVer = expansionMainVersion; mPatchVer = expansionPatchVersion; @@ -239,6 +244,10 @@ public class ReactVideoView extends ScalableVideoView implements MediaPlayer.OnP headers.put("Cookie", cookie); } + if (mRequestHeaders != null) { + headers.putAll(toStringMap(mRequestHeaders)); + } + setDataSource(uriString); } else if (isAsset) { if (uriString.startsWith("content://")) { @@ -285,8 +294,13 @@ public class ReactVideoView extends ScalableVideoView implements MediaPlayer.OnP } WritableMap src = Arguments.createMap(); + + WritableMap wRequestHeaders = Arguments.createMap(); + wRequestHeaders.merge(mRequestHeaders); + src.putString(ReactVideoViewManager.PROP_SRC_URI, uriString); src.putString(ReactVideoViewManager.PROP_SRC_TYPE, type); + src.putMap(ReactVideoViewManager.PROP_SRC_HEADERS, wRequestHeaders); src.putBoolean(ReactVideoViewManager.PROP_SRC_IS_NETWORK, isNetwork); if(mMainVer>0) { src.putInt(ReactVideoViewManager.PROP_SRC_MAINVER, mMainVer); @@ -542,10 +556,10 @@ public class ReactVideoView extends ScalableVideoView implements MediaPlayer.OnP super.onAttachedToWindow(); if(mMainVer>0) { - setSrc(mSrcUriString, mSrcType, mSrcIsNetwork,mSrcIsAsset,mMainVer,mPatchVer); + setSrc(mSrcUriString, mSrcType, mSrcIsNetwork, mSrcIsAsset, mRequestHeaders, mMainVer, mPatchVer); } else { - setSrc(mSrcUriString, mSrcType, mSrcIsNetwork,mSrcIsAsset); + setSrc(mSrcUriString, mSrcType, mSrcIsNetwork, mSrcIsAsset, mRequestHeaders); } } @@ -577,4 +591,28 @@ public class ReactVideoView extends ScalableVideoView implements MediaPlayer.OnP @Override public void onHostDestroy() { } + + /** + * toStringMap converts a {@link ReadableMap} into a HashMap. + * + * @param readableMap The ReadableMap to be conveted. + * @return A HashMap containing the data that was in the ReadableMap. + * @see 'Adapted from https://github.com/artemyarulin/react-native-eval/blob/master/android/src/main/java/com/evaluator/react/ConversionUtil.java' + */ + public static Map toStringMap(@Nullable ReadableMap readableMap) { + if (readableMap == null) + return null; + + com.facebook.react.bridge.ReadableMapKeySetIterator iterator = readableMap.keySetIterator(); + if (!iterator.hasNextKey()) + return null; + + Map result = new HashMap<>(); + while (iterator.hasNextKey()) { + String key = iterator.nextKey(); + result.put(key, readableMap.getString(key)); + } + + return result; + } } diff --git a/android/src/main/java/com/brentvatne/react/ReactVideoViewManager.java b/android/src/main/java/com/brentvatne/react/ReactVideoViewManager.java index 983113d5..404a16ef 100644 --- a/android/src/main/java/com/brentvatne/react/ReactVideoViewManager.java +++ b/android/src/main/java/com/brentvatne/react/ReactVideoViewManager.java @@ -21,6 +21,7 @@ public class ReactVideoViewManager extends SimpleViewManager { public static final String PROP_SRC = "src"; public static final String PROP_SRC_URI = "uri"; public static final String PROP_SRC_TYPE = "type"; + public static final String PROP_SRC_HEADERS = "headers"; public static final String PROP_SRC_IS_NETWORK = "isNetwork"; public static final String PROP_SRC_MAINVER = "mainVer"; public static final String PROP_SRC_PATCHVER = "patchVer"; @@ -85,6 +86,7 @@ public class ReactVideoViewManager extends SimpleViewManager { src.getString(PROP_SRC_TYPE), src.getBoolean(PROP_SRC_IS_NETWORK), src.getBoolean(PROP_SRC_IS_ASSET), + src.getMap(PROP_SRC_HEADERS), mainVer, patchVer ); @@ -94,8 +96,9 @@ public class ReactVideoViewManager extends SimpleViewManager { src.getString(PROP_SRC_URI), src.getString(PROP_SRC_TYPE), src.getBoolean(PROP_SRC_IS_NETWORK), - src.getBoolean(PROP_SRC_IS_ASSET) - ); + src.getBoolean(PROP_SRC_IS_ASSET), + src.getMap(PROP_SRC_HEADERS) + ); } } diff --git a/ios/RCTVideo.m b/ios/RCTVideo.m index 9962c2bb..8538b742 100644 --- a/ios/RCTVideo.m +++ b/ios/RCTVideo.m @@ -312,12 +312,17 @@ static NSString *const timedMetadata = @"timedMetadata"; bool isAsset = [RCTConvert BOOL:[source objectForKey:@"isAsset"]]; NSString *uri = [source objectForKey:@"uri"]; NSString *type = [source objectForKey:@"type"]; - + NSDictionary *headers = [source objectForKey:@"requestHeaders"]; + NSURL *url = (isNetwork || isAsset) ? [NSURL URLWithString:uri] : [[NSURL alloc] initFileURLWithPath:[[NSBundle mainBundle] pathForResource:uri ofType:type]]; if (isNetwork) { + if ([headers count] > 0) { + AVURLAsset* asset = [AVURLAsset URLAssetWithURL:url options:@{@"AVURLAssetHTTPHeaderFieldsKey": headers}]; + return [AVPlayerItem playerItemWithAsset:asset]; + } NSArray *cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies]; AVURLAsset *asset = [AVURLAsset URLAssetWithURL:url options:@{AVURLAssetHTTPCookiesKey : cookies}]; return [AVPlayerItem playerItemWithAsset:asset]; From 2ae99bd484486f468932db7830b7db8b69ccc507 Mon Sep 17 00:00:00 2001 From: Jan Lievens Date: Tue, 24 Oct 2017 09:47:43 +0200 Subject: [PATCH 010/189] remove observers before adding thus preventing multiple observers for the same notification --- ios/RCTVideo.m | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ios/RCTVideo.m b/ios/RCTVideo.m index 9962c2bb..ab0927c6 100644 --- a/ios/RCTVideo.m +++ b/ios/RCTVideo.m @@ -454,10 +454,17 @@ static NSString *const timedMetadata = @"timedMetadata"; - (void)attachListeners { // listen for end of file + [[NSNotificationCenter defaultCenter] removeObserver:self + name:AVPlayerItemDidPlayToEndTimeNotification + object:[_player currentItem]]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playerItemDidReachEnd:) name:AVPlayerItemDidPlayToEndTimeNotification object:[_player currentItem]]; + + [[NSNotificationCenter defaultCenter] removeObserver:self + name:AVPlayerItemPlaybackStalledNotification + object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playbackStalled:) name:AVPlayerItemPlaybackStalledNotification From f7b7f2666a206bc92faa94028b26d65b45a7300c Mon Sep 17 00:00:00 2001 From: Marc-Olivier Duval Date: Tue, 24 Oct 2017 21:49:46 -0400 Subject: [PATCH 011/189] Apply fix in playInBackground props --- .../java/com/brentvatne/exoplayer/ReactExoplayerView.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java index 52bf24e6..c12b2a48 100644 --- a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java +++ b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java @@ -167,6 +167,9 @@ class ReactExoplayerView extends FrameLayout implements @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); + if (playInBackground) { + return; + } stopPlayback(); } @@ -174,9 +177,6 @@ class ReactExoplayerView extends FrameLayout implements @Override public void onHostResume() { - if (playInBackground) { - return; - } setPlayWhenReady(!isPaused); } From ee5818b6ff4e39b1d5bdc5d59616f0f5f255ad7c Mon Sep 17 00:00:00 2001 From: Marc-Olivier Duval Date: Tue, 24 Oct 2017 22:42:41 -0400 Subject: [PATCH 012/189] Fix bug with playInBackground --- .../java/com/brentvatne/exoplayer/ReactExoplayerView.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java index c12b2a48..34df0031 100644 --- a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java +++ b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java @@ -167,9 +167,6 @@ class ReactExoplayerView extends FrameLayout implements @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); - if (playInBackground) { - return; - } stopPlayback(); } @@ -209,12 +206,14 @@ class ReactExoplayerView extends FrameLayout implements player.setMetadataOutput(this); exoPlayerView.setPlayer(player); audioBecomingNoisyReceiver.setListener(this); - setPlayWhenReady(!isPaused); playerNeedsSource = true; PlaybackParameters params = new PlaybackParameters(rate, 1f); player.setPlaybackParameters(params); } + + setPlayWhenReady(!isPaused); + if (playerNeedsSource && srcUri != null) { MediaSource mediaSource = buildMediaSource(srcUri, extension); mediaSource = repeat ? new LoopingMediaSource(mediaSource) : mediaSource; From 0fe621a26db4f9e091649b0304a5715d4d8b2947 Mon Sep 17 00:00:00 2001 From: Marc-Olivier Duval Date: Tue, 24 Oct 2017 22:42:51 -0400 Subject: [PATCH 013/189] Updated exoplayer readme --- android-exoplayer/README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/android-exoplayer/README.md b/android-exoplayer/README.md index e2d4f9fa..9396763b 100644 --- a/android-exoplayer/README.md +++ b/android-exoplayer/README.md @@ -42,6 +42,5 @@ https://github.com/google/ExoPlayer ## Unimplemented props -- `playInBackground={true}` -- `rate={1.0}` - Expansion file - `source={{ mainVer: 1, patchVer: 0 }}` + From 3e293407e8b15cb97b9ed475a0d65e40b079c466 Mon Sep 17 00:00:00 2001 From: Marc-Olivier Duval Date: Tue, 24 Oct 2017 22:50:20 -0400 Subject: [PATCH 014/189] updated readme to with a guid to setup exoplayer --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index 597b71ec..89e46a2f 100644 --- a/README.md +++ b/README.md @@ -269,6 +269,16 @@ Toggles a fullscreen player. Access using a ref to the component. - [Lumpen Radio](https://github.com/jhabdas/lumpen-radio) contains another example integration using local files and full screen background video. +## Use ExoPlayer on Android + +To use ExoPlayer instead of the default player, you have to change android to android-exoplayer in settings.gradle + +**android/settings.gradle** + +```gradle +project(':react-native-video').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-video/android-exoplayer') +``` + ## TODOS - [ ] Add support for captions From fe69081576017200c02d54425ebf7bf2aa30e68a Mon Sep 17 00:00:00 2001 From: Mathias Scherer Date: Fri, 3 Nov 2017 12:08:30 +0100 Subject: [PATCH 015/189] adds supported file extensions Android Expansion files adds mp4 as the only supported file extension for Android Expansion files --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 597b71ec..62fe5ba9 100644 --- a/README.md +++ b/README.md @@ -195,7 +195,7 @@ var styles = StyleSheet.create({ - * *For iOS you also need to specify muted for this to work* ## Android Expansion File Usage - +Only supports .mp4 files ```javascript // Within your render function, assuming you have a file called // "background.mp4" in your expansion file. Just add your main and (if applicable) patch version From 132d420b6ad28f54652778c08b762b4dfca372cc Mon Sep 17 00:00:00 2001 From: Mathias Scherer Date: Mon, 6 Nov 2017 13:17:56 +0100 Subject: [PATCH 016/189] updates readme with additional infos for expansion files adds the info that the mp4 files inside expansion files have not to be compressed to get it working --- README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 62fe5ba9..55a75928 100644 --- a/README.md +++ b/README.md @@ -195,7 +195,12 @@ var styles = StyleSheet.create({ - * *For iOS you also need to specify muted for this to work* ## Android Expansion File Usage -Only supports .mp4 files +Only supports .mp4 files. +The video files have not to be compressed. +Linux command example to exclude .mp4 files from zip compression: +```bash +zip -r -n.mp4 *.mp4 main.1.com.exmample.com +``` ```javascript // Within your render function, assuming you have a file called // "background.mp4" in your expansion file. Just add your main and (if applicable) patch version From c0a8f7c0c9ebf1a82a6f37381de9d96754c931c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kay=20Pl=C3=B6=C3=9Fer?= Date: Fri, 24 Nov 2017 16:22:41 +0100 Subject: [PATCH 017/189] Document fullscreen callbacks fix #861 --- README.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 597b71ec..01470edf 100644 --- a/README.md +++ b/README.md @@ -165,12 +165,16 @@ using System.Collections.Generic; playWhenInactive={false} // [iOS] Video continues to play when control or notification center are shown. ignoreSilentSwitch={"ignore"} // [iOS] ignore | obey - When 'ignore', audio will still play with the iOS hard silent switch set to silent. When 'obey', audio will toggle with the switch. When not specified, will inherit audio settings as usual. progressUpdateInterval={250.0} // [iOS] Interval to fire onProgress (default to ~250ms) + onBuffer={this.onBuffer} // Callback when remote video is buffering + onEnd={this.onEnd} // Callback when playback finishes + onError={this.videoError} // Callback when video cannot be loaded + onFullscreenPlayerWillPresent={this.fullScreenPlayerWillPresent} // Callback before fullscreen starts + onFullscreenPlayerDidPresent={this.fullScreenPlayerDidPresent} // Callback after fullscreen started + onFullscreenPlayerWillDismiss={this.fullScreenPlayerWillDismiss} // Callback before fullscreen stops + onFullscreenPlayerDidDismiss={this.fullScreenPlayerDidDissmiss} // Callback after fullscreen stopped onLoadStart={this.loadStart} // Callback when video starts to load onLoad={this.setDuration} // Callback when video loads onProgress={this.setTime} // Callback every ~250ms with currentTime - onEnd={this.onEnd} // Callback when playback finishes - onError={this.videoError} // Callback when video cannot be loaded - onBuffer={this.onBuffer} // Callback when remote video is buffering onTimedMetadata={this.onTimedMetadata} // Callback when the stream receive some metadata style={styles.backgroundVideo} /> From ce7c732453476cf77b8583981601f521cbb83410 Mon Sep 17 00:00:00 2001 From: Jordan Becker Date: Thu, 7 Dec 2017 19:35:32 +0100 Subject: [PATCH 018/189] Add requiresMainQueueSetup method Since RN 0.49, `requiresMainQueueSetup` needs to be defined if the module overrides `constantsToExport`. --- ios/RCTVideoManager.m | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ios/RCTVideoManager.m b/ios/RCTVideoManager.m index a5cf85e0..c1edb9b7 100644 --- a/ios/RCTVideoManager.m +++ b/ios/RCTVideoManager.m @@ -62,4 +62,9 @@ RCT_EXPORT_VIEW_PROPERTY(onPlaybackRateChange, RCTBubblingEventBlock); }; } ++ (BOOL)requiresMainQueueSetup +{ + return YES; +} + @end From 64191298e514ab52b9cb4fcabcb7e38b40a698fe Mon Sep 17 00:00:00 2001 From: sm2017 Date: Sun, 24 Dec 2017 14:44:00 +0330 Subject: [PATCH 019/189] Update ReactVideoView.cs Fix 'Event' does not contain a constructor that takes 2 arguments ReactNativeVideo --- windows/ReactNativeVideo.Net46/ReactVideoView.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/windows/ReactNativeVideo.Net46/ReactVideoView.cs b/windows/ReactNativeVideo.Net46/ReactVideoView.cs index 8a8b1b29..643965ee 100644 --- a/windows/ReactNativeVideo.Net46/ReactVideoView.cs +++ b/windows/ReactNativeVideo.Net46/ReactVideoView.cs @@ -328,7 +328,7 @@ namespace ReactNativeVideo private readonly JObject _eventData; public ReactVideoEvent(string eventName, int viewTag, JObject eventData) - : base(viewTag, TimeSpan.FromTicks(Environment.TickCount)) + : base(viewTag) { _eventName = eventName; _eventData = eventData; From dd242476a3615055343c0c06a119713f9df6fb0e Mon Sep 17 00:00:00 2001 From: sm2017 Date: Sun, 24 Dec 2017 14:46:02 +0330 Subject: [PATCH 020/189] Update ReactVideoView.cs Fix 'Event' does not contain a constructor that takes 2 arguments ReactNativeVideo --- windows/ReactNativeVideo/ReactVideoView.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/windows/ReactNativeVideo/ReactVideoView.cs b/windows/ReactNativeVideo/ReactVideoView.cs index 22063aff..5a6c103f 100644 --- a/windows/ReactNativeVideo/ReactVideoView.cs +++ b/windows/ReactNativeVideo/ReactVideoView.cs @@ -334,7 +334,7 @@ namespace ReactNativeVideo private readonly JObject _eventData; public ReactVideoEvent(string eventName, int viewTag, JObject eventData) - : base(viewTag, TimeSpan.FromTicks(Environment.TickCount)) + : base(viewTag) { _eventName = eventName; _eventData = eventData; From 7d48f22d9871bf98f4a1208e53d218954135f6fa Mon Sep 17 00:00:00 2001 From: Alejandro Rangel Date: Thu, 11 Jan 2018 09:16:29 -0800 Subject: [PATCH 021/189] add seekableDuration to android ReactVideoView --- android/src/main/java/com/brentvatne/react/ReactVideoView.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/android/src/main/java/com/brentvatne/react/ReactVideoView.java b/android/src/main/java/com/brentvatne/react/ReactVideoView.java index 94a25a0e..f609bcc4 100644 --- a/android/src/main/java/com/brentvatne/react/ReactVideoView.java +++ b/android/src/main/java/com/brentvatne/react/ReactVideoView.java @@ -64,6 +64,7 @@ public class ReactVideoView extends ScalableVideoView implements MediaPlayer.OnP public static final String EVENT_PROP_DURATION = "duration"; public static final String EVENT_PROP_PLAYABLE_DURATION = "playableDuration"; + public static final String EVENT_PROP_SEEKABLE_DURATION = "seekableDuration"; public static final String EVENT_PROP_CURRENT_TIME = "currentTime"; public static final String EVENT_PROP_SEEK_TIME = "seekTime"; public static final String EVENT_PROP_NATURALSIZE = "naturalSize"; @@ -127,6 +128,7 @@ public class ReactVideoView extends ScalableVideoView implements MediaPlayer.OnP WritableMap event = Arguments.createMap(); event.putDouble(EVENT_PROP_CURRENT_TIME, mMediaPlayer.getCurrentPosition() / 1000.0); event.putDouble(EVENT_PROP_PLAYABLE_DURATION, mVideoBufferedDuration / 1000.0); //TODO:mBufferUpdateRunnable + event.putDouble(EVENT_PROP_SEEKABLE_DURATION, mVideoDuration / 1000.0); mEventEmitter.receiveEvent(getId(), Events.EVENT_PROGRESS.toString(), event); // Check for update after an interval From 57a16b23c57b600dd446298a26fdf1eb627d0955 Mon Sep 17 00:00:00 2001 From: Emrah Kaya Date: Sat, 13 Jan 2018 21:28:24 +0100 Subject: [PATCH 022/189] stringsOnlyObject does typechecking before coercion to string --- Video.js | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/Video.js b/Video.js index b835664d..2db74fbd 100644 --- a/Video.js +++ b/Video.js @@ -23,6 +23,29 @@ export default class Video extends Component { setNativeProps(nativeProps) { this._root.setNativeProps(nativeProps); } + + toTypeString(x) { + switch (typeof x) { + case "object": + return x instanceof Date + ? x.toISOString() + : JSON.stringify(x); // object, null + case "undefined": + return ""; + default: // boolean, number, string + return x.toString(); + } + } + + stringsOnlyObject(obj) { + const strObj = {}; + + Object.keys(obj).forEach(x => { + strObj[x] = this.toTypeString(obj[x]); + }); + + return strObj; + } stringsOnlyObject(obj) { const strObj = {}; From db1d83b83e68ed02160d4c8c6eb35a650a29709e Mon Sep 17 00:00:00 2001 From: Emrah Kaya Date: Sat, 13 Jan 2018 21:29:53 +0100 Subject: [PATCH 023/189] constants renamed to requestheader --- .../com/brentvatne/exoplayer/ReactExoplayerViewManager.java | 2 +- .../main/java/com/brentvatne/react/ReactVideoViewManager.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java index cc0bee64..634aefd2 100644 --- a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java +++ b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java @@ -23,7 +23,7 @@ public class ReactExoplayerViewManager extends ViewGroupManager { public static final String PROP_SRC = "src"; public static final String PROP_SRC_URI = "uri"; public static final String PROP_SRC_TYPE = "type"; - public static final String PROP_SRC_HEADERS = "headers"; + public static final String PROP_SRC_HEADERS = "requestHeaders"; public static final String PROP_SRC_IS_NETWORK = "isNetwork"; public static final String PROP_SRC_MAINVER = "mainVer"; public static final String PROP_SRC_PATCHVER = "patchVer"; From 5c8e1bd6d4828842f160bd66eb6c8c6aabb92f47 Mon Sep 17 00:00:00 2001 From: emrah88 Date: Mon, 15 Jan 2018 16:15:25 +0100 Subject: [PATCH 024/189] ensuring datasource is build with headers --- .../src/main/java/com/brentvatne/exoplayer/DataSourceUtil.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/DataSourceUtil.java b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/DataSourceUtil.java index 2c3af708..91bee912 100644 --- a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/DataSourceUtil.java +++ b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/DataSourceUtil.java @@ -49,7 +49,7 @@ public class DataSourceUtil { } public static DataSource.Factory getDefaultDataSourceFactory(Context context, DefaultBandwidthMeter bandwidthMeter, Map requestHeaders) { - if (defaultDataSourceFactory == null) { + if (defaultDataSourceFactory == null || !requestHeaders.isEmpty()) { defaultDataSourceFactory = buildDataSourceFactory(context, bandwidthMeter, requestHeaders); } return defaultDataSourceFactory; From 12f93b5463a525562eb1edff9117d257de0220e8 Mon Sep 17 00:00:00 2001 From: emrah88 Date: Mon, 15 Jan 2018 17:10:54 +0100 Subject: [PATCH 025/189] null pointer --- .../src/main/java/com/brentvatne/exoplayer/DataSourceUtil.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/DataSourceUtil.java b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/DataSourceUtil.java index 91bee912..47d179d7 100644 --- a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/DataSourceUtil.java +++ b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/DataSourceUtil.java @@ -49,7 +49,7 @@ public class DataSourceUtil { } public static DataSource.Factory getDefaultDataSourceFactory(Context context, DefaultBandwidthMeter bandwidthMeter, Map requestHeaders) { - if (defaultDataSourceFactory == null || !requestHeaders.isEmpty()) { + if (defaultDataSourceFactory == null || (requestHeaders != null && !requestHeaders.isEmpty())) { defaultDataSourceFactory = buildDataSourceFactory(context, bandwidthMeter, requestHeaders); } return defaultDataSourceFactory; From 5d274631c8d742a5faa49532bf0a967da760be2c Mon Sep 17 00:00:00 2001 From: Brandon Moon Date: Mon, 29 Jan 2018 13:25:58 -0700 Subject: [PATCH 026/189] Link up cookies so exoplayer can use them --- .../brentvatne/exoplayer/DataSourceUtil.java | 31 +++++++++++++------ .../exoplayer/ReactExoplayerView.java | 16 +++------- 2 files changed, 26 insertions(+), 21 deletions(-) diff --git a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/DataSourceUtil.java b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/DataSourceUtil.java index 0077c3b0..c486bf0b 100644 --- a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/DataSourceUtil.java +++ b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/DataSourceUtil.java @@ -1,7 +1,11 @@ package com.brentvatne.exoplayer; import android.content.Context; +import android.content.ContextWrapper; +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.upstream.DataSource; @@ -10,6 +14,10 @@ import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory; import com.google.android.exoplayer2.upstream.HttpDataSource; import com.google.android.exoplayer2.util.Util; +import okhttp3.Cookie; +import okhttp3.JavaNetCookieJar; +import okhttp3.OkHttpClient; + public class DataSourceUtil { private DataSourceUtil() { @@ -23,14 +31,14 @@ public class DataSourceUtil { DataSourceUtil.userAgent = userAgent; } - public static String getUserAgent(Context context) { + public static String getUserAgent(ReactContext context) { if (userAgent == null) { - userAgent = Util.getUserAgent(context.getApplicationContext(), "ReactNativeVideo"); + userAgent = Util.getUserAgent(context, "ReactNativeVideo"); } return userAgent; } - public static DataSource.Factory getRawDataSourceFactory(Context context) { + public static DataSource.Factory getRawDataSourceFactory(ReactContext context) { if (rawDataSourceFactory == null) { rawDataSourceFactory = buildRawDataSourceFactory(context); } @@ -41,7 +49,7 @@ public class DataSourceUtil { DataSourceUtil.rawDataSourceFactory = factory; } - public static DataSource.Factory getDefaultDataSourceFactory(Context context, DefaultBandwidthMeter bandwidthMeter) { + public static DataSource.Factory getDefaultDataSourceFactory(ReactContext context, DefaultBandwidthMeter bandwidthMeter) { if (defaultDataSourceFactory == null) { defaultDataSourceFactory = buildDataSourceFactory(context, bandwidthMeter); } @@ -52,17 +60,20 @@ public class DataSourceUtil { DataSourceUtil.defaultDataSourceFactory = factory; } - private static DataSource.Factory buildRawDataSourceFactory(Context context) { + private static DataSource.Factory buildRawDataSourceFactory(ReactContext context) { return new RawResourceDataSourceFactory(context.getApplicationContext()); } - private static DataSource.Factory buildDataSourceFactory(Context context, DefaultBandwidthMeter bandwidthMeter) { - Context appContext = context.getApplicationContext(); - return new DefaultDataSourceFactory(appContext, bandwidthMeter, - buildHttpDataSourceFactory(appContext, bandwidthMeter)); + private static DataSource.Factory buildDataSourceFactory(ReactContext context, DefaultBandwidthMeter bandwidthMeter) { + return new DefaultDataSourceFactory(context, bandwidthMeter, + buildHttpDataSourceFactory(context, bandwidthMeter)); } - private static HttpDataSource.Factory buildHttpDataSourceFactory(Context context, DefaultBandwidthMeter bandwidthMeter) { + private static HttpDataSource.Factory buildHttpDataSourceFactory(ReactContext context, DefaultBandwidthMeter bandwidthMeter) { + OkHttpClient client = OkHttpClientProvider.getOkHttpClient(); + CookieJarContainer container = (CookieJarContainer) client.cookieJar(); + ForwardingCookieHandler handler = new ForwardingCookieHandler(context); + container.setCookieJar(new JavaNetCookieJar(handler)); return new OkHttpDataSourceFactory(OkHttpClientProvider.getOkHttpClient(), getUserAgent(context), bandwidthMeter); } diff --git a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java index f24d94c2..074531af 100644 --- a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java +++ b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java @@ -124,14 +124,13 @@ class ReactExoplayerView extends FrameLayout implements public ReactExoplayerView(ThemedReactContext context) { super(context); + this.themedReactContext = context; createViews(); this.eventEmitter = new VideoEventEmitter(context); - this.themedReactContext = context; audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); themedReactContext.addLifecycleEventListener(this); audioBecomingNoisyReceiver = new AudioBecomingNoisyReceiver(themedReactContext); - initializePlayer(); } @@ -353,7 +352,7 @@ class ReactExoplayerView extends FrameLayout implements * @return A new DataSource factory. */ private DataSource.Factory buildDataSourceFactory(boolean useBandwidthMeter) { - return DataSourceUtil.getDefaultDataSourceFactory(getContext(), useBandwidthMeter ? BANDWIDTH_METER : null); + return DataSourceUtil.getDefaultDataSourceFactory(this.themedReactContext, useBandwidthMeter ? BANDWIDTH_METER : null); } // AudioManager.OnAudioFocusChangeListener implementation @@ -482,7 +481,6 @@ class ReactExoplayerView extends FrameLayout implements @Override public void onPlayerError(ExoPlaybackException e) { String errorString = null; - Exception ex = e; if (e.type == ExoPlaybackException.TYPE_RENDERER) { Exception cause = e.getRendererException(); if (cause instanceof MediaCodecRenderer.DecoderInitializationException) { @@ -505,12 +503,8 @@ class ReactExoplayerView extends FrameLayout implements } } } - else if (e.type == ExoPlaybackException.TYPE_SOURCE) { - ex = e.getSourceException(); - errorString = getResources().getString(R.string.unrecognized_media_format); - } if (errorString != null) { - eventEmitter.error(errorString, ex); + eventEmitter.error(errorString, e); } playerNeedsSource = true; if (isBehindLiveWindow(e)) { @@ -549,7 +543,7 @@ class ReactExoplayerView extends FrameLayout implements this.srcUri = uri; this.extension = extension; - this.mediaDataSourceFactory = DataSourceUtil.getDefaultDataSourceFactory(getContext(), BANDWIDTH_METER); + this.mediaDataSourceFactory = DataSourceUtil.getDefaultDataSourceFactory(this.themedReactContext, BANDWIDTH_METER); if (!isOriginalSourceNull && !isSourceEqual) { reloadSource(); @@ -568,7 +562,7 @@ class ReactExoplayerView extends FrameLayout implements this.srcUri = uri; this.extension = extension; - this.mediaDataSourceFactory = DataSourceUtil.getRawDataSourceFactory(getContext()); + this.mediaDataSourceFactory = DataSourceUtil.getRawDataSourceFactory(this.themedReactContext); if (!isOriginalSourceNull && !isSourceEqual) { reloadSource(); From f2e182addc70cb380b56db190b62cca56d3dcac4 Mon Sep 17 00:00:00 2001 From: Brandon Moon Date: Mon, 29 Jan 2018 13:32:31 -0700 Subject: [PATCH 027/189] Bring things up to date with master from copied code --- .../java/com/brentvatne/exoplayer/ReactExoplayerView.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java index 074531af..cf8ebc28 100644 --- a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java +++ b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java @@ -131,6 +131,7 @@ class ReactExoplayerView extends FrameLayout implements themedReactContext.addLifecycleEventListener(this); audioBecomingNoisyReceiver = new AudioBecomingNoisyReceiver(themedReactContext); + initializePlayer(); } @@ -481,6 +482,7 @@ class ReactExoplayerView extends FrameLayout implements @Override public void onPlayerError(ExoPlaybackException e) { String errorString = null; + Exception ex = e; if (e.type == ExoPlaybackException.TYPE_RENDERER) { Exception cause = e.getRendererException(); if (cause instanceof MediaCodecRenderer.DecoderInitializationException) { @@ -503,8 +505,12 @@ class ReactExoplayerView extends FrameLayout implements } } } + else if (e.type == ExoPlaybackException.TYPE_SOURCE) { + ex = e.getSourceException(); + errorString = getResources().getString(R.string.unrecognized_media_format); + } if (errorString != null) { - eventEmitter.error(errorString, e); + eventEmitter.error(errorString, ex); } playerNeedsSource = true; if (isBehindLiveWindow(e)) { From cf9a5fc63596d6095506b01a988af7067e907205 Mon Sep 17 00:00:00 2001 From: Andy Stanberry Date: Wed, 31 Jan 2018 17:53:37 -0500 Subject: [PATCH 028/189] Document poster prop --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 597b71ec..9a6da0f4 100644 --- a/README.md +++ b/README.md @@ -152,6 +152,7 @@ using System.Collections.Generic; // on a single screen if you like.