Enforce unit speed for ad playback

Ad playback shouldn't be affected by manual speed adjustments set
by the user. This change enforces unit speed for ad playback.

Issue: google/ExoPlayer#9018
PiperOrigin-RevId: 424546258
This commit is contained in:
tonihei 2022-01-27 09:27:18 +00:00 committed by Andrew Lewis
parent be43ac7563
commit 73d9728f6a
3 changed files with 88 additions and 4 deletions

View File

@ -70,10 +70,12 @@
When a `DrmSessionManager` is used by an app in a custom `MediaSource`, When a `DrmSessionManager` is used by an app in a custom `MediaSource`,
the `playbackLooper` needs to be passed to `DrmSessionManager.setPlayer` the `playbackLooper` needs to be passed to `DrmSessionManager.setPlayer`
instead. instead.
* IMA: * Ad playback / IMA:
* Add a method to `AdPlaybackState` to allow resetting an ad group so that * Add a method to `AdPlaybackState` to allow resetting an ad group so that
it can be played again it can be played again
([#9615](https://github.com/google/ExoPlayer/issues/9615)). ([#9615](https://github.com/google/ExoPlayer/issues/9615)).
* Enforce playback speed of 1.0 during ad playback
([#9018](https://github.com/google/ExoPlayer/issues/9018)).
* DASH: * DASH:
* Support the `forced-subtitle` track role * Support the `forced-subtitle` track role
([#9727](https://github.com/google/ExoPlayer/issues/9727)). ([#9727](https://github.com/google/ExoPlayer/issues/9727)).

View File

@ -1913,9 +1913,12 @@ import java.util.concurrent.atomic.AtomicBoolean;
MediaPeriodId oldPeriodId, MediaPeriodId oldPeriodId,
long positionForTargetOffsetOverrideUs) { long positionForTargetOffsetOverrideUs) {
if (!shouldUseLivePlaybackSpeedControl(newTimeline, newPeriodId)) { if (!shouldUseLivePlaybackSpeedControl(newTimeline, newPeriodId)) {
// Live playback speed control is unused for the current period, reset speed if adjusted. // Live playback speed control is unused for the current period, reset speed to user-defined
if (!mediaClock.getPlaybackParameters().equals(playbackInfo.playbackParameters)) { // playback parameters or 1.0 for ad playback.
mediaClock.setPlaybackParameters(playbackInfo.playbackParameters); PlaybackParameters targetPlaybackParameters =
newPeriodId.isAd() ? PlaybackParameters.DEFAULT : playbackInfo.playbackParameters;
if (!mediaClock.getPlaybackParameters().equals(targetPlaybackParameters)) {
mediaClock.setPlaybackParameters(targetPlaybackParameters);
} }
return; return;
} }

View File

@ -9324,6 +9324,85 @@ public final class ExoPlayerTest {
.onPlaybackParametersChanged(new PlaybackParameters(/* speed= */ 2, /* pitch= */ 2)); .onPlaybackParametersChanged(new PlaybackParameters(/* speed= */ 2, /* pitch= */ 2));
} }
@Test
public void setPlaybackSpeed_withAdPlayback_onlyAppliesToContent() throws Exception {
// Create renderer with media clock to listen to playback parameter changes.
ArrayList<PlaybackParameters> playbackParameters = new ArrayList<>();
FakeMediaClockRenderer audioRenderer =
new FakeMediaClockRenderer(C.TRACK_TYPE_AUDIO) {
private long positionUs;
@Override
protected void onStreamChanged(Format[] formats, long startPositionUs, long offsetUs) {
this.positionUs = offsetUs;
}
@Override
public long getPositionUs() {
// Continuously increase position to let playback progress.
positionUs += 10_000;
return positionUs;
}
@Override
public void setPlaybackParameters(PlaybackParameters parameters) {
playbackParameters.add(parameters);
}
@Override
public PlaybackParameters getPlaybackParameters() {
return playbackParameters.isEmpty()
? PlaybackParameters.DEFAULT
: Iterables.getLast(playbackParameters);
}
};
ExoPlayer player = new TestExoPlayerBuilder(context).setRenderers(audioRenderer).build();
AdPlaybackState adPlaybackState =
FakeTimeline.createAdPlaybackState(
/* adsPerAdGroup= */ 1,
/* adGroupTimesUs...= */ 0,
7 * C.MICROS_PER_SECOND,
C.TIME_END_OF_SOURCE);
TimelineWindowDefinition adTimelineDefinition =
new TimelineWindowDefinition(
/* periodCount= */ 1,
/* id= */ 0,
/* isSeekable= */ true,
/* isDynamic= */ false,
/* isLive= */ false,
/* isPlaceholder= */ false,
/* durationUs= */ 10 * C.MICROS_PER_SECOND,
/* defaultPositionUs= */ 0,
/* windowOffsetInFirstPeriodUs= */ 0,
adPlaybackState);
player.setMediaSource(
new FakeMediaSource(
new FakeTimeline(adTimelineDefinition), ExoPlayerTestRunner.AUDIO_FORMAT));
Player.Listener mockListener = mock(Player.Listener.class);
player.addListener(mockListener);
player.setPlaybackSpeed(5f);
player.prepare();
player.play();
runUntilPlaybackState(player, Player.STATE_ENDED);
player.release();
// Assert that the renderer received the playback speed updates at each ad/content boundary.
assertThat(playbackParameters)
.containsExactly(
/* preroll ad */ new PlaybackParameters(1f),
/* content after preroll */ new PlaybackParameters(5f),
/* midroll ad */ new PlaybackParameters(1f),
/* content after midroll */ new PlaybackParameters(5f),
/* postroll ad */ new PlaybackParameters(1f),
/* content after postroll */ new PlaybackParameters(5f))
.inOrder();
// Assert that user-set speed was reported, but none of the ad overrides.
verify(mockListener).onPlaybackParametersChanged(any());
verify(mockListener).onPlaybackParametersChanged(new PlaybackParameters(5.0f));
}
@Test @Test
public void targetLiveOffsetInMedia_withSetPlaybackParameters_usesPlaybackParameterSpeed() public void targetLiveOffsetInMedia_withSetPlaybackParameters_usesPlaybackParameterSpeed()
throws Exception { throws Exception {