From 47021c8777e03b2b772e8670aabc1d644facc446 Mon Sep 17 00:00:00 2001 From: tonihei Date: Fri, 4 Oct 2024 08:08:38 -0700 Subject: [PATCH] Account for missing preroll when converting adPodIndex to adGroupIndex IMA always starts midrolls at index 1. So if there is no preroll ad, the ad group index in AdPlaybackState is off by 1 all the time, and may also lead to ArrayIndexOutOfBoundsExceptions when trying to access the last midroll ad Issue: androidx/media#1741 PiperOrigin-RevId: 682324368 --- RELEASENOTES.md | 3 +++ .../ImaServerSideAdInsertionMediaSource.java | 21 +++++++++++++++---- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index e281a7d987..0d7c8057f5 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -82,6 +82,9 @@ * Effect: * Muxers: * IMA extension: + * Fix bug where server-side inserted DAI streams without a preroll can + result in an `ArrayIndexOutOfBoundsException` when playing past the last + midroll ([#1741](https://github.com/androidx/media/issues/1741)). * Session: * Fix bug that caused custom commands sent from a `MediaBrowser` being dispatched to the `MediaSessionCompat.Callback` instead of the diff --git a/libraries/exoplayer_ima/src/main/java/androidx/media3/exoplayer/ima/ImaServerSideAdInsertionMediaSource.java b/libraries/exoplayer_ima/src/main/java/androidx/media3/exoplayer/ima/ImaServerSideAdInsertionMediaSource.java index f823a8e78e..facbc90f27 100644 --- a/libraries/exoplayer_ima/src/main/java/androidx/media3/exoplayer/ima/ImaServerSideAdInsertionMediaSource.java +++ b/libraries/exoplayer_ima/src/main/java/androidx/media3/exoplayer/ima/ImaServerSideAdInsertionMediaSource.java @@ -897,9 +897,7 @@ public final class ImaServerSideAdInsertionMediaSource extends CompositeMediaSou private static AdPlaybackState setVodAdInPlaceholder(Ad ad, AdPlaybackState adPlaybackState) { AdPodInfo adPodInfo = ad.getAdPodInfo(); - // Handle post rolls that have a podIndex of -1. - int adGroupIndex = - adPodInfo.getPodIndex() == -1 ? adPlaybackState.adGroupCount - 1 : adPodInfo.getPodIndex(); + int adGroupIndex = getAdGroupIndexFromAdPodInfo(adPodInfo, adPlaybackState); AdPlaybackState.AdGroup adGroup = adPlaybackState.getAdGroup(adGroupIndex); int adIndexInAdGroup = adPodInfo.getAdPosition() - 1; if (adGroup.count < adPodInfo.getTotalAds()) { @@ -924,12 +922,27 @@ public final class ImaServerSideAdInsertionMediaSource extends CompositeMediaSou private static AdPlaybackState skipAd(Ad ad, AdPlaybackState adPlaybackState) { AdPodInfo adPodInfo = ad.getAdPodInfo(); - int adGroupIndex = adPodInfo.getPodIndex(); + int adGroupIndex = getAdGroupIndexFromAdPodInfo(adPodInfo, adPlaybackState); // IMA SDK always returns index starting at 1. int adIndexInAdGroup = adPodInfo.getAdPosition() - 1; return adPlaybackState.withSkippedAd(adGroupIndex, adIndexInAdGroup); } + private static int getAdGroupIndexFromAdPodInfo( + AdPodInfo adPodInfo, AdPlaybackState adPlaybackState) { + int adPodIndex = adPodInfo.getPodIndex(); + if (adPodIndex == -1) { + // Post-roll + return adPlaybackState.adGroupCount - 1; + } + if (adPlaybackState.getAdGroup(0).timeUs == 0) { + // When a pre-roll exists, the index starts at zero. + return adPodIndex; + } + // Mid-rolls always start at 1. + return adPodIndex - 1; + } + private final class ComponentListener implements AdEvent.AdEventListener, Player.Listener, AdPlaybackStateUpdater {