diff --git a/CHANGELOG.md b/CHANGELOG.md
index c7bfaaa2b..931a7712b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.1.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
+## [11.2.0] - 26-06-04
+
+### Added
+
+- Added support for `CustomAdIntegrationKind`, allowing custom ad integrations on top of the player API.
+- Added support for `breakManifestUrl` for OptiView Ads streams.
+
## [11.1.0] - 26-05-27
### Added
diff --git a/android/build.gradle b/android/build.gradle
index 23139c788..88c71ab9e 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -126,8 +126,8 @@ repositories {
mavenLocal()
}
-// The minimum supported THEOplayer version is 11.0.0
-def theoVersion = safeExtGet('THEOplayer_sdk', '[11.0.0, 12.0.0)')
+// The minimum supported THEOplayer version is 11.4.0
+def theoVersion = safeExtGet('THEOplayer_sdk', '[11.4.0, 12.0.0)')
def theoMediaSessionVersion = safeExtGet('THEOplayer_mediasession', '[11.0.0, 12.0.0)')
def theoAdsWrapperVersion = "11.0.0"
def coroutinesVersion = safeExtGet('coroutinesVersion', '1.10.2')
diff --git a/android/src/main/java/com/theoplayer/ads/AdsModule.kt b/android/src/main/java/com/theoplayer/ads/AdsModule.kt
index fa47a941f..afe0dd30f 100644
--- a/android/src/main/java/com/theoplayer/ads/AdsModule.kt
+++ b/android/src/main/java/com/theoplayer/ads/AdsModule.kt
@@ -45,7 +45,7 @@ class AdsModule(context: ReactApplicationContext) : ReactContextBaseJavaModule(c
fun schedule(tag: Int, ad: ReadableMap) {
viewResolver.resolveViewByTag(tag) { view: ReactTHEOplayerView? ->
try {
- view?.adsApi?.schedule(sourceHelper.parseAdFromJS(ad))
+ view?.adsApi?.schedule(sourceHelper.parseAdDescriptionFromJS(ad))
} catch (exception: THEOplayerException) {
Log.e(NAME, exception.message ?: ERR_SCHEDULE_AD)
}
diff --git a/android/src/main/java/com/theoplayer/source/SourceAdapter.kt b/android/src/main/java/com/theoplayer/source/SourceAdapter.kt
index d01403bca..264a1dd3f 100644
--- a/android/src/main/java/com/theoplayer/source/SourceAdapter.kt
+++ b/android/src/main/java/com/theoplayer/source/SourceAdapter.kt
@@ -23,6 +23,7 @@ import com.theoplayer.android.api.ads.theoads.TheoAdsLayoutOverride
import com.theoplayer.android.api.cmcd.CMCDTransmissionMode
import com.theoplayer.android.api.error.ErrorCode
import com.theoplayer.android.api.source.AdIntegration
+import com.theoplayer.android.api.source.addescription.CustomAdDescriptionRegistry
import com.theoplayer.android.api.source.dash.DashPlaybackConfiguration
import com.theoplayer.android.api.theolive.PlayoutDelay
import com.theoplayer.android.api.theolive.TheoLiveSource
@@ -73,6 +74,7 @@ private const val PROP_RETRIEVE_POD_ID_URI = "retrievePodIdURI"
private const val PROP_INITIALIZATION_DELAY = "initializationDelay"
private const val PROP_SSE_ENDPOINT = "sseEndpoint"
private const val PROP_STREAM_ACTIVITY_MONITOR_ID = "streamActivityMonitorId"
+private const val PROP_BREAK_MANIFEST_URL = "breakManifestUrl"
private const val PROP_LATENCY_CONFIGURATION = "latencyConfiguration"
private const val PROP_PROFILE = "profile"
private const val PROP_WEBRTC: String = "webrtc"
@@ -82,8 +84,8 @@ private const val PROP_PLAYOUT_DELAY_MAX: String = "maximum"
private const val ERROR_IMA_NOT_ENABLED = "Google IMA support not enabled."
private const val ERROR_THEOADS_NOT_ENABLED = "THEOads support not enabled."
-private const val ERROR_UNSUPPORTED_CSAI_INTEGRATION = "Unsupported CSAI integration"
-private const val ERROR_MISSING_CSAI_INTEGRATION = "Missing CSAI integration"
+private const val ERROR_UNSUPPORTED_AD_INTEGRATION = "Unsupported Ad integration"
+private const val ERROR_MISSING_AD_INTEGRATION = "Missing Ad integration"
private const val PROP_SSAI_INTEGRATION_GOOGLE_DAI = "google-dai"
@@ -151,7 +153,9 @@ class SourceAdapter {
val jsonAdDescription = jsonAds[i] as JSONObject
// Currently only ima-ads are supported.
- ads.add(parseAdFromJS(jsonAdDescription))
+ parseAdDescriptionFromJS(jsonAdDescription)?.let {
+ ads.add(it)
+ }
}
}
@@ -278,16 +282,6 @@ class SourceAdapter {
}
}
- @Throws(THEOplayerException::class)
- fun parseAdFromJS(map: ReadableMap): AdDescription? {
- return try {
- parseAdFromJS(JSONObject(gson.toJson(map.toHashMap())))
- } catch (e: JSONException) {
- e.printStackTrace()
- null
- }
- }
-
private fun parseSourceType(jsonTypedSource: JSONObject): SourceType? {
val type = jsonTypedSource.optString(PROP_TYPE)
if (type.isNotEmpty()) {
@@ -308,30 +302,39 @@ class SourceAdapter {
return null
}
+ @Throws(THEOplayerException::class)
+ fun parseAdDescriptionFromJS(map: ReadableMap): AdDescription? {
+ return try {
+ parseAdDescriptionFromJS(JSONObject(gson.toJson(map.toHashMap())))
+ } catch (e: JSONException) {
+ e.printStackTrace()
+ null
+ }
+ }
+
@Throws(JSONException::class, THEOplayerException::class)
- fun parseAdFromJS(jsonAdDescription: JSONObject): AdDescription {
+ fun parseAdDescriptionFromJS(jsonAdDescription: JSONObject): AdDescription? {
val integrationStr = jsonAdDescription.optString(PROP_INTEGRATION)
return if (!TextUtils.isEmpty(integrationStr)) {
when (integrationStr) {
- AdIntegration.GOOGLE_IMA.adIntegration -> parseImaAdFromJS(jsonAdDescription)
- AdIntegration.THEO_ADS.adIntegration -> parseTheoAdFromJS(jsonAdDescription)
- else -> {
- throw THEOplayerException(
+ AdIntegration.GOOGLE_IMA.adIntegration -> parseImaAdDescriptionFromJS(jsonAdDescription)
+ AdIntegration.THEO_ADS.adIntegration -> parseTheoAdDescriptionFromJS(jsonAdDescription)
+ else ->
+ CustomAdDescriptionRegistry.deserialize(integrationStr, jsonAdDescription.toString()) ?: throw THEOplayerException(
ErrorCode.AD_ERROR,
- "$ERROR_UNSUPPORTED_CSAI_INTEGRATION: $integrationStr"
+ "$ERROR_UNSUPPORTED_AD_INTEGRATION: $integrationStr"
)
- }
}
} else {
throw THEOplayerException(
ErrorCode.AD_ERROR,
- "$ERROR_MISSING_CSAI_INTEGRATION: $integrationStr"
+ "$ERROR_MISSING_AD_INTEGRATION: $integrationStr"
)
}
}
@Throws(THEOplayerException::class)
- private fun parseImaAdFromJS(jsonAdDescription: JSONObject): GoogleImaAdDescription {
+ private fun parseImaAdDescriptionFromJS(jsonAdDescription: JSONObject): GoogleImaAdDescription {
if (!BuildConfig.EXTENSION_GOOGLE_IMA) {
throw THEOplayerException(ErrorCode.AD_ERROR, ERROR_IMA_NOT_ENABLED)
}
@@ -349,7 +352,7 @@ class SourceAdapter {
}
@Throws(JSONException::class)
- private fun parseTheoAdFromJS(jsonAdDescription: JSONObject): TheoAdDescription {
+ private fun parseTheoAdDescriptionFromJS(jsonAdDescription: JSONObject): TheoAdDescription {
if (!BuildConfig.EXTENSION_THEOADS) {
throw THEOplayerException(ErrorCode.AD_ERROR, ERROR_THEOADS_NOT_ENABLED)
}
@@ -366,6 +369,7 @@ class SourceAdapter {
initializationDelay = jsonAdDescription.optDouble(PROP_INITIALIZATION_DELAY).takeIf { it.isFinite() },
sseEndpoint = jsonAdDescription.optString(PROP_SSE_ENDPOINT).takeIf { it.isNotEmpty() },
streamActivityMonitorId = jsonAdDescription.optString(PROP_STREAM_ACTIVITY_MONITOR_ID).takeIf { it.isNotEmpty() },
+ breakManifestUrl = jsonAdDescription.optString(PROP_BREAK_MANIFEST_URL).takeIf { it.isNotEmpty() },
)
}
@@ -376,9 +380,9 @@ class SourceAdapter {
private fun parseOverrideLayout(override: String?): TheoAdsLayoutOverride? {
return when (override) {
- "single", "single-if-mobile" -> return TheoAdsLayoutOverride.SINGLE
- "l-shape" -> return TheoAdsLayoutOverride.LSHAPE
- "double" -> return TheoAdsLayoutOverride.DOUBLE
+ "single", "single-if-mobile" -> TheoAdsLayoutOverride.SINGLE
+ "l-shape" -> TheoAdsLayoutOverride.LSHAPE
+ "double" -> TheoAdsLayoutOverride.DOUBLE
else -> null
}
}
@@ -395,11 +399,11 @@ class SourceAdapter {
private fun parseTextTrackKind(kind: String?): TextTrackKind? {
return when (kind) {
- "subtitles" -> return TextTrackKind.SUBTITLES
- "metadata" -> return TextTrackKind.METADATA
- "captions" -> return TextTrackKind.CAPTIONS
- "chapters" -> return TextTrackKind.CHAPTERS
- "descriptions" -> return TextTrackKind.DESCRIPTIONS
+ "subtitles" -> TextTrackKind.SUBTITLES
+ "metadata" -> TextTrackKind.METADATA
+ "captions" -> TextTrackKind.CAPTIONS
+ "chapters" -> TextTrackKind.CHAPTERS
+ "descriptions" -> TextTrackKind.DESCRIPTIONS
else -> null
}
}
diff --git a/e2e/package-lock.json b/e2e/package-lock.json
index 07a360e15..1ceb0d882 100644
--- a/e2e/package-lock.json
+++ b/e2e/package-lock.json
@@ -53,7 +53,7 @@
}
},
"..": {
- "version": "10.13.0",
+ "version": "11.1.0",
"license": "BSD-3-Clause-Clear",
"dependencies": {
"@theoplayer/cmcd-connector-web": "^1.5.0",
@@ -74,7 +74,7 @@
"react": "^19.2.3",
"react-native": "^0.84.1",
"react-native-builder-bob": "^0.39.1",
- "theoplayer": "^11.0.0",
+ "theoplayer": "^11.4.0",
"typedoc": "^0.25.13",
"typedoc-plugin-external-resolver": "^1.0.3",
"typedoc-plugin-mdn-links": "^3.3.4",
@@ -87,7 +87,7 @@
"peerDependencies": {
"react": "*",
"react-native": "*",
- "theoplayer": "^11"
+ "theoplayer": "^11.4.0"
},
"peerDependenciesMeta": {
"theoplayer": {
diff --git a/example/android/gradle.properties b/example/android/gradle.properties
index 9e25e3493..6de786415 100644
--- a/example/android/gradle.properties
+++ b/example/android/gradle.properties
@@ -46,7 +46,7 @@ hermesEnabled=true
edgeToEdgeEnabled=false
# Version of the THEOplayer SDK, if not specified, the latest available version within bounds is set.
-#THEOplayer_sdk=[11.0.0, 12.0.0)
+#THEOplayer_sdk=[11.4.0, 12.0.0)
# Override Android sdk versions
#THEOplayer_compileSdkVersion = 36
diff --git a/example/package-lock.json b/example/package-lock.json
index a14c8be66..ca77249d6 100644
--- a/example/package-lock.json
+++ b/example/package-lock.json
@@ -40,7 +40,7 @@
"eslint": "^8.57.1",
"html-webpack-plugin": "^5.6.3",
"react-native-svg-web": "^1.0.9",
- "theoplayer": "^11",
+ "theoplayer": "^11.4.0",
"typescript": "5.8.3",
"webpack": "^5.105.0",
"webpack-cli": "^6.0.1",
@@ -51,7 +51,7 @@
}
},
"..": {
- "version": "11.0.0",
+ "version": "11.1.0",
"license": "BSD-3-Clause-Clear",
"dependencies": {
"@theoplayer/cmcd-connector-web": "^1.5.0",
@@ -72,7 +72,7 @@
"react": "^19.2.3",
"react-native": "^0.84.1",
"react-native-builder-bob": "^0.39.1",
- "theoplayer": "^11.0.0",
+ "theoplayer": "^11.4.0",
"typedoc": "^0.25.13",
"typedoc-plugin-external-resolver": "^1.0.3",
"typedoc-plugin-mdn-links": "^3.3.4",
@@ -85,7 +85,7 @@
"peerDependencies": {
"react": "*",
"react-native": "*",
- "theoplayer": "^11"
+ "theoplayer": "^11.4.0"
},
"peerDependenciesMeta": {
"theoplayer": {
@@ -13396,9 +13396,9 @@
"license": "MIT"
},
"node_modules/theoplayer": {
- "version": "11.0.0",
- "resolved": "https://registry.npmjs.org/theoplayer/-/theoplayer-11.0.0.tgz",
- "integrity": "sha512-pxjpNtd++m87H5ndEPlNbKpHhXCNbFDgnXB0g6RfTv/v7zSpSLwiB0F0vIJe5asaqEJ6pKH7kvpTgnaEN2TElw==",
+ "version": "11.4.0",
+ "resolved": "https://registry.npmjs.org/theoplayer/-/theoplayer-11.4.0.tgz",
+ "integrity": "sha512-LJEXxDOW41NWM62dyj/4coc1a5jksriFXTGCuGVV+x31DGiAffHdhUBJo7So7wsvMzsoBTzuZZF6Ei/FsIFYJA==",
"license": "SEE LICENSE AT https://www.theoplayer.com/terms"
},
"node_modules/thingies": {
@@ -13697,7 +13697,7 @@
"version": "5.8.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz",
"integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
- "devOptional": true,
+ "dev": true,
"license": "Apache-2.0",
"bin": {
"tsc": "bin/tsc",
diff --git a/example/package.json b/example/package.json
index 487e0d103..ab97f0529 100644
--- a/example/package.json
+++ b/example/package.json
@@ -47,7 +47,7 @@
"eslint": "^8.57.1",
"html-webpack-plugin": "^5.6.3",
"react-native-svg-web": "^1.0.9",
- "theoplayer": "^11",
+ "theoplayer": "^11.4.0",
"typescript": "5.8.3",
"webpack": "^5.105.0",
"webpack-cli": "^6.0.1",
diff --git a/ios/THEOplayerRCTPlayerAPI.swift b/ios/THEOplayerRCTPlayerAPI.swift
index 3269a2120..27a2f3e8c 100644
--- a/ios/THEOplayerRCTPlayerAPI.swift
+++ b/ios/THEOplayerRCTPlayerAPI.swift
@@ -356,8 +356,14 @@ class THEOplayerRCTPlayerAPI: NSObject, RCTBridgeModule {
let quality = foundTrack.qualities.get(index)
return uids.contains { $0.intValue == quality.bandwidth } ? quality : nil
}
- foundTrack.targetQualities = matchingQualities
- if DEBUG_PLAYER_API { PrintUtils.printLog(logText: "[NATIVE] targetQualities: \(uids) set on active videotrack.") }
+ foundTrack.targetQualities = matchingQualities.count > 0 ? matchingQualities : nil
+ if DEBUG_PLAYER_API {
+ if matchingQualities.count > 0 {
+ if DEBUG_PLAYER_API { PrintUtils.printLog(logText: "[NATIVE] targetQualities: \(uids) set on active videotrack. (matching: \(matchingQualities.map(\.bandwidth)))") }
+ } else {
+ if DEBUG_PLAYER_API { PrintUtils.printLog(logText: "[NATIVE] targetQualities: \(uids) set on active videotrack. (no match or empty) => no quality restriction.") }
+ }
+ }
}
}
}
diff --git a/ios/THEOplayerRCTSourceDescriptionBuilder.swift b/ios/THEOplayerRCTSourceDescriptionBuilder.swift
index 177ec9231..edd6e50f9 100644
--- a/ios/THEOplayerRCTSourceDescriptionBuilder.swift
+++ b/ios/THEOplayerRCTSourceDescriptionBuilder.swift
@@ -62,6 +62,7 @@ let SD_PROP_USE_ID3: String = "useId3"
let SD_PROP_RETRIEVE_POD_ID_URI: String = "retrievePodIdURI"
let SD_PROP_INITIALIZATION_DELAY: String = "initializationDelay"
let SD_PROP_HLS_DATE_RANGE: String = "hlsDateRange"
+let SD_PROP_BREAK_MANIFEST_URL: String = "breakManifestUrl"
let SD_PROP_CMCD: String = "cmcd"
let SD_PROP_QUERY_PARAMETERS: String = "queryParameters"
@@ -90,7 +91,7 @@ class THEOplayerRCTSourceDescriptionBuilder {
guard let sourcesData = sourceData[SD_PROP_SOURCES] else {
return (nil, nil)
}
-
+
#if os(iOS)
if let metadataData = sourceData[SD_PROP_METADATA] as? [String:Any],
let cachingTaskId = metadataData[SD_PROP_METADATA_CACHINGTASK_ID] as? String {
@@ -164,7 +165,7 @@ class THEOplayerRCTSourceDescriptionBuilder {
if let metadataData = sourceData[SD_PROP_METADATA] as? [String:Any] {
metadataDescription = THEOplayerRCTSourceDescriptionBuilder.buildMetaDataDescription(metadataData)
}
-
+
// 6. configure CMCD
let cmcd = sourceData[SD_PROP_CMCD] as? [String:Any]
if cmcd != nil {
@@ -179,7 +180,7 @@ class THEOplayerRCTSourceDescriptionBuilder {
ads: adsDescriptions,
poster: poster,
metadata: metadataDescription)
-
+
return (sourceDescription, metadataAndChapterTrackDescriptions)
}
@@ -193,7 +194,7 @@ class THEOplayerRCTSourceDescriptionBuilder {
let contentProtection = extractDrmConfiguration(from: typedSourceData)
let integration = typedSourceData[SD_PROP_INTEGRATION] as? String
let type = typedSourceData[SD_PROP_TYPE] as? String
-
+
if integration == "theolive" || type == "theolive" {
return THEOplayerRCTSourceDescriptionBuilder.buildTHEOliveDescription(typedSourceData, contentProtection: contentProtection)
}
@@ -247,7 +248,7 @@ class THEOplayerRCTSourceDescriptionBuilder {
let textTrackFormat = THEOplayerRCTSourceDescriptionBuilder.extractTextTrackFormat(textTracksData[SD_PROP_FORMAT] as? String)
let textTrackPTS = textTracksData[SD_PROP_PTS] as? String
let textTrackLocalTime = textTracksData[SD_PROP_LOCALTIME] as? String ?? "00:00:00.000"
-
+
#if canImport(THEOplayerConnectorSideloadedSubtitle)
let ttDescription = SSTextTrackDescription(src: textTrackSrc,
srclang: textTrackSrcLang,
@@ -345,7 +346,7 @@ class THEOplayerRCTSourceDescriptionBuilder {
*/
static func buildContentProtection(_ contentProtectionData: [String:Any]) -> MultiplatformDRMConfiguration? {
let customIntegrationId = contentProtectionData[SD_PROP_INTEGRATION] as? String ?? "internal"
-
+
// fairplay
var fairplayKeySystem: THEOplayerSDK.KeySystemConfiguration? = nil
if let fairplayData = contentProtectionData[SD_PROP_FAIRPLAY] as? [String:Any] {
@@ -363,7 +364,7 @@ class THEOplayerRCTSourceDescriptionBuilder {
queryParameters[key] = "\(value)"
}
}
-
+
fairplayKeySystem = KeySystemConfiguration(
licenseAcquisitionURL: licenseAcquisitionURL,
certificateURL: certificateUrl,
@@ -372,7 +373,7 @@ class THEOplayerRCTSourceDescriptionBuilder {
queryParameters: queryParameters
)
}
-
+
// widevine
var widevineKeySystem: THEOplayerSDK.KeySystemConfiguration? = nil
if let widevineData = contentProtectionData[SD_PROP_WIDEVINE] as? [String:Any] {
@@ -390,7 +391,7 @@ class THEOplayerRCTSourceDescriptionBuilder {
queryParameters[key] = "\(value)"
}
}
-
+
widevineKeySystem = KeySystemConfiguration(
licenseAcquisitionURL: licenseAcquisitionURL,
certificateURL: certificateUrl,
@@ -399,7 +400,7 @@ class THEOplayerRCTSourceDescriptionBuilder {
queryParameters: queryParameters
)
}
-
+
// global query parameters
var queryParameters: [String: String] = [:]
if let allQueryParams = contentProtectionData[SD_PROP_QUERY_PARAMETERS] as? [String:Any] {
@@ -408,7 +409,7 @@ class THEOplayerRCTSourceDescriptionBuilder {
}
}
let integrationParameters = contentProtectionData[SD_PROP_INTEGRATION_PARAMETERS] as? [String:Any] ?? [:]
-
+
return MultiplatformDRMConfiguration(
customIntegrationId: customIntegrationId,
integrationParameters: integrationParameters,
diff --git a/ios/ads/THEOplayerRCTSourceDescriptionBuilder+Ads.swift b/ios/ads/THEOplayerRCTSourceDescriptionBuilder+Ads.swift
index d1ceb89c2..820f1e59b 100644
--- a/ios/ads/THEOplayerRCTSourceDescriptionBuilder+Ads.swift
+++ b/ios/ads/THEOplayerRCTSourceDescriptionBuilder+Ads.swift
@@ -6,6 +6,17 @@ import UIKit
let SD_PROP_ADS: String = "ads"
+public class CustomAdDescription: AdDescription {
+ public let integration: THEOplayerSDK.AdIntegration? = AdIntegration.none
+ public let customIntegrationId: String
+ public let integrationData: [String: Any]
+
+ public init(customIntegrationId: String, integrationData: [String: Any] = [:]) {
+ self.customIntegrationId = customIntegrationId
+ self.integrationData = integrationData
+ }
+}
+
extension THEOplayerRCTSourceDescriptionBuilder {
/**
@@ -24,11 +35,16 @@ extension THEOplayerRCTSourceDescriptionBuilder {
adsDescriptions?.append(adDescription)
} else {
if DEBUG_SOURCE_DESCRIPTION_BUILDER {
- PrintUtils.printLog(logText: "[NATIVE] Could not create THEOplayer GoogleImaAdDescription from adsData array")
+ PrintUtils.printLog(logText: "[NATIVE] Could not create AdDescription from adsData")
}
- return nil
}
}
+ if adsDescriptions?.isEmpty == true {
+ if DEBUG_SOURCE_DESCRIPTION_BUILDER {
+ PrintUtils.printLog(logText: "[NATIVE] Could not create any AdDescription from adsData array")
+ }
+ return nil
+ }
}
// case: single ads object
else if let adsData = ads as? [String:Any] {
@@ -36,7 +52,7 @@ extension THEOplayerRCTSourceDescriptionBuilder {
adsDescriptions?.append(adDescription)
} else {
if DEBUG_SOURCE_DESCRIPTION_BUILDER {
- PrintUtils.printLog(logText: "[NATIVE] Could not create THEOplayer GoogleImaAdDescription from adsData")
+ PrintUtils.printLog(logText: "[NATIVE] Could not create AdDescription from adsData")
}
return nil
}
@@ -58,11 +74,22 @@ extension THEOplayerRCTSourceDescriptionBuilder {
case "theoads":
return THEOplayerRCTSourceDescriptionBuilder.buildSingleTHEOadsDescription(adsData)
default:
- if DEBUG_SOURCE_DESCRIPTION_BUILDER { PrintUtils.printLog(logText: "[NATIVE] We currently require and only support the 'google-ima' or 'sgai' integration in the 'ads' description.") }
+ return THEOplayerRCTSourceDescriptionBuilder.buildSingleCustomAdsDescription(adsData)
}
}
return nil
}
+
+ /**
+ Creates a THEOplayer AdDescription, containing all passed properties.
+ - returns: a THEOplayer AdDescription
+ */
+ static func buildSingleCustomAdsDescription(_ adsData: [String:Any]) -> AdDescription? {
+ if let integration = adsData[SD_PROP_INTEGRATION] as? String {
+ return CustomAdDescription(customIntegrationId: integration, integrationData: adsData)
+ }
+ return nil
+ }
/**
Creates a THEOplayer GoogleImaAdDescription. This requires an ads property in the RN source description.
diff --git a/ios/theoAds/THEOplayerRCTSourceDescriptionBuilder+TheoAds.swift b/ios/theoAds/THEOplayerRCTSourceDescriptionBuilder+TheoAds.swift
index a9e003004..a469c4119 100644
--- a/ios/theoAds/THEOplayerRCTSourceDescriptionBuilder+TheoAds.swift
+++ b/ios/theoAds/THEOplayerRCTSourceDescriptionBuilder+TheoAds.swift
@@ -50,7 +50,11 @@ extension THEOplayerRCTSourceDescriptionBuilder {
let streamActivityMonitorId = adsData[SD_PROP_STREAM_ACTIVITY_MONITOR_ID_THEOADS] as? String
let retrievePodIdURI = adsData[SD_PROP_RETRIEVE_POD_ID_URI] as? String
let initializationDelay = adsData[SD_PROP_INITIALIZATION_DELAY] as? Double
-
+ var breakManifestUrl: URL?
+ if let breakManifestUrlString = adsData[SD_PROP_BREAK_MANIFEST_URL] as? String {
+ breakManifestUrl = URL(string: breakManifestUrlString)
+ }
+
return THEOAdDescription(networkCode: networkCode,
customAssetKey: customAssetKey,
backdropDoubleBox: backdropDoubleBox,
@@ -62,7 +66,8 @@ extension THEOplayerRCTSourceDescriptionBuilder {
streamActivityMonitorId: streamActivityMonitorId,
sseEndpoint: sseEndpoint,
retrievePodIdURI: retrievePodIdURI,
- initializationDelay: initializationDelay)
+ initializationDelay: initializationDelay,
+ breakManifestUrl: breakManifestUrl)
#else
return nil
#endif
diff --git a/package-lock.json b/package-lock.json
index e7e27ba61..d5a005e7b 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "react-native-theoplayer",
- "version": "11.1.0",
+ "version": "11.2.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "react-native-theoplayer",
- "version": "11.1.0",
+ "version": "11.2.0",
"license": "BSD-3-Clause-Clear",
"dependencies": {
"@theoplayer/cmcd-connector-web": "^1.5.0",
@@ -27,7 +27,7 @@
"react": "^19.2.3",
"react-native": "^0.84.1",
"react-native-builder-bob": "^0.39.1",
- "theoplayer": "^11.0.0",
+ "theoplayer": "^11.4.0",
"typedoc": "^0.25.13",
"typedoc-plugin-external-resolver": "^1.0.3",
"typedoc-plugin-mdn-links": "^3.3.4",
@@ -40,7 +40,7 @@
"peerDependencies": {
"react": "*",
"react-native": "*",
- "theoplayer": "^11"
+ "theoplayer": "^11.4.0"
},
"peerDependenciesMeta": {
"theoplayer": {
@@ -10937,9 +10937,9 @@
"dev": true
},
"node_modules/theoplayer": {
- "version": "11.0.0",
- "resolved": "https://registry.npmjs.org/theoplayer/-/theoplayer-11.0.0.tgz",
- "integrity": "sha512-pxjpNtd++m87H5ndEPlNbKpHhXCNbFDgnXB0g6RfTv/v7zSpSLwiB0F0vIJe5asaqEJ6pKH7kvpTgnaEN2TElw==",
+ "version": "11.4.0",
+ "resolved": "https://registry.npmjs.org/theoplayer/-/theoplayer-11.4.0.tgz",
+ "integrity": "sha512-LJEXxDOW41NWM62dyj/4coc1a5jksriFXTGCuGVV+x31DGiAffHdhUBJo7So7wsvMzsoBTzuZZF6Ei/FsIFYJA==",
"license": "SEE LICENSE AT https://www.theoplayer.com/terms"
},
"node_modules/throat": {
diff --git a/package.json b/package.json
index bd0dab6fd..809d1e673 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "react-native-theoplayer",
- "version": "11.1.0",
+ "version": "11.2.0",
"description": "A THEOplayer video component for react-native.",
"main": "lib/commonjs/index",
"module": "lib/module/index",
@@ -70,7 +70,7 @@
"react": "^19.2.3",
"react-native": "^0.84.1",
"react-native-builder-bob": "^0.39.1",
- "theoplayer": "^11.0.0",
+ "theoplayer": "^11.4.0",
"typedoc": "^0.25.13",
"typedoc-plugin-external-resolver": "^1.0.3",
"typedoc-plugin-mdn-links": "^3.3.4",
@@ -80,7 +80,7 @@
"peerDependencies": {
"react": "*",
"react-native": "*",
- "theoplayer": "^11"
+ "theoplayer": "^11.4.0"
},
"peerDependenciesMeta": {
"theoplayer": {
diff --git a/react-native-theoplayer.podspec b/react-native-theoplayer.podspec
index 75885c65d..4ae211870 100644
--- a/react-native-theoplayer.podspec
+++ b/react-native-theoplayer.podspec
@@ -43,37 +43,37 @@ Pod::Spec.new do |s|
# THEOplayer Dependency
puts "Adding THEOplayerSDK-core"
- s.dependency "THEOplayerSDK-core", "~> 11.0"
+ s.dependency "THEOplayerSDK-core", "~> 11.4"
# THEOlive Dependency
puts "Adding THEOplayer-Integration-THEOlive"
- s.dependency "THEOplayer-Integration-THEOlive", "~> 11.0"
+ s.dependency "THEOplayer-Integration-THEOlive", "~> 11.4"
# Feature based integration dependencies
if theofeatures.include?("GOOGLE_IMA")
puts "Adding THEOplayer-Integration-GoogleIMA"
- s.dependency "THEOplayer-Integration-GoogleIMA", "~> 11.0"
+ s.dependency "THEOplayer-Integration-GoogleIMA", "~> 11.4"
end
if theofeatures.include?("CHROMECAST")
puts "Adding THEOplayer-Integration-GoogleCast"
- s.ios.dependency "THEOplayer-Integration-GoogleCast", "~> 11.0"
+ s.ios.dependency "THEOplayer-Integration-GoogleCast", "~> 11.4"
end
if theofeatures.include?("THEO_ADS")
puts "Adding THEOplayer-Integration-THEOads"
- s.dependency "THEOplayer-Integration-THEOads", "~> 11.0"
+ s.dependency "THEOplayer-Integration-THEOads", "~> 11.4"
end
if theofeatures.include?("MILLICAST")
puts "Adding THEOplayer-Integration-Millicast"
- s.dependency "THEOplayer-Integration-Millicast", "~> 11.0"
+ s.dependency "THEOplayer-Integration-Millicast", "~> 11.4"
end
# Feature based connector dependencies
if theofeatures.include?("SIDELOADED_TEXTTRACKS")
puts "Adding THEOplayer-Connector-SideloadedSubtitle"
- s.dependency "THEOplayer-Connector-SideloadedSubtitle", "~> 11.0"
+ s.dependency "THEOplayer-Connector-SideloadedSubtitle", "~> 11.0", "> 11.0.1"
end
end
diff --git a/src/api/ads/Ad.ts b/src/api/ads/Ad.ts
index ee71988b6..0ffaf0ea0 100644
--- a/src/api/ads/Ad.ts
+++ b/src/api/ads/Ad.ts
@@ -1,5 +1,6 @@
import type { AdBreak } from './AdBreak';
import type { CompanionAd } from 'theoplayer';
+import { AdIntegrationKind, CustomAdIntegrationKind } from '../source/ads/Ads';
/**
* Represents a VAST creative. It is either a linear or non-linear ad.
@@ -17,15 +18,12 @@ export interface Ad {
adSystem: string | undefined;
/**
- * The integration of the ad, represented by a value from the following list:
- *
- `'theo'`
- *
- `'google-ima'`
- *
- `'google-dai'`
- *
- `'freewheel'`
+ * The integration of the ad, represented by a value from {@link AdIntegrationKind}
+ * or {@link CustomAdIntegrationKind | the identifier of a custom integration}.
*
- * @defaultValue `'theo'`
+ * @defaultValue `'csai'`
*/
- integration?: string;
+ integration?: AdIntegrationKind | CustomAdIntegrationKind;
/**
* The type of the ad, represented by a value from the following list:
diff --git a/src/api/ads/AdBreak.ts b/src/api/ads/AdBreak.ts
index fcd25b60e..aa0712a3e 100644
--- a/src/api/ads/AdBreak.ts
+++ b/src/api/ads/AdBreak.ts
@@ -5,6 +5,7 @@
* @public
*/
import type { Ad } from './Ad';
+import { AdIntegrationKind, CustomAdIntegrationKind } from '../source/ads/Ads';
/**
* Represents an ad break in the VMAP specification or an ad pod in the VAST specification.
@@ -14,13 +15,10 @@ import type { Ad } from './Ad';
*/
export interface AdBreak {
/**
- * The integration of the ad break, represented by a value from the following list:
- *
- `'theo'`
- *
- `'google-ima'`
- *
- `'google-dai'`
- *
- `'freewheel'`
+ * The integration of the ad break, represented by a value from {@link AdIntegrationKind}
+ * or {@link CustomAdIntegrationKind | the identifier of a custom integration}.
*/
- integration: string | undefined;
+ integration: AdIntegrationKind | CustomAdIntegrationKind | undefined;
/**
* List of ads which will be played sequentially at the ad break's time offset.
diff --git a/src/api/source/ads/Ads.ts b/src/api/source/ads/Ads.ts
index b8df9c24b..b50d6d63d 100644
--- a/src/api/source/ads/Ads.ts
+++ b/src/api/source/ads/Ads.ts
@@ -44,10 +44,8 @@ export interface AdSource {
export interface AdDescription {
/**
* The integration of the ad break.
- *
- * @defaultValue `'csai'`
*/
- integration?: AdIntegrationKind;
+ integration?: AdIntegrationKind | CustomAdIntegrationKind;
/**
* Whether the ad replaces playback of the content.
@@ -116,3 +114,10 @@ export enum AdIntegrationKind {
csai = 'csai',
theoads = 'theoads',
}
+
+/**
+ * The identifier of a custom ad integration.
+ *
+ * @category Ads
+ */
+export type CustomAdIntegrationKind = string & {};
diff --git a/src/api/source/ads/TheoAdDescription.ts b/src/api/source/ads/TheoAdDescription.ts
index 6f3bcfc7f..066f18b07 100644
--- a/src/api/source/ads/TheoAdDescription.ts
+++ b/src/api/source/ads/TheoAdDescription.ts
@@ -107,6 +107,14 @@ export interface TheoAdDescription extends AdDescription {
* The amount of seconds we wait to initialize THEOads.
*/
initializationDelay?: number;
+
+ /**
+ * The URL of the break manifest.
+ *
+ * @remarks
+ *
- The break manifest describes the upcoming ad breaks in the stream.
+ */
+ breakManifestUrl?: string;
}
/**
diff --git a/src/internal/adapter/theolive/TheoLiveWebAdapter.ts b/src/internal/adapter/theolive/TheoLiveWebAdapter.ts
index 6376211ae..3911d6956 100644
--- a/src/internal/adapter/theolive/TheoLiveWebAdapter.ts
+++ b/src/internal/adapter/theolive/TheoLiveWebAdapter.ts
@@ -10,17 +10,8 @@ export class TheoLiveWebAdapter implements TheoLiveAPI {
}
get latencies(): Promise {
- const webLatencies = this._player.hesp?.latencies;
- if (webLatencies) {
- return Promise.resolve({
- engineLatency: webLatencies?.engine,
- distributionLatency: webLatencies?.distribution,
- playerLatency: webLatencies?.player,
- theoliveLatency: webLatencies?.theolive,
- });
- } else {
- return Promise.reject('latencies not available');
- }
+ console.warn('The THEOlive latencies metrics are not available');
+ return Promise.resolve({});
}
set authToken(token: string) {