Invert DashHostedTest and inner class Builder to make the design more natural

Builder class was renamed to DashTestRunner and DashHostedTest moved
into it as an inner class.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=150307988
This commit is contained in:
eguven 2017-03-16 05:13:51 -07:00 committed by Oliver Woodman
parent 9b0d24c909
commit 2fe478ad6a
5 changed files with 579 additions and 544 deletions

View File

@ -1,449 +0,0 @@
/*
* Copyright (C) 2017 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.playbacktests.gts;
import static com.google.android.exoplayer2.C.WIDEVINE_UUID;
import android.annotation.TargetApi;
import android.app.Instrumentation;
import android.media.MediaDrm;
import android.media.UnsupportedSchemeException;
import android.net.Uri;
import android.util.Log;
import android.view.Surface;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.DefaultLoadControl;
import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.RendererCapabilities;
import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.decoder.DecoderCounters;
import com.google.android.exoplayer2.drm.DefaultDrmSessionManager;
import com.google.android.exoplayer2.drm.DrmSessionManager;
import com.google.android.exoplayer2.drm.FrameworkMediaCrypto;
import com.google.android.exoplayer2.drm.HttpMediaDrmCallback;
import com.google.android.exoplayer2.drm.MediaDrmCallback;
import com.google.android.exoplayer2.drm.UnsupportedDrmException;
import com.google.android.exoplayer2.mediacodec.MediaCodecUtil;
import com.google.android.exoplayer2.playbacktests.util.ActionSchedule;
import com.google.android.exoplayer2.playbacktests.util.DebugSimpleExoPlayer;
import com.google.android.exoplayer2.playbacktests.util.DecoderCountersUtil;
import com.google.android.exoplayer2.playbacktests.util.ExoHostedTest;
import com.google.android.exoplayer2.playbacktests.util.HostActivity;
import com.google.android.exoplayer2.playbacktests.util.HostActivity.HostedTest;
import com.google.android.exoplayer2.playbacktests.util.MetricsLogger;
import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.source.TrackGroup;
import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.android.exoplayer2.source.dash.DashMediaSource;
import com.google.android.exoplayer2.source.dash.DefaultDashChunkSource;
import com.google.android.exoplayer2.trackselection.FixedTrackSelection;
import com.google.android.exoplayer2.trackselection.MappingTrackSelector;
import com.google.android.exoplayer2.trackselection.RandomTrackSelection;
import com.google.android.exoplayer2.trackselection.TrackSelection;
import com.google.android.exoplayer2.upstream.BandwidthMeter;
import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
import com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory;
import com.google.android.exoplayer2.upstream.TransferListener;
import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.Util;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import junit.framework.AssertionFailedError;
/**
* A {@link HostedTest} for DASH playback tests.
*/
@TargetApi(16)
public final class DashHostedTest extends ExoHostedTest {
/** {@link DashHostedTest} builder. */
public static final class Builder {
private static final long TEST_TIMEOUT_MS = 5 * 60 * 1000;
private static final String REPORT_NAME = "GtsExoPlayerTestCases";
private static final String REPORT_OBJECT_NAME = "playbacktest";
// Whether adaptive tests should enable video formats beyond those mandated by the Android CDD
// if the device advertises support for them.
private static final boolean ALLOW_ADDITIONAL_VIDEO_FORMATS = Util.SDK_INT >= 24;
private final String tag;
private String streamName;
private boolean fullPlaybackNoSeeking;
private String audioFormat;
private boolean canIncludeAdditionalVideoFormats;
private ActionSchedule actionSchedule;
private byte[] offlineLicenseKeySetId;
private String[] videoFormats;
private String manifestUrl;
private boolean useL1Widevine;
private String widevineLicenseUrl;
public Builder(String tag) {
this.tag = tag;
}
public Builder setStreamName(String streamName) {
this.streamName = streamName;
return this;
}
public Builder setFullPlaybackNoSeeking(boolean fullPlaybackNoSeeking) {
this.fullPlaybackNoSeeking = fullPlaybackNoSeeking;
return this;
}
public Builder setCanIncludeAdditionalVideoFormats(
boolean canIncludeAdditionalVideoFormats) {
this.canIncludeAdditionalVideoFormats = canIncludeAdditionalVideoFormats
&& ALLOW_ADDITIONAL_VIDEO_FORMATS;
return this;
}
public Builder setActionSchedule(ActionSchedule actionSchedule) {
this.actionSchedule = actionSchedule;
return this;
}
public Builder setOfflineLicenseKeySetId(byte[] offlineLicenseKeySetId) {
this.offlineLicenseKeySetId = offlineLicenseKeySetId;
return this;
}
public Builder setAudioVideoFormats(String audioFormat, String... videoFormats) {
this.audioFormat = audioFormat;
this.videoFormats = videoFormats;
return this;
}
public Builder setManifestUrl(String manifestUrl) {
this.manifestUrl = manifestUrl;
return this;
}
public Builder setWidevineMimeType(String mimeType) {
this.useL1Widevine = isL1WidevineAvailable(mimeType);
this.widevineLicenseUrl = getWidevineLicenseUrl(useL1Widevine);
return this;
}
private DashHostedTest createDashHostedTest(boolean canIncludeAdditionalVideoFormats,
boolean isCddLimitedRetry, Instrumentation instrumentation) {
MetricsLogger metricsLogger = MetricsLogger.Factory.createDefault(instrumentation, tag,
REPORT_NAME, REPORT_OBJECT_NAME);
return new DashHostedTest(tag, streamName, manifestUrl, metricsLogger, fullPlaybackNoSeeking,
audioFormat, canIncludeAdditionalVideoFormats, isCddLimitedRetry, actionSchedule,
offlineLicenseKeySetId, widevineLicenseUrl, useL1Widevine, videoFormats);
}
public void runTest(HostActivity activity, Instrumentation instrumentation) {
DashHostedTest test = createDashHostedTest(canIncludeAdditionalVideoFormats, false,
instrumentation);
activity.runTest(test, TEST_TIMEOUT_MS);
// Retry test exactly once if adaptive test fails due to excessive dropped buffers when
// playing non-CDD required formats (b/28220076).
if (test.needsCddLimitedRetry) {
activity.runTest(createDashHostedTest(false, true, instrumentation), TEST_TIMEOUT_MS);
}
}
}
private static final String AUDIO_TAG_SUFFIX = ":Audio";
private static final String VIDEO_TAG_SUFFIX = ":Video";
static final int VIDEO_RENDERER_INDEX = 0;
static final int AUDIO_RENDERER_INDEX = 1;
private static final int MIN_LOADABLE_RETRY_COUNT = 10;
private static final int MAX_CONSECUTIVE_DROPPED_VIDEO_FRAMES = 10;
private static final float MAX_DROPPED_VIDEO_FRAME_FRACTION = 0.01f;
private static final String WIDEVINE_LICENSE_URL =
"https://proxy.uat.widevine.com/proxy?provider=widevine_test&video_id=";
private static final String WIDEVINE_SW_CRYPTO_CONTENT_ID = "exoplayer_test_1";
private static final String WIDEVINE_HW_SECURE_DECODE_CONTENT_ID = "exoplayer_test_2";
private static final String WIDEVINE_SECURITY_LEVEL_1 = "L1";
private static final String WIDEVINE_SECURITY_LEVEL_3 = "L3";
private static final String SECURITY_LEVEL_PROPERTY = "securityLevel";
private final String streamName;
private final String manifestUrl;
private final MetricsLogger metricsLogger;
private final boolean fullPlaybackNoSeeking;
private final boolean isCddLimitedRetry;
private final DashTestTrackSelector trackSelector;
private final byte[] offlineLicenseKeySetId;
private final String widevineLicenseUrl;
private final boolean useL1Widevine;
boolean needsCddLimitedRetry;
public static String getWidevineLicenseUrl(boolean useL1Widevine) {
return WIDEVINE_LICENSE_URL
+ (useL1Widevine ? WIDEVINE_HW_SECURE_DECODE_CONTENT_ID : WIDEVINE_SW_CRYPTO_CONTENT_ID);
}
@TargetApi(18)
@SuppressWarnings("ResourceType")
public static boolean isL1WidevineAvailable(String mimeType) {
try {
// Force L3 if secure decoder is not available.
if (MediaCodecUtil.getDecoderInfo(mimeType, true) == null) {
return false;
}
MediaDrm mediaDrm = new MediaDrm(WIDEVINE_UUID);
String securityProperty = mediaDrm.getPropertyString(SECURITY_LEVEL_PROPERTY);
mediaDrm.release();
return WIDEVINE_SECURITY_LEVEL_1.equals(securityProperty);
} catch (MediaCodecUtil.DecoderQueryException | UnsupportedSchemeException e) {
throw new IllegalStateException(e);
}
}
/**
* @param tag A tag to use for logging.
* @param streamName The name of the test stream for metric logging.
* @param manifestUrl The manifest url.
* @param metricsLogger Logger to log metrics from the test.
* @param fullPlaybackNoSeeking Whether the test will play the entire source with no seeking.
* @param audioFormat The audio format.
* @param canIncludeAdditionalVideoFormats Whether to use video formats in addition to those
* listed in the videoFormats argument, if the device is capable of playing them.
* @param isCddLimitedRetry Whether this is a CDD limited retry following a previous failure.
* @param actionSchedule The action schedule for the test.
* @param offlineLicenseKeySetId The key set id of the license to be used.
* @param widevineLicenseUrl If the video is Widevine encrypted, this is the license url
* otherwise null.
* @param useL1Widevine Whether to use L1 Widevine.
* @param videoFormats The video formats.
*/
private DashHostedTest(String tag, String streamName, String manifestUrl,
MetricsLogger metricsLogger, boolean fullPlaybackNoSeeking, String audioFormat,
boolean canIncludeAdditionalVideoFormats, boolean isCddLimitedRetry,
ActionSchedule actionSchedule, byte[] offlineLicenseKeySetId, String widevineLicenseUrl,
boolean useL1Widevine, String... videoFormats) {
super(tag, fullPlaybackNoSeeking);
Assertions.checkArgument(!(isCddLimitedRetry && canIncludeAdditionalVideoFormats));
this.streamName = streamName;
this.manifestUrl = manifestUrl;
this.metricsLogger = metricsLogger;
this.fullPlaybackNoSeeking = fullPlaybackNoSeeking;
this.isCddLimitedRetry = isCddLimitedRetry;
this.offlineLicenseKeySetId = offlineLicenseKeySetId;
this.widevineLicenseUrl = widevineLicenseUrl;
this.useL1Widevine = useL1Widevine;
trackSelector = new DashTestTrackSelector(tag, audioFormat, videoFormats,
canIncludeAdditionalVideoFormats);
if (actionSchedule != null) {
setSchedule(actionSchedule);
}
}
@Override
protected MappingTrackSelector buildTrackSelector(HostActivity host,
BandwidthMeter bandwidthMeter) {
return trackSelector;
}
@Override
protected DefaultDrmSessionManager<FrameworkMediaCrypto> buildDrmSessionManager(
final String userAgent) {
if (widevineLicenseUrl == null) {
return null;
}
try {
MediaDrmCallback drmCallback = new HttpMediaDrmCallback(widevineLicenseUrl,
new DefaultHttpDataSourceFactory(userAgent));
DefaultDrmSessionManager<FrameworkMediaCrypto> drmSessionManager =
DefaultDrmSessionManager.newWidevineInstance(drmCallback, null, null, null);
if (!useL1Widevine) {
drmSessionManager.setPropertyString(
SECURITY_LEVEL_PROPERTY, WIDEVINE_SECURITY_LEVEL_3);
}
if (offlineLicenseKeySetId != null) {
drmSessionManager.setMode(DefaultDrmSessionManager.MODE_PLAYBACK,
offlineLicenseKeySetId);
}
return drmSessionManager;
} catch (UnsupportedDrmException e) {
throw new IllegalStateException(e);
}
}
@Override
protected SimpleExoPlayer buildExoPlayer(HostActivity host, Surface surface,
MappingTrackSelector trackSelector,
DrmSessionManager<FrameworkMediaCrypto> drmSessionManager) {
SimpleExoPlayer player = new DebugSimpleExoPlayer(host, trackSelector,
new DefaultLoadControl(), drmSessionManager);
player.setVideoSurface(surface);
return player;
}
@Override
protected MediaSource buildSource(HostActivity host, String userAgent,
TransferListener<? super DataSource> mediaTransferListener) {
DataSource.Factory manifestDataSourceFactory = new DefaultDataSourceFactory(host, userAgent);
DataSource.Factory mediaDataSourceFactory = new DefaultDataSourceFactory(host, userAgent,
mediaTransferListener);
Uri manifestUri = Uri.parse(manifestUrl);
DefaultDashChunkSource.Factory chunkSourceFactory = new DefaultDashChunkSource.Factory(
mediaDataSourceFactory);
return new DashMediaSource(manifestUri, manifestDataSourceFactory, chunkSourceFactory,
MIN_LOADABLE_RETRY_COUNT, 0 /* livePresentationDelayMs */, null, null);
}
@Override
protected void logMetrics(DecoderCounters audioCounters, DecoderCounters videoCounters) {
metricsLogger.logMetric(MetricsLogger.KEY_TEST_NAME, streamName);
metricsLogger.logMetric(MetricsLogger.KEY_IS_CDD_LIMITED_RETRY, isCddLimitedRetry);
metricsLogger.logMetric(MetricsLogger.KEY_FRAMES_DROPPED_COUNT,
videoCounters.droppedOutputBufferCount);
metricsLogger.logMetric(MetricsLogger.KEY_MAX_CONSECUTIVE_FRAMES_DROPPED_COUNT,
videoCounters.maxConsecutiveDroppedOutputBufferCount);
metricsLogger.logMetric(MetricsLogger.KEY_FRAMES_SKIPPED_COUNT,
videoCounters.skippedOutputBufferCount);
metricsLogger.logMetric(MetricsLogger.KEY_FRAMES_RENDERED_COUNT,
videoCounters.renderedOutputBufferCount);
metricsLogger.close();
}
@Override
protected void assertPassed(DecoderCounters audioCounters, DecoderCounters videoCounters) {
if (fullPlaybackNoSeeking) {
// We shouldn't have skipped any output buffers.
DecoderCountersUtil.assertSkippedOutputBufferCount(tag + AUDIO_TAG_SUFFIX, audioCounters, 0);
DecoderCountersUtil.assertSkippedOutputBufferCount(tag + VIDEO_TAG_SUFFIX, videoCounters, 0);
// We allow one fewer output buffer due to the way that MediaCodecRenderer and the
// underlying decoders handle the end of stream. This should be tightened up in the future.
DecoderCountersUtil.assertTotalOutputBufferCount(tag + AUDIO_TAG_SUFFIX, audioCounters,
audioCounters.inputBufferCount - 1, audioCounters.inputBufferCount);
DecoderCountersUtil.assertTotalOutputBufferCount(tag + VIDEO_TAG_SUFFIX, videoCounters,
videoCounters.inputBufferCount - 1, videoCounters.inputBufferCount);
}
try {
int droppedFrameLimit = (int) Math.ceil(MAX_DROPPED_VIDEO_FRAME_FRACTION
* DecoderCountersUtil.getTotalOutputBuffers(videoCounters));
// Assert that performance is acceptable.
// Assert that total dropped frames were within limit.
DecoderCountersUtil.assertDroppedOutputBufferLimit(tag + VIDEO_TAG_SUFFIX, videoCounters,
droppedFrameLimit);
// Assert that consecutive dropped frames were within limit.
DecoderCountersUtil.assertConsecutiveDroppedOutputBufferLimit(tag + VIDEO_TAG_SUFFIX,
videoCounters, MAX_CONSECUTIVE_DROPPED_VIDEO_FRAMES);
} catch (AssertionFailedError e) {
if (trackSelector.includedAdditionalVideoFormats) {
// Retry limiting to CDD mandated formats (b/28220076).
Log.e(tag, "Too many dropped or consecutive dropped frames.", e);
needsCddLimitedRetry = true;
} else {
throw e;
}
}
}
private static final class DashTestTrackSelector extends MappingTrackSelector {
private final String tag;
private final String audioFormatId;
private final String[] videoFormatIds;
private final boolean canIncludeAdditionalVideoFormats;
public boolean includedAdditionalVideoFormats;
private DashTestTrackSelector(String tag, String audioFormatId, String[] videoFormatIds,
boolean canIncludeAdditionalVideoFormats) {
this.tag = tag;
this.audioFormatId = audioFormatId;
this.videoFormatIds = videoFormatIds;
this.canIncludeAdditionalVideoFormats = canIncludeAdditionalVideoFormats;
}
@Override
protected TrackSelection[] selectTracks(RendererCapabilities[] rendererCapabilities,
TrackGroupArray[] rendererTrackGroupArrays, int[][][] rendererFormatSupports)
throws ExoPlaybackException {
Assertions.checkState(rendererCapabilities[VIDEO_RENDERER_INDEX].getTrackType()
== C.TRACK_TYPE_VIDEO);
Assertions.checkState(rendererCapabilities[AUDIO_RENDERER_INDEX].getTrackType()
== C.TRACK_TYPE_AUDIO);
Assertions.checkState(rendererTrackGroupArrays[VIDEO_RENDERER_INDEX].length == 1);
Assertions.checkState(rendererTrackGroupArrays[AUDIO_RENDERER_INDEX].length == 1);
TrackSelection[] selections = new TrackSelection[rendererCapabilities.length];
selections[VIDEO_RENDERER_INDEX] = new RandomTrackSelection(
rendererTrackGroupArrays[VIDEO_RENDERER_INDEX].get(0),
getVideoTrackIndices(rendererTrackGroupArrays[VIDEO_RENDERER_INDEX].get(0),
rendererFormatSupports[VIDEO_RENDERER_INDEX][0], videoFormatIds,
canIncludeAdditionalVideoFormats),
0 /* seed */);
selections[AUDIO_RENDERER_INDEX] = new FixedTrackSelection(
rendererTrackGroupArrays[AUDIO_RENDERER_INDEX].get(0),
getTrackIndex(rendererTrackGroupArrays[AUDIO_RENDERER_INDEX].get(0), audioFormatId));
includedAdditionalVideoFormats =
selections[VIDEO_RENDERER_INDEX].length() > videoFormatIds.length;
return selections;
}
private int[] getVideoTrackIndices(TrackGroup trackGroup, int[] formatSupport,
String[] formatIds, boolean canIncludeAdditionalFormats) {
List<Integer> trackIndices = new ArrayList<>();
// Always select explicitly listed representations.
for (String formatId : formatIds) {
int trackIndex = getTrackIndex(trackGroup, formatId);
Log.d(tag, "Adding base video format: "
+ Format.toLogString(trackGroup.getFormat(trackIndex)));
trackIndices.add(trackIndex);
}
// Select additional video representations, if supported by the device.
if (canIncludeAdditionalFormats) {
for (int i = 0; i < trackGroup.length; i++) {
if (!trackIndices.contains(i) && isFormatHandled(formatSupport[i])) {
Log.d(tag, "Adding extra video format: "
+ Format.toLogString(trackGroup.getFormat(i)));
trackIndices.add(i);
}
}
}
int[] trackIndicesArray = Util.toArray(trackIndices);
Arrays.sort(trackIndicesArray);
return trackIndicesArray;
}
private static int getTrackIndex(TrackGroup trackGroup, String formatId) {
for (int i = 0; i < trackGroup.length; i++) {
if (trackGroup.getFormat(i).id.equals(formatId)) {
return i;
}
}
throw new IllegalStateException("Format " + formatId + " not found.");
}
private static boolean isFormatHandled(int formatSupport) {
return (formatSupport & RendererCapabilities.FORMAT_SUPPORT_MASK)
== RendererCapabilities.FORMAT_HANDLED;
}
}
}

View File

@ -40,40 +40,54 @@ public final class DashTest extends ActivityInstrumentationTestCase2<HostActivit
.build(); .build();
private static final ActionSchedule RENDERER_DISABLING_SCHEDULE = new ActionSchedule.Builder(TAG) private static final ActionSchedule RENDERER_DISABLING_SCHEDULE = new ActionSchedule.Builder(TAG)
// Wait 10 seconds, disable the video renderer, wait another 10 seconds and enable it again. // Wait 10 seconds, disable the video renderer, wait another 10 seconds and enable it again.
.delay(10000).disableRenderer(DashHostedTest.VIDEO_RENDERER_INDEX) .delay(10000).disableRenderer(DashTestRunner.VIDEO_RENDERER_INDEX)
.delay(10000).enableRenderer(DashHostedTest.VIDEO_RENDERER_INDEX) .delay(10000).enableRenderer(DashTestRunner.VIDEO_RENDERER_INDEX)
// Ditto for the audio renderer. // Ditto for the audio renderer.
.delay(10000).disableRenderer(DashHostedTest.AUDIO_RENDERER_INDEX) .delay(10000).disableRenderer(DashTestRunner.AUDIO_RENDERER_INDEX)
.delay(10000).enableRenderer(DashHostedTest.AUDIO_RENDERER_INDEX) .delay(10000).enableRenderer(DashTestRunner.AUDIO_RENDERER_INDEX)
// Wait 10 seconds, then disable and enable the video renderer 5 times in quick succession. // Wait 10 seconds, then disable and enable the video renderer 5 times in quick succession.
.delay(10000).disableRenderer(DashHostedTest.VIDEO_RENDERER_INDEX) .delay(10000).disableRenderer(DashTestRunner.VIDEO_RENDERER_INDEX)
.enableRenderer(DashHostedTest.VIDEO_RENDERER_INDEX) .enableRenderer(DashTestRunner.VIDEO_RENDERER_INDEX)
.disableRenderer(DashHostedTest.VIDEO_RENDERER_INDEX) .disableRenderer(DashTestRunner.VIDEO_RENDERER_INDEX)
.enableRenderer(DashHostedTest.VIDEO_RENDERER_INDEX) .enableRenderer(DashTestRunner.VIDEO_RENDERER_INDEX)
.disableRenderer(DashHostedTest.VIDEO_RENDERER_INDEX) .disableRenderer(DashTestRunner.VIDEO_RENDERER_INDEX)
.enableRenderer(DashHostedTest.VIDEO_RENDERER_INDEX) .enableRenderer(DashTestRunner.VIDEO_RENDERER_INDEX)
.disableRenderer(DashHostedTest.VIDEO_RENDERER_INDEX) .disableRenderer(DashTestRunner.VIDEO_RENDERER_INDEX)
.enableRenderer(DashHostedTest.VIDEO_RENDERER_INDEX) .enableRenderer(DashTestRunner.VIDEO_RENDERER_INDEX)
.disableRenderer(DashHostedTest.VIDEO_RENDERER_INDEX) .disableRenderer(DashTestRunner.VIDEO_RENDERER_INDEX)
.enableRenderer(DashHostedTest.VIDEO_RENDERER_INDEX) .enableRenderer(DashTestRunner.VIDEO_RENDERER_INDEX)
// Ditto for the audio renderer. // Ditto for the audio renderer.
.delay(10000).disableRenderer(DashHostedTest.AUDIO_RENDERER_INDEX) .delay(10000).disableRenderer(DashTestRunner.AUDIO_RENDERER_INDEX)
.enableRenderer(DashHostedTest.AUDIO_RENDERER_INDEX) .enableRenderer(DashTestRunner.AUDIO_RENDERER_INDEX)
.disableRenderer(DashHostedTest.AUDIO_RENDERER_INDEX) .disableRenderer(DashTestRunner.AUDIO_RENDERER_INDEX)
.enableRenderer(DashHostedTest.AUDIO_RENDERER_INDEX) .enableRenderer(DashTestRunner.AUDIO_RENDERER_INDEX)
.disableRenderer(DashHostedTest.AUDIO_RENDERER_INDEX) .disableRenderer(DashTestRunner.AUDIO_RENDERER_INDEX)
.enableRenderer(DashHostedTest.AUDIO_RENDERER_INDEX) .enableRenderer(DashTestRunner.AUDIO_RENDERER_INDEX)
.disableRenderer(DashHostedTest.AUDIO_RENDERER_INDEX) .disableRenderer(DashTestRunner.AUDIO_RENDERER_INDEX)
.enableRenderer(DashHostedTest.AUDIO_RENDERER_INDEX) .enableRenderer(DashTestRunner.AUDIO_RENDERER_INDEX)
.disableRenderer(DashHostedTest.AUDIO_RENDERER_INDEX) .disableRenderer(DashTestRunner.AUDIO_RENDERER_INDEX)
.enableRenderer(DashHostedTest.AUDIO_RENDERER_INDEX) .enableRenderer(DashTestRunner.AUDIO_RENDERER_INDEX)
.delay(10000).seek(120000) .delay(10000).seek(120000)
.build(); .build();
private DashTestRunner testRunner;
public DashTest() { public DashTest() {
super(HostActivity.class); super(HostActivity.class);
} }
@Override
protected void setUp() throws Exception {
super.setUp();
testRunner = new DashTestRunner(TAG, getActivity(), getInstrumentation());
}
@Override
protected void tearDown() throws Exception {
testRunner = null;
super.tearDown();
}
// H264 CDD. // H264 CDD.
public void testH264Fixed() { public void testH264Fixed() {
@ -81,13 +95,13 @@ public final class DashTest extends ActivityInstrumentationTestCase2<HostActivit
// Pass. // Pass.
return; return;
} }
new DashHostedTest.Builder(TAG) testRunner
.setStreamName("test_h264_fixed") .setStreamName("test_h264_fixed")
.setManifestUrl(DashTestData.H264_MANIFEST) .setManifestUrl(DashTestData.H264_MANIFEST)
.setFullPlaybackNoSeeking(true) .setFullPlaybackNoSeeking(true)
.setCanIncludeAdditionalVideoFormats(false) .setCanIncludeAdditionalVideoFormats(false)
.setAudioVideoFormats(DashTestData.AAC_AUDIO_REPRESENTATION_ID, DashTestData.H264_CDD_FIXED) .setAudioVideoFormats(DashTestData.AAC_AUDIO_REPRESENTATION_ID, DashTestData.H264_CDD_FIXED)
.runTest(getActivity(), getInstrumentation()); .run();
} }
public void testH264Adaptive() throws DecoderQueryException { public void testH264Adaptive() throws DecoderQueryException {
@ -95,14 +109,14 @@ public final class DashTest extends ActivityInstrumentationTestCase2<HostActivit
// Pass. // Pass.
return; return;
} }
new DashHostedTest.Builder(TAG) testRunner
.setStreamName("test_h264_adaptive") .setStreamName("test_h264_adaptive")
.setManifestUrl(DashTestData.H264_MANIFEST) .setManifestUrl(DashTestData.H264_MANIFEST)
.setFullPlaybackNoSeeking(true) .setFullPlaybackNoSeeking(true)
.setCanIncludeAdditionalVideoFormats(true) .setCanIncludeAdditionalVideoFormats(true)
.setAudioVideoFormats(DashTestData.AAC_AUDIO_REPRESENTATION_ID, .setAudioVideoFormats(DashTestData.AAC_AUDIO_REPRESENTATION_ID,
DashTestData.H264_CDD_ADAPTIVE) DashTestData.H264_CDD_ADAPTIVE)
.runTest(getActivity(), getInstrumentation()); .run();
} }
public void testH264AdaptiveWithSeeking() throws DecoderQueryException { public void testH264AdaptiveWithSeeking() throws DecoderQueryException {
@ -111,7 +125,7 @@ public final class DashTest extends ActivityInstrumentationTestCase2<HostActivit
return; return;
} }
final String streamName = "test_h264_adaptive_with_seeking"; final String streamName = "test_h264_adaptive_with_seeking";
new DashHostedTest.Builder(TAG) testRunner
.setStreamName(streamName) .setStreamName(streamName)
.setManifestUrl(DashTestData.H264_MANIFEST) .setManifestUrl(DashTestData.H264_MANIFEST)
.setFullPlaybackNoSeeking(false) .setFullPlaybackNoSeeking(false)
@ -119,7 +133,7 @@ public final class DashTest extends ActivityInstrumentationTestCase2<HostActivit
.setActionSchedule(SEEKING_SCHEDULE) .setActionSchedule(SEEKING_SCHEDULE)
.setAudioVideoFormats(DashTestData.AAC_AUDIO_REPRESENTATION_ID, .setAudioVideoFormats(DashTestData.AAC_AUDIO_REPRESENTATION_ID,
DashTestData.H264_CDD_ADAPTIVE) DashTestData.H264_CDD_ADAPTIVE)
.runTest(getActivity(), getInstrumentation()); .run();
} }
public void testH264AdaptiveWithRendererDisabling() throws DecoderQueryException { public void testH264AdaptiveWithRendererDisabling() throws DecoderQueryException {
@ -128,7 +142,7 @@ public final class DashTest extends ActivityInstrumentationTestCase2<HostActivit
return; return;
} }
final String streamName = "test_h264_adaptive_with_renderer_disabling"; final String streamName = "test_h264_adaptive_with_renderer_disabling";
new DashHostedTest.Builder(TAG) testRunner
.setStreamName(streamName) .setStreamName(streamName)
.setManifestUrl(DashTestData.H264_MANIFEST) .setManifestUrl(DashTestData.H264_MANIFEST)
.setFullPlaybackNoSeeking(false) .setFullPlaybackNoSeeking(false)
@ -136,7 +150,7 @@ public final class DashTest extends ActivityInstrumentationTestCase2<HostActivit
.setActionSchedule(RENDERER_DISABLING_SCHEDULE) .setActionSchedule(RENDERER_DISABLING_SCHEDULE)
.setAudioVideoFormats(DashTestData.AAC_AUDIO_REPRESENTATION_ID, .setAudioVideoFormats(DashTestData.AAC_AUDIO_REPRESENTATION_ID,
DashTestData.H264_CDD_ADAPTIVE) DashTestData.H264_CDD_ADAPTIVE)
.runTest(getActivity(), getInstrumentation()); .run();
} }
// H265 CDD. // H265 CDD.
@ -146,13 +160,13 @@ public final class DashTest extends ActivityInstrumentationTestCase2<HostActivit
// Pass. // Pass.
return; return;
} }
new DashHostedTest.Builder(TAG) testRunner
.setStreamName("test_h265_fixed") .setStreamName("test_h265_fixed")
.setManifestUrl(DashTestData.H265_MANIFEST) .setManifestUrl(DashTestData.H265_MANIFEST)
.setFullPlaybackNoSeeking(true) .setFullPlaybackNoSeeking(true)
.setCanIncludeAdditionalVideoFormats(false) .setCanIncludeAdditionalVideoFormats(false)
.setAudioVideoFormats(DashTestData.AAC_AUDIO_REPRESENTATION_ID, DashTestData.H265_CDD_FIXED) .setAudioVideoFormats(DashTestData.AAC_AUDIO_REPRESENTATION_ID, DashTestData.H265_CDD_FIXED)
.runTest(getActivity(), getInstrumentation()); .run();
} }
public void testH265Adaptive() throws DecoderQueryException { public void testH265Adaptive() throws DecoderQueryException {
@ -160,14 +174,14 @@ public final class DashTest extends ActivityInstrumentationTestCase2<HostActivit
// Pass. // Pass.
return; return;
} }
new DashHostedTest.Builder(TAG) testRunner
.setStreamName("test_h265_adaptive") .setStreamName("test_h265_adaptive")
.setManifestUrl(DashTestData.H265_MANIFEST) .setManifestUrl(DashTestData.H265_MANIFEST)
.setFullPlaybackNoSeeking(true) .setFullPlaybackNoSeeking(true)
.setCanIncludeAdditionalVideoFormats(true) .setCanIncludeAdditionalVideoFormats(true)
.setAudioVideoFormats(DashTestData.AAC_AUDIO_REPRESENTATION_ID, .setAudioVideoFormats(DashTestData.AAC_AUDIO_REPRESENTATION_ID,
DashTestData.H265_CDD_ADAPTIVE) DashTestData.H265_CDD_ADAPTIVE)
.runTest(getActivity(), getInstrumentation()); .run();
} }
public void testH265AdaptiveWithSeeking() throws DecoderQueryException { public void testH265AdaptiveWithSeeking() throws DecoderQueryException {
@ -175,7 +189,7 @@ public final class DashTest extends ActivityInstrumentationTestCase2<HostActivit
// Pass. // Pass.
return; return;
} }
new DashHostedTest.Builder(TAG) testRunner
.setStreamName("test_h265_adaptive_with_seeking") .setStreamName("test_h265_adaptive_with_seeking")
.setManifestUrl(DashTestData.H265_MANIFEST) .setManifestUrl(DashTestData.H265_MANIFEST)
.setFullPlaybackNoSeeking(false) .setFullPlaybackNoSeeking(false)
@ -183,7 +197,7 @@ public final class DashTest extends ActivityInstrumentationTestCase2<HostActivit
.setActionSchedule(SEEKING_SCHEDULE) .setActionSchedule(SEEKING_SCHEDULE)
.setAudioVideoFormats(DashTestData.AAC_AUDIO_REPRESENTATION_ID, .setAudioVideoFormats(DashTestData.AAC_AUDIO_REPRESENTATION_ID,
DashTestData.H265_CDD_ADAPTIVE) DashTestData.H265_CDD_ADAPTIVE)
.runTest(getActivity(), getInstrumentation()); .run();
} }
public void testH265AdaptiveWithRendererDisabling() throws DecoderQueryException { public void testH265AdaptiveWithRendererDisabling() throws DecoderQueryException {
@ -191,7 +205,7 @@ public final class DashTest extends ActivityInstrumentationTestCase2<HostActivit
// Pass. // Pass.
return; return;
} }
new DashHostedTest.Builder(TAG) testRunner
.setStreamName("test_h265_adaptive_with_renderer_disabling") .setStreamName("test_h265_adaptive_with_renderer_disabling")
.setManifestUrl(DashTestData.H265_MANIFEST) .setManifestUrl(DashTestData.H265_MANIFEST)
.setFullPlaybackNoSeeking(false) .setFullPlaybackNoSeeking(false)
@ -199,7 +213,7 @@ public final class DashTest extends ActivityInstrumentationTestCase2<HostActivit
.setActionSchedule(RENDERER_DISABLING_SCHEDULE) .setActionSchedule(RENDERER_DISABLING_SCHEDULE)
.setAudioVideoFormats(DashTestData.AAC_AUDIO_REPRESENTATION_ID, .setAudioVideoFormats(DashTestData.AAC_AUDIO_REPRESENTATION_ID,
DashTestData.H265_CDD_ADAPTIVE) DashTestData.H265_CDD_ADAPTIVE)
.runTest(getActivity(), getInstrumentation()); .run();
} }
// VP9 (CDD). // VP9 (CDD).
@ -209,14 +223,14 @@ public final class DashTest extends ActivityInstrumentationTestCase2<HostActivit
// Pass. // Pass.
return; return;
} }
new DashHostedTest.Builder(TAG) testRunner
.setStreamName("test_vp9_fixed_360p") .setStreamName("test_vp9_fixed_360p")
.setManifestUrl(DashTestData.VP9_MANIFEST) .setManifestUrl(DashTestData.VP9_MANIFEST)
.setFullPlaybackNoSeeking(true) .setFullPlaybackNoSeeking(true)
.setCanIncludeAdditionalVideoFormats(false) .setCanIncludeAdditionalVideoFormats(false)
.setAudioVideoFormats(DashTestData.VP9_VORBIS_AUDIO_REPRESENTATION_ID, .setAudioVideoFormats(DashTestData.VP9_VORBIS_AUDIO_REPRESENTATION_ID,
DashTestData.VP9_CDD_FIXED) DashTestData.VP9_CDD_FIXED)
.runTest(getActivity(), getInstrumentation()); .run();
} }
public void testVp9Adaptive() throws DecoderQueryException { public void testVp9Adaptive() throws DecoderQueryException {
@ -224,14 +238,14 @@ public final class DashTest extends ActivityInstrumentationTestCase2<HostActivit
// Pass. // Pass.
return; return;
} }
new DashHostedTest.Builder(TAG) testRunner
.setStreamName("test_vp9_adaptive") .setStreamName("test_vp9_adaptive")
.setManifestUrl(DashTestData.VP9_MANIFEST) .setManifestUrl(DashTestData.VP9_MANIFEST)
.setFullPlaybackNoSeeking(true) .setFullPlaybackNoSeeking(true)
.setCanIncludeAdditionalVideoFormats(true) .setCanIncludeAdditionalVideoFormats(true)
.setAudioVideoFormats(DashTestData.VP9_VORBIS_AUDIO_REPRESENTATION_ID, .setAudioVideoFormats(DashTestData.VP9_VORBIS_AUDIO_REPRESENTATION_ID,
DashTestData.VP9_CDD_ADAPTIVE) DashTestData.VP9_CDD_ADAPTIVE)
.runTest(getActivity(), getInstrumentation()); .run();
} }
public void testVp9AdaptiveWithSeeking() throws DecoderQueryException { public void testVp9AdaptiveWithSeeking() throws DecoderQueryException {
@ -239,7 +253,7 @@ public final class DashTest extends ActivityInstrumentationTestCase2<HostActivit
// Pass. // Pass.
return; return;
} }
new DashHostedTest.Builder(TAG) testRunner
.setStreamName("test_vp9_adaptive_with_seeking") .setStreamName("test_vp9_adaptive_with_seeking")
.setManifestUrl(DashTestData.VP9_MANIFEST) .setManifestUrl(DashTestData.VP9_MANIFEST)
.setFullPlaybackNoSeeking(false) .setFullPlaybackNoSeeking(false)
@ -247,7 +261,7 @@ public final class DashTest extends ActivityInstrumentationTestCase2<HostActivit
.setActionSchedule(SEEKING_SCHEDULE) .setActionSchedule(SEEKING_SCHEDULE)
.setAudioVideoFormats(DashTestData.VP9_VORBIS_AUDIO_REPRESENTATION_ID, .setAudioVideoFormats(DashTestData.VP9_VORBIS_AUDIO_REPRESENTATION_ID,
DashTestData.VP9_CDD_ADAPTIVE) DashTestData.VP9_CDD_ADAPTIVE)
.runTest(getActivity(), getInstrumentation()); .run();
} }
public void testVp9AdaptiveWithRendererDisabling() throws DecoderQueryException { public void testVp9AdaptiveWithRendererDisabling() throws DecoderQueryException {
@ -255,7 +269,7 @@ public final class DashTest extends ActivityInstrumentationTestCase2<HostActivit
// Pass. // Pass.
return; return;
} }
new DashHostedTest.Builder(TAG) testRunner
.setStreamName("test_vp9_adaptive_with_renderer_disabling") .setStreamName("test_vp9_adaptive_with_renderer_disabling")
.setManifestUrl(DashTestData.VP9_MANIFEST) .setManifestUrl(DashTestData.VP9_MANIFEST)
.setFullPlaybackNoSeeking(false) .setFullPlaybackNoSeeking(false)
@ -263,7 +277,7 @@ public final class DashTest extends ActivityInstrumentationTestCase2<HostActivit
.setActionSchedule(RENDERER_DISABLING_SCHEDULE) .setActionSchedule(RENDERER_DISABLING_SCHEDULE)
.setAudioVideoFormats(DashTestData.VP9_VORBIS_AUDIO_REPRESENTATION_ID, .setAudioVideoFormats(DashTestData.VP9_VORBIS_AUDIO_REPRESENTATION_ID,
DashTestData.VP9_CDD_ADAPTIVE) DashTestData.VP9_CDD_ADAPTIVE)
.runTest(getActivity(), getInstrumentation()); .run();
} }
// H264: Other frame-rates for output buffer count assertions. // H264: Other frame-rates for output buffer count assertions.
@ -274,14 +288,14 @@ public final class DashTest extends ActivityInstrumentationTestCase2<HostActivit
// Pass. // Pass.
return; return;
} }
new DashHostedTest.Builder(TAG) testRunner
.setStreamName("test_23fps_h264_fixed") .setStreamName("test_23fps_h264_fixed")
.setManifestUrl(DashTestData.H264_23_MANIFEST) .setManifestUrl(DashTestData.H264_23_MANIFEST)
.setFullPlaybackNoSeeking(true) .setFullPlaybackNoSeeking(true)
.setCanIncludeAdditionalVideoFormats(false) .setCanIncludeAdditionalVideoFormats(false)
.setAudioVideoFormats(DashTestData.AAC_AUDIO_REPRESENTATION_ID, .setAudioVideoFormats(DashTestData.AAC_AUDIO_REPRESENTATION_ID,
DashTestData.H264_BASELINE_480P_23FPS_VIDEO_REPRESENTATION_ID) DashTestData.H264_BASELINE_480P_23FPS_VIDEO_REPRESENTATION_ID)
.runTest(getActivity(), getInstrumentation()); .run();
} }
// 24 fps. // 24 fps.
@ -290,14 +304,14 @@ public final class DashTest extends ActivityInstrumentationTestCase2<HostActivit
// Pass. // Pass.
return; return;
} }
new DashHostedTest.Builder(TAG) testRunner
.setStreamName("test_24fps_h264_fixed") .setStreamName("test_24fps_h264_fixed")
.setManifestUrl(DashTestData.H264_24_MANIFEST) .setManifestUrl(DashTestData.H264_24_MANIFEST)
.setFullPlaybackNoSeeking(true) .setFullPlaybackNoSeeking(true)
.setCanIncludeAdditionalVideoFormats(false) .setCanIncludeAdditionalVideoFormats(false)
.setAudioVideoFormats(DashTestData.AAC_AUDIO_REPRESENTATION_ID, .setAudioVideoFormats(DashTestData.AAC_AUDIO_REPRESENTATION_ID,
DashTestData.H264_BASELINE_480P_24FPS_VIDEO_REPRESENTATION_ID) DashTestData.H264_BASELINE_480P_24FPS_VIDEO_REPRESENTATION_ID)
.runTest(getActivity(), getInstrumentation()); .run();
} }
// 29.97 fps. // 29.97 fps.
@ -306,14 +320,14 @@ public final class DashTest extends ActivityInstrumentationTestCase2<HostActivit
// Pass. // Pass.
return; return;
} }
new DashHostedTest.Builder(TAG) testRunner
.setStreamName("test_29fps_h264_fixed") .setStreamName("test_29fps_h264_fixed")
.setManifestUrl(DashTestData.H264_29_MANIFEST) .setManifestUrl(DashTestData.H264_29_MANIFEST)
.setFullPlaybackNoSeeking(true) .setFullPlaybackNoSeeking(true)
.setCanIncludeAdditionalVideoFormats(false) .setCanIncludeAdditionalVideoFormats(false)
.setAudioVideoFormats(DashTestData.AAC_AUDIO_REPRESENTATION_ID, .setAudioVideoFormats(DashTestData.AAC_AUDIO_REPRESENTATION_ID,
DashTestData.H264_BASELINE_480P_29FPS_VIDEO_REPRESENTATION_ID) DashTestData.H264_BASELINE_480P_29FPS_VIDEO_REPRESENTATION_ID)
.runTest(getActivity(), getInstrumentation()); .run();
} }
// Widevine encrypted media tests. // Widevine encrypted media tests.
@ -324,7 +338,7 @@ public final class DashTest extends ActivityInstrumentationTestCase2<HostActivit
// Pass. // Pass.
return; return;
} }
new DashHostedTest.Builder(TAG) testRunner
.setStreamName("test_widevine_h264_fixed") .setStreamName("test_widevine_h264_fixed")
.setManifestUrl(DashTestData.WIDEVINE_H264_MANIFEST) .setManifestUrl(DashTestData.WIDEVINE_H264_MANIFEST)
.setWidevineMimeType(MimeTypes.VIDEO_H264) .setWidevineMimeType(MimeTypes.VIDEO_H264)
@ -332,7 +346,7 @@ public final class DashTest extends ActivityInstrumentationTestCase2<HostActivit
.setCanIncludeAdditionalVideoFormats(false) .setCanIncludeAdditionalVideoFormats(false)
.setAudioVideoFormats(DashTestData.WIDEVINE_AAC_AUDIO_REPRESENTATION_ID, .setAudioVideoFormats(DashTestData.WIDEVINE_AAC_AUDIO_REPRESENTATION_ID,
DashTestData.WIDEVINE_H264_CDD_FIXED) DashTestData.WIDEVINE_H264_CDD_FIXED)
.runTest(getActivity(), getInstrumentation()); .run();
} }
public void testWidevineH264Adaptive() throws DecoderQueryException { public void testWidevineH264Adaptive() throws DecoderQueryException {
@ -340,7 +354,7 @@ public final class DashTest extends ActivityInstrumentationTestCase2<HostActivit
// Pass. // Pass.
return; return;
} }
new DashHostedTest.Builder(TAG) testRunner
.setStreamName("test_widevine_h264_adaptive") .setStreamName("test_widevine_h264_adaptive")
.setManifestUrl(DashTestData.WIDEVINE_H264_MANIFEST) .setManifestUrl(DashTestData.WIDEVINE_H264_MANIFEST)
.setWidevineMimeType(MimeTypes.VIDEO_H264) .setWidevineMimeType(MimeTypes.VIDEO_H264)
@ -348,7 +362,7 @@ public final class DashTest extends ActivityInstrumentationTestCase2<HostActivit
.setCanIncludeAdditionalVideoFormats(true) .setCanIncludeAdditionalVideoFormats(true)
.setAudioVideoFormats(DashTestData.WIDEVINE_AAC_AUDIO_REPRESENTATION_ID, .setAudioVideoFormats(DashTestData.WIDEVINE_AAC_AUDIO_REPRESENTATION_ID,
DashTestData.WIDEVINE_H264_CDD_ADAPTIVE) DashTestData.WIDEVINE_H264_CDD_ADAPTIVE)
.runTest(getActivity(), getInstrumentation()); .run();
} }
public void testWidevineH264AdaptiveWithSeeking() throws DecoderQueryException { public void testWidevineH264AdaptiveWithSeeking() throws DecoderQueryException {
@ -356,7 +370,7 @@ public final class DashTest extends ActivityInstrumentationTestCase2<HostActivit
// Pass. // Pass.
return; return;
} }
new DashHostedTest.Builder(TAG) testRunner
.setStreamName("test_widevine_h264_adaptive_with_seeking") .setStreamName("test_widevine_h264_adaptive_with_seeking")
.setManifestUrl(DashTestData.WIDEVINE_H264_MANIFEST) .setManifestUrl(DashTestData.WIDEVINE_H264_MANIFEST)
.setWidevineMimeType(MimeTypes.VIDEO_H264) .setWidevineMimeType(MimeTypes.VIDEO_H264)
@ -365,7 +379,7 @@ public final class DashTest extends ActivityInstrumentationTestCase2<HostActivit
.setActionSchedule(SEEKING_SCHEDULE) .setActionSchedule(SEEKING_SCHEDULE)
.setAudioVideoFormats(DashTestData.WIDEVINE_AAC_AUDIO_REPRESENTATION_ID, .setAudioVideoFormats(DashTestData.WIDEVINE_AAC_AUDIO_REPRESENTATION_ID,
DashTestData.WIDEVINE_H264_CDD_ADAPTIVE) DashTestData.WIDEVINE_H264_CDD_ADAPTIVE)
.runTest(getActivity(), getInstrumentation()); .run();
} }
public void testWidevineH264AdaptiveWithRendererDisabling() throws DecoderQueryException { public void testWidevineH264AdaptiveWithRendererDisabling() throws DecoderQueryException {
@ -373,7 +387,7 @@ public final class DashTest extends ActivityInstrumentationTestCase2<HostActivit
// Pass. // Pass.
return; return;
} }
new DashHostedTest.Builder(TAG) testRunner
.setStreamName("test_widevine_h264_adaptive_with_renderer_disabling") .setStreamName("test_widevine_h264_adaptive_with_renderer_disabling")
.setManifestUrl(DashTestData.WIDEVINE_H264_MANIFEST) .setManifestUrl(DashTestData.WIDEVINE_H264_MANIFEST)
.setWidevineMimeType(MimeTypes.VIDEO_H264) .setWidevineMimeType(MimeTypes.VIDEO_H264)
@ -382,7 +396,7 @@ public final class DashTest extends ActivityInstrumentationTestCase2<HostActivit
.setActionSchedule(RENDERER_DISABLING_SCHEDULE) .setActionSchedule(RENDERER_DISABLING_SCHEDULE)
.setAudioVideoFormats(DashTestData.WIDEVINE_AAC_AUDIO_REPRESENTATION_ID, .setAudioVideoFormats(DashTestData.WIDEVINE_AAC_AUDIO_REPRESENTATION_ID,
DashTestData.WIDEVINE_H264_CDD_ADAPTIVE) DashTestData.WIDEVINE_H264_CDD_ADAPTIVE)
.runTest(getActivity(), getInstrumentation()); .run();
} }
// H265 CDD. // H265 CDD.
@ -392,7 +406,7 @@ public final class DashTest extends ActivityInstrumentationTestCase2<HostActivit
// Pass. // Pass.
return; return;
} }
new DashHostedTest.Builder(TAG) testRunner
.setStreamName("test_widevine_h265_fixed") .setStreamName("test_widevine_h265_fixed")
.setManifestUrl(DashTestData.WIDEVINE_H265_MANIFEST) .setManifestUrl(DashTestData.WIDEVINE_H265_MANIFEST)
.setWidevineMimeType(MimeTypes.VIDEO_H265) .setWidevineMimeType(MimeTypes.VIDEO_H265)
@ -400,7 +414,7 @@ public final class DashTest extends ActivityInstrumentationTestCase2<HostActivit
.setCanIncludeAdditionalVideoFormats(false) .setCanIncludeAdditionalVideoFormats(false)
.setAudioVideoFormats(DashTestData.WIDEVINE_AAC_AUDIO_REPRESENTATION_ID, .setAudioVideoFormats(DashTestData.WIDEVINE_AAC_AUDIO_REPRESENTATION_ID,
DashTestData.WIDEVINE_H265_CDD_FIXED) DashTestData.WIDEVINE_H265_CDD_FIXED)
.runTest(getActivity(), getInstrumentation()); .run();
} }
public void testWidevineH265Adaptive() throws DecoderQueryException { public void testWidevineH265Adaptive() throws DecoderQueryException {
@ -408,7 +422,7 @@ public final class DashTest extends ActivityInstrumentationTestCase2<HostActivit
// Pass. // Pass.
return; return;
} }
new DashHostedTest.Builder(TAG) testRunner
.setStreamName("test_widevine_h265_adaptive") .setStreamName("test_widevine_h265_adaptive")
.setManifestUrl(DashTestData.WIDEVINE_H265_MANIFEST) .setManifestUrl(DashTestData.WIDEVINE_H265_MANIFEST)
.setWidevineMimeType(MimeTypes.VIDEO_H265) .setWidevineMimeType(MimeTypes.VIDEO_H265)
@ -416,7 +430,7 @@ public final class DashTest extends ActivityInstrumentationTestCase2<HostActivit
.setCanIncludeAdditionalVideoFormats(true) .setCanIncludeAdditionalVideoFormats(true)
.setAudioVideoFormats(DashTestData.WIDEVINE_AAC_AUDIO_REPRESENTATION_ID, .setAudioVideoFormats(DashTestData.WIDEVINE_AAC_AUDIO_REPRESENTATION_ID,
DashTestData.WIDEVINE_H265_CDD_ADAPTIVE) DashTestData.WIDEVINE_H265_CDD_ADAPTIVE)
.runTest(getActivity(), getInstrumentation()); .run();
} }
public void testWidevineH265AdaptiveWithSeeking() throws DecoderQueryException { public void testWidevineH265AdaptiveWithSeeking() throws DecoderQueryException {
@ -424,7 +438,7 @@ public final class DashTest extends ActivityInstrumentationTestCase2<HostActivit
// Pass. // Pass.
return; return;
} }
new DashHostedTest.Builder(TAG) testRunner
.setStreamName("test_widevine_h265_adaptive_with_seeking") .setStreamName("test_widevine_h265_adaptive_with_seeking")
.setManifestUrl(DashTestData.WIDEVINE_H265_MANIFEST) .setManifestUrl(DashTestData.WIDEVINE_H265_MANIFEST)
.setWidevineMimeType(MimeTypes.VIDEO_H265) .setWidevineMimeType(MimeTypes.VIDEO_H265)
@ -433,7 +447,7 @@ public final class DashTest extends ActivityInstrumentationTestCase2<HostActivit
.setActionSchedule(SEEKING_SCHEDULE) .setActionSchedule(SEEKING_SCHEDULE)
.setAudioVideoFormats(DashTestData.WIDEVINE_AAC_AUDIO_REPRESENTATION_ID, .setAudioVideoFormats(DashTestData.WIDEVINE_AAC_AUDIO_REPRESENTATION_ID,
DashTestData.WIDEVINE_H265_CDD_ADAPTIVE) DashTestData.WIDEVINE_H265_CDD_ADAPTIVE)
.runTest(getActivity(), getInstrumentation()); .run();
} }
public void testWidevineH265AdaptiveWithRendererDisabling() throws DecoderQueryException { public void testWidevineH265AdaptiveWithRendererDisabling() throws DecoderQueryException {
@ -441,7 +455,7 @@ public final class DashTest extends ActivityInstrumentationTestCase2<HostActivit
// Pass. // Pass.
return; return;
} }
new DashHostedTest.Builder(TAG) testRunner
.setStreamName("test_widevine_h265_adaptive_with_renderer_disabling") .setStreamName("test_widevine_h265_adaptive_with_renderer_disabling")
.setManifestUrl(DashTestData.WIDEVINE_H265_MANIFEST) .setManifestUrl(DashTestData.WIDEVINE_H265_MANIFEST)
.setWidevineMimeType(MimeTypes.VIDEO_H265) .setWidevineMimeType(MimeTypes.VIDEO_H265)
@ -450,7 +464,7 @@ public final class DashTest extends ActivityInstrumentationTestCase2<HostActivit
.setActionSchedule(RENDERER_DISABLING_SCHEDULE) .setActionSchedule(RENDERER_DISABLING_SCHEDULE)
.setAudioVideoFormats(DashTestData.WIDEVINE_AAC_AUDIO_REPRESENTATION_ID, .setAudioVideoFormats(DashTestData.WIDEVINE_AAC_AUDIO_REPRESENTATION_ID,
DashTestData.WIDEVINE_H265_CDD_ADAPTIVE) DashTestData.WIDEVINE_H265_CDD_ADAPTIVE)
.runTest(getActivity(), getInstrumentation()); .run();
} }
// VP9 (CDD). // VP9 (CDD).
@ -460,7 +474,7 @@ public final class DashTest extends ActivityInstrumentationTestCase2<HostActivit
// Pass. // Pass.
return; return;
} }
new DashHostedTest.Builder(TAG) testRunner
.setStreamName("test_widevine_vp9_fixed_360p") .setStreamName("test_widevine_vp9_fixed_360p")
.setManifestUrl(DashTestData.WIDEVINE_VP9_MANIFEST) .setManifestUrl(DashTestData.WIDEVINE_VP9_MANIFEST)
.setWidevineMimeType(MimeTypes.VIDEO_VP9) .setWidevineMimeType(MimeTypes.VIDEO_VP9)
@ -468,7 +482,7 @@ public final class DashTest extends ActivityInstrumentationTestCase2<HostActivit
.setCanIncludeAdditionalVideoFormats(false) .setCanIncludeAdditionalVideoFormats(false)
.setAudioVideoFormats(DashTestData.WIDEVINE_VP9_AAC_AUDIO_REPRESENTATION_ID, .setAudioVideoFormats(DashTestData.WIDEVINE_VP9_AAC_AUDIO_REPRESENTATION_ID,
DashTestData.WIDEVINE_VP9_CDD_FIXED) DashTestData.WIDEVINE_VP9_CDD_FIXED)
.runTest(getActivity(), getInstrumentation()); .run();
} }
public void testWidevineVp9Adaptive() throws DecoderQueryException { public void testWidevineVp9Adaptive() throws DecoderQueryException {
@ -476,7 +490,7 @@ public final class DashTest extends ActivityInstrumentationTestCase2<HostActivit
// Pass. // Pass.
return; return;
} }
new DashHostedTest.Builder(TAG) testRunner
.setStreamName("test_widevine_vp9_adaptive") .setStreamName("test_widevine_vp9_adaptive")
.setManifestUrl(DashTestData.WIDEVINE_VP9_MANIFEST) .setManifestUrl(DashTestData.WIDEVINE_VP9_MANIFEST)
.setWidevineMimeType(MimeTypes.VIDEO_VP9) .setWidevineMimeType(MimeTypes.VIDEO_VP9)
@ -484,7 +498,7 @@ public final class DashTest extends ActivityInstrumentationTestCase2<HostActivit
.setCanIncludeAdditionalVideoFormats(true) .setCanIncludeAdditionalVideoFormats(true)
.setAudioVideoFormats(DashTestData.WIDEVINE_VP9_AAC_AUDIO_REPRESENTATION_ID, .setAudioVideoFormats(DashTestData.WIDEVINE_VP9_AAC_AUDIO_REPRESENTATION_ID,
DashTestData.WIDEVINE_VP9_CDD_ADAPTIVE) DashTestData.WIDEVINE_VP9_CDD_ADAPTIVE)
.runTest(getActivity(), getInstrumentation()); .run();
} }
public void testWidevineVp9AdaptiveWithSeeking() throws DecoderQueryException { public void testWidevineVp9AdaptiveWithSeeking() throws DecoderQueryException {
@ -492,7 +506,7 @@ public final class DashTest extends ActivityInstrumentationTestCase2<HostActivit
// Pass. // Pass.
return; return;
} }
new DashHostedTest.Builder(TAG) testRunner
.setStreamName("test_widevine_vp9_adaptive_with_seeking") .setStreamName("test_widevine_vp9_adaptive_with_seeking")
.setManifestUrl(DashTestData.WIDEVINE_VP9_MANIFEST) .setManifestUrl(DashTestData.WIDEVINE_VP9_MANIFEST)
.setWidevineMimeType(MimeTypes.VIDEO_VP9) .setWidevineMimeType(MimeTypes.VIDEO_VP9)
@ -501,7 +515,7 @@ public final class DashTest extends ActivityInstrumentationTestCase2<HostActivit
.setActionSchedule(SEEKING_SCHEDULE) .setActionSchedule(SEEKING_SCHEDULE)
.setAudioVideoFormats(DashTestData.WIDEVINE_VP9_AAC_AUDIO_REPRESENTATION_ID, .setAudioVideoFormats(DashTestData.WIDEVINE_VP9_AAC_AUDIO_REPRESENTATION_ID,
DashTestData.WIDEVINE_VP9_CDD_ADAPTIVE) DashTestData.WIDEVINE_VP9_CDD_ADAPTIVE)
.runTest(getActivity(), getInstrumentation()); .run();
} }
public void testWidevineVp9AdaptiveWithRendererDisabling() throws DecoderQueryException { public void testWidevineVp9AdaptiveWithRendererDisabling() throws DecoderQueryException {
@ -509,7 +523,7 @@ public final class DashTest extends ActivityInstrumentationTestCase2<HostActivit
// Pass. // Pass.
return; return;
} }
new DashHostedTest.Builder(TAG) testRunner
.setStreamName("test_widevine_vp9_adaptive_with_renderer_disabling") .setStreamName("test_widevine_vp9_adaptive_with_renderer_disabling")
.setManifestUrl(DashTestData.WIDEVINE_VP9_MANIFEST) .setManifestUrl(DashTestData.WIDEVINE_VP9_MANIFEST)
.setWidevineMimeType(MimeTypes.VIDEO_VP9) .setWidevineMimeType(MimeTypes.VIDEO_VP9)
@ -518,7 +532,7 @@ public final class DashTest extends ActivityInstrumentationTestCase2<HostActivit
.setActionSchedule(RENDERER_DISABLING_SCHEDULE) .setActionSchedule(RENDERER_DISABLING_SCHEDULE)
.setAudioVideoFormats(DashTestData.WIDEVINE_VP9_AAC_AUDIO_REPRESENTATION_ID, .setAudioVideoFormats(DashTestData.WIDEVINE_VP9_AAC_AUDIO_REPRESENTATION_ID,
DashTestData.WIDEVINE_VP9_CDD_ADAPTIVE) DashTestData.WIDEVINE_VP9_CDD_ADAPTIVE)
.runTest(getActivity(), getInstrumentation()); .run();
} }
// H264: Other frame-rates for output buffer count assertions. // H264: Other frame-rates for output buffer count assertions.
@ -529,7 +543,7 @@ public final class DashTest extends ActivityInstrumentationTestCase2<HostActivit
// Pass. // Pass.
return; return;
} }
new DashHostedTest.Builder(TAG) testRunner
.setStreamName("test_widevine_23fps_h264_fixed") .setStreamName("test_widevine_23fps_h264_fixed")
.setManifestUrl(DashTestData.WIDEVINE_H264_23_MANIFEST) .setManifestUrl(DashTestData.WIDEVINE_H264_23_MANIFEST)
.setWidevineMimeType(MimeTypes.VIDEO_H264) .setWidevineMimeType(MimeTypes.VIDEO_H264)
@ -537,7 +551,7 @@ public final class DashTest extends ActivityInstrumentationTestCase2<HostActivit
.setCanIncludeAdditionalVideoFormats(false) .setCanIncludeAdditionalVideoFormats(false)
.setAudioVideoFormats(DashTestData.WIDEVINE_AAC_AUDIO_REPRESENTATION_ID, .setAudioVideoFormats(DashTestData.WIDEVINE_AAC_AUDIO_REPRESENTATION_ID,
DashTestData.WIDEVINE_H264_BASELINE_480P_23FPS_VIDEO_REPRESENTATION_ID) DashTestData.WIDEVINE_H264_BASELINE_480P_23FPS_VIDEO_REPRESENTATION_ID)
.runTest(getActivity(), getInstrumentation()); .run();
} }
// 24 fps. // 24 fps.
@ -546,7 +560,7 @@ public final class DashTest extends ActivityInstrumentationTestCase2<HostActivit
// Pass. // Pass.
return; return;
} }
new DashHostedTest.Builder(TAG) testRunner
.setStreamName("test_widevine_24fps_h264_fixed") .setStreamName("test_widevine_24fps_h264_fixed")
.setManifestUrl(DashTestData.WIDEVINE_H264_24_MANIFEST) .setManifestUrl(DashTestData.WIDEVINE_H264_24_MANIFEST)
.setWidevineMimeType(MimeTypes.VIDEO_H264) .setWidevineMimeType(MimeTypes.VIDEO_H264)
@ -554,7 +568,7 @@ public final class DashTest extends ActivityInstrumentationTestCase2<HostActivit
.setCanIncludeAdditionalVideoFormats(false) .setCanIncludeAdditionalVideoFormats(false)
.setAudioVideoFormats(DashTestData.WIDEVINE_AAC_AUDIO_REPRESENTATION_ID, .setAudioVideoFormats(DashTestData.WIDEVINE_AAC_AUDIO_REPRESENTATION_ID,
DashTestData.WIDEVINE_H264_BASELINE_480P_24FPS_VIDEO_REPRESENTATION_ID) DashTestData.WIDEVINE_H264_BASELINE_480P_24FPS_VIDEO_REPRESENTATION_ID)
.runTest(getActivity(), getInstrumentation()); .run();
} }
// 29.97 fps. // 29.97 fps.
@ -563,7 +577,7 @@ public final class DashTest extends ActivityInstrumentationTestCase2<HostActivit
// Pass. // Pass.
return; return;
} }
new DashHostedTest.Builder(TAG) testRunner
.setStreamName("test_widevine_29fps_h264_fixed") .setStreamName("test_widevine_29fps_h264_fixed")
.setManifestUrl(DashTestData.WIDEVINE_H264_29_MANIFEST) .setManifestUrl(DashTestData.WIDEVINE_H264_29_MANIFEST)
.setWidevineMimeType(MimeTypes.VIDEO_H264) .setWidevineMimeType(MimeTypes.VIDEO_H264)
@ -571,7 +585,7 @@ public final class DashTest extends ActivityInstrumentationTestCase2<HostActivit
.setCanIncludeAdditionalVideoFormats(false) .setCanIncludeAdditionalVideoFormats(false)
.setAudioVideoFormats(DashTestData.WIDEVINE_AAC_AUDIO_REPRESENTATION_ID, .setAudioVideoFormats(DashTestData.WIDEVINE_AAC_AUDIO_REPRESENTATION_ID,
DashTestData.WIDEVINE_H264_BASELINE_480P_29FPS_VIDEO_REPRESENTATION_ID) DashTestData.WIDEVINE_H264_BASELINE_480P_29FPS_VIDEO_REPRESENTATION_ID)
.runTest(getActivity(), getInstrumentation()); .run();
} }
// Internal. // Internal.

View File

@ -137,6 +137,16 @@ public final class DashTestData {
WIDEVINE_VP9_180P_VIDEO_REPRESENTATION_ID, WIDEVINE_VP9_180P_VIDEO_REPRESENTATION_ID,
WIDEVINE_VP9_360P_VIDEO_REPRESENTATION_ID}; WIDEVINE_VP9_360P_VIDEO_REPRESENTATION_ID};
private static final String WIDEVINE_LICENSE_URL =
"https://proxy.uat.widevine.com/proxy?provider=widevine_test&video_id=";
private static final String WIDEVINE_SW_CRYPTO_CONTENT_ID = "exoplayer_test_1";
private static final String WIDEVINE_HW_SECURE_DECODE_CONTENT_ID = "exoplayer_test_2";
public static String getWidevineLicenseUrl(boolean useL1Widevine) {
return WIDEVINE_LICENSE_URL
+ (useL1Widevine ? WIDEVINE_HW_SECURE_DECODE_CONTENT_ID : WIDEVINE_SW_CRYPTO_CONTENT_ID);
}
private DashTestData() { private DashTestData() {
} }

View File

@ -0,0 +1,459 @@
/*
* Copyright (C) 2017 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.playbacktests.gts;
import static com.google.android.exoplayer2.C.WIDEVINE_UUID;
import android.annotation.TargetApi;
import android.app.Instrumentation;
import android.media.MediaDrm;
import android.media.UnsupportedSchemeException;
import android.net.Uri;
import android.util.Log;
import android.view.Surface;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.DefaultLoadControl;
import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.RendererCapabilities;
import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.decoder.DecoderCounters;
import com.google.android.exoplayer2.drm.DefaultDrmSessionManager;
import com.google.android.exoplayer2.drm.DrmSessionManager;
import com.google.android.exoplayer2.drm.FrameworkMediaCrypto;
import com.google.android.exoplayer2.drm.HttpMediaDrmCallback;
import com.google.android.exoplayer2.drm.MediaDrmCallback;
import com.google.android.exoplayer2.drm.UnsupportedDrmException;
import com.google.android.exoplayer2.mediacodec.MediaCodecUtil;
import com.google.android.exoplayer2.playbacktests.util.ActionSchedule;
import com.google.android.exoplayer2.playbacktests.util.DebugSimpleExoPlayer;
import com.google.android.exoplayer2.playbacktests.util.DecoderCountersUtil;
import com.google.android.exoplayer2.playbacktests.util.ExoHostedTest;
import com.google.android.exoplayer2.playbacktests.util.HostActivity;
import com.google.android.exoplayer2.playbacktests.util.HostActivity.HostedTest;
import com.google.android.exoplayer2.playbacktests.util.MetricsLogger;
import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.source.TrackGroup;
import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.android.exoplayer2.source.dash.DashMediaSource;
import com.google.android.exoplayer2.source.dash.DefaultDashChunkSource;
import com.google.android.exoplayer2.trackselection.FixedTrackSelection;
import com.google.android.exoplayer2.trackselection.MappingTrackSelector;
import com.google.android.exoplayer2.trackselection.RandomTrackSelection;
import com.google.android.exoplayer2.trackselection.TrackSelection;
import com.google.android.exoplayer2.upstream.BandwidthMeter;
import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
import com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory;
import com.google.android.exoplayer2.upstream.TransferListener;
import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.Util;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import junit.framework.AssertionFailedError;
/** {@link DashHostedTest} builder. */
public final class DashTestRunner {
static final int VIDEO_RENDERER_INDEX = 0;
static final int AUDIO_RENDERER_INDEX = 1;
private static final long TEST_TIMEOUT_MS = 5 * 60 * 1000;
private static final String REPORT_NAME = "GtsExoPlayerTestCases";
private static final String REPORT_OBJECT_NAME = "playbacktest";
// Whether adaptive tests should enable video formats beyond those mandated by the Android CDD
// if the device advertises support for them.
private static final boolean ALLOW_ADDITIONAL_VIDEO_FORMATS = Util.SDK_INT >= 24;
private static final String AUDIO_TAG_SUFFIX = ":Audio";
private static final String VIDEO_TAG_SUFFIX = ":Video";
private static final int MIN_LOADABLE_RETRY_COUNT = 10;
private static final int MAX_CONSECUTIVE_DROPPED_VIDEO_FRAMES = 10;
private static final float MAX_DROPPED_VIDEO_FRAME_FRACTION = 0.01f;
private static final String WIDEVINE_SECURITY_LEVEL_1 = "L1";
private static final String WIDEVINE_SECURITY_LEVEL_3 = "L3";
private static final String SECURITY_LEVEL_PROPERTY = "securityLevel";
private final String tag;
private final HostActivity activity;
private final Instrumentation instrumentation;
private String streamName;
private boolean fullPlaybackNoSeeking;
private String audioFormat;
private boolean canIncludeAdditionalVideoFormats;
private ActionSchedule actionSchedule;
private byte[] offlineLicenseKeySetId;
private String[] videoFormats;
private String manifestUrl;
private boolean useL1Widevine;
private String widevineLicenseUrl;
private DataSource.Factory dataSourceFactory;
@TargetApi(18)
@SuppressWarnings("ResourceType")
public static boolean isL1WidevineAvailable(String mimeType) {
try {
// Force L3 if secure decoder is not available.
if (MediaCodecUtil.getDecoderInfo(mimeType, true) == null) {
return false;
}
MediaDrm mediaDrm = new MediaDrm(WIDEVINE_UUID);
String securityProperty = mediaDrm.getPropertyString(SECURITY_LEVEL_PROPERTY);
mediaDrm.release();
return WIDEVINE_SECURITY_LEVEL_1.equals(securityProperty);
} catch (MediaCodecUtil.DecoderQueryException | UnsupportedSchemeException e) {
throw new IllegalStateException(e);
}
}
public DashTestRunner(String tag, HostActivity activity, Instrumentation instrumentation) {
this.tag = tag;
this.activity = activity;
this.instrumentation = instrumentation;
}
public DashTestRunner setStreamName(String streamName) {
this.streamName = streamName;
return this;
}
public DashTestRunner setFullPlaybackNoSeeking(boolean fullPlaybackNoSeeking) {
this.fullPlaybackNoSeeking = fullPlaybackNoSeeking;
return this;
}
public DashTestRunner setCanIncludeAdditionalVideoFormats(
boolean canIncludeAdditionalVideoFormats) {
this.canIncludeAdditionalVideoFormats = canIncludeAdditionalVideoFormats
&& ALLOW_ADDITIONAL_VIDEO_FORMATS;
return this;
}
public DashTestRunner setActionSchedule(ActionSchedule actionSchedule) {
this.actionSchedule = actionSchedule;
return this;
}
public DashTestRunner setOfflineLicenseKeySetId(byte[] offlineLicenseKeySetId) {
this.offlineLicenseKeySetId = offlineLicenseKeySetId;
return this;
}
public DashTestRunner setAudioVideoFormats(String audioFormat, String... videoFormats) {
this.audioFormat = audioFormat;
this.videoFormats = videoFormats;
return this;
}
public DashTestRunner setManifestUrl(String manifestUrl) {
this.manifestUrl = manifestUrl;
return this;
}
public DashTestRunner setWidevineMimeType(String mimeType) {
this.useL1Widevine = isL1WidevineAvailable(mimeType);
this.widevineLicenseUrl = DashTestData.getWidevineLicenseUrl(useL1Widevine);
return this;
}
public DashTestRunner setDataSourceFactory(DataSource.Factory dataSourceFactory) {
this.dataSourceFactory = dataSourceFactory;
return this;
}
public void run() {
DashHostedTest test = createDashHostedTest(canIncludeAdditionalVideoFormats, false,
instrumentation);
activity.runTest(test, TEST_TIMEOUT_MS);
// Retry test exactly once if adaptive test fails due to excessive dropped buffers when
// playing non-CDD required formats (b/28220076).
if (test.needsCddLimitedRetry) {
activity.runTest(createDashHostedTest(false, true, instrumentation), TEST_TIMEOUT_MS);
}
}
private DashHostedTest createDashHostedTest(boolean canIncludeAdditionalVideoFormats,
boolean isCddLimitedRetry, Instrumentation instrumentation) {
MetricsLogger metricsLogger = MetricsLogger.Factory.createDefault(instrumentation, tag,
REPORT_NAME, REPORT_OBJECT_NAME);
return new DashHostedTest(tag, streamName, manifestUrl, metricsLogger, fullPlaybackNoSeeking,
audioFormat, canIncludeAdditionalVideoFormats, isCddLimitedRetry, actionSchedule,
offlineLicenseKeySetId, widevineLicenseUrl, useL1Widevine, dataSourceFactory,
videoFormats);
}
/**
* A {@link HostedTest} for DASH playback tests.
*/
@TargetApi(16)
private static final class DashHostedTest extends ExoHostedTest {
private final String streamName;
private final String manifestUrl;
private final MetricsLogger metricsLogger;
private final boolean fullPlaybackNoSeeking;
private final boolean isCddLimitedRetry;
private final DashTestTrackSelector trackSelector;
private final byte[] offlineLicenseKeySetId;
private final String widevineLicenseUrl;
private final boolean useL1Widevine;
private final DataSource.Factory dataSourceFactory;
private boolean needsCddLimitedRetry;
/**
* @param tag A tag to use for logging.
* @param streamName The name of the test stream for metric logging.
* @param manifestUrl The manifest url.
* @param metricsLogger Logger to log metrics from the test.
* @param fullPlaybackNoSeeking Whether the test will play the entire source with no seeking.
* @param audioFormat The audio format.
* @param canIncludeAdditionalVideoFormats Whether to use video formats in addition to those
* listed in the videoFormats argument, if the device is capable of playing them.
* @param isCddLimitedRetry Whether this is a CDD limited retry following a previous failure.
* @param actionSchedule The action schedule for the test.
* @param offlineLicenseKeySetId The key set id of the license to be used.
* @param widevineLicenseUrl If the video is Widevine encrypted, this is the license url
* otherwise null.
* @param useL1Widevine Whether to use L1 Widevine.
* @param dataSourceFactory If not null, used to load manifest and media.
* @param videoFormats The video formats.
*/
private DashHostedTest(String tag, String streamName, String manifestUrl,
MetricsLogger metricsLogger, boolean fullPlaybackNoSeeking, String audioFormat,
boolean canIncludeAdditionalVideoFormats, boolean isCddLimitedRetry,
ActionSchedule actionSchedule, byte[] offlineLicenseKeySetId, String widevineLicenseUrl,
boolean useL1Widevine, DataSource.Factory dataSourceFactory, String... videoFormats) {
super(tag, fullPlaybackNoSeeking);
Assertions.checkArgument(!(isCddLimitedRetry && canIncludeAdditionalVideoFormats));
this.streamName = streamName;
this.manifestUrl = manifestUrl;
this.metricsLogger = metricsLogger;
this.fullPlaybackNoSeeking = fullPlaybackNoSeeking;
this.isCddLimitedRetry = isCddLimitedRetry;
this.offlineLicenseKeySetId = offlineLicenseKeySetId;
this.widevineLicenseUrl = widevineLicenseUrl;
this.useL1Widevine = useL1Widevine;
this.dataSourceFactory = dataSourceFactory;
trackSelector = new DashTestTrackSelector(tag, audioFormat, videoFormats,
canIncludeAdditionalVideoFormats);
if (actionSchedule != null) {
setSchedule(actionSchedule);
}
}
@Override
protected MappingTrackSelector buildTrackSelector(HostActivity host,
BandwidthMeter bandwidthMeter) {
return trackSelector;
}
@Override
protected DefaultDrmSessionManager<FrameworkMediaCrypto> buildDrmSessionManager(
final String userAgent) {
if (widevineLicenseUrl == null) {
return null;
}
try {
MediaDrmCallback drmCallback = new HttpMediaDrmCallback(widevineLicenseUrl,
new DefaultHttpDataSourceFactory(userAgent));
DefaultDrmSessionManager<FrameworkMediaCrypto> drmSessionManager =
DefaultDrmSessionManager.newWidevineInstance(drmCallback, null, null, null);
if (!useL1Widevine) {
drmSessionManager.setPropertyString(
SECURITY_LEVEL_PROPERTY, WIDEVINE_SECURITY_LEVEL_3);
}
if (offlineLicenseKeySetId != null) {
drmSessionManager.setMode(DefaultDrmSessionManager.MODE_PLAYBACK,
offlineLicenseKeySetId);
}
return drmSessionManager;
} catch (UnsupportedDrmException e) {
throw new IllegalStateException(e);
}
}
@Override
protected SimpleExoPlayer buildExoPlayer(HostActivity host, Surface surface,
MappingTrackSelector trackSelector,
DrmSessionManager<FrameworkMediaCrypto> drmSessionManager) {
SimpleExoPlayer player = new DebugSimpleExoPlayer(host, trackSelector,
new DefaultLoadControl(), drmSessionManager);
player.setVideoSurface(surface);
return player;
}
@Override
protected MediaSource buildSource(HostActivity host, String userAgent,
TransferListener<? super DataSource> mediaTransferListener) {
DataSource.Factory manifestDataSourceFactory = dataSourceFactory != null
? dataSourceFactory : new DefaultDataSourceFactory(host, userAgent);
DataSource.Factory mediaDataSourceFactory = dataSourceFactory != null
? dataSourceFactory
: new DefaultDataSourceFactory(host, userAgent, mediaTransferListener);
Uri manifestUri = Uri.parse(manifestUrl);
DefaultDashChunkSource.Factory chunkSourceFactory = new DefaultDashChunkSource.Factory(
mediaDataSourceFactory);
return new DashMediaSource(manifestUri, manifestDataSourceFactory, chunkSourceFactory,
MIN_LOADABLE_RETRY_COUNT, 0 /* livePresentationDelayMs */, null, null);
}
@Override
protected void logMetrics(DecoderCounters audioCounters, DecoderCounters videoCounters) {
metricsLogger.logMetric(MetricsLogger.KEY_TEST_NAME, streamName);
metricsLogger.logMetric(MetricsLogger.KEY_IS_CDD_LIMITED_RETRY, isCddLimitedRetry);
metricsLogger.logMetric(MetricsLogger.KEY_FRAMES_DROPPED_COUNT,
videoCounters.droppedOutputBufferCount);
metricsLogger.logMetric(MetricsLogger.KEY_MAX_CONSECUTIVE_FRAMES_DROPPED_COUNT,
videoCounters.maxConsecutiveDroppedOutputBufferCount);
metricsLogger.logMetric(MetricsLogger.KEY_FRAMES_SKIPPED_COUNT,
videoCounters.skippedOutputBufferCount);
metricsLogger.logMetric(MetricsLogger.KEY_FRAMES_RENDERED_COUNT,
videoCounters.renderedOutputBufferCount);
metricsLogger.close();
}
@Override
protected void assertPassed(DecoderCounters audioCounters, DecoderCounters videoCounters) {
if (fullPlaybackNoSeeking) {
// We shouldn't have skipped any output buffers.
DecoderCountersUtil
.assertSkippedOutputBufferCount(tag + AUDIO_TAG_SUFFIX, audioCounters, 0);
DecoderCountersUtil
.assertSkippedOutputBufferCount(tag + VIDEO_TAG_SUFFIX, videoCounters, 0);
// We allow one fewer output buffer due to the way that MediaCodecRenderer and the
// underlying decoders handle the end of stream. This should be tightened up in the future.
DecoderCountersUtil.assertTotalOutputBufferCount(tag + AUDIO_TAG_SUFFIX, audioCounters,
audioCounters.inputBufferCount - 1, audioCounters.inputBufferCount);
DecoderCountersUtil.assertTotalOutputBufferCount(tag + VIDEO_TAG_SUFFIX, videoCounters,
videoCounters.inputBufferCount - 1, videoCounters.inputBufferCount);
}
try {
int droppedFrameLimit = (int) Math.ceil(MAX_DROPPED_VIDEO_FRAME_FRACTION
* DecoderCountersUtil.getTotalOutputBuffers(videoCounters));
// Assert that performance is acceptable.
// Assert that total dropped frames were within limit.
DecoderCountersUtil.assertDroppedOutputBufferLimit(tag + VIDEO_TAG_SUFFIX, videoCounters,
droppedFrameLimit);
// Assert that consecutive dropped frames were within limit.
DecoderCountersUtil.assertConsecutiveDroppedOutputBufferLimit(tag + VIDEO_TAG_SUFFIX,
videoCounters, MAX_CONSECUTIVE_DROPPED_VIDEO_FRAMES);
} catch (AssertionFailedError e) {
if (trackSelector.includedAdditionalVideoFormats) {
// Retry limiting to CDD mandated formats (b/28220076).
Log.e(tag, "Too many dropped or consecutive dropped frames.", e);
needsCddLimitedRetry = true;
} else {
throw e;
}
}
}
}
private static final class DashTestTrackSelector extends MappingTrackSelector {
private final String tag;
private final String audioFormatId;
private final String[] videoFormatIds;
private final boolean canIncludeAdditionalVideoFormats;
public boolean includedAdditionalVideoFormats;
private DashTestTrackSelector(String tag, String audioFormatId, String[] videoFormatIds,
boolean canIncludeAdditionalVideoFormats) {
this.tag = tag;
this.audioFormatId = audioFormatId;
this.videoFormatIds = videoFormatIds;
this.canIncludeAdditionalVideoFormats = canIncludeAdditionalVideoFormats;
}
@Override
protected TrackSelection[] selectTracks(RendererCapabilities[] rendererCapabilities,
TrackGroupArray[] rendererTrackGroupArrays, int[][][] rendererFormatSupports)
throws ExoPlaybackException {
Assertions.checkState(rendererCapabilities[VIDEO_RENDERER_INDEX].getTrackType()
== C.TRACK_TYPE_VIDEO);
Assertions.checkState(rendererCapabilities[AUDIO_RENDERER_INDEX].getTrackType()
== C.TRACK_TYPE_AUDIO);
Assertions.checkState(rendererTrackGroupArrays[VIDEO_RENDERER_INDEX].length == 1);
Assertions.checkState(rendererTrackGroupArrays[AUDIO_RENDERER_INDEX].length == 1);
TrackSelection[] selections = new TrackSelection[rendererCapabilities.length];
selections[VIDEO_RENDERER_INDEX] = new RandomTrackSelection(
rendererTrackGroupArrays[VIDEO_RENDERER_INDEX].get(0),
getVideoTrackIndices(rendererTrackGroupArrays[VIDEO_RENDERER_INDEX].get(0),
rendererFormatSupports[VIDEO_RENDERER_INDEX][0], videoFormatIds,
canIncludeAdditionalVideoFormats),
0 /* seed */);
selections[AUDIO_RENDERER_INDEX] = new FixedTrackSelection(
rendererTrackGroupArrays[AUDIO_RENDERER_INDEX].get(0),
getTrackIndex(rendererTrackGroupArrays[AUDIO_RENDERER_INDEX].get(0), audioFormatId));
includedAdditionalVideoFormats =
selections[VIDEO_RENDERER_INDEX].length() > videoFormatIds.length;
return selections;
}
private int[] getVideoTrackIndices(TrackGroup trackGroup, int[] formatSupport,
String[] formatIds, boolean canIncludeAdditionalFormats) {
List<Integer> trackIndices = new ArrayList<>();
// Always select explicitly listed representations.
for (String formatId : formatIds) {
int trackIndex = getTrackIndex(trackGroup, formatId);
Log.d(tag, "Adding base video format: "
+ Format.toLogString(trackGroup.getFormat(trackIndex)));
trackIndices.add(trackIndex);
}
// Select additional video representations, if supported by the device.
if (canIncludeAdditionalFormats) {
for (int i = 0; i < trackGroup.length; i++) {
if (!trackIndices.contains(i) && isFormatHandled(formatSupport[i])) {
Log.d(tag, "Adding extra video format: "
+ Format.toLogString(trackGroup.getFormat(i)));
trackIndices.add(i);
}
}
}
int[] trackIndicesArray = Util.toArray(trackIndices);
Arrays.sort(trackIndicesArray);
return trackIndicesArray;
}
private static int getTrackIndex(TrackGroup trackGroup, String formatId) {
for (int i = 0; i < trackGroup.length; i++) {
if (trackGroup.getFormat(i).id.equals(formatId)) {
return i;
}
}
throw new IllegalStateException("Format " + formatId + " not found.");
}
private static boolean isFormatHandled(int formatSupport) {
return (formatSupport & RendererCapabilities.FORMAT_SUPPORT_MASK)
== RendererCapabilities.FORMAT_HANDLED;
}
}
}

View File

@ -37,7 +37,7 @@ public final class DashWidevineOfflineTest extends ActivityInstrumentationTestCa
private static final String TAG = "DashWidevineOfflineTest"; private static final String TAG = "DashWidevineOfflineTest";
private static final String USER_AGENT = "ExoPlayerPlaybackTests"; private static final String USER_AGENT = "ExoPlayerPlaybackTests";
private DashHostedTest.Builder builder; private DashTestRunner testRunner;
private DefaultHttpDataSourceFactory httpDataSourceFactory; private DefaultHttpDataSourceFactory httpDataSourceFactory;
private OfflineLicenseHelper<FrameworkMediaCrypto> offlineLicenseHelper; private OfflineLicenseHelper<FrameworkMediaCrypto> offlineLicenseHelper;
private byte[] offlineLicenseKeySetId; private byte[] offlineLicenseKeySetId;
@ -49,7 +49,7 @@ public final class DashWidevineOfflineTest extends ActivityInstrumentationTestCa
@Override @Override
protected void setUp() throws Exception { protected void setUp() throws Exception {
super.setUp(); super.setUp();
builder = new DashHostedTest.Builder(TAG) testRunner = new DashTestRunner(TAG, getActivity(), getInstrumentation())
.setStreamName("test_widevine_h264_fixed_offline") .setStreamName("test_widevine_h264_fixed_offline")
.setManifestUrl(DashTestData.WIDEVINE_H264_MANIFEST) .setManifestUrl(DashTestData.WIDEVINE_H264_MANIFEST)
.setWidevineMimeType(MimeTypes.VIDEO_H264) .setWidevineMimeType(MimeTypes.VIDEO_H264)
@ -58,8 +58,8 @@ public final class DashWidevineOfflineTest extends ActivityInstrumentationTestCa
.setAudioVideoFormats(DashTestData.WIDEVINE_AAC_AUDIO_REPRESENTATION_ID, .setAudioVideoFormats(DashTestData.WIDEVINE_AAC_AUDIO_REPRESENTATION_ID,
DashTestData.WIDEVINE_H264_CDD_FIXED); DashTestData.WIDEVINE_H264_CDD_FIXED);
boolean useL1Widevine = DashHostedTest.isL1WidevineAvailable(MimeTypes.VIDEO_H264); boolean useL1Widevine = DashTestRunner.isL1WidevineAvailable(MimeTypes.VIDEO_H264);
String widevineLicenseUrl = DashHostedTest.getWidevineLicenseUrl(useL1Widevine); String widevineLicenseUrl = DashTestData.getWidevineLicenseUrl(useL1Widevine);
httpDataSourceFactory = new DefaultHttpDataSourceFactory(USER_AGENT); httpDataSourceFactory = new DefaultHttpDataSourceFactory(USER_AGENT);
offlineLicenseHelper = OfflineLicenseHelper.newWidevineInstance(widevineLicenseUrl, offlineLicenseHelper = OfflineLicenseHelper.newWidevineInstance(widevineLicenseUrl,
httpDataSourceFactory); httpDataSourceFactory);
@ -67,12 +67,15 @@ public final class DashWidevineOfflineTest extends ActivityInstrumentationTestCa
@Override @Override
protected void tearDown() throws Exception { protected void tearDown() throws Exception {
testRunner = null;
if (offlineLicenseKeySetId != null) { if (offlineLicenseKeySetId != null) {
releaseLicense(); releaseLicense();
} }
if (offlineLicenseHelper != null) { if (offlineLicenseHelper != null) {
offlineLicenseHelper.releaseResources(); offlineLicenseHelper.releaseResources();
} }
offlineLicenseHelper = null;
httpDataSourceFactory = null;
super.tearDown(); super.tearDown();
} }
@ -83,7 +86,7 @@ public final class DashWidevineOfflineTest extends ActivityInstrumentationTestCa
return; // Pass. return; // Pass.
} }
downloadLicense(); downloadLicense();
builder.runTest(getActivity(), getInstrumentation()); testRunner.run();
// Renew license after playback should still work // Renew license after playback should still work
offlineLicenseKeySetId = offlineLicenseHelper.renew(offlineLicenseKeySetId); offlineLicenseKeySetId = offlineLicenseHelper.renew(offlineLicenseKeySetId);
@ -98,7 +101,7 @@ public final class DashWidevineOfflineTest extends ActivityInstrumentationTestCa
releaseLicense(); // keySetId no longer valid. releaseLicense(); // keySetId no longer valid.
try { try {
builder.runTest(getActivity(), getInstrumentation()); testRunner.run();
fail("Playback should fail because the license has been released."); fail("Playback should fail because the license has been released.");
} catch (Throwable e) { } catch (Throwable e) {
// Get the root cause // Get the root cause
@ -138,7 +141,7 @@ public final class DashWidevineOfflineTest extends ActivityInstrumentationTestCa
} }
// DefaultDrmSessionManager should renew the license and stream play fine // DefaultDrmSessionManager should renew the license and stream play fine
builder.runTest(getActivity(), getInstrumentation()); testRunner.run();
} }
public void testWidevineOfflineLicenseExpiresOnPause() throws Exception { public void testWidevineOfflineLicenseExpiresOnPause() throws Exception {
@ -157,9 +160,7 @@ public final class DashWidevineOfflineTest extends ActivityInstrumentationTestCa
.delay(3000).pause().delay(licenseDuration * 1000 + 2000).play().build(); .delay(3000).pause().delay(licenseDuration * 1000 + 2000).play().build();
// DefaultDrmSessionManager should renew the license and stream play fine // DefaultDrmSessionManager should renew the license and stream play fine
builder testRunner.setActionSchedule(schedule).run();
.setActionSchedule(schedule)
.runTest(getActivity(), getInstrumentation());
} }
private void downloadLicense() throws InterruptedException, DrmSessionException, IOException { private void downloadLicense() throws InterruptedException, DrmSessionException, IOException {
@ -167,7 +168,7 @@ public final class DashWidevineOfflineTest extends ActivityInstrumentationTestCa
httpDataSourceFactory.createDataSource(), DashTestData.WIDEVINE_H264_MANIFEST); httpDataSourceFactory.createDataSource(), DashTestData.WIDEVINE_H264_MANIFEST);
Assert.assertNotNull(offlineLicenseKeySetId); Assert.assertNotNull(offlineLicenseKeySetId);
Assert.assertTrue(offlineLicenseKeySetId.length > 0); Assert.assertTrue(offlineLicenseKeySetId.length > 0);
builder.setOfflineLicenseKeySetId(offlineLicenseKeySetId); testRunner.setOfflineLicenseKeySetId(offlineLicenseKeySetId);
} }
private void releaseLicense() throws DrmSessionException { private void releaseLicense() throws DrmSessionException {