From ce8bb2680213da567798affe96bfdd6ca643f91b Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Fri, 26 Jun 2020 13:34:05 +0100 Subject: [PATCH 1/2] Fix postroll content complete notifications On reaching the end of the content we would notify content complete and skip unplayed ads, causing a timeline change. That timeline change was handled in a way that caused a further timeline change in the 2.11.6 release, where we don't yet deduplicate no-op Timeline changes, causing repeated timeline changes indefinitely. At tip-of-tree, the timeline wouldn't refresh repeatedly. However the code for sending content complete at the point of transitioning to play a preloaded postroll ad was not correct in that it didn't mark previous ads as skipped. Instead they happened to be marked as skipped later on due to the timeline change handling content completion code triggering again. Fix this by only marking ads as skipped when content completes once, to avoid the duplicate timeline change, and moving the skipped ad marking so it happens in the same place as notifying content complete. PiperOrigin-RevId: 318454908 --- RELEASENOTES.md | 4 ++ .../exoplayer2/ext/ima/ImaAdsLoader.java | 46 +++++++++---------- 2 files changed, 27 insertions(+), 23 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index b4e877f5dc..b890defb5d 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -1,6 +1,10 @@ # Release notes # ### 2.11.6 (2020-06-24) ### +* IMA extension: Fix the way 'content complete' is handled to avoid repeatedly + refreshing the timeline after playback ends. + +### 2.11.6 (2020-06-19) ### * UI: Prevent `PlayerView` from temporarily hiding the video surface when seeking to an unprepared period within the current window. For example when diff --git a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java index eecce40314..5436bb192c 100644 --- a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java +++ b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java @@ -1026,7 +1026,7 @@ public final class ImaAdsLoader implements Player.EventListener, AdsLoader { if (imaAdState == IMA_AD_STATE_NONE && playbackState == Player.STATE_BUFFERING && playWhenReady) { - checkForContentComplete(); + ensureSentContentCompleteIfAtEndOfStream(); } else if (imaAdState != IMA_AD_STATE_NONE && playbackState == Player.STATE_ENDED) { AdMediaInfo adMediaInfo = Assertions.checkNotNull(imaAdMediaInfo); if (adMediaInfo == null) { @@ -1048,15 +1048,8 @@ public final class ImaAdsLoader implements Player.EventListener, AdsLoader { return; } if (!playingAd && !player.isPlayingAd()) { - checkForContentComplete(); - if (sentContentComplete) { - for (int i = 0; i < adPlaybackState.adGroupCount; i++) { - if (adPlaybackState.adGroupTimesUs[i] != C.TIME_END_OF_SOURCE) { - adPlaybackState = adPlaybackState.withSkippedAdGroup(/* adGroupIndex= */ i); - } - } - updateAdPlaybackState(); - } else if (!timeline.isEmpty()) { + ensureSentContentCompleteIfAtEndOfStream(); + if (!sentContentComplete && !timeline.isEmpty()) { long positionMs = getContentPeriodPositionMs(player, timeline, period); timeline.getPeriod(/* periodIndex= */ 0, period); int newAdGroupIndex = period.getAdGroupIndexForPositionUs(C.msToUs(positionMs)); @@ -1090,11 +1083,7 @@ public final class ImaAdsLoader implements Player.EventListener, AdsLoader { if (!sentContentComplete && !wasPlayingAd && playingAd && imaAdState == IMA_AD_STATE_NONE) { int adGroupIndex = player.getCurrentAdGroupIndex(); if (adPlaybackState.adGroupTimesUs[adGroupIndex] == C.TIME_END_OF_SOURCE) { - adsLoader.contentComplete(); - if (DEBUG) { - Log.d(TAG, "adsLoader.contentComplete from period transition"); - } - sentContentComplete = true; + sendContentComplete(); } else { // IMA hasn't called playAd yet, so fake the content position. fakeContentProgressElapsedRealtimeMs = SystemClock.elapsedRealtime(); @@ -1212,20 +1201,31 @@ public final class ImaAdsLoader implements Player.EventListener, AdsLoader { updateAdPlaybackState(); } - private void checkForContentComplete() { - long positionMs = getContentPeriodPositionMs(Assertions.checkNotNull(player), timeline, period); + private void ensureSentContentCompleteIfAtEndOfStream() { if (!sentContentComplete && contentDurationMs != C.TIME_UNSET && pendingContentPositionMs == C.TIME_UNSET - && positionMs + THRESHOLD_END_OF_CONTENT_MS >= contentDurationMs) { - adsLoader.contentComplete(); - if (DEBUG) { - Log.d(TAG, "adsLoader.contentComplete from content position check"); - } - sentContentComplete = true; + && getContentPeriodPositionMs(Assertions.checkNotNull(player), timeline, period) + + THRESHOLD_END_OF_CONTENT_MS + >= contentDurationMs) { + sendContentComplete(); } } + private void sendContentComplete() { + adsLoader.contentComplete(); + sentContentComplete = true; + if (DEBUG) { + Log.d(TAG, "adsLoader.contentComplete"); + } + for (int i = 0; i < adPlaybackState.adGroupCount; i++) { + if (adPlaybackState.adGroupTimesUs[i] != C.TIME_END_OF_SOURCE) { + adPlaybackState = adPlaybackState.withSkippedAdGroup(/* adGroupIndex= */ i); + } + } + updateAdPlaybackState(); + } + private void updateAdPlaybackState() { // Ignore updates while detached. When a player is attached it will receive the latest state. if (eventListener != null) { From 8fcbbb09aff3d05a3e60fc052d9c84f20b80f2db Mon Sep 17 00:00:00 2001 From: olly Date: Mon, 29 Jun 2020 12:48:55 +0100 Subject: [PATCH 2/2] Bump release to 2.11.7 PiperOrigin-RevId: 318790917 --- RELEASENOTES.md | 9 +++++---- constants.gradle | 4 ++-- .../google/android/exoplayer2/ExoPlayerLibraryInfo.java | 6 +++--- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index b890defb5d..d99656b5a9 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -1,10 +1,11 @@ # Release notes # -### 2.11.6 (2020-06-24) ### -* IMA extension: Fix the way 'content complete' is handled to avoid repeatedly - refreshing the timeline after playback ends. +### 2.11.7 (2020-06-29) ### -### 2.11.6 (2020-06-19) ### +* IMA extension: Fix the way postroll "content complete" notifications are + handled to avoid repeatedly refreshing the timeline after playback ends. + +### 2.11.6 (2020-06-24) ### * UI: Prevent `PlayerView` from temporarily hiding the video surface when seeking to an unprepared period within the current window. For example when diff --git a/constants.gradle b/constants.gradle index 7b6298e9d4..9d38d82369 100644 --- a/constants.gradle +++ b/constants.gradle @@ -13,8 +13,8 @@ // limitations under the License. project.ext { // ExoPlayer version and version code. - releaseVersion = '2.11.6' - releaseVersionCode = 2011006 + releaseVersion = '2.11.7' + releaseVersionCode = 2011007 minSdkVersion = 16 appTargetSdkVersion = 29 targetSdkVersion = 28 // TODO: Bump once b/143232359 is resolved diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java index f35c3ac498..35b6199cd3 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java @@ -29,11 +29,11 @@ public final class ExoPlayerLibraryInfo { /** The version of the library expressed as a string, for example "1.2.3". */ // Intentionally hardcoded. Do not derive from other constants (e.g. VERSION_INT) or vice versa. - public static final String VERSION = "2.11.6"; + public static final String VERSION = "2.11.7"; /** The version of the library expressed as {@code "ExoPlayerLib/" + VERSION}. */ // Intentionally hardcoded. Do not derive from other constants (e.g. VERSION) or vice versa. - public static final String VERSION_SLASHY = "ExoPlayerLib/2.11.6"; + public static final String VERSION_SLASHY = "ExoPlayerLib/2.11.7"; /** * The version of the library expressed as an integer, for example 1002003. @@ -43,7 +43,7 @@ public final class ExoPlayerLibraryInfo { * integer version 123045006 (123-045-006). */ // Intentionally hardcoded. Do not derive from other constants (e.g. VERSION) or vice versa. - public static final int VERSION_INT = 2011006; + public static final int VERSION_INT = 2011007; /** * Whether the library was compiled with {@link com.google.android.exoplayer2.util.Assertions}