google / google/ExoPlayer

AdTagLoader: Internal error in stopAd when receiving AdEventType.LOADED event, then playing the VAST Ads

Open
#9,423 6 comments 0 reactions 1 assignee Claimed by @andrewlewis View on GitHub
needs triage question
Dominant language
Java
Stars
21.9k
Forks
6k
PR merge metrics
No merged PRs in 30d

Description

ExoPlayer and IMA version: 2.15.0

# Issue description
I try to play the VAST video ads by using the ExoPlayer IMA extension but will receive this error
```
2021-09-10 09:57:39.694 4050-4050/com.example.googleimatest D/AdTagLoader: onAdError
AdError [errorType: PLAY, errorCode: AdErrorCode [name: VAST_MEDIA_LOAD_TIMEOUT, number: 402], message: VAST media file loading reached a timeout of 8 seconds.]
at com.google.ads.interactivemedia.v3.internal.dg.f(IMASDK:1)
at com.google.ads.interactivemedia.v3.internal.ed.k(IMASDK:50)
at com.google.ads.interactivemedia.v3.internal.ej.f(IMASDK:5)
at com.google.ads.interactivemedia.v3.internal.eg.shouldOverrideUrlLoading(IMASDK:2)
at android.webkit.WebViewClient.shouldOverrideUrlLoading(WebViewClient.java:83)
at org.chromium.android_webview.AwContentsClientBridge.shouldOverrideUrlLoading(chromium-TrichromeWebViewGoogle.aab-stable-457706233:14)
at android.os.MessageQueue.nativePollOnce(Native Method)
at android.os.MessageQueue.next(MessageQueue.java:335)
at android.os.Looper.loop(Looper.java:183)
at android.app.ActivityThread.main(ActivityThread.java:7656)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)

2021-09-10 09:57:39.697 4050-4050/com.example.googleimatest D/AdTagLoader: stopAd AdMediaInfo[https://redirector.gvt1.com/videoplayback/id/a33fc5b2685eb16e/itag/15/source/gfp_video_ads/requiressl/yes/acao/yes/mime/video%2Fmp4/ctier/L/ip/0.0.0.0/ipbits/0/expire/1631260631/sparams/ip,ipbits,expire,id,itag,source,requiressl,acao,mime,ctier/signature/6CA0F3E39AF96DB6305D185C63ADD8DBE4168551.7F4C81AA73E3BA30D250E837830CC0F048D1AA6F/key/ck2/file/file.mp4, (0, 0)]
2021-09-10 09:57:39.698 4050-4050/com.example.googleimatest E/AdTagLoader: Internal error in stopAd
java.lang.IllegalArgumentException
at com.google.android.exoplayer2.util.Assertions.checkArgument(Assertions.java:39)
at com.google.android.exoplayer2.source.ads.AdPlaybackState$AdGroup.withAdState(AdPlaybackState.java:232)
at com.google.android.exoplayer2.source.ads.AdPlaybackState.withPlayedAd(AdPlaybackState.java:622)
at com.google.android.exoplayer2.ext.ima.AdTagLoader.stopAdInternal(AdTagLoader.java:1043)
at com.google.android.exoplayer2.ext.ima.AdTagLoader.access$2200(AdTagLoader.java:79)
at com.google.android.exoplayer2.ext.ima.AdTagLoader$ComponentListener.stopAd(AdTagLoader.java:1434)
at com.google.ads.interactivemedia.v3.internal.ek.f(IMASDK:3)
at com.google.ads.interactivemedia.v3.internal.ed.r(IMASDK:3)
at com.google.ads.interactivemedia.v3.internal.ed.k(IMASDK:126)
at com.google.ads.interactivemedia.v3.internal.ej.f(IMASDK:5)
at com.google.ads.interactivemedia.v3.internal.eg.shouldOverrideUrlLoading(IMASDK:2)
at android.webkit.WebViewClient.shouldOverrideUrlLoading(WebViewClient.java:83)
at org.chromium.android_webview.AwContentsClientBridge.shouldOverrideUrlLoading(chromium-TrichromeWebViewGoogle.aab-stable-457706233:14)
at android.os.MessageQueue.nativePollOnce(Native Method)
at android.os.MessageQueue.next(MessageQueue.java:335)
at android.os.Looper.loop(Looper.java:183)
at android.app.ActivityThread.main(ActivityThread.java:7656)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
```
# Reproduction steps
1. setup ExoPlayer, Ads and event listener
```
private fun initPlayer(vastXml: String) {
videoPlayer = SimpleExoPlayer.Builder(requireContext()).build()
.apply { addListener(playerEventListener) }

imaAdsLoader = ImaAdsLoader.Builder(requireContext())
.setDebugModeEnabled(true)
.setAdEventListener(adsEventListener)
.build()
.apply { setPlayer(videoPlayer) }

val mediaSourceWithAds = AdsMediaSource(
// We only want to play ads video and we don't have any content video
// Pass empty url here and it would raise MalformedURLException exception but we ignore it
SilenceMediaSource(0),
DataSpec(Util.getDataUriForString("text/xml", vastXml)),
vastXml,
DefaultMediaSourceFactory(requireContext()),
imaAdsLoader,
videoPlayerView
)

videoPlayer.prepare(mediaSourceWithAds)
videoPlayerView.player = videoPlayer
}
```
2. play ads video when receiving the `AdEventType.LOADED` event,
```
AdEvent.AdEventListener { event ->
if (event.type == AdEvent.AdEventType.LOADED) {
Handler(Looper.getMainLooper()).post {
videoPlayer.playWhenReady = true
}
}
}
```

I found the error coming from `Handler(Looper.getMainLooper()).post`. If I call `videoPlayer.playWhenReady = true` without `Handler(Looper.getMainLooper())`, the error will not happen.

The reason I add `Handler(Looper.getMainLooper())` is because I know that should be a single thread to access the ExoPlayer. I want to make sure `videoPlayer.playWhenReady = true` will be called on the main thread.
> ExoPlayer instances must be accessed from a single application thread. For the vast majority of cases this should be the application’s main thread. Using the application’s main thread is a requirement when using ExoPlayer’s UI components or the IMA extension.

I found there are two workaround solutions:
1. calling `videoPlayer.playWhenReady = true` directly
```
AdEvent.AdEventListener { event ->
if (event.type == AdEvent.AdEventType.LOADED) {
videoPlayer.playWhenReady = true
}
}
```
This solution works but I want to make sure this `videoPlayer.playWhenReady = true` always be calling in the main thread. So I still want to call it with `Handler(Looper.getMainLooper()).post`

2. `postDelayed` with a long time.
```
AdEvent.AdEventListener { event ->
if (event.type == AdEvent.AdEventType.LOADED) {
Handler(Looper.getMainLooper()).postDelayed({
videoPlayer.playWhenReady = true
}, 1000L)
}
}
```
Although this solution works, it will impact the performance of video loading. Also, how long it should `postDelayed` we don't know.

This issue is very similar to the crash 1 on this issue https://github.com/google/ExoPlayer/issues/8290.
The difference is I know how to reproduce.
I still want to know why we have this issue and how to fix it. Thanks

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.