Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand Down
2 changes: 1 addition & 1 deletion android/src/main/java/com/theoplayer/ads/AdsModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down
66 changes: 35 additions & 31 deletions android/src/main/java/com/theoplayer/source/SourceAdapter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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"
Expand All @@ -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"

Expand Down Expand Up @@ -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)
}
}
}

Expand Down Expand Up @@ -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()) {
Expand All @@ -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)
}
Expand All @@ -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)
}
Expand All @@ -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() },
)
}

Expand All @@ -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
}
}
Expand All @@ -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
}
}
Expand Down
6 changes: 3 additions & 3 deletions e2e/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion example/android/gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
16 changes: 8 additions & 8 deletions example/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
10 changes: 8 additions & 2 deletions ios/THEOplayerRCTPlayerAPI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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.") }
}
}
}
}
}
Expand Down
Loading
Loading