From b71effb7b0b2da1f97e62ba8f4e5b659f13f7f85 Mon Sep 17 00:00:00 2001 From: tonihei Date: Thu, 12 Oct 2017 10:12:04 -0700 Subject: [PATCH] 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 --- .../exoplayer2/drm/DefaultDrmSession.java | 38 ++++++++--------- .../playbacktests/gts/DashTestRunner.java | 41 ++++++++++++++----- .../gts/DashWidevineOfflineTest.java | 6 ++- .../android/exoplayer2/testutil/Action.java | 12 ++++++ 4 files changed, 64 insertions(+), 33 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/drm/DefaultDrmSession.java b/library/core/src/main/java/com/google/android/exoplayer2/drm/DefaultDrmSession.java index 4e60e466a8..4e5696ef1f 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/drm/DefaultDrmSession.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/drm/DefaultDrmSession.java @@ -296,26 +296,24 @@ import java.util.UUID; case DefaultDrmSessionManager.MODE_QUERY: if (offlineLicenseKeySetId == null) { postKeyRequest(ExoMediaDrm.KEY_TYPE_STREAMING, allowRetry); - } else { - if (restoreKeys()) { - long licenseDurationRemainingSec = getLicenseDurationRemainingSec(); - if (mode == DefaultDrmSessionManager.MODE_PLAYBACK - && licenseDurationRemainingSec <= MAX_LICENSE_DURATION_TO_RENEW) { - Log.d(TAG, "Offline license has expired or will expire soon. " - + "Remaining seconds: " + licenseDurationRemainingSec); - postKeyRequest(ExoMediaDrm.KEY_TYPE_OFFLINE, allowRetry); - } else if (licenseDurationRemainingSec <= 0) { - onError(new KeysExpiredException()); - } else { - state = STATE_OPENED_WITH_KEYS; - if (eventHandler != null && eventListener != null) { - eventHandler.post(new Runnable() { - @Override - public void run() { - eventListener.onDrmKeysRestored(); - } - }); - } + } else if (state == STATE_OPENED_WITH_KEYS || restoreKeys()) { + long licenseDurationRemainingSec = getLicenseDurationRemainingSec(); + if (mode == DefaultDrmSessionManager.MODE_PLAYBACK + && licenseDurationRemainingSec <= MAX_LICENSE_DURATION_TO_RENEW) { + Log.d(TAG, "Offline license has expired or will expire soon. " + + "Remaining seconds: " + licenseDurationRemainingSec); + postKeyRequest(ExoMediaDrm.KEY_TYPE_OFFLINE, allowRetry); + } else if (licenseDurationRemainingSec <= 0) { + onError(new KeysExpiredException()); + } else { + state = STATE_OPENED_WITH_KEYS; + if (eventHandler != null && eventListener != null) { + eventHandler.post(new Runnable() { + @Override + public void run() { + eventListener.onDrmKeysRestored(); + } + }); } } } diff --git a/playbacktests/src/androidTest/java/com/google/android/exoplayer2/playbacktests/gts/DashTestRunner.java b/playbacktests/src/androidTest/java/com/google/android/exoplayer2/playbacktests/gts/DashTestRunner.java index 06dab1164b..85cefbc2f6 100644 --- a/playbacktests/src/androidTest/java/com/google/android/exoplayer2/playbacktests/gts/DashTestRunner.java +++ b/playbacktests/src/androidTest/java/com/google/android/exoplayer2/playbacktests/gts/DashTestRunner.java @@ -108,21 +108,23 @@ public final class DashTestRunner { 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; + if (Util.SDK_INT >= 18) { + try { + // Force L3 if secure decoder is not available. + 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) { @@ -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); + } + } + + } + } diff --git a/playbacktests/src/androidTest/java/com/google/android/exoplayer2/playbacktests/gts/DashWidevineOfflineTest.java b/playbacktests/src/androidTest/java/com/google/android/exoplayer2/playbacktests/gts/DashWidevineOfflineTest.java index 1ddceb551c..0d79a803d3 100644 --- a/playbacktests/src/androidTest/java/com/google/android/exoplayer2/playbacktests/gts/DashWidevineOfflineTest.java +++ b/playbacktests/src/androidTest/java/com/google/android/exoplayer2/playbacktests/gts/DashWidevineOfflineTest.java @@ -67,8 +67,10 @@ public final class DashWidevineOfflineTest extends ActivityInstrumentationTestCa boolean useL1Widevine = DashTestRunner.isL1WidevineAvailable(MimeTypes.VIDEO_H264); String widevineLicenseUrl = DashTestData.getWidevineLicenseUrl(true, useL1Widevine); httpDataSourceFactory = new DefaultHttpDataSourceFactory(USER_AGENT); - offlineLicenseHelper = OfflineLicenseHelper.newWidevineInstance(widevineLicenseUrl, - httpDataSourceFactory); + if (Util.SDK_INT >= 18) { + offlineLicenseHelper = OfflineLicenseHelper.newWidevineInstance(widevineLicenseUrl, + httpDataSourceFactory); + } } @Override diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/Action.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/Action.java index 66e034f21c..2abe521883 100644 --- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/Action.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/Action.java @@ -322,6 +322,9 @@ public abstract class Action { protected void doActionAndScheduleNextImpl(final SimpleExoPlayer player, final MappingTrackSelector trackSelector, final Surface surface, final Handler handler, final ActionNode nextAction) { + if (nextAction == null) { + return; + } Player.EventListener listener = new Player.DefaultEventListener() { @Override public void onTimelineChanged(Timeline timeline, Object manifest) { @@ -362,6 +365,9 @@ public abstract class Action { protected void doActionAndScheduleNextImpl(final SimpleExoPlayer player, final MappingTrackSelector trackSelector, final Surface surface, final Handler handler, final ActionNode nextAction) { + if (nextAction == null) { + return; + } player.addListener(new Player.DefaultEventListener() { @Override public void onPositionDiscontinuity(@Player.DiscontinuityReason int reason) { @@ -399,6 +405,9 @@ public abstract class Action { protected void doActionAndScheduleNextImpl(final SimpleExoPlayer player, final MappingTrackSelector trackSelector, final Surface surface, final Handler handler, final ActionNode nextAction) { + if (nextAction == null) { + return; + } if (targetPlaybackState == player.getPlaybackState()) { nextAction.schedule(player, trackSelector, surface, handler); } else { @@ -438,6 +447,9 @@ public abstract class Action { protected void doActionAndScheduleNextImpl(final SimpleExoPlayer player, final MappingTrackSelector trackSelector, final Surface surface, final Handler handler, final ActionNode nextAction) { + if (nextAction == null) { + return; + } player.addListener(new Player.DefaultEventListener() { @Override public void onSeekProcessed() {