Chore: rework ad props (#4220)

* fix: move ad configuration in source
This commit is contained in:
Olivier Bouillet 2024-10-10 23:53:39 +02:00 committed by GitHub
parent 9a3fcda3b8
commit d86adc52f3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 171 additions and 76 deletions

View 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
}
}
}

View File

@ -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))

View File

@ -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();

View File

@ -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) {

View File

@ -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']} />

View File

@ -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}

View File

@ -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',

View 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
}
}

View File

@ -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)
} }
} }

View File

@ -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

View File

@ -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);

View File

@ -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,
], ],
); );

View File

@ -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;

View File

@ -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