From 270fdfb657bb298a2c381aa5ff0e455cb2a95423 Mon Sep 17 00:00:00 2001 From: Emrah Kaya Date: Mon, 2 Oct 2017 20:11:41 +0200 Subject: [PATCH 01/12] 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 57a16b23c57b600dd446298a26fdf1eb627d0955 Mon Sep 17 00:00:00 2001 From: Emrah Kaya Date: Sat, 13 Jan 2018 21:28:24 +0100 Subject: [PATCH 02/12] 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 03/12] 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 04/12] 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 05/12] 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 623b5622950cd1ea9c6420212929ee0eeba53c7f Mon Sep 17 00:00:00 2001 From: Emrah Kaya Date: Sat, 9 Jun 2018 21:30:38 +0200 Subject: [PATCH 06/12] resolving conflicts --- .../brentvatne/exoplayer/DataSourceUtil.java | 30 +++++++++++-------- .../exoplayer/ReactExoplayerView.java | 5 ++-- 2 files changed, 21 insertions(+), 14 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 47d179d7..2aca6551 100644 --- a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/DataSourceUtil.java +++ b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/DataSourceUtil.java @@ -1,10 +1,11 @@ package com.brentvatne.exoplayer; import android.content.Context; -import android.util.ArrayMap; +import android.content.ContextWrapper; -import com.facebook.react.bridge.ReadableMap; -import com.facebook.react.bridge.ReadableNativeMap; +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; @@ -13,8 +14,9 @@ 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 okhttp3.Cookie; +import okhttp3.JavaNetCookieJar; +import okhttp3.OkHttpClient; import java.util.Map; public class DataSourceUtil { @@ -48,7 +50,7 @@ public class DataSourceUtil { DataSourceUtil.rawDataSourceFactory = factory; } - public static DataSource.Factory getDefaultDataSourceFactory(Context context, DefaultBandwidthMeter bandwidthMeter, Map requestHeaders) { + public static DataSource.Factory getDefaultDataSourceFactory(ReactContext context, DefaultBandwidthMeter bandwidthMeter, Map requestHeaders) { if (defaultDataSourceFactory == null || (requestHeaders != null && !requestHeaders.isEmpty())) { defaultDataSourceFactory = buildDataSourceFactory(context, bandwidthMeter, requestHeaders); } @@ -63,14 +65,18 @@ public class DataSourceUtil { return new RawResourceDataSourceFactory(context.getApplicationContext()); } - private static DataSource.Factory buildDataSourceFactory(Context context, DefaultBandwidthMeter bandwidthMeter, Map requestHeaders) { - Context appContext = context.getApplicationContext(); - return new DefaultDataSourceFactory(appContext, bandwidthMeter, - buildHttpDataSourceFactory(appContext, bandwidthMeter, requestHeaders)); + private static DataSource.Factory buildDataSourceFactory(ReactContext context, DefaultBandwidthMeter bandwidthMeter, Map requestHeaders) { + return new DefaultDataSourceFactory(context, bandwidthMeter, + buildHttpDataSourceFactory(context, bandwidthMeter, requestHeaders)); } - private static HttpDataSource.Factory buildHttpDataSourceFactory(Context context, DefaultBandwidthMeter bandwidthMeter, Map requestHeaders) { - OkHttpDataSourceFactory okHttpDataSourceFactory = new OkHttpDataSourceFactory(OkHttpClientProvider.getOkHttpClient(), getUserAgent(context), bandwidthMeter); + private static HttpDataSource.Factory buildHttpDataSourceFactory(ReactContext context, DefaultBandwidthMeter bandwidthMeter, Map requestHeaders) { + OkHttpClient client = OkHttpClientProvider.getOkHttpClient(); + CookieJarContainer container = (CookieJarContainer) client.cookieJar(); + ForwardingCookieHandler handler = new ForwardingCookieHandler(context); + container.setCookieJar(new JavaNetCookieJar(handler)); + + OkHttpDataSourceFactory okHttpDataSourceFactory = new OkHttpDataSourceFactory(client, getUserAgent(context), bandwidthMeter); if (requestHeaders != null) okHttpDataSourceFactory.getDefaultRequestProperties().set(requestHeaders); 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 177e1c2c..ec22c7fa 100644 --- a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java +++ b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java @@ -104,6 +104,7 @@ class ReactExoplayerView extends FrameLayout implements private boolean disableFocus; private float mProgressUpdateInterval = 250.0f; private boolean playInBackground = false; + private boolean useTextureView = false; private Map requestHeaders; // \ End props @@ -366,7 +367,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, requestHeaders); + return DataSourceUtil.getDefaultDataSourceFactory(this.themedReactContext, useBandwidthMeter ? BANDWIDTH_METER : null, requestHeaders); } // AudioManager.OnAudioFocusChangeListener implementation @@ -584,7 +585,7 @@ class ReactExoplayerView extends FrameLayout implements this.srcUri = uri; this.extension = extension; this.requestHeaders = headers; - this.mediaDataSourceFactory = DataSourceUtil.getDefaultDataSourceFactory(getContext(), BANDWIDTH_METER, requestHeaders); + this.mediaDataSourceFactory = DataSourceUtil.getDefaultDataSourceFactory(this.themedReactContext, BANDWIDTH_METER, requestHeaders); if (!isOriginalSourceNull && !isSourceEqual) { reloadSource(); From f340025a09f47199c1109c8c30dca30bc515a77d Mon Sep 17 00:00:00 2001 From: Emrah Kaya Date: Sat, 9 Jun 2018 21:53:21 +0200 Subject: [PATCH 07/12] respecting cookies when opting in for headers (ios) --- ios/RCTVideo.m | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/ios/RCTVideo.m b/ios/RCTVideo.m index 94b0223d..c8908734 100644 --- a/ios/RCTVideo.m +++ b/ios/RCTVideo.m @@ -328,12 +328,14 @@ static NSString *const timedMetadata = @"timedMetadata"; [[NSURL alloc] initFileURLWithPath:[[NSBundle mainBundle] pathForResource:uri ofType:type]]; if (isNetwork) { + NSMutableDictionary *assetOptions = [[NSMutableDictionary alloc]init]; if ([headers count] > 0) { - AVURLAsset* asset = [AVURLAsset URLAssetWithURL:url options:@{@"AVURLAssetHTTPHeaderFieldsKey": headers}]; - return [AVPlayerItem playerItemWithAsset:asset]; + [assetOptions setObject:@headers forKey:@"AVURLAssetHTTPHeaderFieldsKey"] } NSArray *cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies]; - AVURLAsset *asset = [AVURLAsset URLAssetWithURL:url options:@{AVURLAssetHTTPCookiesKey : cookies}]; + [assetOptions setObject:@cookies forKey:@AVURLAssetHTTPCookiesKey] + + AVURLAsset *asset = [AVURLAsset URLAssetWithURL:url options:assetOptions]; return [AVPlayerItem playerItemWithAsset:asset]; } else if (isAsset) { From 49cd5b6d018e62e6ed148458d658c32d0035688a Mon Sep 17 00:00:00 2001 From: Emrah Kaya Date: Sat, 9 Jun 2018 23:04:31 +0200 Subject: [PATCH 08/12] passing headers to setDataSource when network video --- android/src/main/java/com/brentvatne/react/ReactVideoView.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/src/main/java/com/brentvatne/react/ReactVideoView.java b/android/src/main/java/com/brentvatne/react/ReactVideoView.java index d265a1a1..3d3968ff 100644 --- a/android/src/main/java/com/brentvatne/react/ReactVideoView.java +++ b/android/src/main/java/com/brentvatne/react/ReactVideoView.java @@ -254,7 +254,7 @@ public class ReactVideoView extends ScalableVideoView implements MediaPlayer.OnP headers.putAll(toStringMap(mRequestHeaders)); } - setDataSource(uriString); + setDataSource(mThemedReactContext, parsedUrl, headers); } else if (isAsset) { if (uriString.startsWith("content://")) { Uri parsedUrl = Uri.parse(uriString); From 6cd7dfeedf10d1b55b5ec2fc30ea5afa449f147b Mon Sep 17 00:00:00 2001 From: Emrah Kaya Date: Mon, 11 Jun 2018 11:10:01 +0200 Subject: [PATCH 09/12] fix syntax errors --- ios/RCTVideo.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ios/RCTVideo.m b/ios/RCTVideo.m index c8908734..d7d61411 100644 --- a/ios/RCTVideo.m +++ b/ios/RCTVideo.m @@ -330,10 +330,10 @@ static NSString *const timedMetadata = @"timedMetadata"; if (isNetwork) { NSMutableDictionary *assetOptions = [[NSMutableDictionary alloc]init]; if ([headers count] > 0) { - [assetOptions setObject:@headers forKey:@"AVURLAssetHTTPHeaderFieldsKey"] + [assetOptions setObject:headers forKey:@"AVURLAssetHTTPHeaderFieldsKey"]; } NSArray *cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies]; - [assetOptions setObject:@cookies forKey:@AVURLAssetHTTPCookiesKey] + [assetOptions setObject:cookies forKey:AVURLAssetHTTPCookiesKey]; AVURLAsset *asset = [AVURLAsset URLAssetWithURL:url options:assetOptions]; return [AVPlayerItem playerItemWithAsset:asset]; From 2649242178d1823d56fac3c0652e77a10103cddf Mon Sep 17 00:00:00 2001 From: Hampton Maxwell Date: Fri, 22 Jun 2018 18:46:48 -0700 Subject: [PATCH 10/12] Remove duplicate outdated stringsOnlyObject implementation --- Video.js | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/Video.js b/Video.js index d0ef212b..f8677bad 100644 --- a/Video.js +++ b/Video.js @@ -47,16 +47,6 @@ export default class Video extends Component { return strObj; } - stringsOnlyObject(obj) { - const strObj = {}; - - Object.keys(obj).forEach(x => { - strObj[x] = obj[x].toString(); - }); - - return strObj; - } - seek = (time) => { this.setNativeProps({ seek: time }); }; From bb2b3eb30657c2482b2b6271b9272d0ac3ec13c8 Mon Sep 17 00:00:00 2001 From: Hampton Maxwell Date: Fri, 22 Jun 2018 19:20:25 -0700 Subject: [PATCH 11/12] Handle converting maps that are null or empty --- .../src/main/java/com/brentvatne/react/ReactVideoView.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/android/src/main/java/com/brentvatne/react/ReactVideoView.java b/android/src/main/java/com/brentvatne/react/ReactVideoView.java index 09e5220f..8eabeff1 100644 --- a/android/src/main/java/com/brentvatne/react/ReactVideoView.java +++ b/android/src/main/java/com/brentvatne/react/ReactVideoView.java @@ -641,14 +641,11 @@ public class ReactVideoView extends ScalableVideoView implements MediaPlayer.OnP * @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) { + Map result = new HashMap<>(); if (readableMap == null) - return null; + return result; 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)); From 448e57ba3fef071345e46f6f9f0772747ffb4147 Mon Sep 17 00:00:00 2001 From: Hampton Maxwell Date: Fri, 22 Jun 2018 19:32:36 -0700 Subject: [PATCH 12/12] Add note about IOException when using bigger setDataSource call --- .../src/main/java/com/brentvatne/react/ReactVideoView.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/android/src/main/java/com/brentvatne/react/ReactVideoView.java b/android/src/main/java/com/brentvatne/react/ReactVideoView.java index 8eabeff1..954130a1 100644 --- a/android/src/main/java/com/brentvatne/react/ReactVideoView.java +++ b/android/src/main/java/com/brentvatne/react/ReactVideoView.java @@ -253,6 +253,10 @@ public class ReactVideoView extends ScalableVideoView implements MediaPlayer.OnP headers.putAll(toStringMap(mRequestHeaders)); } + /* According to https://github.com/react-native-community/react-native-video/pull/537 + * there is an issue with this where it can cause a IOException. + * TODO: diagnose this exception and fix it + */ setDataSource(mThemedReactContext, parsedUrl, headers); } else if (isAsset) { if (uriString.startsWith("content://")) {