use of androidx.media3.common.AdPlaybackState in project media by androidx.
the class AdsMediaSource method createPeriod.
@Override
public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator, long startPositionUs) {
AdPlaybackState adPlaybackState = checkNotNull(this.adPlaybackState);
if (adPlaybackState.adGroupCount > 0 && id.isAd()) {
int adGroupIndex = id.adGroupIndex;
int adIndexInAdGroup = id.adIndexInAdGroup;
if (adMediaSourceHolders[adGroupIndex].length <= adIndexInAdGroup) {
int adCount = adIndexInAdGroup + 1;
adMediaSourceHolders[adGroupIndex] = Arrays.copyOf(adMediaSourceHolders[adGroupIndex], adCount);
}
@Nullable AdMediaSourceHolder adMediaSourceHolder = adMediaSourceHolders[adGroupIndex][adIndexInAdGroup];
if (adMediaSourceHolder == null) {
adMediaSourceHolder = new AdMediaSourceHolder(id);
adMediaSourceHolders[adGroupIndex][adIndexInAdGroup] = adMediaSourceHolder;
maybeUpdateAdMediaSources();
}
return adMediaSourceHolder.createMediaPeriod(id, allocator, startPositionUs);
} else {
MaskingMediaPeriod mediaPeriod = new MaskingMediaPeriod(id, allocator, startPositionUs);
mediaPeriod.setMediaSource(contentMediaSource);
mediaPeriod.createPeriod(id);
return mediaPeriod;
}
}
use of androidx.media3.common.AdPlaybackState in project media by androidx.
the class AdsMediaSource method maybeUpdateAdMediaSources.
/**
* Initializes any {@link AdMediaSourceHolder AdMediaSourceHolders} where the ad media URI is
* newly known.
*/
private void maybeUpdateAdMediaSources() {
@Nullable AdPlaybackState adPlaybackState = this.adPlaybackState;
if (adPlaybackState == null) {
return;
}
for (int adGroupIndex = 0; adGroupIndex < adMediaSourceHolders.length; adGroupIndex++) {
for (int adIndexInAdGroup = 0; adIndexInAdGroup < this.adMediaSourceHolders[adGroupIndex].length; adIndexInAdGroup++) {
@Nullable AdMediaSourceHolder adMediaSourceHolder = this.adMediaSourceHolders[adGroupIndex][adIndexInAdGroup];
AdPlaybackState.AdGroup adGroup = adPlaybackState.getAdGroup(adGroupIndex);
if (adMediaSourceHolder != null && !adMediaSourceHolder.hasMediaSource() && adIndexInAdGroup < adGroup.uris.length) {
@Nullable Uri adUri = adGroup.uris[adIndexInAdGroup];
if (adUri != null) {
MediaItem.Builder adMediaItem = new MediaItem.Builder().setUri(adUri);
// Propagate the content's DRM config into the ad media source.
@Nullable MediaItem.LocalConfiguration contentLocalConfiguration = contentMediaSource.getMediaItem().localConfiguration;
if (contentLocalConfiguration != null) {
adMediaItem.setDrmConfiguration(contentLocalConfiguration.drmConfiguration);
}
MediaSource adMediaSource = adMediaSourceFactory.createMediaSource(adMediaItem.build());
adMediaSourceHolder.initializeWithMediaSource(adMediaSource, adUri);
}
}
}
}
}
use of androidx.media3.common.AdPlaybackState in project media by androidx.
the class ServerSideAdInsertionMediaSource method setAdPlaybackStates.
/**
* Sets the map of {@link AdPlaybackState ad playback states} published by this source. The key is
* the period UID of a period in the {@link
* AdPlaybackStateUpdater#onAdPlaybackStateUpdateRequested(Timeline)} content timeline}.
*
* <p>Each period has an {@link AdPlaybackState} that tells where in the period the ad groups
* start and end. Must only contain server-side inserted ad groups. The number of ad groups and
* the number of ads within an ad group may only increase. The durations of ads may change and the
* positions of future ad groups may change. Post-roll ad groups with {@link C#TIME_END_OF_SOURCE}
* must be empty and can be used as a placeholder for a future ad group.
*
* <p>May be called from any thread.
*
* @param adPlaybackStates The map of {@link AdPlaybackState} keyed by their period UID.
*/
public void setAdPlaybackStates(ImmutableMap<Object, AdPlaybackState> adPlaybackStates) {
checkArgument(!adPlaybackStates.isEmpty());
Object adsId = checkNotNull(adPlaybackStates.values().asList().get(0).adsId);
for (Map.Entry<Object, AdPlaybackState> entry : adPlaybackStates.entrySet()) {
Object periodUid = entry.getKey();
AdPlaybackState adPlaybackState = entry.getValue();
checkArgument(Util.areEqual(adsId, adPlaybackState.adsId));
@Nullable AdPlaybackState oldAdPlaybackState = this.adPlaybackStates.get(periodUid);
if (oldAdPlaybackState != null) {
for (int i = adPlaybackState.removedAdGroupCount; i < adPlaybackState.adGroupCount; i++) {
AdPlaybackState.AdGroup adGroup = adPlaybackState.getAdGroup(i);
checkArgument(adGroup.isServerSideInserted);
if (i < oldAdPlaybackState.adGroupCount) {
checkArgument(getAdCountInGroup(adPlaybackState, /* adGroupIndex= */
i) >= getAdCountInGroup(oldAdPlaybackState, /* adGroupIndex= */
i));
}
if (adGroup.timeUs == C.TIME_END_OF_SOURCE) {
checkArgument(getAdCountInGroup(adPlaybackState, /* adGroupIndex= */
i) == 0);
}
}
}
}
synchronized (this) {
if (playbackHandler == null) {
this.adPlaybackStates = adPlaybackStates;
} else {
playbackHandler.post(() -> {
for (SharedMediaPeriod mediaPeriod : mediaPeriods.values()) {
@Nullable AdPlaybackState adPlaybackState = adPlaybackStates.get(mediaPeriod.periodUid);
if (adPlaybackState != null) {
mediaPeriod.updateAdPlaybackState(adPlaybackState);
}
}
if (lastUsedMediaPeriod != null) {
@Nullable AdPlaybackState adPlaybackState = adPlaybackStates.get(lastUsedMediaPeriod.periodUid);
if (adPlaybackState != null) {
lastUsedMediaPeriod.updateAdPlaybackState(adPlaybackState);
}
}
this.adPlaybackStates = adPlaybackStates;
if (contentTimeline != null) {
refreshSourceInfo(new ServerSideAdInsertionTimeline(contentTimeline, adPlaybackStates));
}
});
}
}
}
use of androidx.media3.common.AdPlaybackState in project media by androidx.
the class ExoPlayerTest method newServerSideInsertedAdAtPlaybackPosition_keepsRenderersEnabled.
@Test
public void newServerSideInsertedAdAtPlaybackPosition_keepsRenderersEnabled() throws Exception {
// Injecting renderer to count number of renderer resets.
AtomicReference<FakeVideoRenderer> videoRenderer = new AtomicReference<>();
ExoPlayer player = new TestExoPlayerBuilder(context).setRenderersFactory((handler, videoListener, audioListener, textOutput, metadataOutput) -> {
videoRenderer.set(new FakeVideoRenderer(handler, videoListener));
return new Renderer[] { videoRenderer.get() };
}).build();
// Live stream timeline with unassigned next ad group.
AdPlaybackState initialAdPlaybackState = new AdPlaybackState(/* adsId= */
new Object(), /* adGroupTimesUs...= */
C.TIME_END_OF_SOURCE).withIsServerSideInserted(/* adGroupIndex= */
0, /* isServerSideInserted= */
true).withAdCount(/* adGroupIndex= */
0, /* adCount= */
1).withAdDurationsUs(new long[][] { new long[] { 10 * C.MICROS_PER_SECOND } });
// Updated timeline with ad group at 18 seconds.
long firstSampleTimeUs = TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US;
Timeline initialTimeline = new FakeTimeline(new TimelineWindowDefinition(/* periodCount= */
1, /* id= */
0, /* isSeekable= */
true, /* isDynamic= */
true, /* durationUs= */
C.TIME_UNSET, initialAdPlaybackState));
AdPlaybackState updatedAdPlaybackState = initialAdPlaybackState.withAdGroupTimeUs(/* adGroupIndex= */
0, /* adGroupTimeUs= */
firstSampleTimeUs + 18 * C.MICROS_PER_SECOND);
Timeline updatedTimeline = new FakeTimeline(new TimelineWindowDefinition(/* periodCount= */
1, /* id= */
0, /* isSeekable= */
true, /* isDynamic= */
true, /* durationUs= */
C.TIME_UNSET, updatedAdPlaybackState));
// Add samples to allow player to load and start playing (but no EOS as this is a live stream).
FakeMediaSource mediaSource = new FakeMediaSource(initialTimeline, DrmSessionManager.DRM_UNSUPPORTED, (format, mediaPeriodId) -> ImmutableList.of(oneByteSample(firstSampleTimeUs, C.BUFFER_FLAG_KEY_FRAME), oneByteSample(firstSampleTimeUs + 40 * C.MICROS_PER_SECOND)), ExoPlayerTestRunner.VIDEO_FORMAT);
// Set updated ad group once we reach 20 seconds, and then continue playing until 40 seconds.
player.createMessage((message, payload) -> mediaSource.setNewSourceInfo(updatedTimeline)).setPosition(20_000).send();
player.setMediaSource(mediaSource);
player.prepare();
playUntilPosition(player, /* mediaItemIndex= */
0, /* positionMs= */
40_000);
player.release();
// Assert that the renderer hasn't been reset despite the inserted ad group.
assertThat(videoRenderer.get().positionResetCount).isEqualTo(1);
}
use of androidx.media3.common.AdPlaybackState in project media by androidx.
the class MediaPeriodQueueTest method updateTimeline.
private void updateTimeline() {
SinglePeriodAdTimeline adTimeline = new SinglePeriodAdTimeline(CONTENT_TIMELINE, adPlaybackState);
fakeMediaSource.setNewSourceInfo(adTimeline);
// Progress the looper so that the source info events have been executed.
shadowOf(Looper.getMainLooper()).idle();
playbackInfo = playbackInfo.copyWithTimeline(mediaSourceList.createTimeline());
}
Aggregations