From e009322edd4eb90a3e02b35113d46df98200bef3 Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Tue, 16 Feb 2021 11:25:48 +0000 Subject: [PATCH] Fix seeking to a non-zero position in a preloaded ad item `ImaAdsLoader` will preload the first ad of a subsequent media item, but the preloaded ad might not actually play because the user could seek to a non-zero position in that media item (which could trigger playback of a midroll, not the preroll). In this case, playback would get stuck because the midroll ad expected to play after the seek would never load, because the IMA SDK expected the preroll to play first. Fix this behavior by discarding the preloaded ad break. If there isn't a seek, the transition to the next media item is still seamless. #minor-release PiperOrigin-RevId: 357682510 --- RELEASENOTES.md | 3 +++ .../exoplayer2/ext/ima/AdTagLoader.java | 24 +++++++++++++++---- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 06fd3cf799..116c2967c9 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -21,6 +21,9 @@ * Remove `extension-jobdispatcher` module. Use the `extension-workmanager` module instead. * IMA extension: + * Fix a bug where playback could get stuck when seeking into a playlist + item with ads, if the preroll ad had preloaded but the window position + of the seek should instead trigger playback of a midroll. * Fix a bug with playback of ads in playlists, where the incorrect period index was used when deciding whether to trigger playback of an ad after a seek. diff --git a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/AdTagLoader.java b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/AdTagLoader.java index 3984d586df..39f9f36fd4 100644 --- a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/AdTagLoader.java +++ b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/AdTagLoader.java @@ -341,11 +341,25 @@ import java.util.Map; boolean playWhenReady = player.getPlayWhenReady(); onTimelineChanged(player.getCurrentTimeline(), Player.TIMELINE_CHANGE_REASON_SOURCE_UPDATE); - if (!AdPlaybackState.NONE.equals(adPlaybackState) - && adsManager != null - && imaPausedContent - && playWhenReady) { - adsManager.resume(); + @Nullable AdsManager adsManager = this.adsManager; + if (!AdPlaybackState.NONE.equals(adPlaybackState) && adsManager != null && imaPausedContent) { + // Check whether the current ad break matches the expected ad break based on the current + // position. If not, discard the current ad break so that the correct ad break can load. + long contentPositionMs = getContentPeriodPositionMs(player, timeline, period); + int adGroupForPositionIndex = + adPlaybackState.getAdGroupIndexForPositionUs( + C.msToUs(contentPositionMs), C.msToUs(contentDurationMs)); + if (adGroupForPositionIndex != C.INDEX_UNSET + && imaAdInfo != null + && imaAdInfo.adGroupIndex != adGroupForPositionIndex) { + if (configuration.debugModeEnabled) { + Log.d(TAG, "Discarding preloaded ad " + imaAdInfo); + } + adsManager.discardAdBreak(); + } + if (playWhenReady) { + adsManager.resume(); + } } }