blob: 5fa9ae082fce20513a6179cc6648174e30e7b2f7 [file] [log] [blame]
/*
* Copyright (C) 2018 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.offline;
import static com.google.common.truth.Truth.assertThat;
import static org.robolectric.shadows.ShadowBaseLooper.shadowMainLooper;
import android.net.Uri;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.Renderer;
import com.google.android.exoplayer2.RenderersFactory;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.offline.DownloadHelper.Callback;
import com.google.android.exoplayer2.source.MediaPeriod;
import com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispatcher;
import com.google.android.exoplayer2.source.TrackGroup;
import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.android.exoplayer2.testutil.FakeMediaPeriod;
import com.google.android.exoplayer2.testutil.FakeMediaSource;
import com.google.android.exoplayer2.testutil.FakeRenderer;
import com.google.android.exoplayer2.testutil.FakeTimeline;
import com.google.android.exoplayer2.testutil.FakeTimeline.TimelineWindowDefinition;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
import com.google.android.exoplayer2.trackselection.MappingTrackSelector.MappedTrackInfo;
import com.google.android.exoplayer2.trackselection.TrackSelection;
import com.google.android.exoplayer2.upstream.Allocator;
import com.google.android.exoplayer2.util.MimeTypes;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.annotation.LooperMode;
/** Unit tests for {@link DownloadHelper}. */
@RunWith(AndroidJUnit4.class)
@LooperMode(LooperMode.Mode.PAUSED)
public class DownloadHelperTest {
private static final String TEST_DOWNLOAD_TYPE = "downloadType";
private static final String TEST_CACHE_KEY = "cacheKey";
private static final Object TEST_MANIFEST = new Object();
private static final Timeline TEST_TIMELINE =
new FakeTimeline(
new Object[] {TEST_MANIFEST},
new TimelineWindowDefinition(/* periodCount= */ 2, /* id= */ new Object()));
private static final Format VIDEO_FORMAT_LOW = createVideoFormat(/* bitrate= */ 200_000);
private static final Format VIDEO_FORMAT_HIGH = createVideoFormat(/* bitrate= */ 800_000);
private static Format audioFormatUs;
private static Format audioFormatZh;
private static Format textFormatUs;
private static Format textFormatZh;
private static final TrackGroup TRACK_GROUP_VIDEO_BOTH =
new TrackGroup(VIDEO_FORMAT_LOW, VIDEO_FORMAT_HIGH);
private static final TrackGroup TRACK_GROUP_VIDEO_SINGLE = new TrackGroup(VIDEO_FORMAT_LOW);
private static TrackGroup trackGroupAudioUs;
private static TrackGroup trackGroupAudioZh;
private static TrackGroup trackGroupTextUs;
private static TrackGroup trackGroupTextZh;
private static TrackGroupArray trackGroupArrayAll;
private static TrackGroupArray trackGroupArraySingle;
private static TrackGroupArray[] trackGroupArrays;
private static Uri testUri;
private DownloadHelper downloadHelper;
@BeforeClass
public static void staticSetUp() {
audioFormatUs = createAudioFormat(/* language= */ "US");
audioFormatZh = createAudioFormat(/* language= */ "ZH");
textFormatUs = createTextFormat(/* language= */ "US");
textFormatZh = createTextFormat(/* language= */ "ZH");
trackGroupAudioUs = new TrackGroup(audioFormatUs);
trackGroupAudioZh = new TrackGroup(audioFormatZh);
trackGroupTextUs = new TrackGroup(textFormatUs);
trackGroupTextZh = new TrackGroup(textFormatZh);
trackGroupArrayAll =
new TrackGroupArray(
TRACK_GROUP_VIDEO_BOTH,
trackGroupAudioUs,
trackGroupAudioZh,
trackGroupTextUs,
trackGroupTextZh);
trackGroupArraySingle =
new TrackGroupArray(TRACK_GROUP_VIDEO_SINGLE, trackGroupAudioUs);
trackGroupArrays =
new TrackGroupArray[] {trackGroupArrayAll, trackGroupArraySingle};
testUri = Uri.parse("http://test.uri");
}
@Before
public void setUp() {
FakeRenderer videoRenderer = new FakeRenderer(C.TRACK_TYPE_VIDEO);
FakeRenderer audioRenderer = new FakeRenderer(C.TRACK_TYPE_AUDIO);
FakeRenderer textRenderer = new FakeRenderer(C.TRACK_TYPE_TEXT);
RenderersFactory renderersFactory =
(handler, videoListener, audioListener, metadata, text) ->
new Renderer[] {textRenderer, audioRenderer, videoRenderer};
downloadHelper =
new DownloadHelper(
TEST_DOWNLOAD_TYPE,
testUri,
TEST_CACHE_KEY,
new TestMediaSource(),
DownloadHelper.DEFAULT_TRACK_SELECTOR_PARAMETERS_WITHOUT_VIEWPORT,
DownloadHelper.getRendererCapabilities(renderersFactory));
}
@Test
public void getManifest_returnsManifest() throws Exception {
prepareDownloadHelper(downloadHelper);
Object manifest = downloadHelper.getManifest();
assertThat(manifest).isEqualTo(TEST_MANIFEST);
}
@Test
public void getPeriodCount_returnsPeriodCount() throws Exception {
prepareDownloadHelper(downloadHelper);
int periodCount = downloadHelper.getPeriodCount();
assertThat(periodCount).isEqualTo(2);
}
@Test
public void getTrackGroups_returnsTrackGroups() throws Exception {
prepareDownloadHelper(downloadHelper);
TrackGroupArray trackGroupArrayPeriod0 = downloadHelper.getTrackGroups(/* periodIndex= */ 0);
TrackGroupArray trackGroupArrayPeriod1 = downloadHelper.getTrackGroups(/* periodIndex= */ 1);
assertThat(trackGroupArrayPeriod0).isEqualTo(trackGroupArrays[0]);
assertThat(trackGroupArrayPeriod1).isEqualTo(trackGroupArrays[1]);
}
@Test
public void getMappedTrackInfo_returnsMappedTrackInfo() throws Exception {
prepareDownloadHelper(downloadHelper);
MappedTrackInfo mappedTracks0 = downloadHelper.getMappedTrackInfo(/* periodIndex= */ 0);
MappedTrackInfo mappedTracks1 = downloadHelper.getMappedTrackInfo(/* periodIndex= */ 1);
assertThat(mappedTracks0.getRendererCount()).isEqualTo(3);
assertThat(mappedTracks0.getRendererType(/* rendererIndex= */ 0)).isEqualTo(C.TRACK_TYPE_TEXT);
assertThat(mappedTracks0.getRendererType(/* rendererIndex= */ 1)).isEqualTo(C.TRACK_TYPE_AUDIO);
assertThat(mappedTracks0.getRendererType(/* rendererIndex= */ 2)).isEqualTo(C.TRACK_TYPE_VIDEO);
assertThat(mappedTracks0.getTrackGroups(/* rendererIndex= */ 0).length).isEqualTo(2);
assertThat(mappedTracks0.getTrackGroups(/* rendererIndex= */ 1).length).isEqualTo(2);
assertThat(mappedTracks0.getTrackGroups(/* rendererIndex= */ 2).length).isEqualTo(1);
assertThat(mappedTracks0.getTrackGroups(/* rendererIndex= */ 0).get(/* index= */ 0))
.isEqualTo(trackGroupTextUs);
assertThat(mappedTracks0.getTrackGroups(/* rendererIndex= */ 0).get(/* index= */ 1))
.isEqualTo(trackGroupTextZh);
assertThat(mappedTracks0.getTrackGroups(/* rendererIndex= */ 1).get(/* index= */ 0))
.isEqualTo(trackGroupAudioUs);
assertThat(mappedTracks0.getTrackGroups(/* rendererIndex= */ 1).get(/* index= */ 1))
.isEqualTo(trackGroupAudioZh);
assertThat(mappedTracks0.getTrackGroups(/* rendererIndex= */ 2).get(/* index= */ 0))
.isEqualTo(TRACK_GROUP_VIDEO_BOTH);
assertThat(mappedTracks1.getRendererCount()).isEqualTo(3);
assertThat(mappedTracks1.getRendererType(/* rendererIndex= */ 0)).isEqualTo(C.TRACK_TYPE_TEXT);
assertThat(mappedTracks1.getRendererType(/* rendererIndex= */ 1)).isEqualTo(C.TRACK_TYPE_AUDIO);
assertThat(mappedTracks1.getRendererType(/* rendererIndex= */ 2)).isEqualTo(C.TRACK_TYPE_VIDEO);
assertThat(mappedTracks1.getTrackGroups(/* rendererIndex= */ 0).length).isEqualTo(0);
assertThat(mappedTracks1.getTrackGroups(/* rendererIndex= */ 1).length).isEqualTo(1);
assertThat(mappedTracks1.getTrackGroups(/* rendererIndex= */ 2).length).isEqualTo(1);
assertThat(mappedTracks1.getTrackGroups(/* rendererIndex= */ 1).get(/* index= */ 0))
.isEqualTo(trackGroupAudioUs);
assertThat(mappedTracks1.getTrackGroups(/* rendererIndex= */ 2).get(/* index= */ 0))
.isEqualTo(TRACK_GROUP_VIDEO_SINGLE);
}
@Test
public void getTrackSelections_returnsInitialSelection() throws Exception {
prepareDownloadHelper(downloadHelper);
List<TrackSelection> selectedText0 =
downloadHelper.getTrackSelections(/* periodIndex= */ 0, /* rendererIndex= */ 0);
List<TrackSelection> selectedAudio0 =
downloadHelper.getTrackSelections(/* periodIndex= */ 0, /* rendererIndex= */ 1);
List<TrackSelection> selectedVideo0 =
downloadHelper.getTrackSelections(/* periodIndex= */ 0, /* rendererIndex= */ 2);
List<TrackSelection> selectedText1 =
downloadHelper.getTrackSelections(/* periodIndex= */ 1, /* rendererIndex= */ 0);
List<TrackSelection> selectedAudio1 =
downloadHelper.getTrackSelections(/* periodIndex= */ 1, /* rendererIndex= */ 1);
List<TrackSelection> selectedVideo1 =
downloadHelper.getTrackSelections(/* periodIndex= */ 1, /* rendererIndex= */ 2);
assertSingleTrackSelectionEquals(selectedText0, trackGroupTextUs, 0);
assertSingleTrackSelectionEquals(selectedAudio0, trackGroupAudioUs, 0);
assertSingleTrackSelectionEquals(selectedVideo0, TRACK_GROUP_VIDEO_BOTH, 1);
assertThat(selectedText1).isEmpty();
assertSingleTrackSelectionEquals(selectedAudio1, trackGroupAudioUs, 0);
assertSingleTrackSelectionEquals(selectedVideo1, TRACK_GROUP_VIDEO_SINGLE, 0);
}
@Test
public void getTrackSelections_afterClearTrackSelections_isEmpty() throws Exception {
prepareDownloadHelper(downloadHelper);
// Clear only one period selection to verify second period selection is untouched.
downloadHelper.clearTrackSelections(/* periodIndex= */ 0);
List<TrackSelection> selectedText0 =
downloadHelper.getTrackSelections(/* periodIndex= */ 0, /* rendererIndex= */ 0);
List<TrackSelection> selectedAudio0 =
downloadHelper.getTrackSelections(/* periodIndex= */ 0, /* rendererIndex= */ 1);
List<TrackSelection> selectedVideo0 =
downloadHelper.getTrackSelections(/* periodIndex= */ 0, /* rendererIndex= */ 2);
List<TrackSelection> selectedText1 =
downloadHelper.getTrackSelections(/* periodIndex= */ 1, /* rendererIndex= */ 0);
List<TrackSelection> selectedAudio1 =
downloadHelper.getTrackSelections(/* periodIndex= */ 1, /* rendererIndex= */ 1);
List<TrackSelection> selectedVideo1 =
downloadHelper.getTrackSelections(/* periodIndex= */ 1, /* rendererIndex= */ 2);
assertThat(selectedText0).isEmpty();
assertThat(selectedAudio0).isEmpty();
assertThat(selectedVideo0).isEmpty();
// Verify
assertThat(selectedText1).isEmpty();
assertSingleTrackSelectionEquals(selectedAudio1, trackGroupAudioUs, 0);
assertSingleTrackSelectionEquals(selectedVideo1, TRACK_GROUP_VIDEO_SINGLE, 0);
}
@Test
public void getTrackSelections_afterReplaceTrackSelections_returnsNewSelections()
throws Exception {
prepareDownloadHelper(downloadHelper);
DefaultTrackSelector.Parameters parameters =
new DefaultTrackSelector.ParametersBuilder(ApplicationProvider.getApplicationContext())
.setPreferredAudioLanguage("ZH")
.setPreferredTextLanguage("ZH")
.setRendererDisabled(/* rendererIndex= */ 2, true)
.build();
// Replace only one period selection to verify second period selection is untouched.
downloadHelper.replaceTrackSelections(/* periodIndex= */ 0, parameters);
List<TrackSelection> selectedText0 =
downloadHelper.getTrackSelections(/* periodIndex= */ 0, /* rendererIndex= */ 0);
List<TrackSelection> selectedAudio0 =
downloadHelper.getTrackSelections(/* periodIndex= */ 0, /* rendererIndex= */ 1);
List<TrackSelection> selectedVideo0 =
downloadHelper.getTrackSelections(/* periodIndex= */ 0, /* rendererIndex= */ 2);
List<TrackSelection> selectedText1 =
downloadHelper.getTrackSelections(/* periodIndex= */ 1, /* rendererIndex= */ 0);
List<TrackSelection> selectedAudio1 =
downloadHelper.getTrackSelections(/* periodIndex= */ 1, /* rendererIndex= */ 1);
List<TrackSelection> selectedVideo1 =
downloadHelper.getTrackSelections(/* periodIndex= */ 1, /* rendererIndex= */ 2);
assertSingleTrackSelectionEquals(selectedText0, trackGroupTextZh, 0);
assertSingleTrackSelectionEquals(selectedAudio0, trackGroupAudioZh, 0);
assertThat(selectedVideo0).isEmpty();
assertThat(selectedText1).isEmpty();
assertSingleTrackSelectionEquals(selectedAudio1, trackGroupAudioUs, 0);
assertSingleTrackSelectionEquals(selectedVideo1, TRACK_GROUP_VIDEO_SINGLE, 0);
}
@Test
public void getTrackSelections_afterAddTrackSelections_returnsCombinedSelections()
throws Exception {
prepareDownloadHelper(downloadHelper);
// Select parameters to require some merging of track groups because the new parameters add
// all video tracks to initial video single track selection.
DefaultTrackSelector.Parameters parameters =
new DefaultTrackSelector.ParametersBuilder(ApplicationProvider.getApplicationContext())
.setPreferredAudioLanguage("ZH")
.setPreferredTextLanguage("US")
.build();
// Add only to one period selection to verify second period selection is untouched.
downloadHelper.addTrackSelection(/* periodIndex= */ 0, parameters);
List<TrackSelection> selectedText0 =
downloadHelper.getTrackSelections(/* periodIndex= */ 0, /* rendererIndex= */ 0);
List<TrackSelection> selectedAudio0 =
downloadHelper.getTrackSelections(/* periodIndex= */ 0, /* rendererIndex= */ 1);
List<TrackSelection> selectedVideo0 =
downloadHelper.getTrackSelections(/* periodIndex= */ 0, /* rendererIndex= */ 2);
List<TrackSelection> selectedText1 =
downloadHelper.getTrackSelections(/* periodIndex= */ 1, /* rendererIndex= */ 0);
List<TrackSelection> selectedAudio1 =
downloadHelper.getTrackSelections(/* periodIndex= */ 1, /* rendererIndex= */ 1);
List<TrackSelection> selectedVideo1 =
downloadHelper.getTrackSelections(/* periodIndex= */ 1, /* rendererIndex= */ 2);
assertSingleTrackSelectionEquals(selectedText0, trackGroupTextUs, 0);
assertThat(selectedAudio0).hasSize(2);
assertTrackSelectionEquals(selectedAudio0.get(0), trackGroupAudioUs, 0);
assertTrackSelectionEquals(selectedAudio0.get(1), trackGroupAudioZh, 0);
assertSingleTrackSelectionEquals(selectedVideo0, TRACK_GROUP_VIDEO_BOTH, 0, 1);
assertThat(selectedText1).isEmpty();
assertSingleTrackSelectionEquals(selectedAudio1, trackGroupAudioUs, 0);
assertSingleTrackSelectionEquals(selectedVideo1, TRACK_GROUP_VIDEO_SINGLE, 0);
}
@Test
public void getTrackSelections_afterAddAudioLanguagesToSelection_returnsCombinedSelections()
throws Exception {
prepareDownloadHelper(downloadHelper);
downloadHelper.clearTrackSelections(/* periodIndex= */ 0);
downloadHelper.clearTrackSelections(/* periodIndex= */ 1);
// Add a non-default language, and a non-existing language (which will select the default).
downloadHelper.addAudioLanguagesToSelection("ZH", "Klingonese");
List<TrackSelection> selectedText0 =
downloadHelper.getTrackSelections(/* periodIndex= */ 0, /* rendererIndex= */ 0);
List<TrackSelection> selectedAudio0 =
downloadHelper.getTrackSelections(/* periodIndex= */ 0, /* rendererIndex= */ 1);
List<TrackSelection> selectedVideo0 =
downloadHelper.getTrackSelections(/* periodIndex= */ 0, /* rendererIndex= */ 2);
List<TrackSelection> selectedText1 =
downloadHelper.getTrackSelections(/* periodIndex= */ 1, /* rendererIndex= */ 0);
List<TrackSelection> selectedAudio1 =
downloadHelper.getTrackSelections(/* periodIndex= */ 1, /* rendererIndex= */ 1);
List<TrackSelection> selectedVideo1 =
downloadHelper.getTrackSelections(/* periodIndex= */ 1, /* rendererIndex= */ 2);
assertThat(selectedVideo0).isEmpty();
assertThat(selectedText0).isEmpty();
assertThat(selectedAudio0).hasSize(2);
assertTrackSelectionEquals(selectedAudio0.get(0), trackGroupAudioZh, 0);
assertTrackSelectionEquals(selectedAudio0.get(1), trackGroupAudioUs, 0);
assertThat(selectedVideo1).isEmpty();
assertThat(selectedText1).isEmpty();
assertSingleTrackSelectionEquals(selectedAudio1, trackGroupAudioUs, 0);
}
@Test
public void getTrackSelections_afterAddTextLanguagesToSelection_returnsCombinedSelections()
throws Exception {
prepareDownloadHelper(downloadHelper);
downloadHelper.clearTrackSelections(/* periodIndex= */ 0);
downloadHelper.clearTrackSelections(/* periodIndex= */ 1);
// Add a non-default language, and a non-existing language (which will select the default).
downloadHelper.addTextLanguagesToSelection(
/* selectUndeterminedTextLanguage= */ true, "ZH", "Klingonese");
List<TrackSelection> selectedText0 =
downloadHelper.getTrackSelections(/* periodIndex= */ 0, /* rendererIndex= */ 0);
List<TrackSelection> selectedAudio0 =
downloadHelper.getTrackSelections(/* periodIndex= */ 0, /* rendererIndex= */ 1);
List<TrackSelection> selectedVideo0 =
downloadHelper.getTrackSelections(/* periodIndex= */ 0, /* rendererIndex= */ 2);
List<TrackSelection> selectedText1 =
downloadHelper.getTrackSelections(/* periodIndex= */ 1, /* rendererIndex= */ 0);
List<TrackSelection> selectedAudio1 =
downloadHelper.getTrackSelections(/* periodIndex= */ 1, /* rendererIndex= */ 1);
List<TrackSelection> selectedVideo1 =
downloadHelper.getTrackSelections(/* periodIndex= */ 1, /* rendererIndex= */ 2);
assertThat(selectedVideo0).isEmpty();
assertThat(selectedAudio0).isEmpty();
assertThat(selectedText0).hasSize(2);
assertTrackSelectionEquals(selectedText0.get(0), trackGroupTextZh, 0);
assertTrackSelectionEquals(selectedText0.get(1), trackGroupTextUs, 0);
assertThat(selectedVideo1).isEmpty();
assertThat(selectedAudio1).isEmpty();
assertThat(selectedText1).isEmpty();
}
@Test
public void getDownloadRequest_createsDownloadRequest_withAllSelectedTracks() throws Exception {
prepareDownloadHelper(downloadHelper);
// Ensure we have track groups with multiple indices, renderers with multiple track groups and
// also renderers without any track groups.
DefaultTrackSelector.Parameters parameters =
new DefaultTrackSelector.ParametersBuilder(ApplicationProvider.getApplicationContext())
.setPreferredAudioLanguage("ZH")
.setPreferredTextLanguage("US")
.build();
downloadHelper.addTrackSelection(/* periodIndex= */ 0, parameters);
byte[] data = new byte[10];
Arrays.fill(data, (byte) 123);
DownloadRequest downloadRequest = downloadHelper.getDownloadRequest(data);
assertThat(downloadRequest.type).isEqualTo(TEST_DOWNLOAD_TYPE);
assertThat(downloadRequest.uri).isEqualTo(testUri);
assertThat(downloadRequest.customCacheKey).isEqualTo(TEST_CACHE_KEY);
assertThat(downloadRequest.data).isEqualTo(data);
assertThat(downloadRequest.streamKeys)
.containsExactly(
new StreamKey(/* periodIndex= */ 0, /* groupIndex= */ 0, /* trackIndex= */ 0),
new StreamKey(/* periodIndex= */ 0, /* groupIndex= */ 0, /* trackIndex= */ 1),
new StreamKey(/* periodIndex= */ 0, /* groupIndex= */ 1, /* trackIndex= */ 0),
new StreamKey(/* periodIndex= */ 0, /* groupIndex= */ 2, /* trackIndex= */ 0),
new StreamKey(/* periodIndex= */ 0, /* groupIndex= */ 3, /* trackIndex= */ 0),
new StreamKey(/* periodIndex= */ 1, /* groupIndex= */ 0, /* trackIndex= */ 0),
new StreamKey(/* periodIndex= */ 1, /* groupIndex= */ 1, /* trackIndex= */ 0));
}
private static void prepareDownloadHelper(DownloadHelper downloadHelper) throws Exception {
AtomicReference<Exception> prepareException = new AtomicReference<>(null);
CountDownLatch preparedLatch = new CountDownLatch(1);
downloadHelper.prepare(
new Callback() {
@Override
public void onPrepared(DownloadHelper helper) {
preparedLatch.countDown();
}
@Override
public void onPrepareError(DownloadHelper helper, IOException e) {
prepareException.set(e);
preparedLatch.countDown();
}
});
while (!preparedLatch.await(0, TimeUnit.MILLISECONDS)) {
shadowMainLooper().idleFor(shadowMainLooper().getNextScheduledTaskTime());
}
if (prepareException.get() != null) {
throw prepareException.get();
}
}
private static Format createVideoFormat(int bitrate) {
return new Format.Builder()
.setSampleMimeType(MimeTypes.VIDEO_H264)
.setAverageBitrate(bitrate)
.build();
}
private static Format createAudioFormat(String language) {
return new Format.Builder()
.setSampleMimeType(MimeTypes.AUDIO_AAC)
.setLanguage(language)
.build();
}
private static Format createTextFormat(String language) {
return new Format.Builder()
.setSampleMimeType(MimeTypes.TEXT_VTT)
.setSelectionFlags(C.SELECTION_FLAG_DEFAULT)
.setLanguage(language)
.build();
}
private static void assertSingleTrackSelectionEquals(
List<TrackSelection> trackSelectionList, TrackGroup trackGroup, int... tracks) {
assertThat(trackSelectionList).hasSize(1);
assertTrackSelectionEquals(trackSelectionList.get(0), trackGroup, tracks);
}
private static void assertTrackSelectionEquals(
TrackSelection trackSelection, TrackGroup trackGroup, int... tracks) {
assertThat(trackSelection.getTrackGroup()).isEqualTo(trackGroup);
assertThat(trackSelection.length()).isEqualTo(tracks.length);
int[] selectedTracksInGroup = new int[trackSelection.length()];
for (int i = 0; i < trackSelection.length(); i++) {
selectedTracksInGroup[i] = trackSelection.getIndexInTrackGroup(i);
}
Arrays.sort(selectedTracksInGroup);
Arrays.sort(tracks);
assertThat(selectedTracksInGroup).isEqualTo(tracks);
}
private static final class TestMediaSource extends FakeMediaSource {
public TestMediaSource() {
super(TEST_TIMELINE);
}
@Override
public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator, long startPositionUs) {
int periodIndex = TEST_TIMELINE.getIndexOfPeriod(id.periodUid);
return new FakeMediaPeriod(
trackGroupArrays[periodIndex],
new EventDispatcher()
.withParameters(/* windowIndex= */ 0, id, /* mediaTimeOffsetMs= */ 0)) {
@Override
public List<StreamKey> getStreamKeys(List<TrackSelection> trackSelections) {
List<StreamKey> result = new ArrayList<>();
for (TrackSelection trackSelection : trackSelections) {
int groupIndex =
trackGroupArrays[periodIndex].indexOf(trackSelection.getTrackGroup());
for (int i = 0; i < trackSelection.length(); i++) {
result.add(
new StreamKey(periodIndex, groupIndex, trackSelection.getIndexInTrackGroup(i)));
}
}
return result;
}
};
}
@Override
public void releasePeriod(MediaPeriod mediaPeriod) {
// Do nothing.
}
}
}