Fix MobileHarness playback tests.

This change fixes various issues:
 - MobileHarness sometimes allocated devices with SDK < 16. As we have no tests running
   on these SDKs, a new dimension filter for the mobile_test target ensures that only
   devices with SDK >= 16 are selected. A similar filter for SDK version is also added
   to the ABR playback tests to ensure no old devices are selected.
 - DRM specific tests are skipped for Api < 18, but were not able to run because the
   DashTestRunner class tried to link to the MediaDrm constructor. Moved the
   constructor to a seperate Builder class to allow execution on Api levels 16 and 17.
 - DashWidevineOfflineTest also tried to access code for Api >= 18 without checking
   the current level.
 - Action implementations which are waiting for events did not ensure that they have a
   nextAction to wait for. This caused NullPointerExceptions when this next action was
   scheduled.
 - DefaultDrmSession always restored the offline keys when a new license was requested,
   even if the keys were already restored. These repeated slow calls to restoreKeys
   resulted in high numbers of dropped buffers.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=171974859
This commit is contained in:
tonihei 2017-10-12 10:12:04 -07:00 committed by Oliver Woodman
parent 333e745e7b
commit b71effb7b0
4 changed files with 64 additions and 33 deletions

View File

@ -296,26 +296,24 @@ import java.util.UUID;
case DefaultDrmSessionManager.MODE_QUERY: case DefaultDrmSessionManager.MODE_QUERY:
if (offlineLicenseKeySetId == null) { if (offlineLicenseKeySetId == null) {
postKeyRequest(ExoMediaDrm.KEY_TYPE_STREAMING, allowRetry); postKeyRequest(ExoMediaDrm.KEY_TYPE_STREAMING, allowRetry);
} else { } else if (state == STATE_OPENED_WITH_KEYS || restoreKeys()) {
if (restoreKeys()) { long licenseDurationRemainingSec = getLicenseDurationRemainingSec();
long licenseDurationRemainingSec = getLicenseDurationRemainingSec(); if (mode == DefaultDrmSessionManager.MODE_PLAYBACK
if (mode == DefaultDrmSessionManager.MODE_PLAYBACK && licenseDurationRemainingSec <= MAX_LICENSE_DURATION_TO_RENEW) {
&& licenseDurationRemainingSec <= MAX_LICENSE_DURATION_TO_RENEW) { Log.d(TAG, "Offline license has expired or will expire soon. "
Log.d(TAG, "Offline license has expired or will expire soon. " + "Remaining seconds: " + licenseDurationRemainingSec);
+ "Remaining seconds: " + licenseDurationRemainingSec); postKeyRequest(ExoMediaDrm.KEY_TYPE_OFFLINE, allowRetry);
postKeyRequest(ExoMediaDrm.KEY_TYPE_OFFLINE, allowRetry); } else if (licenseDurationRemainingSec <= 0) {
} else if (licenseDurationRemainingSec <= 0) { onError(new KeysExpiredException());
onError(new KeysExpiredException()); } else {
} else { state = STATE_OPENED_WITH_KEYS;
state = STATE_OPENED_WITH_KEYS; if (eventHandler != null && eventListener != null) {
if (eventHandler != null && eventListener != null) { eventHandler.post(new Runnable() {
eventHandler.post(new Runnable() { @Override
@Override public void run() {
public void run() { eventListener.onDrmKeysRestored();
eventListener.onDrmKeysRestored(); }
} });
});
}
} }
} }
} }

View File

@ -108,21 +108,23 @@ public final class DashTestRunner {
private String widevineLicenseUrl; private String widevineLicenseUrl;
private DataSource.Factory dataSourceFactory; private DataSource.Factory dataSourceFactory;
@TargetApi(18)
@SuppressWarnings("ResourceType") @SuppressWarnings("ResourceType")
public static boolean isL1WidevineAvailable(String mimeType) { public static boolean isL1WidevineAvailable(String mimeType) {
try { if (Util.SDK_INT >= 18) {
// Force L3 if secure decoder is not available. try {
if (MediaCodecUtil.getDecoderInfo(mimeType, true) == null) { // Force L3 if secure decoder is not available.
return false; if (MediaCodecUtil.getDecoderInfo(mimeType, true) == null) {
return false;
}
MediaDrm mediaDrm = MediaDrmBuilder.build();
String securityProperty = mediaDrm.getPropertyString(SECURITY_LEVEL_PROPERTY);
mediaDrm.release();
return WIDEVINE_SECURITY_LEVEL_1.equals(securityProperty);
} catch (MediaCodecUtil.DecoderQueryException e) {
throw new IllegalStateException(e);
} }
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);
} }
return false;
} }
public DashTestRunner(String tag, HostActivity activity, Instrumentation instrumentation) { public DashTestRunner(String tag, HostActivity activity, Instrumentation instrumentation) {
@ -457,4 +459,21 @@ public final class DashTestRunner {
} }
/**
* Creates a new {@code MediaDrm} object. The encapsulation ensures that the tests can be
* executed for API level < 18.
*/
@TargetApi(18)
private static final class MediaDrmBuilder {
public static MediaDrm build () {
try {
return new MediaDrm(WIDEVINE_UUID);
} catch (UnsupportedSchemeException e) {
throw new IllegalStateException(e);
}
}
}
} }

View File

@ -67,8 +67,10 @@ public final class DashWidevineOfflineTest extends ActivityInstrumentationTestCa
boolean useL1Widevine = DashTestRunner.isL1WidevineAvailable(MimeTypes.VIDEO_H264); boolean useL1Widevine = DashTestRunner.isL1WidevineAvailable(MimeTypes.VIDEO_H264);
String widevineLicenseUrl = DashTestData.getWidevineLicenseUrl(true, useL1Widevine); String widevineLicenseUrl = DashTestData.getWidevineLicenseUrl(true, useL1Widevine);
httpDataSourceFactory = new DefaultHttpDataSourceFactory(USER_AGENT); httpDataSourceFactory = new DefaultHttpDataSourceFactory(USER_AGENT);
offlineLicenseHelper = OfflineLicenseHelper.newWidevineInstance(widevineLicenseUrl, if (Util.SDK_INT >= 18) {
httpDataSourceFactory); offlineLicenseHelper = OfflineLicenseHelper.newWidevineInstance(widevineLicenseUrl,
httpDataSourceFactory);
}
} }
@Override @Override

View File

@ -322,6 +322,9 @@ public abstract class Action {
protected void doActionAndScheduleNextImpl(final SimpleExoPlayer player, protected void doActionAndScheduleNextImpl(final SimpleExoPlayer player,
final MappingTrackSelector trackSelector, final Surface surface, final Handler handler, final MappingTrackSelector trackSelector, final Surface surface, final Handler handler,
final ActionNode nextAction) { final ActionNode nextAction) {
if (nextAction == null) {
return;
}
Player.EventListener listener = new Player.DefaultEventListener() { Player.EventListener listener = new Player.DefaultEventListener() {
@Override @Override
public void onTimelineChanged(Timeline timeline, Object manifest) { public void onTimelineChanged(Timeline timeline, Object manifest) {
@ -362,6 +365,9 @@ public abstract class Action {
protected void doActionAndScheduleNextImpl(final SimpleExoPlayer player, protected void doActionAndScheduleNextImpl(final SimpleExoPlayer player,
final MappingTrackSelector trackSelector, final Surface surface, final Handler handler, final MappingTrackSelector trackSelector, final Surface surface, final Handler handler,
final ActionNode nextAction) { final ActionNode nextAction) {
if (nextAction == null) {
return;
}
player.addListener(new Player.DefaultEventListener() { player.addListener(new Player.DefaultEventListener() {
@Override @Override
public void onPositionDiscontinuity(@Player.DiscontinuityReason int reason) { public void onPositionDiscontinuity(@Player.DiscontinuityReason int reason) {
@ -399,6 +405,9 @@ public abstract class Action {
protected void doActionAndScheduleNextImpl(final SimpleExoPlayer player, protected void doActionAndScheduleNextImpl(final SimpleExoPlayer player,
final MappingTrackSelector trackSelector, final Surface surface, final Handler handler, final MappingTrackSelector trackSelector, final Surface surface, final Handler handler,
final ActionNode nextAction) { final ActionNode nextAction) {
if (nextAction == null) {
return;
}
if (targetPlaybackState == player.getPlaybackState()) { if (targetPlaybackState == player.getPlaybackState()) {
nextAction.schedule(player, trackSelector, surface, handler); nextAction.schedule(player, trackSelector, surface, handler);
} else { } else {
@ -438,6 +447,9 @@ public abstract class Action {
protected void doActionAndScheduleNextImpl(final SimpleExoPlayer player, protected void doActionAndScheduleNextImpl(final SimpleExoPlayer player,
final MappingTrackSelector trackSelector, final Surface surface, final Handler handler, final MappingTrackSelector trackSelector, final Surface surface, final Handler handler,
final ActionNode nextAction) { final ActionNode nextAction) {
if (nextAction == null) {
return;
}
player.addListener(new Player.DefaultEventListener() { player.addListener(new Player.DefaultEventListener() {
@Override @Override
public void onSeekProcessed() { public void onSeekProcessed() {