parent
9a3fcda3b8
commit
d86adc52f3
46
android/src/main/java/com/brentvatne/common/api/AdsProps.kt
Normal file
46
android/src/main/java/com/brentvatne/common/api/AdsProps.kt
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
package com.brentvatne.common.api
|
||||||
|
|
||||||
|
import android.net.Uri
|
||||||
|
import android.text.TextUtils
|
||||||
|
import com.brentvatne.common.toolbox.DebugLog
|
||||||
|
import com.brentvatne.common.toolbox.ReactBridgeUtils
|
||||||
|
import com.facebook.react.bridge.ReadableMap
|
||||||
|
|
||||||
|
class AdsProps {
|
||||||
|
var adTagUrl: Uri? = null
|
||||||
|
var adLanguage: String? = null
|
||||||
|
|
||||||
|
/** return true if this and src are equals */
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (other == null || other !is AdsProps) return false
|
||||||
|
return (
|
||||||
|
adTagUrl == other.adTagUrl &&
|
||||||
|
adLanguage == other.adLanguage
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val PROP_AD_TAG_URL = "adTagUrl"
|
||||||
|
private const val PROP_AD_LANGUAGE = "adLanguage"
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun parse(src: ReadableMap?): AdsProps {
|
||||||
|
val adsProps = AdsProps()
|
||||||
|
DebugLog.w("olivier", "uri: parse AdsProps")
|
||||||
|
|
||||||
|
if (src != null) {
|
||||||
|
val uriString = ReactBridgeUtils.safeGetString(src, PROP_AD_TAG_URL)
|
||||||
|
if (TextUtils.isEmpty(uriString)) {
|
||||||
|
adsProps.adTagUrl = null
|
||||||
|
} else {
|
||||||
|
adsProps.adTagUrl = Uri.parse(uriString)
|
||||||
|
}
|
||||||
|
val languageString = ReactBridgeUtils.safeGetString(src, PROP_AD_LANGUAGE)
|
||||||
|
if (!TextUtils.isEmpty(languageString)) {
|
||||||
|
adsProps.adLanguage = languageString
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return adsProps
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -14,6 +14,7 @@ import com.brentvatne.common.toolbox.ReactBridgeUtils.safeGetBool
|
|||||||
import com.brentvatne.common.toolbox.ReactBridgeUtils.safeGetInt
|
import com.brentvatne.common.toolbox.ReactBridgeUtils.safeGetInt
|
||||||
import com.brentvatne.common.toolbox.ReactBridgeUtils.safeGetMap
|
import com.brentvatne.common.toolbox.ReactBridgeUtils.safeGetMap
|
||||||
import com.brentvatne.common.toolbox.ReactBridgeUtils.safeGetString
|
import com.brentvatne.common.toolbox.ReactBridgeUtils.safeGetString
|
||||||
|
import com.brentvatne.react.BuildConfig
|
||||||
import com.facebook.react.bridge.ReadableMap
|
import com.facebook.react.bridge.ReadableMap
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
import java.util.Objects
|
import java.util.Objects
|
||||||
@ -65,6 +66,11 @@ class Source {
|
|||||||
*/
|
*/
|
||||||
var cmcdProps: CMCDProps? = null
|
var cmcdProps: CMCDProps? = null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ads playback properties
|
||||||
|
*/
|
||||||
|
var adsProps: AdsProps? = null
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The list of sideLoaded text tracks
|
* The list of sideLoaded text tracks
|
||||||
*/
|
*/
|
||||||
@ -84,7 +90,8 @@ class Source {
|
|||||||
drmProps == other.drmProps &&
|
drmProps == other.drmProps &&
|
||||||
contentStartTime == other.contentStartTime &&
|
contentStartTime == other.contentStartTime &&
|
||||||
cmcdProps == other.cmcdProps &&
|
cmcdProps == other.cmcdProps &&
|
||||||
sideLoadedTextTracks == other.sideLoadedTextTracks
|
sideLoadedTextTracks == other.sideLoadedTextTracks &&
|
||||||
|
adsProps == other.adsProps
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,6 +156,7 @@ class Source {
|
|||||||
private const val PROP_SRC_HEADERS = "requestHeaders"
|
private const val PROP_SRC_HEADERS = "requestHeaders"
|
||||||
private const val PROP_SRC_DRM = "drm"
|
private const val PROP_SRC_DRM = "drm"
|
||||||
private const val PROP_SRC_CMCD = "cmcd"
|
private const val PROP_SRC_CMCD = "cmcd"
|
||||||
|
private const val PROP_SRC_ADS = "ad"
|
||||||
private const val PROP_SRC_TEXT_TRACKS_ALLOW_CHUNKLESS_PREPARATION = "textTracksAllowChunklessPreparation"
|
private const val PROP_SRC_TEXT_TRACKS_ALLOW_CHUNKLESS_PREPARATION = "textTracksAllowChunklessPreparation"
|
||||||
private const val PROP_SRC_TEXT_TRACKS = "textTracks"
|
private const val PROP_SRC_TEXT_TRACKS = "textTracks"
|
||||||
|
|
||||||
@ -210,6 +218,9 @@ class Source {
|
|||||||
source.extension = safeGetString(src, PROP_SRC_TYPE, null)
|
source.extension = safeGetString(src, PROP_SRC_TYPE, null)
|
||||||
source.drmProps = parse(safeGetMap(src, PROP_SRC_DRM))
|
source.drmProps = parse(safeGetMap(src, PROP_SRC_DRM))
|
||||||
source.cmcdProps = CMCDProps.parse(safeGetMap(src, PROP_SRC_CMCD))
|
source.cmcdProps = CMCDProps.parse(safeGetMap(src, PROP_SRC_CMCD))
|
||||||
|
if (BuildConfig.USE_EXOPLAYER_IMA) {
|
||||||
|
source.adsProps = AdsProps.parse(safeGetMap(src, PROP_SRC_ADS))
|
||||||
|
}
|
||||||
source.textTracksAllowChunklessPreparation = safeGetBool(src, PROP_SRC_TEXT_TRACKS_ALLOW_CHUNKLESS_PREPARATION, true)
|
source.textTracksAllowChunklessPreparation = safeGetBool(src, PROP_SRC_TEXT_TRACKS_ALLOW_CHUNKLESS_PREPARATION, true)
|
||||||
source.sideLoadedTextTracks = SideLoadedTextTrackList.parse(safeGetArray(src, PROP_SRC_TEXT_TRACKS))
|
source.sideLoadedTextTracks = SideLoadedTextTrackList.parse(safeGetArray(src, PROP_SRC_TEXT_TRACKS))
|
||||||
|
|
||||||
|
@ -102,6 +102,7 @@ import androidx.media3.extractor.metadata.id3.TextInformationFrame;
|
|||||||
import androidx.media3.session.MediaSessionService;
|
import androidx.media3.session.MediaSessionService;
|
||||||
import androidx.media3.ui.LegacyPlayerControlView;
|
import androidx.media3.ui.LegacyPlayerControlView;
|
||||||
|
|
||||||
|
import com.brentvatne.common.api.AdsProps;
|
||||||
import com.brentvatne.common.api.BufferConfig;
|
import com.brentvatne.common.api.BufferConfig;
|
||||||
import com.brentvatne.common.api.BufferingStrategy;
|
import com.brentvatne.common.api.BufferingStrategy;
|
||||||
import com.brentvatne.common.api.ControlsConfig;
|
import com.brentvatne.common.api.ControlsConfig;
|
||||||
@ -240,8 +241,6 @@ public class ReactExoplayerView extends FrameLayout implements
|
|||||||
private boolean playInBackground = false;
|
private boolean playInBackground = false;
|
||||||
private boolean mReportBandwidth = false;
|
private boolean mReportBandwidth = false;
|
||||||
private boolean controls;
|
private boolean controls;
|
||||||
private Uri adTagUrl;
|
|
||||||
private String adLanguage;
|
|
||||||
|
|
||||||
private boolean showNotificationControls = false;
|
private boolean showNotificationControls = false;
|
||||||
// \ End props
|
// \ End props
|
||||||
@ -827,16 +826,23 @@ public class ReactExoplayerView extends FrameLayout implements
|
|||||||
mediaSourceFactory.setDataSourceFactory(RNVSimpleCache.INSTANCE.getCacheFactory(buildHttpDataSourceFactory(true)));
|
mediaSourceFactory.setDataSourceFactory(RNVSimpleCache.INSTANCE.getCacheFactory(buildHttpDataSourceFactory(true)));
|
||||||
}
|
}
|
||||||
|
|
||||||
ImaSdkSettings imaSdkSettings = ImaSdkFactory.getInstance().createImaSdkSettings();
|
if (BuildConfig.USE_EXOPLAYER_IMA) {
|
||||||
imaSdkSettings.setLanguage(adLanguage);
|
AdsProps adProps = source.getAdsProps();
|
||||||
|
|
||||||
|
// Create an AdsLoader.
|
||||||
|
ImaAdsLoader.Builder imaLoaderBuilder = new ImaAdsLoader
|
||||||
|
.Builder(themedReactContext)
|
||||||
|
.setAdEventListener(this)
|
||||||
|
.setAdErrorListener(this);
|
||||||
|
|
||||||
|
if (adProps != null && adProps.getAdLanguage() != null) {
|
||||||
|
ImaSdkSettings imaSdkSettings = ImaSdkFactory.getInstance().createImaSdkSettings();
|
||||||
|
imaSdkSettings.setLanguage(adProps.getAdLanguage());
|
||||||
|
imaLoaderBuilder.setImaSdkSettings(imaSdkSettings);
|
||||||
|
}
|
||||||
|
adsLoader = imaLoaderBuilder.build();
|
||||||
|
}
|
||||||
|
|
||||||
// Create an AdsLoader.
|
|
||||||
adsLoader = new ImaAdsLoader
|
|
||||||
.Builder(themedReactContext)
|
|
||||||
.setImaSdkSettings(imaSdkSettings)
|
|
||||||
.setAdEventListener(this)
|
|
||||||
.setAdErrorListener(this)
|
|
||||||
.build();
|
|
||||||
mediaSourceFactory.setLocalAdInsertionComponents(unusedAdTagUri -> adsLoader, exoPlayerView);
|
mediaSourceFactory.setLocalAdInsertionComponents(unusedAdTagUri -> adsLoader, exoPlayerView);
|
||||||
|
|
||||||
player = new ExoPlayer.Builder(getContext(), renderersFactory)
|
player = new ExoPlayer.Builder(getContext(), renderersFactory)
|
||||||
@ -904,7 +910,11 @@ public class ReactExoplayerView extends FrameLayout implements
|
|||||||
ArrayList<MediaSource> mediaSourceList = buildTextSources();
|
ArrayList<MediaSource> mediaSourceList = buildTextSources();
|
||||||
MediaSource videoSource = buildMediaSource(runningSource.getUri(), runningSource.getExtension(), drmSessionManager, runningSource.getCropStartMs(), runningSource.getCropEndMs());
|
MediaSource videoSource = buildMediaSource(runningSource.getUri(), runningSource.getExtension(), drmSessionManager, runningSource.getCropStartMs(), runningSource.getCropEndMs());
|
||||||
MediaSource mediaSourceWithAds = null;
|
MediaSource mediaSourceWithAds = null;
|
||||||
if (adTagUrl != null && BuildConfig.USE_EXOPLAYER_IMA) {
|
Uri adTagUrl = null;
|
||||||
|
if (source.getAdsProps() != null) {
|
||||||
|
adTagUrl = source.getAdsProps().getAdTagUrl();
|
||||||
|
}
|
||||||
|
if (adTagUrl != null && adsLoader != null) {
|
||||||
DefaultMediaSourceFactory mediaSourceFactory = new DefaultMediaSourceFactory(mediaDataSourceFactory)
|
DefaultMediaSourceFactory mediaSourceFactory = new DefaultMediaSourceFactory(mediaDataSourceFactory)
|
||||||
.setLocalAdInsertionComponents(unusedAdTagUri -> adsLoader, exoPlayerView);
|
.setLocalAdInsertionComponents(unusedAdTagUri -> adsLoader, exoPlayerView);
|
||||||
DataSpec adTagDataSpec = new DataSpec(adTagUrl);
|
DataSpec adTagDataSpec = new DataSpec(adTagUrl);
|
||||||
@ -1105,11 +1115,13 @@ public class ReactExoplayerView extends FrameLayout implements
|
|||||||
if (customMetadata != null) {
|
if (customMetadata != null) {
|
||||||
mediaItemBuilder.setMediaMetadata(customMetadata);
|
mediaItemBuilder.setMediaMetadata(customMetadata);
|
||||||
}
|
}
|
||||||
|
if (source.getAdsProps() != null) {
|
||||||
if (adTagUrl != null) {
|
Uri adTagUrl = source.getAdsProps().getAdTagUrl();
|
||||||
mediaItemBuilder.setAdsConfiguration(
|
if (adTagUrl != null) {
|
||||||
new MediaItem.AdsConfiguration.Builder(adTagUrl).build()
|
mediaItemBuilder.setAdsConfiguration(
|
||||||
);
|
new MediaItem.AdsConfiguration.Builder(adTagUrl).build()
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MediaItem.LiveConfiguration.Builder liveConfiguration = ConfigurationUtils.getLiveConfiguration(bufferConfig);
|
MediaItem.LiveConfiguration.Builder liveConfiguration = ConfigurationUtils.getLiveConfiguration(bufferConfig);
|
||||||
@ -1261,8 +1273,8 @@ public class ReactExoplayerView extends FrameLayout implements
|
|||||||
|
|
||||||
if (adsLoader != null) {
|
if (adsLoader != null) {
|
||||||
adsLoader.release();
|
adsLoader.release();
|
||||||
|
adsLoader = null;
|
||||||
}
|
}
|
||||||
adsLoader = null;
|
|
||||||
progressHandler.removeMessages(SHOW_PROGRESS);
|
progressHandler.removeMessages(SHOW_PROGRESS);
|
||||||
audioBecomingNoisyReceiver.removeListener();
|
audioBecomingNoisyReceiver.removeListener();
|
||||||
bandwidthMeter.removeEventListener(this);
|
bandwidthMeter.removeEventListener(this);
|
||||||
@ -1926,15 +1938,6 @@ public class ReactExoplayerView extends FrameLayout implements
|
|||||||
mReportBandwidth = reportBandwidth;
|
mReportBandwidth = reportBandwidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAdTagUrl(final Uri uri) {
|
|
||||||
DebugLog.w(TAG, "setAdTagUrl" + uri);
|
|
||||||
adTagUrl = uri;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAdLanguage(final String language) {
|
|
||||||
adLanguage = language;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void reloadSource() {
|
private void reloadSource() {
|
||||||
playerNeedsSource = true;
|
playerNeedsSource = true;
|
||||||
initializePlayer();
|
initializePlayer();
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
package com.brentvatne.exoplayer
|
package com.brentvatne.exoplayer
|
||||||
|
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
import android.net.Uri
|
|
||||||
import android.text.TextUtils
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import com.brentvatne.common.api.BufferConfig
|
import com.brentvatne.common.api.BufferConfig
|
||||||
import com.brentvatne.common.api.BufferingStrategy
|
import com.brentvatne.common.api.BufferingStrategy
|
||||||
@ -26,8 +24,6 @@ class ReactExoplayerViewManager(private val config: ReactExoplayerConfig) : View
|
|||||||
private const val TAG = "ExoViewManager"
|
private const val TAG = "ExoViewManager"
|
||||||
private const val REACT_CLASS = "RCTVideo"
|
private const val REACT_CLASS = "RCTVideo"
|
||||||
private const val PROP_SRC = "src"
|
private const val PROP_SRC = "src"
|
||||||
private const val PROP_AD_TAG_URL = "adTagUrl"
|
|
||||||
private const val PROP_AD_LANGUAGE = "adLanguage"
|
|
||||||
private const val PROP_RESIZE_MODE = "resizeMode"
|
private const val PROP_RESIZE_MODE = "resizeMode"
|
||||||
private const val PROP_REPEAT = "repeat"
|
private const val PROP_REPEAT = "repeat"
|
||||||
private const val PROP_SELECTED_AUDIO_TRACK = "selectedAudioTrack"
|
private const val PROP_SELECTED_AUDIO_TRACK = "selectedAudioTrack"
|
||||||
@ -92,26 +88,6 @@ class ReactExoplayerViewManager(private val config: ReactExoplayerConfig) : View
|
|||||||
videoView.setSrc(Source.parse(src, context))
|
videoView.setSrc(Source.parse(src, context))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = PROP_AD_TAG_URL)
|
|
||||||
fun setAdTagUrl(videoView: ReactExoplayerView, uriString: String?) {
|
|
||||||
if (TextUtils.isEmpty(uriString)) {
|
|
||||||
videoView.setAdTagUrl(null)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
val adTagUrl = Uri.parse(uriString)
|
|
||||||
videoView.setAdTagUrl(adTagUrl)
|
|
||||||
}
|
|
||||||
|
|
||||||
@ReactProp(name = PROP_AD_LANGUAGE)
|
|
||||||
fun setAdLanguage(videoView: ReactExoplayerView, languageString: String?) {
|
|
||||||
if (TextUtils.isEmpty(languageString)) {
|
|
||||||
videoView.setAdLanguage(null) // Maybe "en" default?
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
videoView.setAdLanguage(languageString)
|
|
||||||
}
|
|
||||||
|
|
||||||
@ReactProp(name = PROP_RESIZE_MODE)
|
@ReactProp(name = PROP_RESIZE_MODE)
|
||||||
fun setResizeMode(videoView: ReactExoplayerView, resizeMode: String) {
|
fun setResizeMode(videoView: ReactExoplayerView, resizeMode: String) {
|
||||||
when (resizeMode) {
|
when (resizeMode) {
|
||||||
|
@ -8,6 +8,9 @@ This page shows the list of available properties to configure player
|
|||||||
|
|
||||||
### `adTagUrl`
|
### `adTagUrl`
|
||||||
|
|
||||||
|
> [!WARNING]
|
||||||
|
> Deprecated, use source.ad.adTagUrl instead
|
||||||
|
|
||||||
<PlatformsList types={['Android', 'iOS']} />
|
<PlatformsList types={['Android', 'iOS']} />
|
||||||
|
|
||||||
Sets the VAST uri to play AVOD ads.
|
Sets the VAST uri to play AVOD ads.
|
||||||
@ -858,6 +861,26 @@ source={{
|
|||||||
}}
|
}}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### `ad`
|
||||||
|
|
||||||
|
<PlatformsList types={['Android', 'iOS']} />
|
||||||
|
|
||||||
|
Sets the ad configuration.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```
|
||||||
|
ad: {
|
||||||
|
adTagUrl="https://pubads.g.doubleclick.net/gampad/ads?iu=/21775744923/external/vmap_ad_samples&sz=640x480&cust_params=sample_ar%3Dpremidpostoptimizedpodbumper&ciu_szs=300x250&gdfp_req=1&ad_rule=1&output=vmap&unviewed_position_start=1&env=vp&impl=s&cmsid=496&vid=short_onecue&correlator="
|
||||||
|
adLanguage="fr"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
See: [./ads.md] for more informations
|
||||||
|
|
||||||
|
Note: You need enable IMA SDK in gradle or pod file - [enable client side ads insertion](/installation)
|
||||||
|
|
||||||
|
|
||||||
#### `contentStartTime`
|
#### `contentStartTime`
|
||||||
|
|
||||||
<PlatformsList types={['Android']} />
|
<PlatformsList types={['Android']} />
|
||||||
|
@ -265,8 +265,7 @@ const VideoPlayer: FC<Props> = ({}) => {
|
|||||||
<Video
|
<Video
|
||||||
showNotificationControls={showNotificationControls}
|
showNotificationControls={showNotificationControls}
|
||||||
ref={videoRef}
|
ref={videoRef}
|
||||||
// source={currentSrc as ReactVideoSource}
|
// source={currentSrc as ReactVideoSource}
|
||||||
adTagUrl={additional?.adTagUrl}
|
|
||||||
drm={additional?.drm}
|
drm={additional?.drm}
|
||||||
style={viewStyle}
|
style={viewStyle}
|
||||||
rate={rate}
|
rate={rate}
|
||||||
|
@ -107,6 +107,14 @@ export const srcAllPlatformList = [
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
description: '(mp4) big buck bunny With Ads',
|
||||||
|
ad: {
|
||||||
|
adTagUrl:
|
||||||
|
'https://pubads.g.doubleclick.net/gampad/ads?iu=/21775744923/external/vmap_ad_samples&sz=640x480&cust_params=sample_ar%3Dpremidpostoptimizedpodbumper&ciu_szs=300x250&gdfp_req=1&ad_rule=1&output=vmap&unviewed_position_start=1&env=vp&impl=s&cmsid=496&vid=short_onecue&correlator=',
|
||||||
|
},
|
||||||
|
uri: 'https://d23dyxeqlo5psv.cloudfront.net/big_buck_bunny.mp4',
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export const srcIosList: SampleVideoSource[] = [];
|
export const srcIosList: SampleVideoSource[] = [];
|
||||||
@ -133,12 +141,6 @@ export const srcAndroidList: SampleVideoSource[] = [
|
|||||||
uri: 'http://www.youtube.com/api/manifest/dash/id/bf5bb2419360daf1/source/youtube?as=fmp4_audio_clear,fmp4_sd_hd_clear&sparams=ip,ipbits,expire,source,id,as&ip=0.0.0.0&ipbits=0&expire=19000000000&signature=51AF5F39AB0CEC3E5497CD9C900EBFEAECCCB5C7.8506521BFC350652163895D4C26DEE124209AA9E&key=ik0',
|
uri: 'http://www.youtube.com/api/manifest/dash/id/bf5bb2419360daf1/source/youtube?as=fmp4_audio_clear,fmp4_sd_hd_clear&sparams=ip,ipbits,expire,source,id,as&ip=0.0.0.0&ipbits=0&expire=19000000000&signature=51AF5F39AB0CEC3E5497CD9C900EBFEAECCCB5C7.8506521BFC350652163895D4C26DEE124209AA9E&key=ik0',
|
||||||
type: 'mpd',
|
type: 'mpd',
|
||||||
},
|
},
|
||||||
{
|
|
||||||
description: '(mp4) big buck bunny With Ads',
|
|
||||||
adTagUrl:
|
|
||||||
'https://pubads.g.doubleclick.net/gampad/ads?iu=/21775744923/external/vmap_ad_samples&sz=640x480&cust_params=sample_ar%3Dpremidpostoptimizedpodbumper&ciu_szs=300x250&gdfp_req=1&ad_rule=1&output=vmap&unviewed_position_start=1&env=vp&impl=s&cmsid=496&vid=short_onecue&correlator=',
|
|
||||||
uri: 'http://d23dyxeqlo5psv.cloudfront.net/big_buck_bunny.mp4',
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
description: 'WV: Secure SD & HD (cbcs,MP4,H264)',
|
description: 'WV: Secure SD & HD (cbcs,MP4,H264)',
|
||||||
uri: 'https://storage.googleapis.com/wvmedia/cbcs/h264/tears/tears_aes_cbcs.mpd',
|
uri: 'https://storage.googleapis.com/wvmedia/cbcs/h264/tears/tears_aes_cbcs.mpd',
|
||||||
|
18
ios/Video/DataStructures/AdParams.swift
Normal file
18
ios/Video/DataStructures/AdParams.swift
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
struct AdParams {
|
||||||
|
let adTagUrl: String?
|
||||||
|
let adLanguage: String?
|
||||||
|
|
||||||
|
let json: NSDictionary?
|
||||||
|
|
||||||
|
init(_ json: NSDictionary!) {
|
||||||
|
guard json != nil else {
|
||||||
|
self.json = nil
|
||||||
|
adTagUrl = nil
|
||||||
|
adLanguage = nil
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.json = json
|
||||||
|
adTagUrl = json["adTagUrl"] as? String
|
||||||
|
adLanguage = json["adLanguage"] as? String
|
||||||
|
}
|
||||||
|
}
|
@ -12,6 +12,7 @@ struct VideoSource {
|
|||||||
/* DRM */
|
/* DRM */
|
||||||
let drm: DRMParams
|
let drm: DRMParams
|
||||||
var textTracks: [TextTrack] = []
|
var textTracks: [TextTrack] = []
|
||||||
|
let adParams: AdParams
|
||||||
|
|
||||||
let json: NSDictionary?
|
let json: NSDictionary?
|
||||||
|
|
||||||
@ -29,6 +30,7 @@ struct VideoSource {
|
|||||||
self.cropEnd = nil
|
self.cropEnd = nil
|
||||||
self.customMetadata = nil
|
self.customMetadata = nil
|
||||||
self.drm = DRMParams(nil)
|
self.drm = DRMParams(nil)
|
||||||
|
adParams = AdParams(nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
self.json = json
|
self.json = json
|
||||||
@ -56,5 +58,6 @@ struct VideoSource {
|
|||||||
self.textTracks = (json["textTracks"] as? NSArray)?.map { trackDict in
|
self.textTracks = (json["textTracks"] as? NSArray)?.map { trackDict in
|
||||||
return TextTrack(trackDict as? NSDictionary)
|
return TextTrack(trackDict as? NSDictionary)
|
||||||
} ?? []
|
} ?? []
|
||||||
|
adParams = AdParams(json["ad"] as? NSDictionary)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -86,8 +86,6 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* IMA Ads */
|
/* IMA Ads */
|
||||||
private var _adTagUrl: String?
|
|
||||||
private var _adLanguage: String?
|
|
||||||
#if USE_GOOGLE_IMA
|
#if USE_GOOGLE_IMA
|
||||||
private var _imaAdsManager: RCTIMAAdsManager!
|
private var _imaAdsManager: RCTIMAAdsManager!
|
||||||
/* Playhead used by the SDK to track content video progress and insert mid-rolls. */
|
/* Playhead used by the SDK to track content video progress and insert mid-rolls. */
|
||||||
@ -374,7 +372,7 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
|
|||||||
|
|
||||||
if currentTimeSecs >= 0 {
|
if currentTimeSecs >= 0 {
|
||||||
#if USE_GOOGLE_IMA
|
#if USE_GOOGLE_IMA
|
||||||
if !_didRequestAds && currentTimeSecs >= 0.0001 && _adTagUrl != nil {
|
if !_didRequestAds && currentTimeSecs >= 0.0001 && _source?.adParams.adTagUrl != nil {
|
||||||
_imaAdsManager.requestAds()
|
_imaAdsManager.requestAds()
|
||||||
_didRequestAds = true
|
_didRequestAds = true
|
||||||
}
|
}
|
||||||
@ -527,7 +525,7 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if USE_GOOGLE_IMA
|
#if USE_GOOGLE_IMA
|
||||||
if _adTagUrl != nil {
|
if _source?.adParams.adTagUrl != nil {
|
||||||
// Set up your content playhead and contentComplete callback.
|
// Set up your content playhead and contentComplete callback.
|
||||||
_contentPlayhead = IMAAVPlayerContentPlayhead(avPlayer: _player!)
|
_contentPlayhead = IMAAVPlayerContentPlayhead(avPlayer: _player!)
|
||||||
|
|
||||||
@ -1216,16 +1214,11 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
|
|||||||
// MARK: - RCTIMAAdsManager
|
// MARK: - RCTIMAAdsManager
|
||||||
|
|
||||||
func getAdLanguage() -> String? {
|
func getAdLanguage() -> String? {
|
||||||
return _adLanguage
|
return _source?.adParams.adLanguage
|
||||||
}
|
}
|
||||||
|
|
||||||
func getAdTagUrl() -> String? {
|
func getAdTagUrl() -> String? {
|
||||||
return _adTagUrl
|
return _source?.adParams.adTagUrl
|
||||||
}
|
|
||||||
|
|
||||||
@objc
|
|
||||||
func setAdTagUrl(_ adTagUrl: String?) {
|
|
||||||
_adTagUrl = adTagUrl
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if USE_GOOGLE_IMA
|
#if USE_GOOGLE_IMA
|
||||||
|
@ -5,8 +5,6 @@
|
|||||||
|
|
||||||
RCT_EXPORT_VIEW_PROPERTY(src, NSDictionary);
|
RCT_EXPORT_VIEW_PROPERTY(src, NSDictionary);
|
||||||
RCT_EXPORT_VIEW_PROPERTY(drm, NSDictionary);
|
RCT_EXPORT_VIEW_PROPERTY(drm, NSDictionary);
|
||||||
RCT_EXPORT_VIEW_PROPERTY(adTagUrl, NSString);
|
|
||||||
RCT_EXPORT_VIEW_PROPERTY(adLanguage, NSString);
|
|
||||||
RCT_EXPORT_VIEW_PROPERTY(maxBitRate, float);
|
RCT_EXPORT_VIEW_PROPERTY(maxBitRate, float);
|
||||||
RCT_EXPORT_VIEW_PROPERTY(resizeMode, NSString);
|
RCT_EXPORT_VIEW_PROPERTY(resizeMode, NSString);
|
||||||
RCT_EXPORT_VIEW_PROPERTY(repeat, BOOL);
|
RCT_EXPORT_VIEW_PROPERTY(repeat, BOOL);
|
||||||
|
@ -91,6 +91,8 @@ const Video = forwardRef<VideoRef, ReactVideoProps>(
|
|||||||
useSecureView,
|
useSecureView,
|
||||||
viewType,
|
viewType,
|
||||||
shutterColor,
|
shutterColor,
|
||||||
|
adTagUrl,
|
||||||
|
adLanguage,
|
||||||
onLoadStart,
|
onLoadStart,
|
||||||
onLoad,
|
onLoad,
|
||||||
onError,
|
onError,
|
||||||
@ -225,6 +227,12 @@ const Video = forwardRef<VideoRef, ReactVideoProps>(
|
|||||||
const selectedContentStartTime =
|
const selectedContentStartTime =
|
||||||
_source.contentStartTime || contentStartTime;
|
_source.contentStartTime || contentStartTime;
|
||||||
|
|
||||||
|
const _ad =
|
||||||
|
_source.ad ||
|
||||||
|
(adTagUrl || adLanguage
|
||||||
|
? {adTagUrl: adTagUrl, adLanguage: adLanguage}
|
||||||
|
: undefined);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
uri,
|
uri,
|
||||||
isNetwork,
|
isNetwork,
|
||||||
@ -240,6 +248,7 @@ const Video = forwardRef<VideoRef, ReactVideoProps>(
|
|||||||
contentStartTime: selectedContentStartTime,
|
contentStartTime: selectedContentStartTime,
|
||||||
metadata: resolvedSource.metadata,
|
metadata: resolvedSource.metadata,
|
||||||
drm: _drm,
|
drm: _drm,
|
||||||
|
ad: _ad,
|
||||||
cmcd: _cmcd,
|
cmcd: _cmcd,
|
||||||
textTracks: _textTracks,
|
textTracks: _textTracks,
|
||||||
textTracksAllowChunklessPreparation:
|
textTracksAllowChunklessPreparation:
|
||||||
@ -247,10 +256,12 @@ const Video = forwardRef<VideoRef, ReactVideoProps>(
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
|
adLanguage,
|
||||||
|
adTagUrl,
|
||||||
contentStartTime,
|
contentStartTime,
|
||||||
drm,
|
drm,
|
||||||
localSourceEncryptionKeyScheme,
|
localSourceEncryptionKeyScheme,
|
||||||
source,
|
source?.cmcd,
|
||||||
textTracks,
|
textTracks,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
@ -26,6 +26,11 @@ type VideoMetadata = Readonly<{
|
|||||||
imageUri?: string;
|
imageUri?: string;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
export type AdsConfig = Readonly<{
|
||||||
|
adTagUrl?: string;
|
||||||
|
adLanguage?: string;
|
||||||
|
}>;
|
||||||
|
|
||||||
export type VideoSrc = Readonly<{
|
export type VideoSrc = Readonly<{
|
||||||
uri?: string;
|
uri?: string;
|
||||||
isNetwork?: boolean;
|
isNetwork?: boolean;
|
||||||
@ -44,6 +49,7 @@ export type VideoSrc = Readonly<{
|
|||||||
cmcd?: NativeCmcdConfiguration; // android
|
cmcd?: NativeCmcdConfiguration; // android
|
||||||
textTracksAllowChunklessPreparation?: boolean; // android
|
textTracksAllowChunklessPreparation?: boolean; // android
|
||||||
textTracks?: TextTracks;
|
textTracks?: TextTracks;
|
||||||
|
ad?: AdsConfig;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
type DRMType = WithDefault<string, 'widevine'>;
|
type DRMType = WithDefault<string, 'widevine'>;
|
||||||
@ -319,8 +325,6 @@ export type OnControlsVisibilityChange = Readonly<{
|
|||||||
|
|
||||||
export interface VideoNativeProps extends ViewProps {
|
export interface VideoNativeProps extends ViewProps {
|
||||||
src?: VideoSrc;
|
src?: VideoSrc;
|
||||||
adTagUrl?: string;
|
|
||||||
adLanguage?: string;
|
|
||||||
allowsExternalPlayback?: boolean; // ios, true
|
allowsExternalPlayback?: boolean; // ios, true
|
||||||
disableFocus?: boolean; // android
|
disableFocus?: boolean; // android
|
||||||
maxBitRate?: Float;
|
maxBitRate?: Float;
|
||||||
|
@ -38,6 +38,7 @@ export type ReactVideoSourceProperties = {
|
|||||||
cmcd?: Cmcd; // android
|
cmcd?: Cmcd; // android
|
||||||
textTracksAllowChunklessPreparation?: boolean;
|
textTracksAllowChunklessPreparation?: boolean;
|
||||||
textTracks?: TextTracks;
|
textTracks?: TextTracks;
|
||||||
|
ad?: AdConfig;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ReactVideoSource = Readonly<
|
export type ReactVideoSource = Readonly<
|
||||||
@ -73,6 +74,11 @@ export enum DRMType {
|
|||||||
FAIRPLAY = 'fairplay',
|
FAIRPLAY = 'fairplay',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type AdConfig = Readonly<{
|
||||||
|
adTagUrl?: string;
|
||||||
|
adLanguage?: ISO639_1;
|
||||||
|
}>;
|
||||||
|
|
||||||
export type Drm = Readonly<{
|
export type Drm = Readonly<{
|
||||||
type?: DRMType;
|
type?: DRMType;
|
||||||
licenseServer?: string;
|
licenseServer?: string;
|
||||||
@ -276,7 +282,9 @@ export interface ReactVideoProps extends ReactVideoEvents, ViewProps {
|
|||||||
/** @deprecated Use source.drm */
|
/** @deprecated Use source.drm */
|
||||||
drm?: Drm;
|
drm?: Drm;
|
||||||
style?: StyleProp<ViewStyle>;
|
style?: StyleProp<ViewStyle>;
|
||||||
|
/** @deprecated Use source.ad.adTagUrl */
|
||||||
adTagUrl?: string;
|
adTagUrl?: string;
|
||||||
|
/** @deprecated Use source.ad.adLanguage */
|
||||||
adLanguage?: ISO639_1;
|
adLanguage?: ISO639_1;
|
||||||
audioOutput?: AudioOutput; // Mobile
|
audioOutput?: AudioOutput; // Mobile
|
||||||
automaticallyWaitsToMinimizeStalling?: boolean; // iOS
|
automaticallyWaitsToMinimizeStalling?: boolean; // iOS
|
||||||
|
Loading…
Reference in New Issue
Block a user