diff --git a/library/core/build.gradle b/library/core/build.gradle index 81e1a3d543..bebd62beb9 100644 --- a/library/core/build.gradle +++ b/library/core/build.gradle @@ -48,6 +48,7 @@ dependencies { androidTestImplementation(project(modulePrefix + 'testutils')) { exclude module: modulePrefix.substring(1) + 'library-core' } + androidTestImplementation 'com.squareup.okhttp3:mockwebserver:' + okhttpVersion testImplementation 'com.squareup.okhttp3:mockwebserver:' + okhttpVersion testImplementation 'org.robolectric:robolectric:' + robolectricVersion testImplementation project(modulePrefix + 'testutils') diff --git a/library/core/src/androidTest/AndroidManifest.xml b/library/core/src/androidTest/AndroidManifest.xml index 4ffc92ac24..db8d89e66e 100644 --- a/library/core/src/androidTest/AndroidManifest.xml +++ b/library/core/src/androidTest/AndroidManifest.xml @@ -19,11 +19,13 @@ package="com.google.android.exoplayer2.core.test"> + + tools:ignore="MissingApplicationIcon,HardcodedDebugMode" + android:usesCleartextTraffic="true"> diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/drm/DrmPlaybackTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/drm/DrmPlaybackTest.java new file mode 100644 index 0000000000..c342e9a1a7 --- /dev/null +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/drm/DrmPlaybackTest.java @@ -0,0 +1,101 @@ +/* + * Copyright 2021 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.drm; + +import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; +import static com.google.common.truth.Truth.assertThat; + +import androidx.test.ext.junit.runners.AndroidJUnit4; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.ExoPlayer; +import com.google.android.exoplayer2.MediaItem; +import com.google.android.exoplayer2.PlaybackException; +import com.google.android.exoplayer2.Player; +import com.google.android.exoplayer2.SimpleExoPlayer; +import com.google.android.exoplayer2.util.ConditionVariable; +import java.util.concurrent.atomic.AtomicReference; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** Instrumentation tests for DRM playback. */ +@RunWith(AndroidJUnit4.class) +public final class DrmPlaybackTest { + + /** The license response needed to play the {@code drm/sample_fragmented_clearkey.mp4} file. */ + // NOTE: Changing this response *should* make the test fail, but it seems the clearkey CDM + // implementation is quite robust. This means an 'invalid' response means it just incorrectly + // decrypts the content, resulting in invalid data fed to the decoder and no video shown on the + // screen (but no error thrown that's detectable by this test). + private static final String CLEARKEY_RESPONSE = + "{\"keys\":" + + "[{" + + "\"kty\":\"oct\"," + + "\"k\":\"Y8tfcYTdS2iaXF_xHuajKA\"," + + "\"kid\":\"zX65_4jzTK6wYYWwACTkwg\"" + + "}]," + + "\"type\":\"temporary\"}"; + + @Test + public void clearkeyPlayback() throws Exception { + MockWebServer mockWebServer = new MockWebServer(); + mockWebServer.enqueue(new MockResponse().setResponseCode(200).setBody(CLEARKEY_RESPONSE)); + mockWebServer.start(); + + MediaItem mediaItem = + new MediaItem.Builder() + .setUri("asset:///media/drm/sample_fragmented_clearkey.mp4") + .setDrmConfiguration( + new MediaItem.DrmConfiguration.Builder(C.CLEARKEY_UUID) + .setLicenseUri(mockWebServer.url("license").toString()) + .build()) + .build(); + AtomicReference player = new AtomicReference<>(); + ConditionVariable playbackComplete = new ConditionVariable(); + AtomicReference playbackException = new AtomicReference<>(); + getInstrumentation() + .runOnMainSync( + () -> { + player.set(new ExoPlayer.Builder(getInstrumentation().getContext()).build()); + player + .get() + .addListener( + new Player.Listener() { + @Override + public void onPlaybackStateChanged(@Player.State int playbackState) { + if (playbackState == Player.STATE_ENDED) { + playbackComplete.open(); + } + } + + @Override + public void onPlayerError(PlaybackException error) { + playbackException.set(error); + playbackComplete.open(); + } + }); + player.get().setMediaItem(mediaItem); + player.get().prepare(); + player.get().play(); + }); + + playbackComplete.block(); + getInstrumentation().runOnMainSync(() -> player.get().release()); + getInstrumentation().waitForIdleSync(); + assertThat(playbackException.get()).isNull(); + } +} diff --git a/testdata/src/test/assets/media/drm/sample_fragmented_clearkey.mp4 b/testdata/src/test/assets/media/drm/sample_fragmented_clearkey.mp4 new file mode 100644 index 0000000000..1efacc5d22 Binary files /dev/null and b/testdata/src/test/assets/media/drm/sample_fragmented_clearkey.mp4 differ