Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/sgai android #418

Merged
merged 7 commits into from
Oct 21, 2024
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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.

## [Unreleased]

### Added

- Added the `THEOads` SGAI ad integration for Android. See [THEOads](https://www.theoplayer.com/product/theoads) for more details.

### Fixed

- Fixed an issue on Web where all text tracks other than the selected would be set to `disabled` when enabling a text track.
Expand Down
13 changes: 12 additions & 1 deletion android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ static def versionString(version) {
// Extensions
def enabledGoogleIMA = safeExtGet("THEOplayer_extensionGoogleIMA", 'false').toBoolean()
def enabledGoogleDAI = safeExtGet("THEOplayer_extensionGoogleDAI", 'false').toBoolean()
def enabledAds = enabledGoogleIMA || enabledGoogleDAI
def enabledTHEOads = safeExtGet("THEOplayer_extensionTHEOads", 'false').toBoolean()
def enabledAds = enabledGoogleIMA || enabledGoogleDAI || enabledTHEOads
def enabledCast = safeExtGet("THEOplayer_extensionCast", 'false').toBoolean()
def enabledMediaSession = safeExtGet("THEOplayer_extensionMediaSession", 'true').toBoolean()

Expand Down Expand Up @@ -61,6 +62,7 @@ android {
// Extension buildConfig fields
buildConfigField "boolean", "EXTENSION_GOOGLE_IMA", "${enabledGoogleIMA}"
buildConfigField "boolean", "EXTENSION_GOOGLE_DAI", "${enabledGoogleDAI}"
buildConfigField "boolean", "EXTENSION_THEOADS", "${enabledTHEOads}"
buildConfigField "boolean", "EXTENSION_ADS", "${enabledAds}"
buildConfigField "boolean", "EXTENSION_CAST", "${enabledCast}"
buildConfigField "boolean", "EXTENSION_MEDIASESSION", "${enabledMediaSession}"
Expand Down Expand Up @@ -139,6 +141,14 @@ dependencies {
compileOnly "com.theoplayer.theoplayer-sdk-android:integration-ads-dai:${theoplayer_sdk_version}"
}

if (enabledTHEOads) {
println('Enable THEOplayer THEOads extension.')
implementation "com.theoplayer.theoplayer-sdk-android:integration-ads-theoads:${theoplayer_sdk_version}"
} else {
println('Disable THEOplayer THEOads extension.')
compileOnly "com.theoplayer.theoplayer-sdk-android:integration-ads-theoads:${theoplayer_sdk_version}"
}

if (enabledCast) {
println('Enable THEOplayer cast extension.')
implementation "com.theoplayer.theoplayer-sdk-android:integration-cast:${theoplayer_sdk_version}"
Expand All @@ -153,6 +163,7 @@ configurations.configureEach {
resolutionStrategy {
force "com.theoplayer.theoplayer-sdk-android:integration-ads-ima:${theoplayer_sdk_version}"
force "com.theoplayer.theoplayer-sdk-android:integration-ads-dai:${theoplayer_sdk_version}"
force "com.theoplayer.theoplayer-sdk-android:integration-ads-theoads:${theoplayer_sdk_version}"
}
}

14 changes: 14 additions & 0 deletions android/src/main/java/com/theoplayer/ReactTHEOplayerContext.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import com.theoplayer.android.api.ads.dai.GoogleDaiIntegration
import com.theoplayer.android.api.ads.dai.GoogleDaiIntegrationFactory
import com.theoplayer.android.api.ads.ima.GoogleImaIntegration
import com.theoplayer.android.api.ads.ima.GoogleImaIntegrationFactory
import com.theoplayer.android.api.ads.theoads.TheoAdsIntegration
import com.theoplayer.android.api.ads.theoads.TheoAdsIntegrationFactory
import com.theoplayer.android.api.cast.CastIntegration
import com.theoplayer.android.api.cast.CastIntegrationFactory
import com.theoplayer.android.api.event.EventListener
Expand Down Expand Up @@ -80,6 +82,7 @@ class ReactTHEOplayerContext private constructor(

var daiIntegration: GoogleDaiIntegration? = null
var imaIntegration: GoogleImaIntegration? = null
private var theoAdsIntegration: TheoAdsIntegration? = null
var castIntegration: CastIntegration? = null
var wasPlayingOnHostPause: Boolean = false
private var isHostPaused: Boolean = false
Expand Down Expand Up @@ -295,6 +298,17 @@ class ReactTHEOplayerContext private constructor(
} catch (e: Exception) {
Log.w(TAG, "Failed to configure Google DAI integration ${e.message}")
}
try {
if (BuildConfig.EXTENSION_THEOADS) {
theoAdsIntegration = TheoAdsIntegrationFactory.createTheoAdsIntegration(
playerView
).also {
playerView.player.addIntegration(it)
}
}
} catch (e: Exception) {
Log.w(TAG, "Failed to configure THEOAds integration ${e.message}")
}
try {
if (BuildConfig.EXTENSION_CAST) {
castIntegration = CastIntegrationFactory.createCastIntegration(
Expand Down
48 changes: 48 additions & 0 deletions android/src/main/java/com/theoplayer/source/SourceAdapter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.theoplayer.source
import android.text.TextUtils
import android.util.Log
import com.google.gson.Gson
import com.theoplayer.android.api.ads.theoads.TheoAdDescription
import com.theoplayer.android.api.error.THEOplayerException
import com.facebook.react.bridge.ReadableMap
import com.facebook.react.bridge.WritableMap
Expand All @@ -17,6 +18,7 @@ import com.theoplayer.android.api.source.addescription.GoogleImaAdDescription
import com.theoplayer.android.api.player.track.texttrack.TextTrackKind
import com.theoplayer.android.api.source.metadata.ChromecastMetadataImage
import com.theoplayer.BuildConfig
import com.theoplayer.android.api.ads.theoads.TheoAdsLayoutOverride
import com.theoplayer.android.api.error.ErrorCode
import com.theoplayer.android.api.source.AdIntegration
import com.theoplayer.android.api.source.dash.DashPlaybackConfiguration
Expand Down Expand Up @@ -52,7 +54,16 @@ private const val PROP_ADS = "ads"
private const val PROP_DASH = "dash"
private const val PROP_DASH_IGNORE_AVAILABILITYWINDOW = "ignoreAvailabilityWindow"
private const val PROP_HEADERS = "headers"
private const val PROP_AD_TAG_PARAMETERS = "adTagParameters"
private const val PROP_BACKDROP_DOUBLE_BOX = "backdropDoubleBox"
private const val PROP_BACKDROP_LSHAPE = "backdropLShape"
private const val PROP_CUSTOM_ASSET_KEY = "customAssetKey"
private const val PROP_OVERRIDE_LAYOUT = "overrideLayout"
private const val PROP_NETWORK_CODE = "networkCode"
private const val PROP_USE_ID3 = "useId3"

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"

Expand Down Expand Up @@ -252,6 +263,9 @@ class SourceAdapter {
AdIntegration.GOOGLE_IMA.adIntegration -> parseImaAdFromJS(
jsonAdDescription
)
AdIntegration.THEO_ADS.adIntegration -> parseTheoAdFromJS(
jsonAdDescription
)
else -> {
throw THEOplayerException(
ErrorCode.AD_ERROR,
Expand Down Expand Up @@ -285,6 +299,40 @@ class SourceAdapter {
.build()
}

@Throws(JSONException::class)
private fun parseTheoAdFromJS(jsonAdDescription: JSONObject): TheoAdDescription {
if (!BuildConfig.EXTENSION_THEOADS) {
throw THEOplayerException(ErrorCode.AD_ERROR, ERROR_THEOADS_NOT_ENABLED)
}
return TheoAdDescription(
adTagParameters = parseAdTagParameters(jsonAdDescription.optJSONObject(PROP_AD_TAG_PARAMETERS)),
backdropDoubleBox = jsonAdDescription.optString(PROP_BACKDROP_DOUBLE_BOX),
backdropLShape = jsonAdDescription.optString(PROP_BACKDROP_LSHAPE),
customAssetKey = jsonAdDescription.optString(PROP_CUSTOM_ASSET_KEY),
networkCode = jsonAdDescription.optString(PROP_NETWORK_CODE),
overrideLayout = parseOverrideLayout(jsonAdDescription.optString(PROP_OVERRIDE_LAYOUT)),
useId3 = jsonAdDescription.optBoolean(PROP_USE_ID3),
)
}

private fun parseAdTagParameters(params: JSONObject?): Map<String, String> =
params?.keys()?.asSequence()
?.mapNotNull { key -> key to params.optString(key) }
?.toMap() ?: emptyMap()

private fun parseOverrideLayout(override: String?): TheoAdsLayoutOverride? {
if (override == null) {
return null
}
when (override) {
"single" -> return TheoAdsLayoutOverride.SINGLE
"single-if-mobile" -> return TheoAdsLayoutOverride.SINGLE
"l-shape" -> return TheoAdsLayoutOverride.LSHAPE
"double" -> return TheoAdsLayoutOverride.DOUBLE
}
return null
}

@Throws(JSONException::class)
private fun parseTextTrackFromJS(jsonTextTrack: JSONObject): TextTrackDescription {
val builder = TextTrackDescription.Builder(jsonTextTrack.optString(PROP_SRC))
Expand Down
1 change: 1 addition & 0 deletions example/android/gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ THEOplayer_logMediaSessionEvents = true
THEOplayer_extensionGoogleIMA = true
THEOplayer_extensionGoogleDAI = true
THEOplayer_extensionCast = true
THEOplayer_extensionTHEOads = true
THEOplayer_extensionMediaSession = true

# Optionally limit timeUpdate rate, which could improve performance.
Expand Down
20 changes: 20 additions & 0 deletions example/src/custom/sources.json
Original file line number Diff line number Diff line change
Expand Up @@ -436,5 +436,25 @@
"src": "https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3"
}
}
},
{
"name": "HLS - THEOads",
"os": ["ios", "web", "android"],
"source": {
"sources": {
"src": "https://cluster.dev.theostream.live/nfl-unified-channel/hls/k8s/live/scte35.isml/.m3u8",
"type": "application/x-mpegurl",
"hlsDateRange": true
},
"ads": [
{
"integration": "theoads",
"networkCode": "51636543",
"customAssetKey": "nfl-sgai-demo",
"backdropDoubleBox": "https://demo.theoads.live/img/THEOads_double_box.svg",
"backdropLShape": "https://demo.theoads.live/img/THEOads_L_Shape.svg"
}
]
}
}
]
Loading