mirror of
https://github.com/samsonjs/media.git
synced 2026-03-26 09:35:47 +00:00
Fix position reporting with fetch errors
On receiving a fetch error for an ad that would otherwise play based on an initial/seek position, the pending content position wasn't cleared which meant that position reporting was broken after a fetch error. Fix this by always clearing the pending position (if there was a pending position that will have triggered the fetch error). Also deduplicate the code for handling empty ad groups (fetch errors) and ad group load errors. Issue: #7956 PiperOrigin-RevId: 334113131
This commit is contained in:
parent
9819664bd1
commit
1bdccd4bfb
3 changed files with 42 additions and 28 deletions
|
|
@ -20,6 +20,9 @@
|
|||
* Add the option to sort tracks by `Format` in `TrackSelectionView` and
|
||||
`TrackSelectionDialogBuilder`
|
||||
([#7709](https://github.com/google/ExoPlayer/issues/7709)).
|
||||
* IMA extension:
|
||||
* Fix position reporting after fetch errors
|
||||
([#7956](https://github.com/google/ExoPlayer/issues/7956)).
|
||||
|
||||
### 2.12.0 (2020-09-11) ###
|
||||
|
||||
|
|
|
|||
|
|
@ -1077,7 +1077,7 @@ public final class ImaAdsLoader
|
|||
adGroupTimeSeconds == -1.0
|
||||
? adPlaybackState.adGroupCount - 1
|
||||
: getAdGroupIndexForCuePointTimeSeconds(adGroupTimeSeconds);
|
||||
handleAdGroupFetchError(adGroupIndex);
|
||||
markAdGroupInErrorStateAndClearPendingContentPosition(adGroupIndex);
|
||||
break;
|
||||
case CONTENT_PAUSE_REQUESTED:
|
||||
// After CONTENT_PAUSE_REQUESTED, IMA will playAd/pauseAd/stopAd to show one or more ads
|
||||
|
|
@ -1364,35 +1364,20 @@ public final class ImaAdsLoader
|
|||
}
|
||||
}
|
||||
|
||||
private void handleAdGroupFetchError(int adGroupIndex) {
|
||||
AdPlaybackState.AdGroup adGroup = adPlaybackState.adGroups[adGroupIndex];
|
||||
if (adGroup.count == C.LENGTH_UNSET) {
|
||||
adPlaybackState = adPlaybackState.withAdCount(adGroupIndex, max(1, adGroup.states.length));
|
||||
adGroup = adPlaybackState.adGroups[adGroupIndex];
|
||||
}
|
||||
for (int i = 0; i < adGroup.count; i++) {
|
||||
if (adGroup.states[i] == AdPlaybackState.AD_STATE_UNAVAILABLE) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "Removing ad " + i + " in ad group " + adGroupIndex);
|
||||
}
|
||||
adPlaybackState = adPlaybackState.withAdLoadError(adGroupIndex, i);
|
||||
}
|
||||
}
|
||||
updateAdPlaybackState();
|
||||
}
|
||||
|
||||
private void handleAdGroupLoadError(Exception error) {
|
||||
if (player == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Once IMA signals which ad group failed to load, remove this call.
|
||||
int adGroupIndex = getLoadingAdGroupIndex();
|
||||
if (adGroupIndex == C.INDEX_UNSET) {
|
||||
Log.w(TAG, "Unable to determine ad group index for ad group load error", error);
|
||||
return;
|
||||
}
|
||||
markAdGroupInErrorStateAndClearPendingContentPosition(adGroupIndex);
|
||||
if (pendingAdLoadError == null) {
|
||||
pendingAdLoadError = AdLoadException.createForAdGroup(error, adGroupIndex);
|
||||
}
|
||||
}
|
||||
|
||||
private void markAdGroupInErrorStateAndClearPendingContentPosition(int adGroupIndex) {
|
||||
// Update the ad playback state so all ads in the ad group are in the error state.
|
||||
AdPlaybackState.AdGroup adGroup = adPlaybackState.adGroups[adGroupIndex];
|
||||
if (adGroup.count == C.LENGTH_UNSET) {
|
||||
adPlaybackState = adPlaybackState.withAdCount(adGroupIndex, max(1, adGroup.states.length));
|
||||
|
|
@ -1407,9 +1392,7 @@ public final class ImaAdsLoader
|
|||
}
|
||||
}
|
||||
updateAdPlaybackState();
|
||||
if (pendingAdLoadError == null) {
|
||||
pendingAdLoadError = AdLoadException.createForAdGroup(error, adGroupIndex);
|
||||
}
|
||||
// Clear any pending content position that triggered attempting to load the ad group.
|
||||
pendingContentPositionMs = C.TIME_UNSET;
|
||||
fakeContentProgressElapsedRealtimeMs = C.TIME_UNSET;
|
||||
}
|
||||
|
|
@ -1522,8 +1505,10 @@ public final class ImaAdsLoader
|
|||
* no such ad group.
|
||||
*/
|
||||
private int getLoadingAdGroupIndex() {
|
||||
long playerPositionUs =
|
||||
C.msToUs(getContentPeriodPositionMs(checkNotNull(player), timeline, period));
|
||||
if (player == null) {
|
||||
return C.INDEX_UNSET;
|
||||
}
|
||||
long playerPositionUs = C.msToUs(getContentPeriodPositionMs(player, timeline, period));
|
||||
int adGroupIndex =
|
||||
adPlaybackState.getAdGroupIndexForPositionUs(playerPositionUs, C.msToUs(contentDurationMs));
|
||||
if (adGroupIndex == C.INDEX_UNSET) {
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ import com.google.ads.interactivemedia.v3.api.ImaSdkSettings;
|
|||
import com.google.ads.interactivemedia.v3.api.player.AdMediaInfo;
|
||||
import com.google.ads.interactivemedia.v3.api.player.ContentProgressProvider;
|
||||
import com.google.ads.interactivemedia.v3.api.player.VideoAdPlayer;
|
||||
import com.google.ads.interactivemedia.v3.api.player.VideoProgressUpdate;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.ExoPlaybackException;
|
||||
import com.google.android.exoplayer2.MediaItem;
|
||||
|
|
@ -311,6 +312,31 @@ public final class ImaAdsLoaderTest {
|
|||
.withAdLoadError(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void playback_withMidrollFetchError_updatesContentProgress() {
|
||||
AdEvent mockMidrollFetchErrorAdEvent = mock(AdEvent.class);
|
||||
when(mockMidrollFetchErrorAdEvent.getType()).thenReturn(AdEventType.AD_BREAK_FETCH_ERROR);
|
||||
when(mockMidrollFetchErrorAdEvent.getAdData())
|
||||
.thenReturn(ImmutableMap.of("adBreakTime", "5.5"));
|
||||
setupPlayback(CONTENT_TIMELINE, ImmutableList.of(5.5f));
|
||||
|
||||
// Simulate loading an empty midroll ad and advancing the player position.
|
||||
imaAdsLoader.start(adsLoaderListener, adViewProvider);
|
||||
adEventListener.onAdEvent(mockMidrollFetchErrorAdEvent);
|
||||
long playerPositionUs = CONTENT_DURATION_US - C.MICROS_PER_SECOND;
|
||||
long playerPositionInPeriodUs =
|
||||
playerPositionUs + TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US;
|
||||
long periodDurationUs =
|
||||
CONTENT_TIMELINE.getPeriod(/* periodIndex= */ 0, new Period()).durationUs;
|
||||
fakeExoPlayer.setPlayingContentPosition(C.usToMs(playerPositionUs));
|
||||
|
||||
// Verify the content progress is updated to reflect the new player position.
|
||||
assertThat(contentProgressProvider.getContentProgress())
|
||||
.isEqualTo(
|
||||
new VideoProgressUpdate(
|
||||
C.usToMs(playerPositionInPeriodUs), C.usToMs(periodDurationUs)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void playback_withPostrollFetchError_marksAdAsInErrorState() {
|
||||
AdEvent mockPostrollFetchErrorAdEvent = mock(AdEvent.class);
|
||||
|
|
|
|||
Loading…
Reference in a new issue