From 87e828b22d4ab15831d17b6c5947bb62c22b6cd1 Mon Sep 17 00:00:00 2001 From: Tomislav Kordic <32546640+tomkordic@users.noreply.github.com> Date: Mon, 30 Sep 2024 22:56:40 +0200 Subject: [PATCH 1/7] VideoPlayerAdCallback added to IMA integration (#82) * VideoPlayerAdCallback added to ima. * Some error desc * Use aderror + cleanup * Doc clarification * Add kotlin APIs * cleanup * Actually set the ad player callback --------- Co-authored-by: Emily Dixon --- .../stats/sdk/media3_ima/ImaAdsLoaderExt.kt | 13 ++- .../stats/sdk/media3_ima/MuxImaAdsListener.kt | 82 +++++++++++++++---- .../media3_ima/ServerSideImaAdsLoaderExt.kt | 7 +- 3 files changed, 81 insertions(+), 21 deletions(-) diff --git a/library-ima/src/main/java/com/mux/stats/sdk/media3_ima/ImaAdsLoaderExt.kt b/library-ima/src/main/java/com/mux/stats/sdk/media3_ima/ImaAdsLoaderExt.kt index 31243342..b34a037f 100644 --- a/library-ima/src/main/java/com/mux/stats/sdk/media3_ima/ImaAdsLoaderExt.kt +++ b/library-ima/src/main/java/com/mux/stats/sdk/media3_ima/ImaAdsLoaderExt.kt @@ -5,13 +5,15 @@ import androidx.media3.common.util.UnstableApi import androidx.media3.exoplayer.ima.ImaAdsLoader import com.google.ads.interactivemedia.v3.api.AdErrorEvent.AdErrorListener import com.google.ads.interactivemedia.v3.api.AdEvent.AdEventListener +import com.google.ads.interactivemedia.v3.api.player.VideoAdPlayer.VideoAdPlayerCallback import com.mux.stats.sdk.muxstats.MuxStatsSdkMedia3 /** * Monitors the [ImaAdsLoader] created by the given [ImaAdsLoader.Builder]. * - * Mux must take ownership of the [AdErrorListener] and [AdEventListener] for this ads loader, but - * you can provide your own listeners and logic using the provided optional params + * Mux must take ownership of the [AdErrorListener], [AdEventListener], and [VideoAdPlayerCallback] + * for this ads loader, but you can provide your own listeners and logic using the provided optional + * params. * * @param muxStats The [MuxStatsSdkMedia3] instance monitoring your player * @param customerAdEventListener Optional. An [AdEventListener] with your apps custom ad-event handling @@ -23,15 +25,18 @@ fun ImaAdsLoader.Builder.monitorWith( muxStats: MuxStatsSdkMedia3<*>, customerAdEventListener: AdEventListener = AdEventListener { }, customerAdErrorListener: AdErrorListener = AdErrorListener { }, + customerAdPlayerAdCallback: VideoAdPlayerCallback? = null ): ImaAdsLoader.Builder { val adsListener = MuxImaAdsListener.newListener( - { muxStats }, + muxStats, customerAdEventListener, - customerAdErrorListener + customerAdErrorListener, + customerAdPlayerAdCallback, ) setAdEventListener(adsListener) setAdErrorListener(adsListener) + customerAdPlayerAdCallback?.let { setVideoAdPlayerCallback(adsListener) } return this } diff --git a/library-ima/src/main/java/com/mux/stats/sdk/media3_ima/MuxImaAdsListener.kt b/library-ima/src/main/java/com/mux/stats/sdk/media3_ima/MuxImaAdsListener.kt index e8b3d10e..3589ec8f 100644 --- a/library-ima/src/main/java/com/mux/stats/sdk/media3_ima/MuxImaAdsListener.kt +++ b/library-ima/src/main/java/com/mux/stats/sdk/media3_ima/MuxImaAdsListener.kt @@ -6,6 +6,9 @@ import com.google.ads.interactivemedia.v3.api.AdErrorEvent import com.google.ads.interactivemedia.v3.api.AdErrorEvent.AdErrorListener import com.google.ads.interactivemedia.v3.api.AdEvent import com.google.ads.interactivemedia.v3.api.AdEvent.AdEventListener +import com.google.ads.interactivemedia.v3.api.player.AdMediaInfo +import com.google.ads.interactivemedia.v3.api.player.VideoAdPlayer.VideoAdPlayerCallback +import com.google.ads.interactivemedia.v3.api.player.VideoProgressUpdate import com.mux.android.util.oneOf import com.mux.stats.sdk.core.events.playback.* import com.mux.stats.sdk.core.model.AdData @@ -24,7 +27,8 @@ class MuxImaAdsListener private constructor( private val provider: Provider, private val customerAdEventListener: AdEventListener = AdEventListener { }, private val customerAdErrorListener: AdErrorListener = AdErrorListener { }, -) : AdErrorListener, AdEventListener { + private val customerVideoAdPlayerCallback: VideoAdPlayerCallback? = null, +) : AdErrorListener, AdEventListener, VideoAdPlayerCallback { /** The ExoPlayer that is playing the ads */ private val exoPlayer: Player? get() = provider.boundPlayer @@ -222,6 +226,50 @@ class MuxImaAdsListener private constructor( adCollector?.dispatch(event) } + + /** VideoAdPlayerCallback */ + override fun onAdProgress(mediaInfo: AdMediaInfo, progress: VideoProgressUpdate) { + customerVideoAdPlayerCallback?.onAdProgress(mediaInfo, progress) + } + + override fun onBuffering(mediaInfo: AdMediaInfo) { + customerVideoAdPlayerCallback?.onBuffering(mediaInfo) + } + + override fun onContentComplete() { + customerVideoAdPlayerCallback?.onContentComplete() + } + + override fun onEnded(mediaInfo: AdMediaInfo) { + customerVideoAdPlayerCallback?.onEnded(mediaInfo) + } + + override fun onError(mediaInfo: AdMediaInfo) { + adCollector?.dispatch(MuxAdErrorEvent(null)) + customerVideoAdPlayerCallback?.onError(mediaInfo) + } + + override fun onLoaded(mediaInfo: AdMediaInfo) { + adCollector?.dispatch(AdResponseEvent(null)) + customerVideoAdPlayerCallback?.onLoaded(mediaInfo) + } + + override fun onPause(mediaInfo: AdMediaInfo) { + customerVideoAdPlayerCallback?.onPause(mediaInfo) + } + + override fun onPlay(mediaInfo: AdMediaInfo) { + customerVideoAdPlayerCallback?.onPlay(mediaInfo) + } + + override fun onResume(mediaInfo: AdMediaInfo) { + customerVideoAdPlayerCallback?.onResume(mediaInfo) + } + + override fun onVolumeChanged(mediaInfo: AdMediaInfo, p1: Int) { + customerVideoAdPlayerCallback?.onVolumeChanged(mediaInfo, p1) + } + companion object { private const val TAG = "MuxImaAdsListener" @@ -233,28 +281,30 @@ class MuxImaAdsListener private constructor( muxSdk: MuxStatsSdkMedia3<*>, customerAdEventListener: AdEventListener = AdEventListener { }, customerAdErrorListener: AdErrorListener = AdErrorListener { }, + customerVideoAdPlayerCallback: VideoAdPlayerCallback? = null, ): MuxImaAdsListener { return MuxImaAdsListener( Provider { muxSdk }, customerAdEventListener, + customerAdErrorListener, + customerVideoAdPlayerCallback + ) + } + /** + * Creates a new [MuxImaAdsListener] based on the given [MuxStatsSdkMedia3] + */ + @JvmStatic + fun newListener( + muxSdkProvider:() -> MuxStatsSdkMedia3<*>?, + customerAdEventListener: AdEventListener = AdEventListener { }, + customerAdErrorListener: AdErrorListener = AdErrorListener { }, + ): MuxImaAdsListener { + return MuxImaAdsListener( + Provider { muxSdkProvider() }, + customerAdEventListener, customerAdErrorListener ) } - /** - * Creates a new [MuxImaAdsListener] based on the given [MuxStatsSdkMedia3] - */ - @JvmStatic - fun newListener( - muxSdkProvider:() -> MuxStatsSdkMedia3<*>?, - customerAdEventListener: AdEventListener = AdEventListener { }, - customerAdErrorListener: AdErrorListener = AdErrorListener { }, - ): MuxImaAdsListener { - return MuxImaAdsListener( - Provider { muxSdkProvider() }, - customerAdEventListener, - customerAdErrorListener - ) - } } } diff --git a/library-ima/src/main/java/com/mux/stats/sdk/media3_ima/ServerSideImaAdsLoaderExt.kt b/library-ima/src/main/java/com/mux/stats/sdk/media3_ima/ServerSideImaAdsLoaderExt.kt index 1d7ee89d..7902d748 100644 --- a/library-ima/src/main/java/com/mux/stats/sdk/media3_ima/ServerSideImaAdsLoaderExt.kt +++ b/library-ima/src/main/java/com/mux/stats/sdk/media3_ima/ServerSideImaAdsLoaderExt.kt @@ -3,13 +3,18 @@ package com.mux.stats.sdk.media3_ima import androidx.annotation.OptIn import androidx.media3.common.util.UnstableApi import androidx.media3.exoplayer.ima.ImaAdsLoader +import androidx.media3.exoplayer.ima.ImaServerSideAdInsertionMediaSource import androidx.media3.exoplayer.ima.ImaServerSideAdInsertionMediaSource.AdsLoader import com.google.ads.interactivemedia.v3.api.AdErrorEvent.AdErrorListener import com.google.ads.interactivemedia.v3.api.AdEvent.AdEventListener import com.mux.stats.sdk.muxstats.MuxStatsSdkMedia3 /** - * Monitors the [ImaAdsLoader] created by the given [ImaAdsLoader.Builder]. + * Monitors the [ImaServerSideAdInsertionMediaSource.AdsLoader] created by the a + * [ImaServerSideAdInsertionMediaSource.AdsLoader.Builder]. + * + * This method is just for DAI server-side ad-insertion. If you're doing Client-Side Ad Insertion + * (CSAI), use [ImaAdsLoader.Builder.monitorWith] * * Mux must take ownership of the [AdErrorListener] and [AdEventListener] for this ads loader, but * you can provide your own listeners and logic using the provided optional params From 4bf8bb8fb912994c1cabc0cb11bc8a6595fbfb4c Mon Sep 17 00:00:00 2001 From: Emily Dixon Date: Tue, 1 Oct 2024 17:53:28 -0700 Subject: [PATCH 2/7] Update cores 8.1.1 and 1.4.1 --- build.gradle | 6 +++--- gradle/wrapper/gradle-wrapper.properties | 2 +- .../java/com/mux/stats/sdk/muxstats/MuxStatsSdkMedia3.kt | 2 ++ 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/build.gradle b/build.gradle index 7754f986..6686ff0d 100644 --- a/build.gradle +++ b/build.gradle @@ -1,7 +1,7 @@ import org.jetbrains.dokka.gradle.DokkaTaskPartial plugins { - id 'com.android.application' version '8.5.2' apply false - id 'com.android.library' version '8.5.2' apply false + id 'com.android.application' version '8.6.0' apply false + id 'com.android.library' version '8.6.0' apply false id 'org.jetbrains.kotlin.android' version '1.9.24' apply false id 'com.mux.gradle.android.mux-android-distribution' version '1.3.0' apply false id "org.jetbrains.dokka" version "1.6.10" @@ -9,7 +9,7 @@ plugins { allprojects { project.ext { - coreVersion = '1.4.0' + coreVersion = '1.4.1' } tasks.withType(DokkaTaskPartial.class) { diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 029fdfb2..bd3e7f16 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ #Fri Nov 18 08:57:39 PST 2022 distributionBase=GRADLE_USER_HOME -distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip distributionPath=wrapper/dists zipStorePath=wrapper/dists zipStoreBase=GRADLE_USER_HOME diff --git a/library/src/main/java/com/mux/stats/sdk/muxstats/MuxStatsSdkMedia3.kt b/library/src/main/java/com/mux/stats/sdk/muxstats/MuxStatsSdkMedia3.kt index cbb52088..215d00a8 100644 --- a/library/src/main/java/com/mux/stats/sdk/muxstats/MuxStatsSdkMedia3.kt +++ b/library/src/main/java/com/mux/stats/sdk/muxstats/MuxStatsSdkMedia3.kt @@ -11,6 +11,7 @@ import com.mux.stats.sdk.core.events.EventBus import com.mux.stats.sdk.core.events.playback.AdEvent import com.mux.stats.sdk.core.model.CustomerData import com.mux.stats.sdk.core.model.CustomerVideoData +import com.mux.stats.sdk.core.util.MuxLogger import com.mux.stats.sdk.muxstats.media3.BuildConfig import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -61,6 +62,7 @@ class MuxStatsSdkMedia3

@OptIn(UnstableApi::class) @JvmOverloads con ), makeNetworkRequest = { iDevice -> network ?: MuxNetwork(iDevice, CoroutineScope(Dispatchers.IO)) } ) { + /** * Collects events related to ad playback and reports them. If you are using Google IMA, you don't * need to interact with this class directly. Instead, use the `media3-ima` library provided by From ec0db1156bf0d33ae339273e57bebd9bd3f9de4a Mon Sep 17 00:00:00 2001 From: Emily Dixon Date: Tue, 1 Oct 2024 19:13:53 -0700 Subject: [PATCH 3/7] 1.4.2 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 6686ff0d..af276e5e 100644 --- a/build.gradle +++ b/build.gradle @@ -9,7 +9,7 @@ plugins { allprojects { project.ext { - coreVersion = '1.4.1' + coreVersion = '1.4.2' } tasks.withType(DokkaTaskPartial.class) { From d4e09616de25e920c0bd9db27c55ed64761876f1 Mon Sep 17 00:00:00 2001 From: Emily Dixon Date: Wed, 2 Oct 2024 09:29:44 -0700 Subject: [PATCH 4/7] Oh wait videoTitle --- .../muxdatasdkformedia3/examples/ima/ImaClientAdsActivity.kt | 2 +- .../muxdatasdkformedia3/examples/ima/ImaServerAdsActivity.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/mux/stats/muxdatasdkformedia3/examples/ima/ImaClientAdsActivity.kt b/app/src/main/java/com/mux/stats/muxdatasdkformedia3/examples/ima/ImaClientAdsActivity.kt index e0218403..2ebeff84 100644 --- a/app/src/main/java/com/mux/stats/muxdatasdkformedia3/examples/ima/ImaClientAdsActivity.kt +++ b/app/src/main/java/com/mux/stats/muxdatasdkformedia3/examples/ima/ImaClientAdsActivity.kt @@ -99,7 +99,7 @@ class ImaClientAdsActivity : AppCompatActivity() { val customerData = CustomerData( CustomerPlayerData().apply { }, CustomerVideoData().apply { - title = "Mux Data SDK for Media3 Demo" + videoTitle = "Mux Data for Media3 - CSAI Ads" }, CustomerViewData().apply { } ) diff --git a/app/src/main/java/com/mux/stats/muxdatasdkformedia3/examples/ima/ImaServerAdsActivity.kt b/app/src/main/java/com/mux/stats/muxdatasdkformedia3/examples/ima/ImaServerAdsActivity.kt index c55806ed..f202e5ef 100644 --- a/app/src/main/java/com/mux/stats/muxdatasdkformedia3/examples/ima/ImaServerAdsActivity.kt +++ b/app/src/main/java/com/mux/stats/muxdatasdkformedia3/examples/ima/ImaServerAdsActivity.kt @@ -161,7 +161,7 @@ class ImaServerAdsActivity : AppCompatActivity() { val customerData = CustomerData( CustomerPlayerData().apply { }, CustomerVideoData().apply { - title = "Mux Data SDK for Media3 Demo" + videoTitle = "Mux Data SDK for Media3 Demo" }, CustomerViewData().apply { } ) From 835cd7cd9f70cdef1d4d2f2beb832cd231bfffce Mon Sep 17 00:00:00 2001 From: Emily Dixon Date: Wed, 2 Oct 2024 09:34:13 -0700 Subject: [PATCH 5/7] fix the titles --- .../muxdatasdkformedia3/examples/ima/ImaServerAdsActivity.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/mux/stats/muxdatasdkformedia3/examples/ima/ImaServerAdsActivity.kt b/app/src/main/java/com/mux/stats/muxdatasdkformedia3/examples/ima/ImaServerAdsActivity.kt index f202e5ef..43a231cb 100644 --- a/app/src/main/java/com/mux/stats/muxdatasdkformedia3/examples/ima/ImaServerAdsActivity.kt +++ b/app/src/main/java/com/mux/stats/muxdatasdkformedia3/examples/ima/ImaServerAdsActivity.kt @@ -161,7 +161,7 @@ class ImaServerAdsActivity : AppCompatActivity() { val customerData = CustomerData( CustomerPlayerData().apply { }, CustomerVideoData().apply { - videoTitle = "Mux Data SDK for Media3 Demo" + videoTitle = "Mux Data SDK for Media3 - Server Ads" }, CustomerViewData().apply { } ) From 9f79494600d09bfd4fbb81f634c9927882a362fd Mon Sep 17 00:00:00 2001 From: Emily Dixon Date: Wed, 2 Oct 2024 10:19:28 -0700 Subject: [PATCH 6/7] last-minute fix: actually set listener --- .../main/java/com/mux/stats/sdk/media3_ima/ImaAdsLoaderExt.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library-ima/src/main/java/com/mux/stats/sdk/media3_ima/ImaAdsLoaderExt.kt b/library-ima/src/main/java/com/mux/stats/sdk/media3_ima/ImaAdsLoaderExt.kt index b34a037f..e5e6b02c 100644 --- a/library-ima/src/main/java/com/mux/stats/sdk/media3_ima/ImaAdsLoaderExt.kt +++ b/library-ima/src/main/java/com/mux/stats/sdk/media3_ima/ImaAdsLoaderExt.kt @@ -36,7 +36,7 @@ fun ImaAdsLoader.Builder.monitorWith( setAdEventListener(adsListener) setAdErrorListener(adsListener) - customerAdPlayerAdCallback?.let { setVideoAdPlayerCallback(adsListener) } + setVideoAdPlayerCallback(adsListener) return this } From fbacc1592d77dd34479d1fdfc84f126185b7bb13 Mon Sep 17 00:00:00 2001 From: Emily Dixon Date: Wed, 2 Oct 2024 12:25:01 -0700 Subject: [PATCH 7/7] add errored ad tag --- app/src/main/java/com/mux/stats/muxdatasdkformedia3/Constants.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/com/mux/stats/muxdatasdkformedia3/Constants.kt b/app/src/main/java/com/mux/stats/muxdatasdkformedia3/Constants.kt index e5fd2d7c..94cb3e42 100644 --- a/app/src/main/java/com/mux/stats/muxdatasdkformedia3/Constants.kt +++ b/app/src/main/java/com/mux/stats/muxdatasdkformedia3/Constants.kt @@ -8,5 +8,6 @@ object Constants { const val VOD_TEST_URL_BIG_BUCK_BUNNY = "https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8" const val AD_TAG_SIMPLE_W_MID_ROLL = "https://pubads.g.doubleclick.net/gampad/ads?iu=/21775744923/external/vmap_ad_samples&sz=640x480&cust_params=sample_ar%3Dpremidpostoptimizedpod&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=" const val AD_TAG_COMPLEX = "https://pubads.g.doubleclick.net/gampad/ads?iu=/21775744923/external/vmap_ad_samples&sz=640x480&cust_params=sample_ar%3Dpremidpostlongpod&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=" + const val AD_TAG_BROKEN_REDIRECT = "https://pubads.g.doubleclick.net/gampad/ads?iu=/21775744923/external/single_ad_samples&sz=640x480&cust_params=sample_ct%3Dredirecterror&ciu_szs=300x250%2C728x90&gdfp_req=1&output=vast&unviewed_position_start=1&env=vp&impl=s&correlator=" const val SSAI_ASSET_TAG_BUCK = "c-rArva4ShKVIAkNfy6HUQ" } \ No newline at end of file