Handle buffers in DefaultAudioSink with AudioProcessingPipeline.

PiperOrigin-RevId: 488412695
This commit is contained in:
samrobinson 2022-11-14 18:53:40 +00:00 committed by microkatz
parent 095c52e7ba
commit 52f3ee81d4
43 changed files with 1058 additions and 404 deletions

View File

@ -680,7 +680,7 @@ public final class ImaServerSideAdInsertionMediaSource extends CompositeMediaSou
adPlaybackState,
/* fromPositionUs= */ fromPositionUs,
/* contentResumeOffsetUs= */ 0,
/* adDurationsUs...= */ getAdDuration(
/* adDurationsUs= */ getAdDuration(
/* startTimeSeconds= */ cuePoint.getStartTime(),
/* endTimeSeconds= */ cuePoint.getEndTime()));
}

View File

@ -443,7 +443,7 @@ import java.util.Set;
private static AdPlaybackState splitAdGroupForPeriod(
Object adsId, AdGroup adGroup, long periodStartUs, long periodDurationUs) {
AdPlaybackState adPlaybackState =
new AdPlaybackState(checkNotNull(adsId), /* adGroupTimesUs...= */ 0)
new AdPlaybackState(checkNotNull(adsId), /* adGroupTimesUs= */ 0)
.withAdCount(/* adGroupIndex= */ 0, /* adCount= */ 1)
.withAdDurationsUs(/* adGroupIndex= */ 0, periodDurationUs)
.withIsServerSideInserted(/* adGroupIndex= */ 0, true)
@ -605,7 +605,7 @@ import java.util.Set;
adPlaybackState,
/* fromPositionUs= */ currentContentPeriodPositionUs,
/* contentResumeOffsetUs= */ sum(adDurationsUs),
/* adDurationsUs...= */ adDurationsUs);
/* adDurationsUs= */ adDurationsUs);
adGroupIndex =
adPlaybackState.getAdGroupIndexForPositionUs(
mediaPeriodPositionUs, /* periodDurationUs= */ C.TIME_UNSET);

View File

@ -239,7 +239,7 @@ public final class ImaAdsLoaderTest {
assertThat(getAdPlaybackState(/* periodIndex= */ 0))
.isEqualTo(
new AdPlaybackState(TEST_ADS_ID, /* adGroupTimesUs...= */ 0)
new AdPlaybackState(TEST_ADS_ID, /* adGroupTimesUs= */ 0)
.withContentDurationUs(CONTENT_PERIOD_DURATION_US));
}
@ -312,7 +312,7 @@ public final class ImaAdsLoaderTest {
// Verify that the preroll ad has been marked as played.
assertThat(getAdPlaybackState(/* periodIndex= */ 0))
.isEqualTo(
new AdPlaybackState(TEST_ADS_ID, /* adGroupTimesUs...= */ 0)
new AdPlaybackState(TEST_ADS_ID, /* adGroupTimesUs= */ 0)
.withContentDurationUs(CONTENT_PERIOD_DURATION_US)
.withAdCount(/* adGroupIndex= */ 0, /* adCount= */ 1)
.withAvailableAdUri(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0, TEST_URI)
@ -336,7 +336,7 @@ public final class ImaAdsLoaderTest {
assertThat(getAdPlaybackState(/* periodIndex= */ 0))
.isEqualTo(
new AdPlaybackState(TEST_ADS_ID, /* adGroupTimesUs...= */ 20_500_000)
new AdPlaybackState(TEST_ADS_ID, /* adGroupTimesUs= */ 20_500_000)
.withContentDurationUs(CONTENT_PERIOD_DURATION_US)
.withAdDurationsUs(new long[][] {{TEST_AD_DURATION_US}})
.withAdCount(/* adGroupIndex= */ 0, /* adCount= */ 1)
@ -384,7 +384,7 @@ public final class ImaAdsLoaderTest {
assertThat(getAdPlaybackState(/* periodIndex= */ 0))
.isEqualTo(
new AdPlaybackState(TEST_ADS_ID, /* adGroupTimesUs...= */ C.TIME_END_OF_SOURCE)
new AdPlaybackState(TEST_ADS_ID, /* adGroupTimesUs= */ C.TIME_END_OF_SOURCE)
.withContentDurationUs(CONTENT_PERIOD_DURATION_US)
.withAdDurationsUs(new long[][] {{TEST_AD_DURATION_US}})
.withAdCount(/* adGroupIndex= */ 0, /* adCount= */ 1)
@ -1114,7 +1114,7 @@ public final class ImaAdsLoaderTest {
// Verify that the preroll ad has been marked as played.
assertThat(getAdPlaybackState(/* periodIndex= */ 0))
.isEqualTo(
new AdPlaybackState(TEST_ADS_ID, /* adGroupTimesUs...= */ 0)
new AdPlaybackState(TEST_ADS_ID, /* adGroupTimesUs= */ 0)
.withContentDurationUs(CONTENT_PERIOD_DURATION_US)
.withAdCount(/* adGroupIndex= */ 0, /* adCount= */ 1)
.withAvailableAdUri(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0, TEST_URI)
@ -1123,7 +1123,7 @@ public final class ImaAdsLoaderTest {
.withAdResumePositionUs(/* adResumePositionUs= */ 0));
// Verify that the second source's ad cue points have preloaded.
assertThat(getAdPlaybackState(/* periodIndex= */ 1))
.isEqualTo(new AdPlaybackState(secondAdsId, /* adGroupTimesUs...= */ 0));
.isEqualTo(new AdPlaybackState(secondAdsId, /* adGroupTimesUs= */ 0));
}
@Test
@ -1181,7 +1181,7 @@ public final class ImaAdsLoaderTest {
// Verify that the preroll ad has been marked as played.
assertThat(getAdPlaybackState(/* periodIndex= */ 0))
.isEqualTo(
new AdPlaybackState(TEST_ADS_ID, /* adGroupTimesUs...= */ 0)
new AdPlaybackState(TEST_ADS_ID, /* adGroupTimesUs= */ 0)
.withContentDurationUs(CONTENT_PERIOD_DURATION_US)
.withAdCount(/* adGroupIndex= */ 0, /* adCount= */ 1)
.withAvailableAdUri(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0, TEST_URI)
@ -1190,7 +1190,7 @@ public final class ImaAdsLoaderTest {
.withAdResumePositionUs(/* adResumePositionUs= */ 0));
// Verify that the second source's ad cue points have preloaded.
assertThat(getAdPlaybackState(/* periodIndex= */ 1))
.isEqualTo(new AdPlaybackState(secondAdsId, /* adGroupTimesUs...= */ 0));
.isEqualTo(new AdPlaybackState(secondAdsId, /* adGroupTimesUs= */ 0));
}
@Test

View File

@ -37,7 +37,7 @@ public class ImaServerSideAdInsertionMediaSourceTest {
new AdPlaybackState("adsId1"),
/* fromPositionUs= */ 0,
/* contentResumeOffsetUs= */ 10,
/* adDurationsUs...= */ 5_000_000,
/* adDurationsUs= */ 5_000_000,
10_000_000,
20_000_000);
AdPlaybackState secondAdPlaybackState =
@ -45,20 +45,20 @@ public class ImaServerSideAdInsertionMediaSourceTest {
new AdPlaybackState("adsId2"),
/* fromPositionUs= */ 0,
/* contentResumeOffsetUs= */ 10,
/* adDurationsUs...= */ 10_000_000)
/* adDurationsUs= */ 10_000_000)
.withPlayedAd(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0);
AdPlaybackState thirdAdPlaybackState =
ServerSideAdInsertionUtil.addAdGroupToAdPlaybackState(
new AdPlaybackState("adsId3"),
/* fromPositionUs= */ C.TIME_END_OF_SOURCE,
/* contentResumeOffsetUs= */ 10,
/* adDurationsUs...= */ 10_000_000);
/* adDurationsUs= */ 10_000_000);
thirdAdPlaybackState =
ServerSideAdInsertionUtil.addAdGroupToAdPlaybackState(
thirdAdPlaybackState,
/* fromPositionUs= */ 0,
/* contentResumeOffsetUs= */ 10,
/* adDurationsUs...= */ 10_000_000)
/* adDurationsUs= */ 10_000_000)
.withRemovedAdGroupCount(1);
State state =
new State(

View File

@ -435,7 +435,7 @@ public class ImaUtilTest {
new AdPlaybackState(/* adsId= */ "adsId", 0)
.withAdCount(/* adGroupIndex= */ 0, periodCount)
.withAdDurationsUs(
/* adGroupIndex= */ 0, /* adDurationsUs...= */
/* adGroupIndex= */ 0, /* adDurationsUs= */
DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US + periodDurationUs,
periodDurationUs,
periodDurationUs,
@ -475,12 +475,10 @@ public class ImaUtilTest {
.withAdCount(/* adGroupIndex= */ 1, 1)
.withAdCount(/* adGroupIndex= */ 2, 1)
.withAdDurationsUs(
/* adGroupIndex= */ 0, /* adDurationsUs...= */
/* adGroupIndex= */ 0, /* adDurationsUs= */
DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US + (2 * periodDurationUs))
.withAdDurationsUs(
/* adGroupIndex= */ 1, /* adDurationsUs...= */ (2 * periodDurationUs))
.withAdDurationsUs(
/* adGroupIndex= */ 2, /* adDurationsUs...= */ (2 * periodDurationUs))
.withAdDurationsUs(/* adGroupIndex= */ 1, /* adDurationsUs= */ (2 * periodDurationUs))
.withAdDurationsUs(/* adGroupIndex= */ 2, /* adDurationsUs= */ (2 * periodDurationUs))
.withPlayedAd(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0)
.withPlayedAd(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 0)
.withIsServerSideInserted(/* adGroupIndex= */ 0, true)
@ -522,7 +520,7 @@ public class ImaUtilTest {
// around removed.
DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US + periodDurationUs + 2)
.withAdCount(/* adGroupIndex= */ 0, 1)
.withAdDurationsUs(/* adGroupIndex= */ 0, /* adDurationsUs...= */ periodDurationUs)
.withAdDurationsUs(/* adGroupIndex= */ 0, /* adDurationsUs= */ periodDurationUs)
.withIsServerSideInserted(/* adGroupIndex= */ 0, true);
FakeTimeline timeline =
new FakeTimeline(
@ -545,7 +543,7 @@ public class ImaUtilTest {
AdPlaybackState adPlaybackState =
new AdPlaybackState(/* adsId= */ "adsId", periodDurationUs - 1)
.withAdCount(/* adGroupIndex= */ 0, 1)
.withAdDurationsUs(/* adGroupIndex= */ 0, /* adDurationsUs...= */ periodDurationUs)
.withAdDurationsUs(/* adGroupIndex= */ 0, /* adDurationsUs= */ periodDurationUs)
.withIsServerSideInserted(/* adGroupIndex= */ 0, true);
FakeTimeline timeline =
new FakeTimeline(
@ -569,7 +567,7 @@ public class ImaUtilTest {
AdPlaybackState.NONE,
/* fromPositionUs= */ 0,
/* contentResumeOffsetUs= */ 0,
/* adDurationsUs...= */ 30_000_000);
/* adDurationsUs= */ 30_000_000);
adPlaybackState =
ImaUtil.expandAdGroupPlaceholder(
@ -594,7 +592,7 @@ public class ImaUtilTest {
AdPlaybackState.NONE,
/* fromPositionUs= */ 0,
/* contentResumeOffsetUs= */ 0,
/* adDurationsUs...= */ 30_000_000);
/* adDurationsUs= */ 30_000_000);
adPlaybackState =
ImaUtil.expandAdGroupPlaceholder(
@ -619,7 +617,7 @@ public class ImaUtilTest {
AdPlaybackState.NONE,
/* fromPositionUs= */ 0,
/* contentResumeOffsetUs= */ 0,
/* adDurationsUs...= */ 30_000_000);
/* adDurationsUs= */ 30_000_000);
adPlaybackState =
ImaUtil.expandAdGroupPlaceholder(
@ -644,7 +642,7 @@ public class ImaUtilTest {
AdPlaybackState.NONE,
/* fromPositionUs= */ 0,
/* contentResumeOffsetUs= */ 0,
/* adDurationsUs...= */ 30_000_000);
/* adDurationsUs= */ 30_000_000);
adPlaybackState =
ImaUtil.expandAdGroupPlaceholder(
@ -667,7 +665,7 @@ public class ImaUtilTest {
AdPlaybackState.NONE,
/* fromPositionUs= */ 0,
/* contentResumeOffsetUs= */ 0,
/* adDurationsUs...= */ 10_000_001);
/* adDurationsUs= */ 10_000_001);
adPlaybackState =
ImaUtil.expandAdGroupPlaceholder(
@ -690,7 +688,7 @@ public class ImaUtilTest {
AdPlaybackState.NONE,
/* fromPositionUs= */ 0,
/* contentResumeOffsetUs= */ 0,
/* adDurationsUs...= */ 30_000_000);
/* adDurationsUs= */ 30_000_000);
adPlaybackState =
ImaUtil.expandAdGroupPlaceholder(
@ -714,7 +712,7 @@ public class ImaUtilTest {
AdPlaybackState.NONE,
/* fromPositionUs= */ 0,
/* contentResumeOffsetUs= */ 0,
/* adDurationsUs...= */ 10_000_000,
/* adDurationsUs= */ 10_000_000,
20_000_000,
0);
@ -739,7 +737,7 @@ public class ImaUtilTest {
AdPlaybackState.NONE,
/* fromPositionUs= */ 0,
/* contentResumeOffsetUs= */ 0,
/* adDurationsUs...= */ 0,
/* adDurationsUs= */ 0,
10_000_000,
20_000_000);
@ -764,7 +762,7 @@ public class ImaUtilTest {
AdPlaybackState.NONE,
/* fromPositionUs= */ 0,
/* contentResumeOffsetUs= */ 0,
/* adDurationsUs...= */ 5_000_000,
/* adDurationsUs= */ 5_000_000,
10_000_000,
20_000_000);

View File

@ -264,7 +264,7 @@ public final class LeanbackPlayerAdapter extends PlayerAdapter implements Runnab
// int arguments (int what, int extra). Since PlaybackException defines a single error
// code, we pass 0 as the extra.
context.getString(
R.string.lb_media_player_error, /* formatArgs...= */ error.errorCode, 0));
R.string.lb_media_player_error, /* formatArgs= */ error.errorCode, 0));
}
}

View File

@ -0,0 +1,331 @@
/*
* Copyright 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.exoplayer2.audio;
import static com.google.android.exoplayer2.audio.AudioProcessor.EMPTY_BUFFER;
import static com.google.android.exoplayer2.util.Assertions.checkState;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.audio.AudioProcessor.AudioFormat;
import com.google.common.collect.ImmutableList;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
/**
* Handles passing buffers through multiple {@link AudioProcessor} instances.
*
* <p>Two instances of {@link AudioProcessingPipeline} are considered {@linkplain #equals(Object)
* equal} if they have the same underlying {@link AudioProcessor} references, in the same order.
*
* <p>To make use of this class, the caller must:
*
* <ul>
* <li>Initialize an instance, passing in all audio processors that may be used for processing.
* <li>Call {@link #configure(AudioFormat)} with the {@link AudioFormat} of the input data. This
* method will give back the {@link AudioFormat} that will be output from the pipeline when
* this configuration is in use.
* <li>Call {@link #flush()} to apply the pending configuration.
* <li>Check if the pipeline {@link #isOperational()}. If not, then the pipeline can not be used
* to process buffers in the current configuration. This is because none of the underlying
* {@link AudioProcessor} instances are {@linkplain AudioProcessor#isActive active}.
* <li>If the pipeline {@link #isOperational()}, {@link #queueInput(ByteBuffer)} then {@link
* #getOutput()} to process buffers.
* <li>{@link #queueEndOfStream()} to inform the pipeline the current input stream is at an end.
* <li>Repeatedly call {@link #getOutput()} and handle those buffers until {@link #isEnded()}
* returns true.
* <li>When finished with the pipeline, call {@link #reset()} to release underlying resources.
* </ul>
*
* <p>If underlying {@link AudioProcessor} instances have pending configuration changes, or the
* {@link AudioFormat} of the input is changing:
*
* <ul>
* <li>Call {@link #configure(AudioFormat)} to configure the pipeline for the new input stream.
* You can still {@link #queueInput(ByteBuffer)} and {@link #getOutput()} in the old setup at
* this time.
* <li>{@link #queueEndOfStream()} to inform the pipeline the current input stream is at an end.
* <li>Repeatedly call {@link #getOutput()} until {@link #isEnded()} returns true.
* <li>Call {@link #flush()} to apply the new configuration and flush the pipeline.
* <li>Begin {@linkplain #queueInput(ByteBuffer) queuing input} and handling the {@linkplain
* #getOutput() output} in the new configuration.
* </ul>
*/
public final class AudioProcessingPipeline {
/** The {@link AudioProcessor} instances passed to {@link AudioProcessingPipeline}. */
private final ImmutableList<AudioProcessor> audioProcessors;
/**
* The processors that are {@linkplain AudioProcessor#isActive() active} based on the current
* configuration.
*/
private final List<AudioProcessor> activeAudioProcessors;
/**
* The buffers output by the {@link #activeAudioProcessors}. This has the same number of elements
* as {@link #activeAudioProcessors}.
*/
private ByteBuffer[] outputBuffers;
/** The {@link AudioFormat} currently being output by the pipeline. */
private AudioFormat outputAudioFormat;
/** The {@link AudioFormat} that will be output following a {@link #flush()}. */
private AudioFormat pendingOutputAudioFormat;
/** Whether input has ended, either due to configuration change or end of stream. */
private boolean inputEnded;
/**
* Creates an instance.
*
* @param audioProcessors The {@link AudioProcessor} instances to be used for processing buffers.
*/
public AudioProcessingPipeline(ImmutableList<AudioProcessor> audioProcessors) {
this.audioProcessors = audioProcessors;
activeAudioProcessors = new ArrayList<>();
outputBuffers = new ByteBuffer[0];
outputAudioFormat = AudioFormat.NOT_SET;
pendingOutputAudioFormat = AudioFormat.NOT_SET;
inputEnded = false;
}
/**
* Configures the pipeline to process input audio with the specified format. Returns the
* configured output audio format.
*
* <p>To apply the new configuration for use, the pipeline must be {@linkplain #flush() flushed}.
* Before applying the new configuration, it is safe to queue input and get output in the old
* input/output formats/configuration. Call {@link #queueEndOfStream()} when no more input will be
* supplied for processing in the old configuration.
*
* @param inputAudioFormat The format of audio that will be queued after the next call to {@link
* #flush()}.
* @return The configured output audio format.
* @throws AudioProcessor.UnhandledAudioFormatException If the specified format is not supported
* by the pipeline.
*/
@CanIgnoreReturnValue
public AudioFormat configure(AudioFormat inputAudioFormat)
throws AudioProcessor.UnhandledAudioFormatException {
if (inputAudioFormat.equals(AudioFormat.NOT_SET)) {
throw new AudioProcessor.UnhandledAudioFormatException(inputAudioFormat);
}
AudioFormat intermediateAudioFormat = inputAudioFormat;
for (int i = 0; i < audioProcessors.size(); i++) {
AudioProcessor audioProcessor = audioProcessors.get(i);
AudioFormat nextFormat = audioProcessor.configure(intermediateAudioFormat);
if (audioProcessor.isActive()) {
checkState(!nextFormat.equals(AudioFormat.NOT_SET));
intermediateAudioFormat = nextFormat;
}
}
return pendingOutputAudioFormat = intermediateAudioFormat;
}
/**
* Clears any buffered data and pending output. If any underlying audio processors are {@linkplain
* AudioProcessor#isActive() active}, this also prepares them to receive a new stream of input in
* the last {@linkplain #configure(AudioFormat) configured} (pending) format.
*
* <p>{@link #configure(AudioFormat)} must have been called at least once since the last call to
* {@link #reset()} before calling this.
*/
public void flush() {
activeAudioProcessors.clear();
outputAudioFormat = pendingOutputAudioFormat;
inputEnded = false;
for (int i = 0; i < audioProcessors.size(); i++) {
AudioProcessor audioProcessor = audioProcessors.get(i);
audioProcessor.flush();
if (audioProcessor.isActive()) {
activeAudioProcessors.add(audioProcessor);
}
}
outputBuffers = new ByteBuffer[activeAudioProcessors.size()];
for (int i = 0; i <= getFinalOutputBufferIndex(); i++) {
outputBuffers[i] = activeAudioProcessors.get(i).getOutput();
}
}
/** Returns the {@link AudioFormat} currently being output. */
public AudioFormat getOutputAudioFormat() {
return outputAudioFormat;
}
/**
* Whether the pipeline can be used for processing buffers.
*
* <p>For this to happen the pipeline must be {@linkplain #configure(AudioFormat) configured},
* {@linkplain #flush() flushed} and have {@linkplain AudioProcessor#isActive() active}
* {@linkplain AudioProcessor underlying audio processors} that are ready to process buffers with
* the current configuration.
*/
public boolean isOperational() {
return !activeAudioProcessors.isEmpty();
}
/**
* Queues audio data between the position and limit of the {@code inputBuffer} for processing.
* After calling this method, processed output may be available via {@link #getOutput()}.
*
* @param inputBuffer The input buffer to process. It must be a direct {@link ByteBuffer} with
* native byte order. Its contents are treated as read-only. Its position will be advanced by
* the number of bytes consumed (which may be zero). The caller retains ownership of the
* provided buffer.
*/
public void queueInput(ByteBuffer inputBuffer) {
if (!isOperational() || inputEnded) {
return;
}
processData(inputBuffer);
}
/**
* Returns a {@link ByteBuffer} containing processed output data between its position and limit.
* The buffer will be empty if no output is available.
*
* <p>Buffers returned from this method are retained by pipeline, and it is necessary to consume
* the data (or copy it into another buffer) to allow the pipeline to progress.
*
* @return A buffer containing processed output data between its position and limit.
*/
public ByteBuffer getOutput() {
if (!isOperational()) {
return EMPTY_BUFFER;
}
processData(EMPTY_BUFFER);
return outputBuffers[getFinalOutputBufferIndex()];
}
/**
* Queues an end of stream signal. After this method has been called, {@link
* #queueInput(ByteBuffer)} should not be called until after the next call to {@link #flush()}.
* Calling {@link #getOutput()} will return any remaining output data. Multiple calls may be
* required to read all of the remaining output data. {@link #isEnded()} will return {@code true}
* once all remaining output data has been read.
*/
public void queueEndOfStream() {
if (!isOperational() || inputEnded) {
return;
}
inputEnded = true;
activeAudioProcessors.get(0).queueEndOfStream();
}
/**
* Returns whether the pipeline has ended.
*
* <p>The pipeline is considered ended when:
*
* <ul>
* <li>End of stream has been {@linkplain #queueEndOfStream() queued}.
* <li>Every {@linkplain #queueInput(ByteBuffer) input buffer} has been processed.
* <li>Every {@linkplain #getOutput() output buffer} has been fully consumed.
* </ul>
*/
public boolean isEnded() {
return inputEnded
&& activeAudioProcessors.get(getFinalOutputBufferIndex()).isEnded()
&& !outputBuffers[getFinalOutputBufferIndex()].hasRemaining();
}
/**
* Resets the pipeline and its underlying {@link AudioProcessor} instances to their unconfigured
* state, releasing any resources.
*/
public void reset() {
for (int i = 0; i < audioProcessors.size(); i++) {
AudioProcessor audioProcessor = audioProcessors.get(i);
audioProcessor.flush();
audioProcessor.reset();
}
outputBuffers = new ByteBuffer[0];
outputAudioFormat = AudioFormat.NOT_SET;
pendingOutputAudioFormat = AudioFormat.NOT_SET;
inputEnded = false;
}
/**
* Indicates whether some other object is "equal to" this one.
*
* <p>Two instances of {@link AudioProcessingPipeline} are considered equal if they have the same
* underlying {@link AudioProcessor} references in the same order.
*/
@Override
public boolean equals(@Nullable Object o) {
if (this == o) {
return true;
}
if (!(o instanceof AudioProcessingPipeline)) {
return false;
}
AudioProcessingPipeline that = (AudioProcessingPipeline) o;
if (this.audioProcessors.size() != that.audioProcessors.size()) {
return false;
}
for (int i = 0; i < this.audioProcessors.size(); i++) {
if (this.audioProcessors.get(i) != that.audioProcessors.get(i)) {
return false;
}
}
return true;
}
@Override
public int hashCode() {
return audioProcessors.hashCode();
}
private void processData(ByteBuffer inputBuffer) {
boolean progressMade = true;
while (progressMade) {
progressMade = false;
for (int index = 0; index <= getFinalOutputBufferIndex(); index++) {
if (outputBuffers[index].hasRemaining()) {
// Processor at this index has output that has not been consumed. Do not queue input.
continue;
}
AudioProcessor audioProcessor = activeAudioProcessors.get(index);
if (audioProcessor.isEnded()) {
if (!outputBuffers[index].hasRemaining() && index < getFinalOutputBufferIndex()) {
activeAudioProcessors.get(index + 1).queueEndOfStream();
}
continue;
}
ByteBuffer input =
index > 0
? outputBuffers[index - 1]
: inputBuffer.hasRemaining() ? inputBuffer : EMPTY_BUFFER;
long inputBytes = input.remaining();
audioProcessor.queueInput(input);
outputBuffers[index] = audioProcessor.getOutput();
progressMade |= (inputBytes - input.remaining()) > 0 || outputBuffers[index].hasRemaining();
}
}
}
private int getFinalOutputBufferIndex() {
return outputBuffers.length - 1;
}
}

View File

@ -35,6 +35,13 @@ public interface AudioProcessor {
/** PCM audio format that may be handled by an audio processor. */
final class AudioFormat {
/**
* An {@link AudioFormat} instance to represent an unset {@link AudioFormat}. This should not be
* returned by {@link #configure(AudioFormat)} if the processor {@link #isActive()}.
*
* <p>Typically used to represent an inactive {@link AudioProcessor} {@linkplain
* #configure(AudioFormat) output format}.
*/
public static final AudioFormat NOT_SET =
new AudioFormat(
/* sampleRate= */ Format.NO_VALUE,

View File

@ -0,0 +1,368 @@
/*
* Copyright 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.exoplayer2.audio;
import static com.google.common.truth.Truth.assertThat;
import static java.lang.Math.min;
import androidx.annotation.Nullable;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.audio.AudioProcessor.AudioFormat;
import com.google.common.collect.ImmutableList;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.List;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
import org.junit.Test;
import org.junit.runner.RunWith;
// TODO(b/198772621): Add tests for PlaybackParameter changes once Sonic or
// DefaultAudioProcessorChain is in common.
/** Unit tests for {@link AudioProcessingPipeline}. */
@RunWith(AndroidJUnit4.class)
public final class AudioProcessingPipelineTest {
private static final AudioFormat AUDIO_FORMAT =
new AudioFormat(/* sampleRate= */ 44100, /* channelCount= */ 2, C.ENCODING_PCM_16BIT);
@Test
public void noAudioProcessors_isNotOperational() throws Exception {
AudioProcessingPipeline audioProcessingPipeline =
new AudioProcessingPipeline(ImmutableList.of());
audioProcessingPipeline.configure(AUDIO_FORMAT);
audioProcessingPipeline.flush();
assertThat(audioProcessingPipeline.isOperational()).isFalse();
}
@Test
public void sameProcessors_pipelinesAreOnlyEqualIfSameOrderAndReference() throws Exception {
AudioProcessor audioProcessorOne = new FakeAudioProcessor(/* active= */ true);
AudioProcessor audioProcessorTwo = new FakeAudioProcessor(/* active= */ false);
AudioProcessor audioProcessorThree = new FakeAudioProcessor(/* active= */ true);
AudioProcessingPipeline pipelineOne =
new AudioProcessingPipeline(
ImmutableList.of(audioProcessorOne, audioProcessorTwo, audioProcessorThree));
// The internal state of the pipeline does not affect equality.
pipelineOne.configure(AUDIO_FORMAT);
pipelineOne.flush();
AudioProcessingPipeline pipelineTwo =
new AudioProcessingPipeline(
ImmutableList.of(audioProcessorOne, audioProcessorTwo, audioProcessorThree));
assertThat(pipelineOne).isEqualTo(pipelineTwo);
AudioProcessingPipeline pipelineThree =
new AudioProcessingPipeline(
ImmutableList.of(audioProcessorThree, audioProcessorTwo, audioProcessorOne));
assertThat(pipelineTwo).isNotEqualTo(pipelineThree);
}
@Test
public void configuringPipeline_givesFormat() throws Exception {
FakeAudioProcessor fakeSampleRateChangingAudioProcessor =
new FakeAudioProcessor(/* active= */ true) {
@Override
public AudioFormat configure(AudioFormat inputAudioFormat)
throws UnhandledAudioFormatException {
AudioFormat outputFormat =
new AudioFormat(
inputAudioFormat.sampleRate * 2,
inputAudioFormat.channelCount,
inputAudioFormat.encoding);
return super.configure(outputFormat);
}
};
AudioProcessingPipeline audioProcessingPipeline =
new AudioProcessingPipeline(ImmutableList.of(fakeSampleRateChangingAudioProcessor));
AudioFormat outputFormat = audioProcessingPipeline.configure(AUDIO_FORMAT);
assertThat(outputFormat.sampleRate).isEqualTo(AUDIO_FORMAT.sampleRate * 2);
}
@Test
public void configuringAndFlushingPipeline_isOperational() throws Exception {
FakeAudioProcessor fakeSampleRateChangingAudioProcessor =
new FakeAudioProcessor(/* active= */ true) {
@Override
public AudioFormat configure(AudioFormat inputAudioFormat)
throws UnhandledAudioFormatException {
AudioFormat outputFormat =
new AudioFormat(
inputAudioFormat.sampleRate * 2,
inputAudioFormat.channelCount,
inputAudioFormat.encoding);
return super.configure(outputFormat);
}
};
AudioProcessingPipeline audioProcessingPipeline =
new AudioProcessingPipeline(ImmutableList.of(fakeSampleRateChangingAudioProcessor));
assertThat(audioProcessingPipeline.isOperational()).isFalse();
audioProcessingPipeline.configure(AUDIO_FORMAT);
// Configuring the pipeline is not enough for it to be operational.
assertThat(audioProcessingPipeline.isOperational()).isFalse();
audioProcessingPipeline.flush();
assertThat(audioProcessingPipeline.isOperational()).isTrue();
}
@Test
public void reconfigure_doesNotChangeOperational_untilFlush() throws Exception {
FakeAudioProcessor audioProcessor = new FakeAudioProcessor(/* active= */ true);
AudioProcessingPipeline audioProcessingPipeline =
new AudioProcessingPipeline(ImmutableList.of(audioProcessor));
audioProcessingPipeline.configure(AUDIO_FORMAT);
audioProcessingPipeline.flush();
assertThat(audioProcessingPipeline.isOperational()).isTrue();
audioProcessor.setActive(false);
audioProcessingPipeline.configure(AUDIO_FORMAT);
assertThat(audioProcessingPipeline.isOperational()).isTrue();
audioProcessingPipeline.flush();
assertThat(audioProcessingPipeline.isOperational()).isFalse();
}
@Test
public void inactiveProcessor_isIgnoredInConfiguration() throws Exception {
FakeAudioProcessor fakeSampleRateChangingAudioProcessor =
new FakeAudioProcessor(/* active= */ false) {
@Override
public AudioFormat configure(AudioFormat inputAudioFormat)
throws UnhandledAudioFormatException {
AudioFormat outputFormat =
new AudioFormat(
inputAudioFormat.sampleRate * 2,
inputAudioFormat.channelCount,
inputAudioFormat.encoding);
return super.configure(outputFormat);
}
};
AudioProcessingPipeline audioProcessingPipeline =
new AudioProcessingPipeline(ImmutableList.of(fakeSampleRateChangingAudioProcessor));
AudioFormat outputFormat = audioProcessingPipeline.configure(AUDIO_FORMAT);
audioProcessingPipeline.flush();
assertThat(outputFormat).isEqualTo(AUDIO_FORMAT);
assertThat(audioProcessingPipeline.isOperational()).isFalse();
}
@Test
public void queueInput_producesOutputBuffer() throws Exception {
FakeAudioProcessor audioProcessor = new FakeAudioProcessor(/* active= */ true);
AudioProcessingPipeline audioProcessingPipeline =
new AudioProcessingPipeline(ImmutableList.of(audioProcessor));
audioProcessingPipeline.configure(AUDIO_FORMAT);
audioProcessingPipeline.flush();
ByteBuffer inputBuffer = createOneSecondDefaultSilenceBuffer(AUDIO_FORMAT);
long inputBytes = inputBuffer.remaining();
audioProcessingPipeline.queueInput(inputBuffer);
inputBytes -= inputBuffer.remaining();
ByteBuffer outputBuffer = audioProcessingPipeline.getOutput();
assertThat(inputBytes).isEqualTo(outputBuffer.remaining());
assertThat(inputBuffer).isNotSameInstanceAs(outputBuffer);
}
@Test
public void isEnded_needsBufferConsuming() throws Exception {
FakeAudioProcessor audioProcessor = new FakeAudioProcessor(/* active= */ true);
AudioProcessingPipeline audioProcessingPipeline =
new AudioProcessingPipeline(ImmutableList.of(audioProcessor));
audioProcessingPipeline.configure(AUDIO_FORMAT);
audioProcessingPipeline.flush();
ByteBuffer inputBuffer = createOneSecondDefaultSilenceBuffer(AUDIO_FORMAT);
audioProcessingPipeline.queueInput(inputBuffer);
audioProcessingPipeline.queueEndOfStream();
assertThat(audioProcessingPipeline.isEnded()).isFalse();
ByteBuffer outputBuffer = audioProcessingPipeline.getOutput();
assertThat(audioProcessingPipeline.isEnded()).isFalse();
// "consume" the buffer
outputBuffer.position(outputBuffer.limit());
assertThat(audioProcessingPipeline.isEnded()).isTrue();
}
@Test
public void pipelineWithAdvancedAudioProcessors_drainsAndFeedsCorrectly_duplicatesBytes()
throws Exception {
AudioProcessingPipeline audioProcessingPipeline =
new AudioProcessingPipeline(
ImmutableList.of(
new FakeAudioProcessor(
/* active= */ true, /* maxInputBytesAtOnce= */ 8, /* duplicateBytes= */ true),
new FakeAudioProcessor(
/* active= */ true, /* maxInputBytesAtOnce= */ 0, /* duplicateBytes= */ false),
new FakeAudioProcessor(
/* active= */ true, /* maxInputBytesAtOnce= */ 12, /* duplicateBytes= */ true),
new FakeAudioProcessor(
/* active= */ true,
/* maxInputBytesAtOnce= */ 160,
/* duplicateBytes= */ false)));
audioProcessingPipeline.configure(AUDIO_FORMAT);
audioProcessingPipeline.flush();
ByteBuffer inputBuffer = createOneSecondDefaultSilenceBuffer(AUDIO_FORMAT);
inputBuffer.put(0, (byte) 24);
inputBuffer.put(1, (byte) 36);
inputBuffer.put(2, (byte) 6);
int bytesInput = inputBuffer.remaining();
List<Byte> bytesOutput = new ArrayList<>();
while (!audioProcessingPipeline.isEnded()) {
ByteBuffer bufferToConsume;
while ((bufferToConsume = audioProcessingPipeline.getOutput()).hasRemaining()) {
// "consume" the buffer. Equivalent to writing downstream.
bytesOutput.add(bufferToConsume.get());
}
if (!inputBuffer.hasRemaining()) {
audioProcessingPipeline.queueEndOfStream();
} else {
audioProcessingPipeline.queueInput(inputBuffer);
}
}
assertThat(audioProcessingPipeline.isEnded()).isTrue();
assertThat(4 * bytesInput).isEqualTo(bytesOutput.size());
assertThat(bytesOutput.get(0)).isEqualTo((byte) 24);
assertThat(bytesOutput.get(1)).isEqualTo((byte) 24);
assertThat(bytesOutput.get(2)).isEqualTo((byte) 24);
assertThat(bytesOutput.get(3)).isEqualTo((byte) 24);
assertThat(bytesOutput.get(4)).isEqualTo((byte) 36);
assertThat(bytesOutput.get(5)).isEqualTo((byte) 36);
assertThat(bytesOutput.get(6)).isEqualTo((byte) 36);
assertThat(bytesOutput.get(7)).isEqualTo((byte) 36);
assertThat(bytesOutput.get(8)).isEqualTo((byte) 6);
assertThat(bytesOutput.get(9)).isEqualTo((byte) 6);
assertThat(bytesOutput.get(10)).isEqualTo((byte) 6);
assertThat(bytesOutput.get(11)).isEqualTo((byte) 6);
assertThat(bytesOutput.get(12)).isEqualTo((byte) 0);
}
// TODO(b/198772621): Consider implementing BaseAudioProcessor once that is in common.
private static class FakeAudioProcessor implements AudioProcessor {
protected ByteBuffer internalBuffer;
private boolean inputEnded;
private boolean active;
private final int maxInputBytesAtOnce;
private final boolean duplicateBytes;
private @MonotonicNonNull AudioFormat pendingOutputFormat;
private @MonotonicNonNull AudioFormat outputFormat;
public FakeAudioProcessor(boolean active) {
this(active, /* maxInputBytesAtOnce= */ 0, /* duplicateBytes= */ false);
}
public FakeAudioProcessor(boolean active, int maxInputBytesAtOnce, boolean duplicateBytes) {
this.active = active;
this.maxInputBytesAtOnce = maxInputBytesAtOnce;
this.duplicateBytes = duplicateBytes;
internalBuffer = EMPTY_BUFFER;
}
public void setActive(boolean active) {
this.active = active;
}
@Override
public AudioFormat configure(AudioFormat inputAudioFormat)
throws UnhandledAudioFormatException {
pendingOutputFormat = inputAudioFormat;
return pendingOutputFormat;
}
@Override
public boolean isActive() {
return active && !pendingOutputFormat.equals(AudioFormat.NOT_SET);
}
@Override
public void queueInput(ByteBuffer inputBuffer) {
if (outputFormat.equals(AudioFormat.NOT_SET)) {
return;
}
int remaining = inputBuffer.remaining();
if (remaining == 0) {
return;
}
internalBuffer =
createOrReplaceBuffer(
maxInputBytesAtOnce > 0 ? min(remaining, maxInputBytesAtOnce) : remaining,
internalBuffer);
while (internalBuffer.hasRemaining()) {
byte b = inputBuffer.get();
internalBuffer.put(b);
if (duplicateBytes) {
internalBuffer.put(b);
}
}
internalBuffer.flip();
}
@Override
public void queueEndOfStream() {
inputEnded = true;
}
@Override
public ByteBuffer getOutput() {
return internalBuffer;
}
@Override
public boolean isEnded() {
return inputEnded && !internalBuffer.hasRemaining();
}
@Override
public void flush() {
internalBuffer.clear();
internalBuffer = EMPTY_BUFFER;
inputEnded = false;
outputFormat = pendingOutputFormat;
}
@Override
public void reset() {
flush();
}
}
private static ByteBuffer createOrReplaceBuffer(int size, @Nullable ByteBuffer buffer) {
if (buffer == null || buffer.capacity() < size) {
buffer = ByteBuffer.allocateDirect(size).order(ByteOrder.nativeOrder());
}
buffer.clear();
return buffer;
}
/** Creates a one second silence buffer for the given {@link AudioFormat}. */
private static ByteBuffer createOneSecondDefaultSilenceBuffer(AudioFormat audioFormat) {
return createOrReplaceBuffer(
/* size= */ audioFormat.sampleRate * audioFormat.channelCount * audioFormat.bytesPerFrame,
/* buffer= */ null);
}
}

View File

@ -81,7 +81,7 @@ public class AdPlaybackStateTest {
@Test
public void withAdGroupTimeUs_updatesAdGroupTimeUs() {
AdPlaybackState state =
new AdPlaybackState(TEST_ADS_ID, /* adGroupTimesUs...= */ 0, 5_000, 10_000)
new AdPlaybackState(TEST_ADS_ID, /* adGroupTimesUs= */ 0, 5_000, 10_000)
.withRemovedAdGroupCount(1);
state =
@ -97,7 +97,7 @@ public class AdPlaybackStateTest {
@Test
public void withNewAdGroup_addsGroupAndKeepsExistingGroups() {
AdPlaybackState state =
new AdPlaybackState(TEST_ADS_ID, /* adGroupTimesUs...= */ 0, 3_000, 6_000)
new AdPlaybackState(TEST_ADS_ID, /* adGroupTimesUs= */ 0, 3_000, 6_000)
.withRemovedAdGroupCount(1)
.withAdCount(/* adGroupIndex= */ 1, /* adCount= */ 2)
.withAdCount(/* adGroupIndex= */ 2, /* adCount= */ 1)
@ -123,12 +123,12 @@ public class AdPlaybackStateTest {
@Test
public void withAdDurationsUs_updatesAdDurations() {
AdPlaybackState state =
new AdPlaybackState(TEST_ADS_ID, /* adGroupTimesUs...= */ 0, 10_000)
new AdPlaybackState(TEST_ADS_ID, /* adGroupTimesUs= */ 0, 10_000)
.withAdCount(/* adGroupIndex= */ 0, /* adCount= */ 2)
.withAdCount(/* adGroupIndex= */ 1, /* adCount= */ 2)
.withAdDurationsUs(new long[][] {new long[] {5_000, 6_000}, new long[] {7_000, 8_000}});
state = state.withAdDurationsUs(/* adGroupIndex= */ 1, /* adDurationsUs...= */ 1_000, 2_000);
state = state.withAdDurationsUs(/* adGroupIndex= */ 1, /* adDurationsUs= */ 1_000, 2_000);
assertThat(state.getAdGroup(0).durationsUs[0]).isEqualTo(5_000);
assertThat(state.getAdGroup(0).durationsUs[1]).isEqualTo(6_000);
@ -315,7 +315,7 @@ public class AdPlaybackStateTest {
@Test
public void withOriginalAdCount() {
AdPlaybackState state =
new AdPlaybackState(TEST_ADS_ID, /* adGroupTimesUs...= */ 5_000_000)
new AdPlaybackState(TEST_ADS_ID, /* adGroupTimesUs= */ 5_000_000)
.withAdCount(/* adGroupIndex= */ 0, /* adCount= */ 2);
state = state.withOriginalAdCount(/* adGroupIndex= */ 0, /* originalAdCount= */ 3);
@ -327,7 +327,7 @@ public class AdPlaybackStateTest {
@Test
public void withOriginalAdCount_unsetValue_defaultsToIndexUnset() {
AdPlaybackState state =
new AdPlaybackState(TEST_ADS_ID, /* adGroupTimesUs...= */ 5_000_000)
new AdPlaybackState(TEST_ADS_ID, /* adGroupTimesUs= */ 5_000_000)
.withAdCount(/* adGroupIndex= */ 0, /* adCount= */ 2);
assertThat(state.getAdGroup(0).count).isEqualTo(2);
@ -336,7 +336,7 @@ public class AdPlaybackStateTest {
@Test
public void withLastAdGroupRemoved() {
AdPlaybackState state = new AdPlaybackState(TEST_ADS_ID, /* adGroupTimesUs...= */ 5_000_000);
AdPlaybackState state = new AdPlaybackState(TEST_ADS_ID, /* adGroupTimesUs= */ 5_000_000);
state =
state
.withAdCount(/* adGroupIndex= */ 0, 3)
@ -363,7 +363,7 @@ public class AdPlaybackStateTest {
state = state.withAdCount(/* adGroupIndex= */ 1, /* adCount= */ 5);
state =
state.withAdDurationsUs(
/* adGroupIndex= */ 1, /* adDurationsUs...= */ 1_000L, 2_000L, 3_000L, 4_000L, 5_000L);
/* adGroupIndex= */ 1, /* adDurationsUs= */ 1_000L, 2_000L, 3_000L, 4_000L, 5_000L);
state = state.withAvailableAdUri(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 1, TEST_URI);
state = state.withAvailableAdUri(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 2, TEST_URI);
state = state.withAvailableAdUri(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 3, TEST_URI);
@ -419,8 +419,8 @@ public class AdPlaybackStateTest {
.withContentResumeOffsetUs(/* adGroupIndex= */ 2, /* contentResumeOffsetUs= */ 3333)
.withIsServerSideInserted(/* adGroupIndex= */ 1, /* isServerSideInserted= */ true)
.withIsServerSideInserted(/* adGroupIndex= */ 2, /* isServerSideInserted= */ true)
.withAdDurationsUs(/* adGroupIndex= */ 1, /* adDurationsUs...= */ 12)
.withAdDurationsUs(/* adGroupIndex= */ 2, /* adDurationsUs...= */ 34, 56)
.withAdDurationsUs(/* adGroupIndex= */ 1, /* adDurationsUs= */ 12)
.withAdDurationsUs(/* adGroupIndex= */ 2, /* adDurationsUs= */ 34, 56)
.withAdResumePositionUs(123)
.withContentDurationUs(456);
@ -457,7 +457,7 @@ public class AdPlaybackStateTest {
AdPlaybackState state =
new AdPlaybackState(
/* adsId= */ new Object(),
/* adGroupTimesUs...= */ 0,
/* adGroupTimesUs= */ 0,
1000,
2000,
3000,
@ -540,7 +540,7 @@ public class AdPlaybackStateTest {
@Test
public void getAdGroupIndexAfterPositionUs_withServerSideInsertedAds_returnsNextAdGroup() {
AdPlaybackState state =
new AdPlaybackState(/* adsId= */ new Object(), /* adGroupTimesUs...= */ 0, 1000, 2000)
new AdPlaybackState(/* adsId= */ new Object(), /* adGroupTimesUs= */ 0, 1000, 2000)
.withIsServerSideInserted(/* adGroupIndex= */ 0, /* isServerSideInserted= */ true)
.withIsServerSideInserted(/* adGroupIndex= */ 1, /* isServerSideInserted= */ true)
.withIsServerSideInserted(/* adGroupIndex= */ 2, /* isServerSideInserted= */ true)

View File

@ -80,7 +80,7 @@ public final class FlagSetTest {
public void containsAny_withoutAdd_returnsFalseForAllValues() {
FlagSet flags = new FlagSet.Builder().build();
assertThat(flags.containsAny(/* flags...= */ -1234, 0, 2, Integer.MAX_VALUE)).isFalse();
assertThat(flags.containsAny(/* flags= */ -1234, 0, 2, Integer.MAX_VALUE)).isFalse();
}
@Test
@ -95,9 +95,9 @@ public final class FlagSetTest {
assertThat(
flags.containsAny(
/* flags...= */ -1235, -1234, 0, 1, 2, Integer.MAX_VALUE - 1, Integer.MAX_VALUE))
/* flags= */ -1235, -1234, 0, 1, 2, Integer.MAX_VALUE - 1, Integer.MAX_VALUE))
.isTrue();
assertThat(flags.containsAny(/* flags...= */ -1235, 1, Integer.MAX_VALUE - 1)).isFalse();
assertThat(flags.containsAny(/* flags= */ -1235, 1, Integer.MAX_VALUE - 1)).isFalse();
}
@Test

View File

@ -394,8 +394,11 @@ public abstract class DecoderAudioRenderer<
}
private boolean drainOutputBuffer()
throws ExoPlaybackException, DecoderException, AudioSink.ConfigurationException,
AudioSink.InitializationException, AudioSink.WriteException {
throws ExoPlaybackException,
DecoderException,
AudioSink.ConfigurationException,
AudioSink.InitializationException,
AudioSink.WriteException {
if (outputBuffer == null) {
outputBuffer = decoder.dequeueOutputBuffer();
if (outputBuffer == null) {

View File

@ -50,6 +50,7 @@ import com.google.android.exoplayer2.util.ConditionVariable;
import com.google.android.exoplayer2.util.Log;
import com.google.android.exoplayer2.util.MimeTypes;
import com.google.android.exoplayer2.util.Util;
import com.google.common.collect.ImmutableList;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
@ -58,8 +59,6 @@ import java.lang.annotation.Target;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collections;
import java.util.concurrent.ExecutorService;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
import org.checkerframework.checker.nullness.qual.RequiresNonNull;
@ -455,8 +454,8 @@ public final class DefaultAudioSink implements AudioSink {
private final boolean enableFloatOutput;
private final ChannelMappingAudioProcessor channelMappingAudioProcessor;
private final TrimmingAudioProcessor trimmingAudioProcessor;
private final AudioProcessor[] toIntPcmAvailableAudioProcessors;
private final AudioProcessor[] toFloatPcmAvailableAudioProcessors;
private final ImmutableList<AudioProcessor> toIntPcmAvailableAudioProcessors;
private final ImmutableList<AudioProcessor> toFloatPcmAvailableAudioProcessors;
private final ConditionVariable releasingConditionVariable;
private final AudioTrackPositionTracker audioTrackPositionTracker;
private final ArrayDeque<MediaPositionParameters> mediaPositionParametersCheckpoints;
@ -473,6 +472,7 @@ public final class DefaultAudioSink implements AudioSink {
@Nullable private Listener listener;
@Nullable private Configuration pendingConfiguration;
private @MonotonicNonNull Configuration configuration;
private @MonotonicNonNull AudioProcessingPipeline audioProcessingPipeline;
@Nullable private AudioTrack audioTrack;
private AudioAttributes audioAttributes;
@ -493,14 +493,11 @@ public final class DefaultAudioSink implements AudioSink {
private long startMediaTimeUs;
private float volume;
private AudioProcessor[] activeAudioProcessors;
private ByteBuffer[] outputBuffers;
@Nullable private ByteBuffer inputBuffer;
private int inputBufferAccessUnitCount;
@Nullable private ByteBuffer outputBuffer;
private @MonotonicNonNull byte[] preV21OutputBuffer;
private int preV21OutputBufferOffset;
private int drainingAudioProcessorIndex;
private boolean handledEndOfStream;
private boolean stoppedAudioTrack;
@ -527,15 +524,10 @@ public final class DefaultAudioSink implements AudioSink {
audioTrackPositionTracker = new AudioTrackPositionTracker(new PositionTrackerListener());
channelMappingAudioProcessor = new ChannelMappingAudioProcessor();
trimmingAudioProcessor = new TrimmingAudioProcessor();
ArrayList<AudioProcessor> toIntPcmAudioProcessors = new ArrayList<>();
Collections.addAll(
toIntPcmAudioProcessors,
new ResamplingAudioProcessor(),
channelMappingAudioProcessor,
trimmingAudioProcessor);
Collections.addAll(toIntPcmAudioProcessors, audioProcessorChain.getAudioProcessors());
toIntPcmAvailableAudioProcessors = toIntPcmAudioProcessors.toArray(new AudioProcessor[0]);
toFloatPcmAvailableAudioProcessors = new AudioProcessor[] {new FloatResamplingAudioProcessor()};
toIntPcmAvailableAudioProcessors =
ImmutableList.of(
new ResamplingAudioProcessor(), channelMappingAudioProcessor, trimmingAudioProcessor);
toFloatPcmAvailableAudioProcessors = ImmutableList.of(new FloatResamplingAudioProcessor());
volume = 1f;
audioAttributes = AudioAttributes.DEFAULT;
audioSessionId = C.AUDIO_SESSION_ID_UNSET;
@ -547,9 +539,6 @@ public final class DefaultAudioSink implements AudioSink {
/* mediaTimeUs= */ 0,
/* audioTrackPositionUs= */ 0);
audioTrackPlaybackParameters = PlaybackParameters.DEFAULT;
drainingAudioProcessorIndex = C.INDEX_UNSET;
activeAudioProcessors = new AudioProcessor[0];
outputBuffers = new ByteBuffer[0];
mediaPositionParametersCheckpoints = new ArrayDeque<>();
initializationExceptionPendingExceptionHolder =
new PendingExceptionHolder<>(AUDIO_TRACK_RETRY_DURATION_MS);
@ -612,9 +601,8 @@ public final class DefaultAudioSink implements AudioSink {
@Override
public void configure(Format inputFormat, int specifiedBufferSize, @Nullable int[] outputChannels)
throws ConfigurationException {
AudioProcessingPipeline audioProcessingPipeline;
int inputPcmFrameSize;
@Nullable AudioProcessor[] availableAudioProcessors;
@OutputMode int outputMode;
@C.Encoding int outputEncoding;
int outputSampleRate;
@ -625,10 +613,21 @@ public final class DefaultAudioSink implements AudioSink {
Assertions.checkArgument(Util.isEncodingLinearPcm(inputFormat.pcmEncoding));
inputPcmFrameSize = Util.getPcmFrameSize(inputFormat.pcmEncoding, inputFormat.channelCount);
availableAudioProcessors =
shouldUseFloatOutput(inputFormat.pcmEncoding)
? toFloatPcmAvailableAudioProcessors
: toIntPcmAvailableAudioProcessors;
ImmutableList.Builder<AudioProcessor> pipelineProcessors = new ImmutableList.Builder<>();
if (shouldUseFloatOutput(inputFormat.pcmEncoding)) {
pipelineProcessors.addAll(toFloatPcmAvailableAudioProcessors);
} else {
pipelineProcessors.addAll(toIntPcmAvailableAudioProcessors);
pipelineProcessors.add(audioProcessorChain.getAudioProcessors());
}
audioProcessingPipeline = new AudioProcessingPipeline(pipelineProcessors.build());
// If the underlying processors of the new pipeline are the same as the existing pipeline,
// then use the existing one when the configuration is used.
if (audioProcessingPipeline.equals(this.audioProcessingPipeline)) {
audioProcessingPipeline = this.audioProcessingPipeline;
}
trimmingAudioProcessor.setTrimFrameCount(
inputFormat.encoderDelay, inputFormat.encoderPadding);
@ -646,16 +645,11 @@ public final class DefaultAudioSink implements AudioSink {
AudioProcessor.AudioFormat outputFormat =
new AudioProcessor.AudioFormat(
inputFormat.sampleRate, inputFormat.channelCount, inputFormat.pcmEncoding);
for (AudioProcessor audioProcessor : availableAudioProcessors) {
try {
AudioProcessor.AudioFormat nextFormat = audioProcessor.configure(outputFormat);
if (audioProcessor.isActive()) {
outputFormat = nextFormat;
}
outputFormat = audioProcessingPipeline.configure(outputFormat);
} catch (UnhandledAudioFormatException e) {
throw new ConfigurationException(e, inputFormat);
}
}
outputMode = OUTPUT_MODE_PCM;
outputEncoding = outputFormat.encoding;
@ -663,8 +657,9 @@ public final class DefaultAudioSink implements AudioSink {
outputChannelConfig = Util.getAudioTrackChannelConfig(outputFormat.channelCount);
outputPcmFrameSize = Util.getPcmFrameSize(outputEncoding, outputFormat.channelCount);
} else {
// Audio processing is not supported in offload or passthrough mode.
audioProcessingPipeline = new AudioProcessingPipeline(ImmutableList.of());
inputPcmFrameSize = C.LENGTH_UNSET;
availableAudioProcessors = new AudioProcessor[0];
outputSampleRate = inputFormat.sampleRate;
outputPcmFrameSize = C.LENGTH_UNSET;
if (useOffloadedPlayback(inputFormat, audioAttributes)) {
@ -717,7 +712,7 @@ public final class DefaultAudioSink implements AudioSink {
outputChannelConfig,
outputEncoding,
bufferSize,
availableAudioProcessors);
audioProcessingPipeline);
if (isAudioTrackInitialized()) {
this.pendingConfiguration = pendingConfiguration;
} else {
@ -726,27 +721,8 @@ public final class DefaultAudioSink implements AudioSink {
}
private void setupAudioProcessors() {
AudioProcessor[] audioProcessors = configuration.availableAudioProcessors;
ArrayList<AudioProcessor> newAudioProcessors = new ArrayList<>();
for (AudioProcessor audioProcessor : audioProcessors) {
if (audioProcessor.isActive()) {
newAudioProcessors.add(audioProcessor);
} else {
audioProcessor.flush();
}
}
int count = newAudioProcessors.size();
activeAudioProcessors = newAudioProcessors.toArray(new AudioProcessor[count]);
outputBuffers = new ByteBuffer[count];
flushAudioProcessors();
}
private void flushAudioProcessors() {
for (int i = 0; i < activeAudioProcessors.length; i++) {
AudioProcessor audioProcessor = activeAudioProcessors[i];
audioProcessor.flush();
outputBuffers[i] = audioProcessor.getOutput();
}
audioProcessingPipeline = configuration.audioProcessingPipeline;
audioProcessingPipeline.flush();
}
private boolean initializeAudioTrack() throws InitializationException {
@ -1010,39 +986,56 @@ public final class DefaultAudioSink implements AudioSink {
offloadStreamEventCallbackV29.register(audioTrack);
}
/**
* Repeatedly drains and feeds the {@link AudioProcessingPipeline} until {@link
* #writeBuffer(ByteBuffer, long)} is not accepting any more input or there is no more input to
* feed into the pipeline.
*
* <p>If the {@link AudioProcessingPipeline} is not {@linkplain
* AudioProcessingPipeline#isOperational() operational}, input buffers are passed straight to
* {@link #writeBuffer(ByteBuffer, long)}.
*/
private void processBuffers(long avSyncPresentationTimeUs) throws WriteException {
int count = activeAudioProcessors.length;
int index = count;
while (index >= 0) {
ByteBuffer input =
index > 0
? outputBuffers[index - 1]
: (inputBuffer != null ? inputBuffer : AudioProcessor.EMPTY_BUFFER);
if (index == count) {
writeBuffer(input, avSyncPresentationTimeUs);
} else {
AudioProcessor audioProcessor = activeAudioProcessors[index];
if (index > drainingAudioProcessorIndex) {
audioProcessor.queueInput(input);
}
ByteBuffer output = audioProcessor.getOutput();
outputBuffers[index] = output;
if (output.hasRemaining()) {
// Handle the output as input to the next audio processor or the AudioTrack.
index++;
continue;
}
}
if (input.hasRemaining()) {
// The input wasn't consumed and no output was produced, so give up for now.
if (!audioProcessingPipeline.isOperational() && inputBuffer != null) {
writeBuffer(inputBuffer, avSyncPresentationTimeUs);
return;
}
// Get more input from upstream.
index--;
while (!audioProcessingPipeline.isEnded()) {
ByteBuffer bufferToWrite;
while ((bufferToWrite = audioProcessingPipeline.getOutput()).hasRemaining()) {
writeBuffer(bufferToWrite, avSyncPresentationTimeUs);
if (bufferToWrite.hasRemaining()) {
// writeBuffer method is providing back pressure.
return;
}
}
if (inputBuffer == null || !inputBuffer.hasRemaining()) {
return;
}
audioProcessingPipeline.queueInput(inputBuffer);
}
}
/**
* Queues end of stream and then fully drains all buffers.
*
* @return Whether the buffers have been fully drained.
*/
private boolean drainToEndOfStream() throws WriteException {
if (!audioProcessingPipeline.isOperational()) {
if (outputBuffer == null) {
return true;
}
writeBuffer(outputBuffer, C.TIME_UNSET);
return outputBuffer == null;
}
audioProcessingPipeline.queueEndOfStream();
processBuffers(C.TIME_UNSET);
return audioProcessingPipeline.isEnded()
&& (outputBuffer == null || !outputBuffer.hasRemaining());
}
@SuppressWarnings("ReferenceEquality")
private void writeBuffer(ByteBuffer buffer, long avSyncPresentationTimeUs) throws WriteException {
@ -1168,36 +1161,6 @@ public final class DefaultAudioSink implements AudioSink {
|| status == ERROR_NATIVE_DEAD_OBJECT;
}
private boolean drainToEndOfStream() throws WriteException {
boolean audioProcessorNeedsEndOfStream = false;
if (drainingAudioProcessorIndex == C.INDEX_UNSET) {
drainingAudioProcessorIndex = 0;
audioProcessorNeedsEndOfStream = true;
}
while (drainingAudioProcessorIndex < activeAudioProcessors.length) {
AudioProcessor audioProcessor = activeAudioProcessors[drainingAudioProcessorIndex];
if (audioProcessorNeedsEndOfStream) {
audioProcessor.queueEndOfStream();
}
processBuffers(C.TIME_UNSET);
if (!audioProcessor.isEnded()) {
return false;
}
audioProcessorNeedsEndOfStream = true;
drainingAudioProcessorIndex++;
}
// Finish writing any remaining output to the track.
if (outputBuffer != null) {
writeBuffer(outputBuffer, C.TIME_UNSET);
if (outputBuffer != null) {
return false;
}
}
drainingAudioProcessorIndex = C.INDEX_UNSET;
return true;
}
@Override
public boolean isEnded() {
return !isAudioTrackInitialized() || (handledEndOfStream && !hasPendingData());
@ -1413,6 +1376,9 @@ public final class DefaultAudioSink implements AudioSink {
for (AudioProcessor audioProcessor : toFloatPcmAvailableAudioProcessors) {
audioProcessor.reset();
}
if (audioProcessingPipeline != null) {
audioProcessingPipeline.reset();
}
playing = false;
offloadDisabledUntilNextConfiguration = false;
}
@ -1440,11 +1406,10 @@ public final class DefaultAudioSink implements AudioSink {
outputBuffer = null;
stoppedAudioTrack = false;
handledEndOfStream = false;
drainingAudioProcessorIndex = C.INDEX_UNSET;
avSyncHeader = null;
bytesUntilNextAvSync = 0;
trimmingAudioProcessor.resetTrimmedFrameCount();
flushAudioProcessors();
setupAudioProcessors();
}
@RequiresApi(23)
@ -1982,7 +1947,7 @@ public final class DefaultAudioSink implements AudioSink {
public final int outputChannelConfig;
public final @C.Encoding int outputEncoding;
public final int bufferSize;
public final AudioProcessor[] availableAudioProcessors;
public final AudioProcessingPipeline audioProcessingPipeline;
public Configuration(
Format inputFormat,
@ -1993,7 +1958,7 @@ public final class DefaultAudioSink implements AudioSink {
int outputChannelConfig,
int outputEncoding,
int bufferSize,
AudioProcessor[] availableAudioProcessors) {
AudioProcessingPipeline audioProcessingPipeline) {
this.inputFormat = inputFormat;
this.inputPcmFrameSize = inputPcmFrameSize;
this.outputMode = outputMode;
@ -2002,7 +1967,7 @@ public final class DefaultAudioSink implements AudioSink {
this.outputChannelConfig = outputChannelConfig;
this.outputEncoding = outputEncoding;
this.bufferSize = bufferSize;
this.availableAudioProcessors = availableAudioProcessors;
this.audioProcessingPipeline = audioProcessingPipeline;
}
public Configuration copyWithBufferSize(int bufferSize) {
@ -2015,7 +1980,7 @@ public final class DefaultAudioSink implements AudioSink {
outputChannelConfig,
outputEncoding,
bufferSize,
availableAudioProcessors);
audioProcessingPipeline);
}
/** Returns if the configurations are sufficiently compatible to reuse the audio track. */

View File

@ -746,7 +746,7 @@ public final class ExoPlayerTest {
public void adGroupWithLoadError_noFurtherAdGroup_isSkipped() throws Exception {
AdPlaybackState initialAdPlaybackState =
FakeTimeline.createAdPlaybackState(
/* adsPerAdGroup= */ 1, /* adGroupTimesUs...= */
/* adsPerAdGroup= */ 1, /* adGroupTimesUs= */
TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US
+ 5 * C.MICROS_PER_SECOND);
Timeline fakeTimeline =
@ -799,7 +799,7 @@ public final class ExoPlayerTest {
public void adGroupWithLoadError_withFurtherAdGroup_isSkipped() throws Exception {
AdPlaybackState initialAdPlaybackState =
FakeTimeline.createAdPlaybackState(
/* adsPerAdGroup= */ 1, /* adGroupTimesUs...= */
/* adsPerAdGroup= */ 1, /* adGroupTimesUs= */
TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US
+ 5 * C.MICROS_PER_SECOND,
TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US
@ -2928,8 +2928,7 @@ public final class ExoPlayerTest {
AdPlaybackState adPlaybackStateWithMidroll =
FakeTimeline.createAdPlaybackState(
/* adsPerAdGroup= */ 1,
/* adGroupTimesUs...= */ TimelineWindowDefinition
.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US
/* adGroupTimesUs= */ TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US
+ 5 * C.MICROS_PER_SECOND);
Timeline timeline2 =
new FakeTimeline(
@ -2980,8 +2979,7 @@ public final class ExoPlayerTest {
AdPlaybackState adPlaybackState =
FakeTimeline.createAdPlaybackState(
/* adsPerAdGroup= */ 1,
/* adGroupTimesUs...= */ TimelineWindowDefinition
.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US
/* adGroupTimesUs= */ TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US
+ Util.msToUs(adGroupWindowTimeMs));
Timeline timeline =
new FakeTimeline(
@ -3614,7 +3612,7 @@ public final class ExoPlayerTest {
@Test
public void contentWithInitialSeekPositionAfterPrerollAdStartsAtSeekPosition() throws Exception {
AdPlaybackState adPlaybackState =
FakeTimeline.createAdPlaybackState(/* adsPerAdGroup= */ 3, /* adGroupTimesUs...= */ 0);
FakeTimeline.createAdPlaybackState(/* adsPerAdGroup= */ 3, /* adGroupTimesUs= */ 0);
Timeline fakeTimeline =
new FakeTimeline(
new TimelineWindowDefinition(
@ -3663,7 +3661,7 @@ public final class ExoPlayerTest {
@Test
public void contentWithoutInitialSeekStartsAtDefaultPositionAfterPrerollAd() throws Exception {
AdPlaybackState adPlaybackState =
FakeTimeline.createAdPlaybackState(/* adsPerAdGroup= */ 3, /* adGroupTimesUs...= */ 0);
FakeTimeline.createAdPlaybackState(/* adsPerAdGroup= */ 3, /* adGroupTimesUs= */ 0);
Timeline fakeTimeline =
new FakeTimeline(
new TimelineWindowDefinition(
@ -3717,7 +3715,7 @@ public final class ExoPlayerTest {
ExoPlayer player = new TestExoPlayerBuilder(context).build();
AdPlaybackState adPlaybackState =
FakeTimeline.createAdPlaybackState(
/* adsPerAdGroup= */ 1, /* adGroupTimesUs...= */ 42_000_004_000_000L);
/* adsPerAdGroup= */ 1, /* adGroupTimesUs= */ 42_000_004_000_000L);
Timeline liveTimeline1 =
new FakeTimeline(
new TimelineWindowDefinition(
@ -4722,7 +4720,7 @@ public final class ExoPlayerTest {
long contentDurationMs = 10_000;
long adDurationMs = 100_000;
AdPlaybackState adPlaybackState =
new AdPlaybackState(/* adsId= */ new Object(), /* adGroupTimesUs...= */ 0);
new AdPlaybackState(/* adsId= */ new Object(), /* adGroupTimesUs= */ 0);
adPlaybackState = adPlaybackState.withAdCount(/* adGroupIndex= */ 0, /* adCount= */ 1);
adPlaybackState =
adPlaybackState.withAvailableAdUri(
@ -4824,7 +4822,7 @@ public final class ExoPlayerTest {
long contentDurationMs = 10_000;
long adDurationMs = 4_000;
AdPlaybackState adPlaybackState =
new AdPlaybackState(/* adsId= */ new Object(), /* adGroupTimesUs...= */ 0);
new AdPlaybackState(/* adsId= */ new Object(), /* adGroupTimesUs= */ 0);
adPlaybackState = adPlaybackState.withAdCount(/* adGroupIndex= */ 0, /* adCount= */ 1);
adPlaybackState =
adPlaybackState.withAvailableAdUri(
@ -4907,7 +4905,7 @@ public final class ExoPlayerTest {
long contentDurationMs = 10_000;
long adDurationMs = 4_000;
AdPlaybackState adPlaybackState =
new AdPlaybackState(/* adsId= */ new Object(), /* adGroupTimesUs...= */ 0)
new AdPlaybackState(/* adsId= */ new Object(), /* adGroupTimesUs= */ 0)
.withAdCount(/* adGroupIndex= */ 0, /* adCount= */ 1)
.withAvailableAdUri(
/* adGroupIndex= */ 0,
@ -4952,7 +4950,7 @@ public final class ExoPlayerTest {
FakeTimeline.createMultiPeriodAdTimeline(
"windowId",
/* numberOfPlayedAds= */ 0,
/* isAdPeriodFlags...= */ false,
/* isAdPeriodFlags= */ false,
true,
true,
false);
@ -5043,7 +5041,7 @@ public final class ExoPlayerTest {
FakeTimeline.createMultiPeriodAdTimeline(
"windowId",
/* numberOfPlayedAds= */ 0,
/* isAdPeriodFlags...= */ false,
/* isAdPeriodFlags= */ false,
true,
false,
false);
@ -5105,7 +5103,7 @@ public final class ExoPlayerTest {
FakeTimeline.createMultiPeriodAdTimeline(
"windowId",
/* numberOfPlayedAds= */ 0,
/* isAdPeriodFlags...= */ false,
/* isAdPeriodFlags= */ false,
true,
true,
false);
@ -5172,7 +5170,7 @@ public final class ExoPlayerTest {
FakeTimeline.createMultiPeriodAdTimeline(
"windowId",
/* numberOfPlayedAds= */ 0,
/* isAdPeriodFlags...= */ false,
/* isAdPeriodFlags= */ false,
true,
true,
false);
@ -5253,7 +5251,7 @@ public final class ExoPlayerTest {
FakeTimeline.createMultiPeriodAdTimeline(
"windowId",
/* numberOfPlayedAds= */ 2,
/* isAdPeriodFlags...= */ false,
/* isAdPeriodFlags= */ false,
true,
true,
false);
@ -5308,7 +5306,7 @@ public final class ExoPlayerTest {
FakeTimeline.createMultiPeriodAdTimeline(
"windowId",
/* numberOfPlayedAds= */ Integer.MAX_VALUE,
/* isAdPeriodFlags...= */ true,
/* isAdPeriodFlags= */ true,
false,
true,
true,
@ -5376,28 +5374,28 @@ public final class ExoPlayerTest {
new AdPlaybackState("adsId"),
/* fromPositionUs= */ DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US,
/* contentResumeOffsetUs= */ 0,
/* adDurationsUs...= */ C.MICROS_PER_SECOND);
/* adDurationsUs= */ C.MICROS_PER_SECOND);
adPlaybackState =
addAdGroupToAdPlaybackState(
adPlaybackState,
/* fromPositionUs= */ DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US
+ (3 * C.MICROS_PER_SECOND),
/* contentResumeOffsetUs= */ 0,
/* adDurationsUs...= */ C.MICROS_PER_SECOND);
/* adDurationsUs= */ C.MICROS_PER_SECOND);
adPlaybackState =
addAdGroupToAdPlaybackState(
adPlaybackState,
/* fromPositionUs= */ DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US
+ (5 * C.MICROS_PER_SECOND),
/* contentResumeOffsetUs= */ 0,
/* adDurationsUs...= */ C.MICROS_PER_SECOND);
/* adDurationsUs= */ C.MICROS_PER_SECOND);
adPlaybackState =
addAdGroupToAdPlaybackState(
adPlaybackState,
/* fromPositionUs= */ DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US
+ (9 * C.MICROS_PER_SECOND),
/* contentResumeOffsetUs= */ 0,
/* adDurationsUs...= */ C.MICROS_PER_SECOND);
/* adDurationsUs= */ C.MICROS_PER_SECOND);
adPlaybackState =
adPlaybackState.withPlayedAd(/* adGroupIndex= */ 0, /* adIndexInAdGroup+ */ 0);
adPlaybackState =
@ -5643,7 +5641,7 @@ public final class ExoPlayerTest {
@Test
public void shortAdFollowedByUnpreparedAd_playbackDoesNotGetStuck() throws Exception {
AdPlaybackState adPlaybackState =
FakeTimeline.createAdPlaybackState(/* adsPerAdGroup= */ 2, /* adGroupTimesUs...= */ 0);
FakeTimeline.createAdPlaybackState(/* adsPerAdGroup= */ 2, /* adGroupTimesUs= */ 0);
long shortAdDurationMs = 1_000;
adPlaybackState =
adPlaybackState.withAdDurationsUs(new long[][] {{shortAdDurationMs, shortAdDurationMs}});
@ -9055,7 +9053,7 @@ public final class ExoPlayerTest {
@Test
public void isCommandAvailable_duringAd_isFalseForSeekCommands() throws Exception {
AdPlaybackState adPlaybackState =
new AdPlaybackState(/* adsId= */ new Object(), /* adGroupTimesUs...= */ 0)
new AdPlaybackState(/* adsId= */ new Object(), /* adGroupTimesUs= */ 0)
.withAdCount(/* adGroupIndex= */ 0, /* adCount= */ 1)
.withAvailableAdUri(
/* adGroupIndex= */ 0,
@ -10026,7 +10024,7 @@ public final class ExoPlayerTest {
AdPlaybackState adPlaybackState =
FakeTimeline.createAdPlaybackState(
/* adsPerAdGroup= */ 1,
/* adGroupTimesUs...= */ 0,
/* adGroupTimesUs= */ 0,
7 * C.MICROS_PER_SECOND,
C.TIME_END_OF_SOURCE);
TimelineWindowDefinition adTimelineDefinition =
@ -10615,7 +10613,7 @@ public final class ExoPlayerTest {
AdPlaybackState adPlaybackState =
FakeTimeline.createAdPlaybackState(
/* adsPerAdGroup= */ 2,
/* adGroupTimesUs...= */ 0,
/* adGroupTimesUs= */ 0,
7 * C.MICROS_PER_SECOND,
C.TIME_END_OF_SOURCE);
TimelineWindowDefinition adTimeline =
@ -10752,7 +10750,7 @@ public final class ExoPlayerTest {
player.addListener(listener);
AdPlaybackState adPlaybackState =
FakeTimeline.createAdPlaybackState(
/* adsPerAdGroup= */ 1, /* adGroupTimesUs...= */ 2 * C.MICROS_PER_SECOND);
/* adsPerAdGroup= */ 1, /* adGroupTimesUs= */ 2 * C.MICROS_PER_SECOND);
TimelineWindowDefinition adTimeline =
new TimelineWindowDefinition(
/* periodCount= */ 1,
@ -10841,7 +10839,7 @@ public final class ExoPlayerTest {
player.addListener(listener);
AdPlaybackState postRollAdPlaybackState =
FakeTimeline.createAdPlaybackState(
/* adsPerAdGroup= */ 1, /* adGroupTimesUs...= */ C.TIME_END_OF_SOURCE);
/* adsPerAdGroup= */ 1, /* adGroupTimesUs= */ C.TIME_END_OF_SOURCE);
TimelineWindowDefinition postRollWindow =
new TimelineWindowDefinition(
/* periodCount= */ 1,
@ -10855,7 +10853,7 @@ public final class ExoPlayerTest {
/* windowOffsetInFirstPeriodUs= */ 0,
postRollAdPlaybackState);
AdPlaybackState preRollAdPlaybackState =
FakeTimeline.createAdPlaybackState(/* adsPerAdGroup= */ 1, /* adGroupTimesUs...= */ 0);
FakeTimeline.createAdPlaybackState(/* adsPerAdGroup= */ 1, /* adGroupTimesUs= */ 0);
TimelineWindowDefinition preRollWindow =
new TimelineWindowDefinition(
/* periodCount= */ 1,
@ -11893,8 +11891,7 @@ public final class ExoPlayerTest {
.build();
// Live stream timeline with unassigned next ad group.
AdPlaybackState initialAdPlaybackState =
new AdPlaybackState(
/* adsId= */ new Object(), /* adGroupTimesUs...= */ C.TIME_END_OF_SOURCE)
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}});

View File

@ -121,7 +121,7 @@ public final class MediaPeriodQueueTest {
@Test
public void getNextMediaPeriodInfo_withPrerollAd_returnsCorrectMediaPeriodInfos() {
setupAdTimeline(/* adGroupTimesUs...= */ 0);
setupAdTimeline(/* adGroupTimesUs= */ 0);
setAdGroupLoaded(/* adGroupIndex= */ 0);
assertNextMediaPeriodInfoIsAd(
/* adGroupIndex= */ 0,
@ -143,7 +143,7 @@ public final class MediaPeriodQueueTest {
@Test
public void getNextMediaPeriodInfo_withMidrollAds_returnsCorrectMediaPeriodInfos() {
setupAdTimeline(/* adGroupTimesUs...= */ FIRST_AD_START_TIME_US, SECOND_AD_START_TIME_US);
setupAdTimeline(/* adGroupTimesUs= */ FIRST_AD_START_TIME_US, SECOND_AD_START_TIME_US);
assertGetNextMediaPeriodInfoReturnsContentMediaPeriod(
/* periodUid= */ firstPeriodUid,
/* startPositionUs= */ 0,
@ -199,7 +199,7 @@ public final class MediaPeriodQueueTest {
@Test
public void getNextMediaPeriodInfo_withMidrollAndPostroll_returnsCorrectMediaPeriodInfos() {
setupAdTimeline(/* adGroupTimesUs...= */ FIRST_AD_START_TIME_US, C.TIME_END_OF_SOURCE);
setupAdTimeline(/* adGroupTimesUs= */ FIRST_AD_START_TIME_US, C.TIME_END_OF_SOURCE);
assertGetNextMediaPeriodInfoReturnsContentMediaPeriod(
/* periodUid= */ firstPeriodUid,
/* startPositionUs= */ 0,
@ -253,7 +253,7 @@ public final class MediaPeriodQueueTest {
adPlaybackState =
new AdPlaybackState(
/* adsId= */ new Object(),
/* adGroupTimesUs...= */ 0,
/* adGroupTimesUs= */ 0,
FIRST_AD_START_TIME_US,
C.TIME_END_OF_SOURCE)
.withContentDurationUs(CONTENT_DURATION_US)
@ -324,7 +324,7 @@ public final class MediaPeriodQueueTest {
adPlaybackState =
new AdPlaybackState(
/* adsId= */ new Object(),
/* adGroupTimesUs...= */ 0,
/* adGroupTimesUs= */ 0,
FIRST_AD_START_TIME_US,
SECOND_AD_START_TIME_US)
.withContentDurationUs(CONTENT_DURATION_US)
@ -392,7 +392,7 @@ public final class MediaPeriodQueueTest {
@Test
public void getNextMediaPeriodInfo_withPostrollLoadError_returnsEmptyFinalMediaPeriodInfo() {
setupAdTimeline(/* adGroupTimesUs...= */ C.TIME_END_OF_SOURCE);
setupAdTimeline(/* adGroupTimesUs= */ C.TIME_END_OF_SOURCE);
assertGetNextMediaPeriodInfoReturnsContentMediaPeriod(
/* periodUid= */ firstPeriodUid,
/* startPositionUs= */ 0,
@ -419,7 +419,7 @@ public final class MediaPeriodQueueTest {
@Test
public void getNextMediaPeriodInfo_withPlayedAdGroups_returnsCorrectMediaPeriodInfos() {
setupAdTimeline(/* adGroupTimesUs...= */ 0, FIRST_AD_START_TIME_US, C.TIME_END_OF_SOURCE);
setupAdTimeline(/* adGroupTimesUs= */ 0, FIRST_AD_START_TIME_US, C.TIME_END_OF_SOURCE);
setAdGroupLoaded(/* adGroupIndex= */ 0);
setAdGroupLoaded(/* adGroupIndex= */ 1);
setAdGroupLoaded(/* adGroupIndex= */ 2);
@ -503,14 +503,14 @@ public final class MediaPeriodQueueTest {
@Test
public void
updateQueuedPeriods_withDurationChangeInPlayingContent_handlesChangeAndRemovesPeriodsAfterChangedPeriod() {
setupAdTimeline(/* adGroupTimesUs...= */ FIRST_AD_START_TIME_US);
setupAdTimeline(/* adGroupTimesUs= */ FIRST_AD_START_TIME_US);
setAdGroupLoaded(/* adGroupIndex= */ 0);
enqueueNext(); // Content before ad.
enqueueNext(); // Ad.
enqueueNext(); // Content after ad.
// Change position of first ad (= change duration of playing content before first ad).
updateAdPlaybackStateAndTimeline(/* adGroupTimesUs...= */ FIRST_AD_START_TIME_US - 2000);
updateAdPlaybackStateAndTimeline(/* adGroupTimesUs= */ FIRST_AD_START_TIME_US - 2000);
setAdGroupLoaded(/* adGroupIndex= */ 0);
long maxRendererReadPositionUs =
MediaPeriodQueue.INITIAL_RENDERER_POSITION_OFFSET_US + FIRST_AD_START_TIME_US - 3000;
@ -531,14 +531,14 @@ public final class MediaPeriodQueueTest {
@Test
public void
updateQueuedPeriods_withDurationChangeInPlayingContentAfterReadingPosition_doesntHandleChangeAndRemovesPeriodsAfterChangedPeriod() {
setupAdTimeline(/* adGroupTimesUs...= */ FIRST_AD_START_TIME_US);
setupAdTimeline(/* adGroupTimesUs= */ FIRST_AD_START_TIME_US);
setAdGroupLoaded(/* adGroupIndex= */ 0);
enqueueNext(); // Content before ad.
enqueueNext(); // Ad.
enqueueNext(); // Content after ad.
// Change position of first ad (= change duration of playing content before first ad).
updateAdPlaybackStateAndTimeline(/* adGroupTimesUs...= */ FIRST_AD_START_TIME_US - 2000);
updateAdPlaybackStateAndTimeline(/* adGroupTimesUs= */ FIRST_AD_START_TIME_US - 2000);
setAdGroupLoaded(/* adGroupIndex= */ 0);
long maxRendererReadPositionUs =
MediaPeriodQueue.INITIAL_RENDERER_POSITION_OFFSET_US + FIRST_AD_START_TIME_US - 1000;
@ -573,7 +573,7 @@ public final class MediaPeriodQueueTest {
// Change position of first ad (= change duration of playing content before first ad).
adPlaybackState =
new AdPlaybackState(
/* adsId= */ new Object(), /* adGroupTimesUs...= */ FIRST_AD_START_TIME_US - 2000)
/* adsId= */ new Object(), /* adGroupTimesUs= */ FIRST_AD_START_TIME_US - 2000)
.withIsServerSideInserted(/* adGroupIndex= */ 0, /* isServerSideInserted= */ true);
updateTimeline();
setAdGroupLoaded(/* adGroupIndex= */ 0);
@ -596,7 +596,7 @@ public final class MediaPeriodQueueTest {
@Test
public void
updateQueuedPeriods_withDurationChangeAfterReadingPeriod_handlesChangeAndRemovesPeriodsAfterChangedPeriod() {
setupAdTimeline(/* adGroupTimesUs...= */ FIRST_AD_START_TIME_US, SECOND_AD_START_TIME_US);
setupAdTimeline(/* adGroupTimesUs= */ FIRST_AD_START_TIME_US, SECOND_AD_START_TIME_US);
setAdGroupLoaded(/* adGroupIndex= */ 0);
setAdGroupLoaded(/* adGroupIndex= */ 1);
enqueueNext(); // Content before first ad.
@ -606,7 +606,7 @@ public final class MediaPeriodQueueTest {
// Change position of second ad (= change duration of content between ads).
updateAdPlaybackStateAndTimeline(
/* adGroupTimesUs...= */ FIRST_AD_START_TIME_US, SECOND_AD_START_TIME_US - 1000);
/* adGroupTimesUs= */ FIRST_AD_START_TIME_US, SECOND_AD_START_TIME_US - 1000);
setAdGroupLoaded(/* adGroupIndex= */ 0);
setAdGroupLoaded(/* adGroupIndex= */ 1);
boolean changeHandled =
@ -622,7 +622,7 @@ public final class MediaPeriodQueueTest {
@Test
public void
updateQueuedPeriods_withDurationChangeBeforeReadingPeriod_doesntHandleChangeAndRemovesPeriodsAfterChangedPeriod() {
setupAdTimeline(/* adGroupTimesUs...= */ FIRST_AD_START_TIME_US, SECOND_AD_START_TIME_US);
setupAdTimeline(/* adGroupTimesUs= */ FIRST_AD_START_TIME_US, SECOND_AD_START_TIME_US);
setAdGroupLoaded(/* adGroupIndex= */ 0);
setAdGroupLoaded(/* adGroupIndex= */ 1);
enqueueNext(); // Content before first ad.
@ -635,7 +635,7 @@ public final class MediaPeriodQueueTest {
// Change position of second ad (= change duration of content between ads).
updateAdPlaybackStateAndTimeline(
/* adGroupTimesUs...= */ FIRST_AD_START_TIME_US, SECOND_AD_START_TIME_US - 1000);
/* adGroupTimesUs= */ FIRST_AD_START_TIME_US, SECOND_AD_START_TIME_US - 1000);
setAdGroupLoaded(/* adGroupIndex= */ 0);
setAdGroupLoaded(/* adGroupIndex= */ 1);
long maxRendererReadPositionUs =
@ -653,7 +653,7 @@ public final class MediaPeriodQueueTest {
@Test
public void
updateQueuedPeriods_withDurationChangeInReadingPeriodAfterReadingPosition_handlesChangeAndRemovesPeriodsAfterChangedPeriod() {
setupAdTimeline(/* adGroupTimesUs...= */ FIRST_AD_START_TIME_US, SECOND_AD_START_TIME_US);
setupAdTimeline(/* adGroupTimesUs= */ FIRST_AD_START_TIME_US, SECOND_AD_START_TIME_US);
setAdGroupLoaded(/* adGroupIndex= */ 0);
setAdGroupLoaded(/* adGroupIndex= */ 1);
enqueueNext(); // Content before first ad.
@ -665,7 +665,7 @@ public final class MediaPeriodQueueTest {
// Change position of second ad (= change duration of content between ads).
updateAdPlaybackStateAndTimeline(
/* adGroupTimesUs...= */ FIRST_AD_START_TIME_US, SECOND_AD_START_TIME_US - 1000);
/* adGroupTimesUs= */ FIRST_AD_START_TIME_US, SECOND_AD_START_TIME_US - 1000);
setAdGroupLoaded(/* adGroupIndex= */ 0);
setAdGroupLoaded(/* adGroupIndex= */ 1);
long readingPositionAtStartOfContentBetweenAds =
@ -685,7 +685,7 @@ public final class MediaPeriodQueueTest {
@Test
public void
updateQueuedPeriods_withDurationChangeInReadingPeriodBeforeReadingPosition_doesntHandleChangeAndRemovesPeriodsAfterChangedPeriod() {
setupAdTimeline(/* adGroupTimesUs...= */ FIRST_AD_START_TIME_US, SECOND_AD_START_TIME_US);
setupAdTimeline(/* adGroupTimesUs= */ FIRST_AD_START_TIME_US, SECOND_AD_START_TIME_US);
setAdGroupLoaded(/* adGroupIndex= */ 0);
setAdGroupLoaded(/* adGroupIndex= */ 1);
enqueueNext(); // Content before first ad.
@ -697,7 +697,7 @@ public final class MediaPeriodQueueTest {
// Change position of second ad (= change duration of content between ads).
updateAdPlaybackStateAndTimeline(
/* adGroupTimesUs...= */ FIRST_AD_START_TIME_US, SECOND_AD_START_TIME_US - 1000);
/* adGroupTimesUs= */ FIRST_AD_START_TIME_US, SECOND_AD_START_TIME_US - 1000);
setAdGroupLoaded(/* adGroupIndex= */ 0);
setAdGroupLoaded(/* adGroupIndex= */ 1);
long readingPositionAtEndOfContentBetweenAds =
@ -717,7 +717,7 @@ public final class MediaPeriodQueueTest {
@Test
public void
updateQueuedPeriods_withDurationChangeInReadingPeriodReadToEnd_doesntHandleChangeAndRemovesPeriodsAfterChangedPeriod() {
setupAdTimeline(/* adGroupTimesUs...= */ FIRST_AD_START_TIME_US, SECOND_AD_START_TIME_US);
setupAdTimeline(/* adGroupTimesUs= */ FIRST_AD_START_TIME_US, SECOND_AD_START_TIME_US);
setAdGroupLoaded(/* adGroupIndex= */ 0);
setAdGroupLoaded(/* adGroupIndex= */ 1);
enqueueNext(); // Content before first ad.
@ -729,7 +729,7 @@ public final class MediaPeriodQueueTest {
// Change position of second ad (= change duration of content between ads).
updateAdPlaybackStateAndTimeline(
/* adGroupTimesUs...= */ FIRST_AD_START_TIME_US, SECOND_AD_START_TIME_US - 1000);
/* adGroupTimesUs= */ FIRST_AD_START_TIME_US, SECOND_AD_START_TIME_US - 1000);
setAdGroupLoaded(/* adGroupIndex= */ 0);
setAdGroupLoaded(/* adGroupIndex= */ 1);
boolean changeHandled =
@ -832,7 +832,7 @@ public final class MediaPeriodQueueTest {
createMultiPeriodServerSideInsertedTimeline(
windowId,
/* numberOfPlayedAds= */ 0,
/* isAdPeriodFlags...= */ true,
/* isAdPeriodFlags= */ true,
false,
true,
true,
@ -867,7 +867,7 @@ public final class MediaPeriodQueueTest {
createMultiPeriodServerSideInsertedTimeline(
windowId,
/* numberOfPlayedAds= */ 4,
/* isAdPeriodFlags...= */ true,
/* isAdPeriodFlags= */ true,
false,
true,
true,
@ -902,7 +902,7 @@ public final class MediaPeriodQueueTest {
createMultiPeriodServerSideInsertedTimeline(
windowId,
/* numberOfPlayedAds= */ 2,
/* isAdPeriodFlags...= */ true,
/* isAdPeriodFlags= */ true,
false,
true,
true,
@ -926,7 +926,7 @@ public final class MediaPeriodQueueTest {
Object windowId = new Object();
Timeline timeline =
createMultiPeriodServerSideInsertedTimeline(
windowId, /* numberOfPlayedAds= */ 0, /* isAdPeriodFlags...= */ false, true);
windowId, /* numberOfPlayedAds= */ 0, /* isAdPeriodFlags= */ false, true);
MediaPeriodId mediaPeriodId =
mediaPeriodQueue.resolveMediaPeriodIdForAdsAfterPeriodPositionChange(
@ -945,7 +945,7 @@ public final class MediaPeriodQueueTest {
Object windowId = new Object();
Timeline timeline =
createMultiPeriodServerSideInsertedTimeline(
windowId, /* numberOfPlayedAds= */ 0, /* isAdPeriodFlags...= */ false, true, false);
windowId, /* numberOfPlayedAds= */ 0, /* isAdPeriodFlags= */ false, true, false);
MediaPeriodId mediaPeriodId =
mediaPeriodQueue.resolveMediaPeriodIdForAdsAfterPeriodPositionChange(
@ -964,7 +964,7 @@ public final class MediaPeriodQueueTest {
Object windowId = new Object();
Timeline timeline =
createMultiPeriodServerSideInsertedTimeline(
windowId, /* numberOfPlayedAds= */ 1, /* isAdPeriodFlags...= */ false, true, false);
windowId, /* numberOfPlayedAds= */ 1, /* isAdPeriodFlags= */ false, true, false);
MediaPeriodId mediaPeriodId =
mediaPeriodQueue.resolveMediaPeriodIdForAdsAfterPeriodPositionChange(
@ -983,7 +983,7 @@ public final class MediaPeriodQueueTest {
Object windowId = new Object();
Timeline timeline =
createMultiPeriodServerSideInsertedTimeline(
windowId, /* numberOfPlayedAds= */ 2, /* isAdPeriodFlags...= */ true, true, false);
windowId, /* numberOfPlayedAds= */ 2, /* isAdPeriodFlags= */ true, true, false);
MediaPeriodId mediaPeriodId =
mediaPeriodQueue.resolveMediaPeriodIdForAdsAfterPeriodPositionChange(
timeline, new Pair<>(windowId, 0), /* positionUs= */ 0);
@ -1003,7 +1003,7 @@ public final class MediaPeriodQueueTest {
createMultiPeriodServerSideInsertedTimeline(
windowId,
/* numberOfPlayedAds= */ 4,
/* isAdPeriodFlags...= */ false,
/* isAdPeriodFlags= */ false,
true,
true,
true,
@ -1026,12 +1026,7 @@ public final class MediaPeriodQueueTest {
Object windowId = new Object();
Timeline timeline =
createMultiPeriodServerSideInsertedTimeline(
windowId,
/* numberOfPlayedAds= */ 0,
/* isAdPeriodFlags...= */ true,
false,
false,
false);
windowId, /* numberOfPlayedAds= */ 0, /* isAdPeriodFlags= */ true, false, false, false);
MediaPeriodId mediaPeriodId =
mediaPeriodQueue.resolveMediaPeriodIdForAdsAfterPeriodPositionChange(
@ -1052,7 +1047,7 @@ public final class MediaPeriodQueueTest {
createMultiPeriodServerSideInsertedTimeline(
windowId,
/* numberOfPlayedAds= */ 0,
/* isAdPeriodFlags...= */ false,
/* isAdPeriodFlags= */ false,
false,
false,
false);

View File

@ -1027,7 +1027,7 @@ public final class DefaultAnalyticsCollectorTest {
new AtomicReference<>(
FakeTimeline.createAdPlaybackState(
/* adsPerAdGroup= */ 1,
/* adGroupTimesUs...= */ windowOffsetInFirstPeriodUs,
/* adGroupTimesUs= */ windowOffsetInFirstPeriodUs,
windowOffsetInFirstPeriodUs + 5 * C.MICROS_PER_SECOND,
C.TIME_END_OF_SOURCE));
AtomicInteger playedAdCount = new AtomicInteger(0);
@ -1300,7 +1300,7 @@ public final class DefaultAnalyticsCollectorTest {
/* isDynamic= */ false,
10 * C.MICROS_PER_SECOND,
FakeTimeline.createAdPlaybackState(
/* adsPerAdGroup= */ 1, /* adGroupTimesUs...= */
/* adsPerAdGroup= */ 1, /* adGroupTimesUs= */
windowOffsetInFirstPeriodUs + 5 * C.MICROS_PER_SECOND)));
FakeMediaSource fakeMediaSource =
new FakeMediaSource(

View File

@ -289,11 +289,10 @@ public final class SilenceSkippingAudioProcessorTest {
Pcm16BitAudioBuilder audioBuilder = new Pcm16BitAudioBuilder(channelCount, totalFrameCount);
while (!audioBuilder.isFull()) {
int silenceDurationFrames = (silenceDurationMs * sampleRate) / 1000;
audioBuilder.appendFrames(
/* count= */ silenceDurationFrames, /* channelLevels...= */ (short) 0);
audioBuilder.appendFrames(/* count= */ silenceDurationFrames, /* channelLevels= */ (short) 0);
int noiseDurationFrames = (noiseDurationMs * sampleRate) / 1000;
audioBuilder.appendFrames(
/* count= */ noiseDurationFrames, /* channelLevels...= */ Short.MAX_VALUE);
/* count= */ noiseDurationFrames, /* channelLevels= */ Short.MAX_VALUE);
}
return new InputBufferProvider(audioBuilder.build());
}

View File

@ -78,7 +78,7 @@ public final class AdsMediaSourceTest {
CONTENT_TIMELINE.getUidOfPeriod(/* periodIndex= */ 0);
private static final AdPlaybackState AD_PLAYBACK_STATE =
new AdPlaybackState(/* adsId= */ new Object(), /* adGroupTimesUs...= */ 0)
new AdPlaybackState(/* adsId= */ new Object(), /* adGroupTimesUs= */ 0)
.withContentDurationUs(CONTENT_DURATION_US)
.withAdCount(/* adGroupIndex= */ 0, /* adCount= */ 1)
.withAvailableAdUri(

View File

@ -90,19 +90,16 @@ public final class ServerSideAdInsertionMediaSourceTest {
// Test with one ad group before the window, and the window starting within the second ad group.
AdPlaybackState adPlaybackState =
new AdPlaybackState(
/* adsId= */ new Object(), /* adGroupTimesUs...= */
15_000_000,
41_500_000,
42_200_000)
/* adsId= */ new Object(), /* adGroupTimesUs= */ 15_000_000, 41_500_000, 42_200_000)
.withIsServerSideInserted(/* adGroupIndex= */ 0, /* isServerSideInserted= */ true)
.withIsServerSideInserted(/* adGroupIndex= */ 1, /* isServerSideInserted= */ true)
.withIsServerSideInserted(/* adGroupIndex= */ 2, /* isServerSideInserted= */ true)
.withAdCount(/* adGroupIndex= */ 0, /* adCount= */ 1)
.withAdCount(/* adGroupIndex= */ 1, /* adCount= */ 2)
.withAdCount(/* adGroupIndex= */ 2, /* adCount= */ 1)
.withAdDurationsUs(/* adGroupIndex= */ 0, /* adDurationsUs...= */ 500_000)
.withAdDurationsUs(/* adGroupIndex= */ 1, /* adDurationsUs...= */ 300_000, 100_000)
.withAdDurationsUs(/* adGroupIndex= */ 2, /* adDurationsUs...= */ 400_000)
.withAdDurationsUs(/* adGroupIndex= */ 0, /* adDurationsUs= */ 500_000)
.withAdDurationsUs(/* adGroupIndex= */ 1, /* adDurationsUs= */ 300_000, 100_000)
.withAdDurationsUs(/* adGroupIndex= */ 2, /* adDurationsUs= */ 400_000)
.withContentResumeOffsetUs(/* adGroupIndex= */ 0, /* contentResumeOffsetUs= */ 100_000)
.withContentResumeOffsetUs(/* adGroupIndex= */ 1, /* contentResumeOffsetUs= */ 400_000)
.withContentResumeOffsetUs(/* adGroupIndex= */ 2, /* contentResumeOffsetUs= */ 200_000);
@ -183,19 +180,19 @@ public final class ServerSideAdInsertionMediaSourceTest {
adPlaybackState,
/* fromPositionUs= */ 0,
/* contentResumeOffsetUs= */ 0,
/* adDurationsUs...= */ 200_000);
/* adDurationsUs= */ 200_000);
adPlaybackState =
addAdGroupToAdPlaybackState(
adPlaybackState,
/* fromPositionUs= */ 400_000,
/* contentResumeOffsetUs= */ 1_000_000,
/* adDurationsUs...= */ 300_000);
/* adDurationsUs= */ 300_000);
AdPlaybackState firstAdPlaybackState =
addAdGroupToAdPlaybackState(
adPlaybackState,
/* fromPositionUs= */ 900_000,
/* contentResumeOffsetUs= */ 0,
/* adDurationsUs...= */ 100_000);
/* adDurationsUs= */ 100_000);
AtomicReference<ServerSideAdInsertionMediaSource> mediaSourceRef = new AtomicReference<>();
mediaSourceRef.set(
@ -253,7 +250,7 @@ public final class ServerSideAdInsertionMediaSourceTest {
new AdPlaybackState(/* adsId= */ new Object()),
/* fromPositionUs= */ 900_000,
/* contentResumeOffsetUs= */ 0,
/* adDurationsUs...= */ 100_000);
/* adDurationsUs= */ 100_000);
AtomicReference<ServerSideAdInsertionMediaSource> mediaSourceRef = new AtomicReference<>();
mediaSourceRef.set(
new ServerSideAdInsertionMediaSource(
@ -281,7 +278,7 @@ public final class ServerSideAdInsertionMediaSourceTest {
firstAdPlaybackState,
/* fromPositionUs= */ 0,
/* contentResumeOffsetUs= */ 0,
/* adDurationsUs...= */ 500_000);
/* adDurationsUs= */ 500_000);
mediaSourceRef
.get()
.setAdPlaybackStates(ImmutableMap.of(periodUid.get(), secondAdPlaybackState));
@ -324,7 +321,7 @@ public final class ServerSideAdInsertionMediaSourceTest {
new AdPlaybackState(/* adsId= */ new Object()),
/* fromPositionUs= */ 0,
/* contentResumeOffsetUs= */ 0,
/* adDurationsUs...= */ 500_000);
/* adDurationsUs= */ 500_000);
AtomicReference<ServerSideAdInsertionMediaSource> mediaSourceRef = new AtomicReference<>();
mediaSourceRef.set(
new ServerSideAdInsertionMediaSource(
@ -354,7 +351,7 @@ public final class ServerSideAdInsertionMediaSourceTest {
firstAdPlaybackState
.withAdCount(/* adGroupIndex= */ 0, /* adCount= */ 3)
.withAdDurationsUs(
/* adGroupIndex= */ 0, /* adDurationsUs...= */ 50_000, 250_000, 200_000);
/* adGroupIndex= */ 0, /* adDurationsUs= */ 50_000, 250_000, 200_000);
mediaSourceRef
.get()
.setAdPlaybackStates(ImmutableMap.of(periodUid.get(), secondAdPlaybackState));
@ -392,19 +389,19 @@ public final class ServerSideAdInsertionMediaSourceTest {
adPlaybackState,
/* fromPositionUs= */ 0,
/* contentResumeOffsetUs= */ 0,
/* adDurationsUs...= */ 100_000);
/* adDurationsUs= */ 100_000);
adPlaybackState =
addAdGroupToAdPlaybackState(
adPlaybackState,
/* fromPositionUs= */ 600_000,
/* contentResumeOffsetUs= */ 1_000_000,
/* adDurationsUs...= */ 100_000);
/* adDurationsUs= */ 100_000);
AdPlaybackState firstAdPlaybackState =
addAdGroupToAdPlaybackState(
adPlaybackState,
/* fromPositionUs= */ 900_000,
/* contentResumeOffsetUs= */ 0,
/* adDurationsUs...= */ 100_000);
/* adDurationsUs= */ 100_000);
AtomicReference<ServerSideAdInsertionMediaSource> mediaSourceRef = new AtomicReference<>();
mediaSourceRef.set(

View File

@ -38,7 +38,7 @@ public final class ServerSideAdInsertionUtilTest {
@Test
public void addAdGroupToAdPlaybackState_insertsCorrectAdGroupData() {
AdPlaybackState state =
new AdPlaybackState(ADS_ID, /* adGroupTimesUs...= */ 0, 1, C.TIME_END_OF_SOURCE)
new AdPlaybackState(ADS_ID, /* adGroupTimesUs= */ 0, 1, C.TIME_END_OF_SOURCE)
.withRemovedAdGroupCount(2);
// stream: 0-- content --4300-- ad1 --4500-- content
@ -48,16 +48,16 @@ public final class ServerSideAdInsertionUtilTest {
state,
/* fromPositionUs= */ 4300,
/* contentResumeOffsetUs= */ 400,
/* adDurationsUs...= */ 200);
/* adDurationsUs= */ 200);
assertThat(state)
.isEqualTo(
new AdPlaybackState(ADS_ID, /* adGroupTimesUs...= */ 0, 0, 4300, C.TIME_END_OF_SOURCE)
new AdPlaybackState(ADS_ID, /* adGroupTimesUs= */ 0, 0, 4300, C.TIME_END_OF_SOURCE)
.withRemovedAdGroupCount(2)
.withAdCount(/* adGroupIndex= */ 2, /* adCount= */ 1)
.withIsServerSideInserted(/* adGroupIndex= */ 2, /* isServerSideInserted= */ true)
.withContentResumeOffsetUs(/* adGroupIndex= */ 2, /* contentResumeOffsetUs= */ 400)
.withAdDurationsUs(/* adGroupIndex= */ 2, /* adDurationsUs...= */ 200));
.withAdDurationsUs(/* adGroupIndex= */ 2, /* adDurationsUs= */ 200));
// stream: 0-- content --2100-- ad1 --2400-- content --4300-- ad2 --4500-- content
// content timeline: 0-2100 - [ad1] - 2100-4000 - [ad2] - 4400-end
@ -66,20 +66,20 @@ public final class ServerSideAdInsertionUtilTest {
state,
/* fromPositionUs= */ 2100,
/* contentResumeOffsetUs= */ 0,
/* adDurationsUs...= */ 300);
/* adDurationsUs= */ 300);
assertThat(state)
.isEqualTo(
new AdPlaybackState(
ADS_ID, /* adGroupTimesUs...= */ 0, 0, 2100, 4000, C.TIME_END_OF_SOURCE)
ADS_ID, /* adGroupTimesUs= */ 0, 0, 2100, 4000, C.TIME_END_OF_SOURCE)
.withRemovedAdGroupCount(2)
.withAdCount(/* adGroupIndex= */ 2, /* adCount= */ 1)
.withAdCount(/* adGroupIndex= */ 3, /* adCount= */ 1)
.withIsServerSideInserted(/* adGroupIndex= */ 2, /* isServerSideInserted= */ true)
.withIsServerSideInserted(/* adGroupIndex= */ 3, /* isServerSideInserted= */ true)
.withContentResumeOffsetUs(/* adGroupIndex= */ 3, /* contentResumeOffsetUs= */ 400)
.withAdDurationsUs(/* adGroupIndex= */ 2, /* adDurationsUs...= */ 300)
.withAdDurationsUs(/* adGroupIndex= */ 3, /* adDurationsUs...= */ 200));
.withAdDurationsUs(/* adGroupIndex= */ 2, /* adDurationsUs= */ 300)
.withAdDurationsUs(/* adGroupIndex= */ 3, /* adDurationsUs= */ 200));
// stream: 0-- ad1 --100-- content --2100-- ad2 --2400-- content --4300-- ad3 --4500-- content
// content timeline: 0 - [ad1] - 50-2050 -[ad2] - 2050-3950 - [ad3] - 4350-end
@ -88,12 +88,12 @@ public final class ServerSideAdInsertionUtilTest {
state,
/* fromPositionUs= */ 0,
/* contentResumeOffsetUs= */ 50,
/* adDurationsUs...= */ 100);
/* adDurationsUs= */ 100);
assertThat(state)
.isEqualTo(
new AdPlaybackState(
ADS_ID, /* adGroupTimesUs...= */ 0, 0, 0, 2050, 3950, C.TIME_END_OF_SOURCE)
ADS_ID, /* adGroupTimesUs= */ 0, 0, 0, 2050, 3950, C.TIME_END_OF_SOURCE)
.withRemovedAdGroupCount(2)
.withAdCount(/* adGroupIndex= */ 2, /* adCount= */ 1)
.withAdCount(/* adGroupIndex= */ 3, /* adCount= */ 1)
@ -103,9 +103,9 @@ public final class ServerSideAdInsertionUtilTest {
.withIsServerSideInserted(/* adGroupIndex= */ 4, /* isServerSideInserted= */ true)
.withContentResumeOffsetUs(/* adGroupIndex= */ 2, /* contentResumeOffsetUs= */ 50)
.withContentResumeOffsetUs(/* adGroupIndex= */ 4, /* contentResumeOffsetUs= */ 400)
.withAdDurationsUs(/* adGroupIndex= */ 2, /* adDurationsUs...= */ 100)
.withAdDurationsUs(/* adGroupIndex= */ 3, /* adDurationsUs...= */ 300)
.withAdDurationsUs(/* adGroupIndex= */ 4, /* adDurationsUs...= */ 200));
.withAdDurationsUs(/* adGroupIndex= */ 2, /* adDurationsUs= */ 100)
.withAdDurationsUs(/* adGroupIndex= */ 3, /* adDurationsUs= */ 300)
.withAdDurationsUs(/* adGroupIndex= */ 4, /* adDurationsUs= */ 200));
// stream: 0-- ad1 --100-- c --2100-- ad2 --2400-- c --4300-- ad3 --4500-- c --5000-- ad4 --6000
// content timeline: 0 - [ad1] - 50-2050 -[ad2] - 2050-3950 - [ad3] - 4350-4850 - [ad4] - 4850
@ -114,19 +114,12 @@ public final class ServerSideAdInsertionUtilTest {
state,
/* fromPositionUs= */ 5000,
/* contentResumeOffsetUs= */ 0,
/* adDurationsUs...= */ 1000);
/* adDurationsUs= */ 1000);
assertThat(state)
.isEqualTo(
new AdPlaybackState(
ADS_ID, /* adGroupTimesUs...= */
0,
0,
0,
2050,
3950,
4850,
C.TIME_END_OF_SOURCE)
ADS_ID, /* adGroupTimesUs= */ 0, 0, 0, 2050, 3950, 4850, C.TIME_END_OF_SOURCE)
.withRemovedAdGroupCount(2)
.withAdCount(/* adGroupIndex= */ 2, /* adCount= */ 1)
.withAdCount(/* adGroupIndex= */ 3, /* adCount= */ 1)
@ -138,10 +131,10 @@ public final class ServerSideAdInsertionUtilTest {
.withIsServerSideInserted(/* adGroupIndex= */ 5, /* isServerSideInserted= */ true)
.withContentResumeOffsetUs(/* adGroupIndex= */ 2, /* contentResumeOffsetUs= */ 50)
.withContentResumeOffsetUs(/* adGroupIndex= */ 4, /* contentResumeOffsetUs= */ 400)
.withAdDurationsUs(/* adGroupIndex= */ 2, /* adDurationsUs...= */ 100)
.withAdDurationsUs(/* adGroupIndex= */ 3, /* adDurationsUs...= */ 300)
.withAdDurationsUs(/* adGroupIndex= */ 4, /* adDurationsUs...= */ 200)
.withAdDurationsUs(/* adGroupIndex= */ 5, /* adDurationsUs...= */ 1000));
.withAdDurationsUs(/* adGroupIndex= */ 2, /* adDurationsUs= */ 100)
.withAdDurationsUs(/* adGroupIndex= */ 3, /* adDurationsUs= */ 300)
.withAdDurationsUs(/* adGroupIndex= */ 4, /* adDurationsUs= */ 200)
.withAdDurationsUs(/* adGroupIndex= */ 5, /* adDurationsUs= */ 1000));
}
@Test
@ -153,7 +146,7 @@ public final class ServerSideAdInsertionUtilTest {
state,
/* fromPositionUs= */ 0,
/* contentResumeOffsetUs= */ 50_000,
/* adDurationsUs...= */ 0,
/* adDurationsUs= */ 0,
0,
10_000,
40_000,
@ -176,7 +169,7 @@ public final class ServerSideAdInsertionUtilTest {
// stream: 0-- ad1 --200-- content --2100-- ad2 --2300-- content --4300-- ad3 --4500-- content
// content timeline: 0 - [ad1] - 100-2000 -[ad2] - 2000-4000 - [ad3] - 4400-end
AdPlaybackState state =
new AdPlaybackState(ADS_ID, /* adGroupTimesUs...= */ 0, 0, 0, 2000, 4000)
new AdPlaybackState(ADS_ID, /* adGroupTimesUs= */ 0, 0, 0, 2000, 4000)
.withRemovedAdGroupCount(2)
.withAdCount(/* adGroupIndex= */ 2, /* adCount= */ 2)
.withAdCount(/* adGroupIndex= */ 3, /* adCount= */ 1)
@ -184,9 +177,9 @@ public final class ServerSideAdInsertionUtilTest {
.withContentResumeOffsetUs(/* adGroupIndex= */ 2, /* contentResumeOffsetUs= */ 100)
.withContentResumeOffsetUs(/* adGroupIndex= */ 3, /* contentResumeOffsetUs= */ 0)
.withContentResumeOffsetUs(/* adGroupIndex= */ 4, /* contentResumeOffsetUs= */ 400)
.withAdDurationsUs(/* adGroupIndex= */ 2, /* adDurationsUs...= */ 150, 50)
.withAdDurationsUs(/* adGroupIndex= */ 3, /* adDurationsUs...= */ 200)
.withAdDurationsUs(/* adGroupIndex= */ 4, /* adDurationsUs...= */ 50, 50, 100);
.withAdDurationsUs(/* adGroupIndex= */ 2, /* adDurationsUs= */ 150, 50)
.withAdDurationsUs(/* adGroupIndex= */ 3, /* adDurationsUs= */ 200)
.withAdDurationsUs(/* adGroupIndex= */ 4, /* adDurationsUs= */ 50, 50, 100);
assertThat(
getStreamPositionUsForAd(
@ -276,7 +269,7 @@ public final class ServerSideAdInsertionUtilTest {
// stream: 0-- ad1 --200-- content --2100-- ad2 --2300-- content --4300-- ad3 --4500-- content
// content timeline: 0 - [ad1] - 100-2000 -[ad2] - 2000-4000 - [ad3] - 4400-end
AdPlaybackState state =
new AdPlaybackState(ADS_ID, /* adGroupTimesUs...= */ 0, 0, 0, 2000, 4000)
new AdPlaybackState(ADS_ID, /* adGroupTimesUs= */ 0, 0, 0, 2000, 4000)
.withRemovedAdGroupCount(2)
.withAdCount(/* adGroupIndex= */ 2, /* adCount= */ 2)
.withAdCount(/* adGroupIndex= */ 3, /* adCount= */ 1)
@ -284,9 +277,9 @@ public final class ServerSideAdInsertionUtilTest {
.withContentResumeOffsetUs(/* adGroupIndex= */ 2, /* contentResumeOffsetUs= */ 100)
.withContentResumeOffsetUs(/* adGroupIndex= */ 3, /* contentResumeOffsetUs= */ 0)
.withContentResumeOffsetUs(/* adGroupIndex= */ 4, /* contentResumeOffsetUs= */ 400)
.withAdDurationsUs(/* adGroupIndex= */ 2, /* adDurationsUs...= */ 150, 50)
.withAdDurationsUs(/* adGroupIndex= */ 3, /* adDurationsUs...= */ 200)
.withAdDurationsUs(/* adGroupIndex= */ 4, /* adDurationsUs...= */ 50, 50, 100);
.withAdDurationsUs(/* adGroupIndex= */ 2, /* adDurationsUs= */ 150, 50)
.withAdDurationsUs(/* adGroupIndex= */ 3, /* adDurationsUs= */ 200)
.withAdDurationsUs(/* adGroupIndex= */ 4, /* adDurationsUs= */ 50, 50, 100);
assertThat(
getMediaPeriodPositionUsForAd(
@ -381,7 +374,7 @@ public final class ServerSideAdInsertionUtilTest {
// stream: 0-- ad1 --200-- content --2100-- ad2 --2300-- content --4300-- ad3 --4500-- content
// content timeline: 0 - [ad1] - 100-2000 -[ad2] - 2000-4000 - [ad3] - 4400-end
AdPlaybackState state =
new AdPlaybackState(ADS_ID, /* adGroupTimesUs...= */ 0, 0, 0, 2000, 4000)
new AdPlaybackState(ADS_ID, /* adGroupTimesUs= */ 0, 0, 0, 2000, 4000)
.withRemovedAdGroupCount(2)
.withAdCount(/* adGroupIndex= */ 2, /* adCount= */ 2)
.withAdCount(/* adGroupIndex= */ 3, /* adCount= */ 1)
@ -389,9 +382,9 @@ public final class ServerSideAdInsertionUtilTest {
.withContentResumeOffsetUs(/* adGroupIndex= */ 2, /* contentResumeOffsetUs= */ 100)
.withContentResumeOffsetUs(/* adGroupIndex= */ 3, /* contentResumeOffsetUs= */ 0)
.withContentResumeOffsetUs(/* adGroupIndex= */ 4, /* contentResumeOffsetUs= */ 400)
.withAdDurationsUs(/* adGroupIndex= */ 2, /* adDurationsUs...= */ 150, 50)
.withAdDurationsUs(/* adGroupIndex= */ 3, /* adDurationsUs...= */ 200)
.withAdDurationsUs(/* adGroupIndex= */ 4, /* adDurationsUs...= */ 50, 50, 100);
.withAdDurationsUs(/* adGroupIndex= */ 2, /* adDurationsUs= */ 150, 50)
.withAdDurationsUs(/* adGroupIndex= */ 3, /* adDurationsUs= */ 200)
.withAdDurationsUs(/* adGroupIndex= */ 4, /* adDurationsUs= */ 50, 50, 100);
assertThat(getStreamPositionUsForContent(/* positionUs= */ 0, /* nextAdGroupIndex= */ 2, state))
.isEqualTo(0);
@ -477,7 +470,7 @@ public final class ServerSideAdInsertionUtilTest {
// stream: 0-- ad1 --200-- content --2100-- ad2 --2300-- content --4300-- ad3 --4500-- content
// content timeline: 0 - [ad1] - 100-2000 -[ad2] - 2000-4000 - [ad3] - 4400-end
AdPlaybackState state =
new AdPlaybackState(ADS_ID, /* adGroupTimesUs...= */ 0, 0, 0, 2000, 4000)
new AdPlaybackState(ADS_ID, /* adGroupTimesUs= */ 0, 0, 0, 2000, 4000)
.withRemovedAdGroupCount(2)
.withAdCount(/* adGroupIndex= */ 2, /* adCount= */ 2)
.withAdCount(/* adGroupIndex= */ 3, /* adCount= */ 1)
@ -485,9 +478,9 @@ public final class ServerSideAdInsertionUtilTest {
.withContentResumeOffsetUs(/* adGroupIndex= */ 2, /* contentResumeOffsetUs= */ 100)
.withContentResumeOffsetUs(/* adGroupIndex= */ 3, /* contentResumeOffsetUs= */ 0)
.withContentResumeOffsetUs(/* adGroupIndex= */ 4, /* contentResumeOffsetUs= */ 400)
.withAdDurationsUs(/* adGroupIndex= */ 2, /* adDurationsUs...= */ 150, 50)
.withAdDurationsUs(/* adGroupIndex= */ 3, /* adDurationsUs...= */ 200)
.withAdDurationsUs(/* adGroupIndex= */ 4, /* adDurationsUs...= */ 50, 50, 100);
.withAdDurationsUs(/* adGroupIndex= */ 2, /* adDurationsUs= */ 150, 50)
.withAdDurationsUs(/* adGroupIndex= */ 3, /* adDurationsUs= */ 200)
.withAdDurationsUs(/* adGroupIndex= */ 4, /* adDurationsUs= */ 50, 50, 100);
assertThat(
getMediaPeriodPositionUsForContent(
@ -594,7 +587,7 @@ public final class ServerSideAdInsertionUtilTest {
@Test
public void getAdCountInGroup_withUnsetCount_returnsZero() {
AdPlaybackState state = new AdPlaybackState(ADS_ID, /* adGroupTimesUs...= */ 0, 2000);
AdPlaybackState state = new AdPlaybackState(ADS_ID, /* adGroupTimesUs= */ 0, 2000);
assertThat(getAdCountInGroup(state, /* adGroupIndex= */ 0)).isEqualTo(0);
assertThat(getAdCountInGroup(state, /* adGroupIndex= */ 1)).isEqualTo(0);
@ -603,7 +596,7 @@ public final class ServerSideAdInsertionUtilTest {
@Test
public void getAdCountInGroup_withSetCount_returnsCount() {
AdPlaybackState state =
new AdPlaybackState(ADS_ID, /* adGroupTimesUs...= */ 0, 2000)
new AdPlaybackState(ADS_ID, /* adGroupTimesUs= */ 0, 2000)
.withAdCount(/* adGroupIndex= */ 0, /* adCount= */ 4)
.withAdCount(/* adGroupIndex= */ 1, /* adCount= */ 6);

View File

@ -570,9 +570,9 @@ public final class AdaptiveTrackSelectionTest {
TrackGroup trackGroupMultipleFixed = new TrackGroup(formatFixed1, formatFixed2);
TrackGroup trackGroupAdaptive =
new TrackGroup(formatAdaptive1, formatAdaptive2, formatAdaptive3, formatAdaptive4);
Definition definitionFixed1 = new Definition(trackGroupMultipleFixed, /* tracks...= */ 0);
Definition definitionFixed2 = new Definition(trackGroupMultipleFixed, /* tracks...= */ 1);
Definition definitionAdaptive = new Definition(trackGroupAdaptive, /* tracks...= */ 1, 2, 3);
Definition definitionFixed1 = new Definition(trackGroupMultipleFixed, /* tracks= */ 0);
Definition definitionFixed2 = new Definition(trackGroupMultipleFixed, /* tracks= */ 1);
Definition definitionAdaptive = new Definition(trackGroupAdaptive, /* tracks= */ 1, 2, 3);
List<List<AdaptationCheckpoint>> checkPoints = new ArrayList<>();
AdaptiveTrackSelection.Factory factory =
new AdaptiveTrackSelection.Factory() {
@ -621,9 +621,9 @@ public final class AdaptiveTrackSelectionTest {
TrackGroup trackGroup2 =
new TrackGroup(group2Format1, group2Format2, group2Format3, group2UnusedFormat);
TrackGroup fixedGroup = new TrackGroup(fixedFormat);
Definition definition1 = new Definition(trackGroup1, /* tracks...= */ 0, 1);
Definition definition2 = new Definition(trackGroup2, /* tracks...= */ 0, 1, 2);
Definition fixedDefinition = new Definition(fixedGroup, /* tracks...= */ 0);
Definition definition1 = new Definition(trackGroup1, /* tracks= */ 0, 1);
Definition definition2 = new Definition(trackGroup2, /* tracks= */ 0, 1, 2);
Definition fixedDefinition = new Definition(fixedGroup, /* tracks= */ 0);
List<List<AdaptationCheckpoint>> checkPoints = new ArrayList<>();
AdaptiveTrackSelection.Factory factory =
new AdaptiveTrackSelection.Factory() {

View File

@ -2171,10 +2171,8 @@ public final class DefaultTrackSelectorTest {
TIMELINE);
assertThat(result.length).isEqualTo(2);
assertAdaptiveSelection(
result.selections[0], trackGroups.get(0), /* expectedTracks...= */ 1, 0);
assertAdaptiveSelection(
result.selections[1], trackGroups.get(1), /* expectedTracks...= */ 1, 0);
assertAdaptiveSelection(result.selections[0], trackGroups.get(0), /* expectedTracks= */ 1, 0);
assertAdaptiveSelection(result.selections[1], trackGroups.get(1), /* expectedTracks= */ 1, 0);
// Multiple adaptive selection disallowed.
trackSelector.setParameters(
@ -2187,8 +2185,7 @@ public final class DefaultTrackSelectorTest {
TIMELINE);
assertThat(result.length).isEqualTo(2);
assertAdaptiveSelection(
result.selections[0], trackGroups.get(0), /* expectedTracks...= */ 1, 0);
assertAdaptiveSelection(result.selections[0], trackGroups.get(0), /* expectedTracks= */ 1, 0);
assertFixedSelection(result.selections[1], trackGroups.get(1), /* expectedTrack= */ 1);
}
@ -2232,7 +2229,7 @@ public final class DefaultTrackSelectorTest {
trackSelector.selectTracks(
new RendererCapabilities[] {VIDEO_CAPABILITIES}, trackGroups, periodId, TIMELINE);
assertThat(result.length).isEqualTo(1);
assertAdaptiveSelection(result.selections[0], adaptiveGroup, /* expectedTracks...= */ 1, 0);
assertAdaptiveSelection(result.selections[0], adaptiveGroup, /* expectedTracks= */ 1, 0);
// Select default (=most tracks) if no preference is specified.
trackSelector.setParameters(defaultParameters.buildUpon().setPreferredVideoMimeType(null));
@ -2240,7 +2237,7 @@ public final class DefaultTrackSelectorTest {
trackSelector.selectTracks(
new RendererCapabilities[] {VIDEO_CAPABILITIES}, trackGroups, periodId, TIMELINE);
assertThat(result.length).isEqualTo(1);
assertAdaptiveSelection(result.selections[0], adaptiveGroup, /* expectedTracks...= */ 1, 0);
assertAdaptiveSelection(result.selections[0], adaptiveGroup, /* expectedTracks= */ 1, 0);
}
/**
@ -2419,7 +2416,7 @@ public final class DefaultTrackSelectorTest {
@Test
public void roundTripViaBundle_ofSelectionOverride_yieldsEqualInstance() {
SelectionOverride selectionOverrideToBundle =
new SelectionOverride(/* groupIndex= */ 1, /* tracks...= */ 2, 3);
new SelectionOverride(/* groupIndex= */ 1, /* tracks= */ 2, 3);
SelectionOverride selectionOverrideFromBundle =
DefaultTrackSelector.SelectionOverride.CREATOR.fromBundle(

View File

@ -447,7 +447,9 @@ public final class DefaultExtractorsFactory implements ExtractorsFactory {
@Nullable
private static Constructor<? extends Extractor> getFlacExtractorConstructor()
throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException,
throws ClassNotFoundException,
NoSuchMethodException,
InvocationTargetException,
IllegalAccessException {
@SuppressWarnings("nullness:argument")
boolean isFlacNativeLibraryAvailable =
@ -468,7 +470,9 @@ public final class DefaultExtractorsFactory implements ExtractorsFactory {
public interface ConstructorSupplier {
@Nullable
Constructor<? extends Extractor> getConstructor()
throws InvocationTargetException, IllegalAccessException, NoSuchMethodException,
throws InvocationTargetException,
IllegalAccessException,
NoSuchMethodException,
ClassNotFoundException;
}

View File

@ -687,7 +687,7 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsPlaylistTracker.Pla
sampleStreamWrapper.prepareWithMultivariantPlaylistInfo(
muxedTrackGroups.toArray(new TrackGroup[0]),
/* primaryTrackGroupIndex= */ 0,
/* optionalTrackGroupsIndices...= */ muxedTrackGroups.indexOf(id3TrackGroup));
/* optionalTrackGroupsIndices= */ muxedTrackGroups.indexOf(id3TrackGroup));
}
}

View File

@ -67,7 +67,7 @@ public class FakeTrackSelector extends DefaultTrackSelector {
boolean hasTracks = trackGroupArray.length > 0;
definitions[i] =
hasTracks
? new ExoTrackSelection.Definition(trackGroupArray.get(0), /* tracks...= */ 0)
? new ExoTrackSelection.Definition(trackGroupArray.get(0), /* tracks= */ 0)
: null;
}
return definitions;

View File

@ -39,7 +39,7 @@ public class FakeTimelineTest {
FakeTimeline.createMultiPeriodAdTimeline(
windowId,
numberOfPlayedAds,
/* isAdPeriodFlags...= */ true,
/* isAdPeriodFlags= */ true,
false,
true,
true,
@ -94,7 +94,7 @@ public class FakeTimelineTest {
FakeTimeline.createMultiPeriodAdTimeline(
/* windowId= */ new Object(),
/* numberOfPlayedAds= */ 0,
/* isAdPeriodFlags...= */ false,
/* isAdPeriodFlags= */ false,
true,
true,
false);