Commit 9c8cd4b5 by ibaker Committed by Andrew Lewis

Add DRM data to AnalyticsCollectorTest

This requires lots of new DRM plumbing in FakeMedia{Period,Source} and
FakeSampleStream.

Part of issue:#6765

PiperOrigin-RevId: 312072332
parent 5b0e971f
...@@ -42,6 +42,7 @@ import com.google.android.exoplayer2.Player.EventListener; ...@@ -42,6 +42,7 @@ import com.google.android.exoplayer2.Player.EventListener;
import com.google.android.exoplayer2.Timeline.Window; import com.google.android.exoplayer2.Timeline.Window;
import com.google.android.exoplayer2.analytics.AnalyticsListener; import com.google.android.exoplayer2.analytics.AnalyticsListener;
import com.google.android.exoplayer2.audio.AudioAttributes; import com.google.android.exoplayer2.audio.AudioAttributes;
import com.google.android.exoplayer2.drm.DrmSessionManager;
import com.google.android.exoplayer2.source.ClippingMediaSource; import com.google.android.exoplayer2.source.ClippingMediaSource;
import com.google.android.exoplayer2.source.CompositeMediaSource; import com.google.android.exoplayer2.source.CompositeMediaSource;
import com.google.android.exoplayer2.source.ConcatenatingMediaSource; import com.google.android.exoplayer2.source.ConcatenatingMediaSource;
...@@ -600,6 +601,7 @@ public final class ExoPlayerTest { ...@@ -600,6 +601,7 @@ public final class ExoPlayerTest {
MediaPeriodId id, MediaPeriodId id,
TrackGroupArray trackGroupArray, TrackGroupArray trackGroupArray,
Allocator allocator, Allocator allocator,
DrmSessionManager drmSessionManager,
EventDispatcher eventDispatcher, EventDispatcher eventDispatcher,
@Nullable TransferListener transferListener) { @Nullable TransferListener transferListener) {
FakeMediaPeriod mediaPeriod = new FakeMediaPeriod(trackGroupArray, eventDispatcher); FakeMediaPeriod mediaPeriod = new FakeMediaPeriod(trackGroupArray, eventDispatcher);
...@@ -635,6 +637,7 @@ public final class ExoPlayerTest { ...@@ -635,6 +637,7 @@ public final class ExoPlayerTest {
MediaPeriodId id, MediaPeriodId id,
TrackGroupArray trackGroupArray, TrackGroupArray trackGroupArray,
Allocator allocator, Allocator allocator,
DrmSessionManager drmSessionManager,
EventDispatcher eventDispatcher, EventDispatcher eventDispatcher,
@Nullable TransferListener transferListener) { @Nullable TransferListener transferListener) {
FakeMediaPeriod mediaPeriod = new FakeMediaPeriod(trackGroupArray, eventDispatcher); FakeMediaPeriod mediaPeriod = new FakeMediaPeriod(trackGroupArray, eventDispatcher);
...@@ -661,6 +664,7 @@ public final class ExoPlayerTest { ...@@ -661,6 +664,7 @@ public final class ExoPlayerTest {
MediaPeriodId id, MediaPeriodId id,
TrackGroupArray trackGroupArray, TrackGroupArray trackGroupArray,
Allocator allocator, Allocator allocator,
DrmSessionManager drmSessionManager,
EventDispatcher eventDispatcher, EventDispatcher eventDispatcher,
@Nullable TransferListener transferListener) { @Nullable TransferListener transferListener) {
FakeMediaPeriod mediaPeriod = new FakeMediaPeriod(trackGroupArray, eventDispatcher); FakeMediaPeriod mediaPeriod = new FakeMediaPeriod(trackGroupArray, eventDispatcher);
...@@ -904,11 +908,16 @@ public final class ExoPlayerTest { ...@@ -904,11 +908,16 @@ public final class ExoPlayerTest {
MediaPeriodId id, MediaPeriodId id,
TrackGroupArray trackGroupArray, TrackGroupArray trackGroupArray,
Allocator allocator, Allocator allocator,
DrmSessionManager drmSessionManager,
EventDispatcher eventDispatcher, EventDispatcher eventDispatcher,
@Nullable TransferListener transferListener) { @Nullable TransferListener transferListener) {
// Defer completing preparation of the period until playback parameters have been set. // Defer completing preparation of the period until playback parameters have been set.
fakeMediaPeriodHolder[0] = fakeMediaPeriodHolder[0] =
new FakeMediaPeriod(trackGroupArray, eventDispatcher, /* deferOnPrepared= */ true); new FakeMediaPeriod(
trackGroupArray,
drmSessionManager,
eventDispatcher,
/* deferOnPrepared= */ true);
createPeriodCalledCountDownLatch.countDown(); createPeriodCalledCountDownLatch.countDown();
return fakeMediaPeriodHolder[0]; return fakeMediaPeriodHolder[0];
} }
...@@ -950,11 +959,16 @@ public final class ExoPlayerTest { ...@@ -950,11 +959,16 @@ public final class ExoPlayerTest {
MediaPeriodId id, MediaPeriodId id,
TrackGroupArray trackGroupArray, TrackGroupArray trackGroupArray,
Allocator allocator, Allocator allocator,
DrmSessionManager drmSessionManager,
EventDispatcher eventDispatcher, EventDispatcher eventDispatcher,
@Nullable TransferListener transferListener) { @Nullable TransferListener transferListener) {
// Defer completing preparation of the period until seek has been sent. // Defer completing preparation of the period until seek has been sent.
fakeMediaPeriodHolder[0] = fakeMediaPeriodHolder[0] =
new FakeMediaPeriod(trackGroupArray, eventDispatcher, /* deferOnPrepared= */ true); new FakeMediaPeriod(
trackGroupArray,
drmSessionManager,
eventDispatcher,
/* deferOnPrepared= */ true);
createPeriodCalledCountDownLatch.countDown(); createPeriodCalledCountDownLatch.countDown();
return fakeMediaPeriodHolder[0]; return fakeMediaPeriodHolder[0];
} }
...@@ -3666,6 +3680,7 @@ public final class ExoPlayerTest { ...@@ -3666,6 +3680,7 @@ public final class ExoPlayerTest {
MediaPeriodId id, MediaPeriodId id,
TrackGroupArray trackGroupArray, TrackGroupArray trackGroupArray,
Allocator allocator, Allocator allocator,
DrmSessionManager drmSessionManager,
EventDispatcher eventDispatcher, EventDispatcher eventDispatcher,
@Nullable TransferListener transferListener) { @Nullable TransferListener transferListener) {
return new FakeMediaPeriod(trackGroupArray, eventDispatcher) { return new FakeMediaPeriod(trackGroupArray, eventDispatcher) {
...@@ -6367,6 +6382,7 @@ public final class ExoPlayerTest { ...@@ -6367,6 +6382,7 @@ public final class ExoPlayerTest {
MediaPeriodId id, MediaPeriodId id,
TrackGroupArray trackGroupArray, TrackGroupArray trackGroupArray,
Allocator allocator, Allocator allocator,
DrmSessionManager drmSessionManager,
EventDispatcher eventDispatcher, EventDispatcher eventDispatcher,
@Nullable TransferListener transferListener) { @Nullable TransferListener transferListener) {
return new FakeMediaPeriod(trackGroupArray, eventDispatcher) { return new FakeMediaPeriod(trackGroupArray, eventDispatcher) {
...@@ -6442,9 +6458,10 @@ public final class ExoPlayerTest { ...@@ -6442,9 +6458,10 @@ public final class ExoPlayerTest {
MediaPeriodId id, MediaPeriodId id,
TrackGroupArray trackGroupArray, TrackGroupArray trackGroupArray,
Allocator allocator, Allocator allocator,
DrmSessionManager drmSessionManager,
EventDispatcher eventDispatcher, EventDispatcher eventDispatcher,
@Nullable TransferListener transferListener) { @Nullable TransferListener transferListener) {
return new FakeMediaPeriod(trackGroupArray, eventDispatcher) { return new FakeMediaPeriod(trackGroupArray, drmSessionManager, eventDispatcher) {
private Loader loader = new Loader("oomLoader"); private Loader loader = new Loader("oomLoader");
@Override @Override
...@@ -6456,11 +6473,15 @@ public final class ExoPlayerTest { ...@@ -6456,11 +6473,15 @@ public final class ExoPlayerTest {
@Override @Override
protected SampleStream createSampleStream( protected SampleStream createSampleStream(
long positionUs, TrackSelection selection, EventDispatcher eventDispatcher) { long positionUs,
TrackSelection selection,
DrmSessionManager drmSessionManager,
EventDispatcher eventDispatcher) {
// Create 3 samples without end of stream signal to test that all 3 samples are // Create 3 samples without end of stream signal to test that all 3 samples are
// still played before the exception is thrown. // still played before the exception is thrown.
return new FakeSampleStream( return new FakeSampleStream(
selection.getSelectedFormat(), selection.getSelectedFormat(),
drmSessionManager,
eventDispatcher, eventDispatcher,
positionUs, positionUs,
/* timeUsIncrement= */ 0, /* timeUsIncrement= */ 0,
......
...@@ -31,6 +31,12 @@ import com.google.android.exoplayer2.SimpleExoPlayer; ...@@ -31,6 +31,12 @@ import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.Timeline.Window; import com.google.android.exoplayer2.Timeline.Window;
import com.google.android.exoplayer2.decoder.DecoderCounters; import com.google.android.exoplayer2.decoder.DecoderCounters;
import com.google.android.exoplayer2.drm.DefaultDrmSessionManager;
import com.google.android.exoplayer2.drm.DrmInitData;
import com.google.android.exoplayer2.drm.DrmSessionManager;
import com.google.android.exoplayer2.drm.ExoMediaDrm;
import com.google.android.exoplayer2.drm.MediaDrmCallback;
import com.google.android.exoplayer2.drm.MediaDrmCallbackException;
import com.google.android.exoplayer2.metadata.Metadata; import com.google.android.exoplayer2.metadata.Metadata;
import com.google.android.exoplayer2.source.ConcatenatingMediaSource; import com.google.android.exoplayer2.source.ConcatenatingMediaSource;
import com.google.android.exoplayer2.source.LoadEventInfo; import com.google.android.exoplayer2.source.LoadEventInfo;
...@@ -43,16 +49,19 @@ import com.google.android.exoplayer2.testutil.ActionSchedule; ...@@ -43,16 +49,19 @@ import com.google.android.exoplayer2.testutil.ActionSchedule;
import com.google.android.exoplayer2.testutil.ActionSchedule.PlayerRunnable; import com.google.android.exoplayer2.testutil.ActionSchedule.PlayerRunnable;
import com.google.android.exoplayer2.testutil.ExoPlayerTestRunner; import com.google.android.exoplayer2.testutil.ExoPlayerTestRunner;
import com.google.android.exoplayer2.testutil.FakeAudioRenderer; import com.google.android.exoplayer2.testutil.FakeAudioRenderer;
import com.google.android.exoplayer2.testutil.FakeExoMediaDrm;
import com.google.android.exoplayer2.testutil.FakeMediaSource; import com.google.android.exoplayer2.testutil.FakeMediaSource;
import com.google.android.exoplayer2.testutil.FakeTimeline; import com.google.android.exoplayer2.testutil.FakeTimeline;
import com.google.android.exoplayer2.testutil.FakeTimeline.TimelineWindowDefinition; import com.google.android.exoplayer2.testutil.FakeTimeline.TimelineWindowDefinition;
import com.google.android.exoplayer2.testutil.FakeVideoRenderer; import com.google.android.exoplayer2.testutil.FakeVideoRenderer;
import com.google.android.exoplayer2.testutil.TestUtil;
import com.google.android.exoplayer2.trackselection.TrackSelectionArray; import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import org.junit.Test; import org.junit.Test;
...@@ -107,6 +116,24 @@ public final class AnalyticsCollectorTest { ...@@ -107,6 +116,24 @@ public final class AnalyticsCollectorTest {
private static final int EVENT_DRM_SESSION_RELEASED = 38; private static final int EVENT_DRM_SESSION_RELEASED = 38;
private static final int EVENT_VIDEO_FRAME_PROCESSING_OFFSET = 39; private static final int EVENT_VIDEO_FRAME_PROCESSING_OFFSET = 39;
private static final UUID DRM_SCHEME_UUID =
UUID.nameUUIDFromBytes(TestUtil.createByteArray(7, 8, 9));
public static final DrmInitData DRM_DATA_1 =
new DrmInitData(
new DrmInitData.SchemeData(
DRM_SCHEME_UUID,
ExoPlayerTestRunner.VIDEO_FORMAT.sampleMimeType,
/* data= */ TestUtil.createByteArray(1, 2, 3)));
public static final DrmInitData DRM_DATA_2 =
new DrmInitData(
new DrmInitData.SchemeData(
DRM_SCHEME_UUID,
ExoPlayerTestRunner.VIDEO_FORMAT.sampleMimeType,
/* data= */ TestUtil.createByteArray(4, 5, 6)));
private static final Format VIDEO_FORMAT_DRM_1 =
ExoPlayerTestRunner.VIDEO_FORMAT.buildUpon().setDrmInitData(DRM_DATA_1).build();
private static final int TIMEOUT_MS = 10000; private static final int TIMEOUT_MS = 10000;
private static final Timeline SINGLE_PERIOD_TIMELINE = new FakeTimeline(/* windowCount= */ 1); private static final Timeline SINGLE_PERIOD_TIMELINE = new FakeTimeline(/* windowCount= */ 1);
private static final EventWindowAndPeriodId WINDOW_0 = private static final EventWindowAndPeriodId WINDOW_0 =
...@@ -114,6 +141,12 @@ public final class AnalyticsCollectorTest { ...@@ -114,6 +141,12 @@ public final class AnalyticsCollectorTest {
private static final EventWindowAndPeriodId WINDOW_1 = private static final EventWindowAndPeriodId WINDOW_1 =
new EventWindowAndPeriodId(/* windowIndex= */ 1, /* mediaPeriodId= */ null); new EventWindowAndPeriodId(/* windowIndex= */ 1, /* mediaPeriodId= */ null);
private final DrmSessionManager drmSessionManager =
new DefaultDrmSessionManager.Builder()
.setUuidAndExoMediaDrmProvider(DRM_SCHEME_UUID, uuid -> new FakeExoMediaDrm())
.setMultiSession(true)
.build(new EmptyDrmCallback());
private EventWindowAndPeriodId period0; private EventWindowAndPeriodId period0;
private EventWindowAndPeriodId period1; private EventWindowAndPeriodId period1;
private EventWindowAndPeriodId period0Seq0; private EventWindowAndPeriodId period0Seq0;
...@@ -1158,6 +1191,71 @@ public final class AnalyticsCollectorTest { ...@@ -1158,6 +1191,71 @@ public final class AnalyticsCollectorTest {
assertThat(listener.getEvents(EVENT_SEEK_PROCESSED)).containsExactly(period0); assertThat(listener.getEvents(EVENT_SEEK_PROCESSED)).containsExactly(period0);
} }
@Test
public void drmEvents_singlePeriod() throws Exception {
MediaSource mediaSource =
new FakeMediaSource(SINGLE_PERIOD_TIMELINE, drmSessionManager, VIDEO_FORMAT_DRM_1);
TestAnalyticsListener listener = runAnalyticsTest(mediaSource);
populateEventIds(listener.lastReportedTimeline);
assertThat(listener.getEvents(EVENT_DRM_ERROR)).isEmpty();
assertThat(listener.getEvents(EVENT_DRM_SESSION_ACQUIRED)).containsExactly(period0);
assertThat(listener.getEvents(EVENT_DRM_KEYS_LOADED)).containsExactly(period0);
// The release event is lost because it's posted to "ExoPlayerTest thread" after that thread
// has been quit during clean-up.
assertThat(listener.getEvents(EVENT_DRM_SESSION_RELEASED)).isEmpty();
}
@Test
public void drmEvents_periodWithSameDrmData_keysReused() throws Exception {
MediaSource mediaSource =
new ConcatenatingMediaSource(
new FakeMediaSource(SINGLE_PERIOD_TIMELINE, drmSessionManager, VIDEO_FORMAT_DRM_1),
new FakeMediaSource(SINGLE_PERIOD_TIMELINE, drmSessionManager, VIDEO_FORMAT_DRM_1));
TestAnalyticsListener listener = runAnalyticsTest(mediaSource);
populateEventIds(listener.lastReportedTimeline);
assertThat(listener.getEvents(EVENT_DRM_ERROR)).isEmpty();
assertThat(listener.getEvents(EVENT_DRM_SESSION_ACQUIRED)).containsExactly(period0, period1);
assertThat(listener.getEvents(EVENT_DRM_KEYS_LOADED)).containsExactly(period0);
// The period1 release event is lost because it's posted to "ExoPlayerTest thread" after that
// thread has been quit during clean-up.
assertThat(listener.getEvents(EVENT_DRM_SESSION_RELEASED)).containsExactly(period0);
}
@Test
public void drmEvents_periodWithDifferentDrmData_keysLoadedAgain() throws Exception {
MediaSource mediaSource =
new ConcatenatingMediaSource(
new FakeMediaSource(SINGLE_PERIOD_TIMELINE, drmSessionManager, VIDEO_FORMAT_DRM_1),
new FakeMediaSource(
SINGLE_PERIOD_TIMELINE,
drmSessionManager,
VIDEO_FORMAT_DRM_1.buildUpon().setDrmInitData(DRM_DATA_2).build()));
TestAnalyticsListener listener = runAnalyticsTest(mediaSource);
populateEventIds(listener.lastReportedTimeline);
assertThat(listener.getEvents(EVENT_DRM_ERROR)).isEmpty();
assertThat(listener.getEvents(EVENT_DRM_SESSION_ACQUIRED)).containsExactly(period0, period1);
assertThat(listener.getEvents(EVENT_DRM_KEYS_LOADED)).containsExactly(period0, period1);
// The period1 release event is lost because it's posted to "ExoPlayerTest thread" after that
// thread has been quit during clean-up.
assertThat(listener.getEvents(EVENT_DRM_SESSION_RELEASED)).containsExactly(period0);
}
@Test
public void drmEvents_errorHandling() throws Exception {
DrmSessionManager failingDrmSessionManager =
new DefaultDrmSessionManager.Builder().build(new FailingDrmCallback());
MediaSource mediaSource =
new FakeMediaSource(SINGLE_PERIOD_TIMELINE, failingDrmSessionManager, VIDEO_FORMAT_DRM_1);
TestAnalyticsListener listener = runAnalyticsTest(mediaSource);
populateEventIds(listener.lastReportedTimeline);
assertThat(listener.getEvents(EVENT_DRM_ERROR)).containsExactly(period0);
assertThat(listener.getEvents(EVENT_PLAYER_ERROR)).containsExactly(period0);
}
private void populateEventIds(Timeline timeline) { private void populateEventIds(Timeline timeline) {
period0 = period0 =
new EventWindowAndPeriodId( new EventWindowAndPeriodId(
...@@ -1544,4 +1642,42 @@ public final class AnalyticsCollectorTest { ...@@ -1544,4 +1642,42 @@ public final class AnalyticsCollectorTest {
} }
} }
} }
/**
* A {@link MediaDrmCallback} that returns empty byte arrays for both {@link
* #executeProvisionRequest(UUID, ExoMediaDrm.ProvisionRequest)} and {@link
* #executeKeyRequest(UUID, ExoMediaDrm.KeyRequest)}.
*/
private static final class EmptyDrmCallback implements MediaDrmCallback {
@Override
public byte[] executeProvisionRequest(UUID uuid, ExoMediaDrm.ProvisionRequest request)
throws MediaDrmCallbackException {
return new byte[0];
}
@Override
public byte[] executeKeyRequest(UUID uuid, ExoMediaDrm.KeyRequest request)
throws MediaDrmCallbackException {
return new byte[0];
}
}
/**
* A {@link MediaDrmCallback} that throws exceptions for both {@link
* #executeProvisionRequest(UUID, ExoMediaDrm.ProvisionRequest)} and {@link
* #executeKeyRequest(UUID, ExoMediaDrm.KeyRequest)}.
*/
private static final class FailingDrmCallback implements MediaDrmCallback {
@Override
public byte[] executeProvisionRequest(UUID uuid, ExoMediaDrm.ProvisionRequest request)
throws MediaDrmCallbackException {
throw new RuntimeException("executeProvision failed");
}
@Override
public byte[] executeKeyRequest(UUID uuid, ExoMediaDrm.KeyRequest request)
throws MediaDrmCallbackException {
throw new RuntimeException("executeKey failed");
}
}
} }
...@@ -28,6 +28,7 @@ import com.google.android.exoplayer2.C; ...@@ -28,6 +28,7 @@ import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.RendererCapabilities; import com.google.android.exoplayer2.RendererCapabilities;
import com.google.android.exoplayer2.RendererConfiguration; import com.google.android.exoplayer2.RendererConfiguration;
import com.google.android.exoplayer2.drm.DrmSessionManager;
import com.google.android.exoplayer2.mediacodec.MediaCodecInfo; import com.google.android.exoplayer2.mediacodec.MediaCodecInfo;
import com.google.android.exoplayer2.mediacodec.MediaCodecSelector; import com.google.android.exoplayer2.mediacodec.MediaCodecSelector;
import com.google.android.exoplayer2.mediacodec.MediaCodecUtil.DecoderQueryException; import com.google.android.exoplayer2.mediacodec.MediaCodecUtil.DecoderQueryException;
...@@ -111,6 +112,7 @@ public class MediaCodecAudioRendererTest { ...@@ -111,6 +112,7 @@ public class MediaCodecAudioRendererTest {
FakeSampleStream fakeSampleStream = FakeSampleStream fakeSampleStream =
new FakeSampleStream( new FakeSampleStream(
/* format= */ AUDIO_AAC, /* format= */ AUDIO_AAC,
DrmSessionManager.DUMMY,
/* eventDispatcher= */ null, /* eventDispatcher= */ null,
/* firstSampleTimeUs= */ 0, /* firstSampleTimeUs= */ 0,
/* timeUsIncrement= */ 50, /* timeUsIncrement= */ 50,
......
...@@ -22,6 +22,7 @@ import static java.nio.charset.StandardCharsets.UTF_8; ...@@ -22,6 +22,7 @@ import static java.nio.charset.StandardCharsets.UTF_8;
import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.android.exoplayer2.ExoPlaybackException; import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.drm.DrmSessionManager;
import com.google.android.exoplayer2.metadata.emsg.EventMessage; import com.google.android.exoplayer2.metadata.emsg.EventMessage;
import com.google.android.exoplayer2.metadata.emsg.EventMessageEncoder; import com.google.android.exoplayer2.metadata.emsg.EventMessageEncoder;
import com.google.android.exoplayer2.metadata.id3.TextInformationFrame; import com.google.android.exoplayer2.metadata.id3.TextInformationFrame;
...@@ -144,6 +145,7 @@ public class MetadataRendererTest { ...@@ -144,6 +145,7 @@ public class MetadataRendererTest {
new Format[] {EMSG_FORMAT}, new Format[] {EMSG_FORMAT},
new FakeSampleStream( new FakeSampleStream(
EMSG_FORMAT, EMSG_FORMAT,
DrmSessionManager.DUMMY,
/* eventDispatcher= */ null, /* eventDispatcher= */ null,
/* firstSampleTimeUs= */ 0, /* firstSampleTimeUs= */ 0,
/* timeUsIncrement= */ 0, /* timeUsIncrement= */ 0,
......
...@@ -25,6 +25,7 @@ import com.google.android.exoplayer2.Player; ...@@ -25,6 +25,7 @@ import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.Timeline.Period; import com.google.android.exoplayer2.Timeline.Period;
import com.google.android.exoplayer2.Timeline.Window; import com.google.android.exoplayer2.Timeline.Window;
import com.google.android.exoplayer2.drm.DrmSessionManager;
import com.google.android.exoplayer2.source.ClippingMediaSource.IllegalClippingException; import com.google.android.exoplayer2.source.ClippingMediaSource.IllegalClippingException;
import com.google.android.exoplayer2.source.MaskingMediaSource.DummyTimeline; import com.google.android.exoplayer2.source.MaskingMediaSource.DummyTimeline;
import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId; import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
...@@ -566,6 +567,7 @@ public final class ClippingMediaSourceTest { ...@@ -566,6 +567,7 @@ public final class ClippingMediaSourceTest {
MediaPeriodId id, MediaPeriodId id,
TrackGroupArray trackGroupArray, TrackGroupArray trackGroupArray,
Allocator allocator, Allocator allocator,
DrmSessionManager drmSessionManager,
EventDispatcher eventDispatcher, EventDispatcher eventDispatcher,
@Nullable TransferListener transferListener) { @Nullable TransferListener transferListener) {
eventDispatcher.downstreamFormatChanged( eventDispatcher.downstreamFormatChanged(
...@@ -578,7 +580,12 @@ public final class ClippingMediaSourceTest { ...@@ -578,7 +580,12 @@ public final class ClippingMediaSourceTest {
C.usToMs(eventStartUs), C.usToMs(eventStartUs),
C.usToMs(eventEndUs))); C.usToMs(eventEndUs)));
return super.createFakeMediaPeriod( return super.createFakeMediaPeriod(
id, trackGroupArray, allocator, eventDispatcher, transferListener); id,
trackGroupArray,
allocator,
drmSessionManager,
eventDispatcher,
transferListener);
} }
}; };
final ClippingMediaSource clippingMediaSource = final ClippingMediaSource clippingMediaSource =
......
...@@ -34,6 +34,7 @@ import com.google.android.exoplayer2.RendererConfiguration; ...@@ -34,6 +34,7 @@ import com.google.android.exoplayer2.RendererConfiguration;
import com.google.android.exoplayer2.decoder.DecoderException; import com.google.android.exoplayer2.decoder.DecoderException;
import com.google.android.exoplayer2.decoder.DecoderInputBuffer; import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
import com.google.android.exoplayer2.decoder.SimpleDecoder; import com.google.android.exoplayer2.decoder.SimpleDecoder;
import com.google.android.exoplayer2.drm.DrmSessionManager;
import com.google.android.exoplayer2.drm.ExoMediaCrypto; import com.google.android.exoplayer2.drm.ExoMediaCrypto;
import com.google.android.exoplayer2.testutil.FakeSampleStream; import com.google.android.exoplayer2.testutil.FakeSampleStream;
import com.google.android.exoplayer2.testutil.FakeSampleStream.FakeSampleStreamItem; import com.google.android.exoplayer2.testutil.FakeSampleStream.FakeSampleStreamItem;
...@@ -185,6 +186,7 @@ public final class DecoderVideoRendererTest { ...@@ -185,6 +186,7 @@ public final class DecoderVideoRendererTest {
FakeSampleStream fakeSampleStream = FakeSampleStream fakeSampleStream =
new FakeSampleStream( new FakeSampleStream(
/* format= */ H264_FORMAT, /* format= */ H264_FORMAT,
DrmSessionManager.DUMMY,
/* eventDispatcher= */ null, /* eventDispatcher= */ null,
/* firstSampleTimeUs= */ 0, /* firstSampleTimeUs= */ 0,
/* timeUsIncrement= */ 50, /* timeUsIncrement= */ 50,
...@@ -213,6 +215,7 @@ public final class DecoderVideoRendererTest { ...@@ -213,6 +215,7 @@ public final class DecoderVideoRendererTest {
FakeSampleStream fakeSampleStream = FakeSampleStream fakeSampleStream =
new FakeSampleStream( new FakeSampleStream(
/* format= */ H264_FORMAT, /* format= */ H264_FORMAT,
DrmSessionManager.DUMMY,
/* eventDispatcher= */ null, /* eventDispatcher= */ null,
/* firstSampleTimeUs= */ 0, /* firstSampleTimeUs= */ 0,
/* timeUsIncrement= */ 50, /* timeUsIncrement= */ 50,
...@@ -240,6 +243,7 @@ public final class DecoderVideoRendererTest { ...@@ -240,6 +243,7 @@ public final class DecoderVideoRendererTest {
FakeSampleStream fakeSampleStream = FakeSampleStream fakeSampleStream =
new FakeSampleStream( new FakeSampleStream(
/* format= */ H264_FORMAT, /* format= */ H264_FORMAT,
DrmSessionManager.DUMMY,
/* eventDispatcher= */ null, /* eventDispatcher= */ null,
/* firstSampleTimeUs= */ 0, /* firstSampleTimeUs= */ 0,
/* timeUsIncrement= */ 50, /* timeUsIncrement= */ 50,
...@@ -270,6 +274,7 @@ public final class DecoderVideoRendererTest { ...@@ -270,6 +274,7 @@ public final class DecoderVideoRendererTest {
FakeSampleStream fakeSampleStream1 = FakeSampleStream fakeSampleStream1 =
new FakeSampleStream( new FakeSampleStream(
/* format= */ H264_FORMAT, /* format= */ H264_FORMAT,
DrmSessionManager.DUMMY,
/* eventDispatcher= */ null, /* eventDispatcher= */ null,
/* firstSampleTimeUs= */ 0, /* firstSampleTimeUs= */ 0,
/* timeUsIncrement= */ 50, /* timeUsIncrement= */ 50,
...@@ -278,6 +283,7 @@ public final class DecoderVideoRendererTest { ...@@ -278,6 +283,7 @@ public final class DecoderVideoRendererTest {
FakeSampleStream fakeSampleStream2 = FakeSampleStream fakeSampleStream2 =
new FakeSampleStream( new FakeSampleStream(
/* format= */ H264_FORMAT, /* format= */ H264_FORMAT,
DrmSessionManager.DUMMY,
/* eventDispatcher= */ null, /* eventDispatcher= */ null,
/* firstSampleTimeUs= */ 0, /* firstSampleTimeUs= */ 0,
/* timeUsIncrement= */ 50, /* timeUsIncrement= */ 50,
...@@ -314,6 +320,7 @@ public final class DecoderVideoRendererTest { ...@@ -314,6 +320,7 @@ public final class DecoderVideoRendererTest {
FakeSampleStream fakeSampleStream1 = FakeSampleStream fakeSampleStream1 =
new FakeSampleStream( new FakeSampleStream(
/* format= */ H264_FORMAT, /* format= */ H264_FORMAT,
DrmSessionManager.DUMMY,
/* eventDispatcher= */ null, /* eventDispatcher= */ null,
/* firstSampleTimeUs= */ 0, /* firstSampleTimeUs= */ 0,
/* timeUsIncrement= */ 50, /* timeUsIncrement= */ 50,
...@@ -322,6 +329,7 @@ public final class DecoderVideoRendererTest { ...@@ -322,6 +329,7 @@ public final class DecoderVideoRendererTest {
FakeSampleStream fakeSampleStream2 = FakeSampleStream fakeSampleStream2 =
new FakeSampleStream( new FakeSampleStream(
/* format= */ H264_FORMAT, /* format= */ H264_FORMAT,
DrmSessionManager.DUMMY,
/* eventDispatcher= */ null, /* eventDispatcher= */ null,
/* firstSampleTimeUs= */ 0, /* firstSampleTimeUs= */ 0,
/* timeUsIncrement= */ 50, /* timeUsIncrement= */ 50,
......
...@@ -38,6 +38,7 @@ import com.google.android.exoplayer2.Format; ...@@ -38,6 +38,7 @@ import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.Renderer; import com.google.android.exoplayer2.Renderer;
import com.google.android.exoplayer2.RendererCapabilities; import com.google.android.exoplayer2.RendererCapabilities;
import com.google.android.exoplayer2.RendererConfiguration; import com.google.android.exoplayer2.RendererConfiguration;
import com.google.android.exoplayer2.drm.DrmSessionManager;
import com.google.android.exoplayer2.mediacodec.MediaCodecInfo; import com.google.android.exoplayer2.mediacodec.MediaCodecInfo;
import com.google.android.exoplayer2.mediacodec.MediaCodecSelector; import com.google.android.exoplayer2.mediacodec.MediaCodecSelector;
import com.google.android.exoplayer2.mediacodec.MediaCodecUtil.DecoderQueryException; import com.google.android.exoplayer2.mediacodec.MediaCodecUtil.DecoderQueryException;
...@@ -126,6 +127,7 @@ public class MediaCodecVideoRendererTest { ...@@ -126,6 +127,7 @@ public class MediaCodecVideoRendererTest {
FakeSampleStream fakeSampleStream = FakeSampleStream fakeSampleStream =
new FakeSampleStream( new FakeSampleStream(
/* format= */ VIDEO_H264, /* format= */ VIDEO_H264,
DrmSessionManager.DUMMY,
/* eventDispatcher= */ null, /* eventDispatcher= */ null,
/* firstSampleTimeUs= */ 0, /* firstSampleTimeUs= */ 0,
/* timeUsIncrement= */ 50_000, /* timeUsIncrement= */ 50_000,
...@@ -162,6 +164,7 @@ public class MediaCodecVideoRendererTest { ...@@ -162,6 +164,7 @@ public class MediaCodecVideoRendererTest {
new Format[] {VIDEO_H264}, new Format[] {VIDEO_H264},
new FakeSampleStream( new FakeSampleStream(
/* format= */ VIDEO_H264, /* format= */ VIDEO_H264,
DrmSessionManager.DUMMY,
/* eventDispatcher= */ null, /* eventDispatcher= */ null,
/* firstSampleTimeUs= */ 0, /* firstSampleTimeUs= */ 0,
/* timeUsIncrement= */ 0, /* timeUsIncrement= */ 0,
...@@ -199,6 +202,7 @@ public class MediaCodecVideoRendererTest { ...@@ -199,6 +202,7 @@ public class MediaCodecVideoRendererTest {
FakeSampleStream fakeSampleStream = FakeSampleStream fakeSampleStream =
new FakeSampleStream( new FakeSampleStream(
/* format= */ pAsp1, /* format= */ pAsp1,
DrmSessionManager.DUMMY,
/* eventDispatcher= */ null, /* eventDispatcher= */ null,
/* firstSampleTimeUs= */ 0, /* firstSampleTimeUs= */ 0,
/* timeUsIncrement= */ 5000, /* timeUsIncrement= */ 5000,
...@@ -248,6 +252,7 @@ public class MediaCodecVideoRendererTest { ...@@ -248,6 +252,7 @@ public class MediaCodecVideoRendererTest {
FakeSampleStream fakeSampleStream = FakeSampleStream fakeSampleStream =
new FakeSampleStream( new FakeSampleStream(
/* format= */ VIDEO_H264, /* format= */ VIDEO_H264,
DrmSessionManager.DUMMY,
/* eventDispatcher= */ null, /* eventDispatcher= */ null,
/* firstSampleTimeUs= */ 0, /* firstSampleTimeUs= */ 0,
/* timeUsIncrement= */ 50, /* timeUsIncrement= */ 50,
...@@ -282,6 +287,7 @@ public class MediaCodecVideoRendererTest { ...@@ -282,6 +287,7 @@ public class MediaCodecVideoRendererTest {
FakeSampleStream fakeSampleStream = FakeSampleStream fakeSampleStream =
new FakeSampleStream( new FakeSampleStream(
/* format= */ VIDEO_H264, /* format= */ VIDEO_H264,
DrmSessionManager.DUMMY,
/* eventDispatcher= */ null, /* eventDispatcher= */ null,
/* firstSampleTimeUs= */ 0, /* firstSampleTimeUs= */ 0,
/* timeUsIncrement= */ 50, /* timeUsIncrement= */ 50,
...@@ -308,6 +314,7 @@ public class MediaCodecVideoRendererTest { ...@@ -308,6 +314,7 @@ public class MediaCodecVideoRendererTest {
FakeSampleStream fakeSampleStream = FakeSampleStream fakeSampleStream =
new FakeSampleStream( new FakeSampleStream(
/* format= */ VIDEO_H264, /* format= */ VIDEO_H264,
DrmSessionManager.DUMMY,
/* eventDispatcher= */ null, /* eventDispatcher= */ null,
/* firstSampleTimeUs= */ 0, /* firstSampleTimeUs= */ 0,
/* timeUsIncrement= */ 50, /* timeUsIncrement= */ 50,
...@@ -333,6 +340,7 @@ public class MediaCodecVideoRendererTest { ...@@ -333,6 +340,7 @@ public class MediaCodecVideoRendererTest {
FakeSampleStream fakeSampleStream = FakeSampleStream fakeSampleStream =
new FakeSampleStream( new FakeSampleStream(
/* format= */ VIDEO_H264, /* format= */ VIDEO_H264,
DrmSessionManager.DUMMY,
/* eventDispatcher= */ null, /* eventDispatcher= */ null,
/* firstSampleTimeUs= */ 0, /* firstSampleTimeUs= */ 0,
/* timeUsIncrement= */ 50, /* timeUsIncrement= */ 50,
...@@ -359,6 +367,7 @@ public class MediaCodecVideoRendererTest { ...@@ -359,6 +367,7 @@ public class MediaCodecVideoRendererTest {
FakeSampleStream fakeSampleStream1 = FakeSampleStream fakeSampleStream1 =
new FakeSampleStream( new FakeSampleStream(
/* format= */ VIDEO_H264, /* format= */ VIDEO_H264,
DrmSessionManager.DUMMY,
/* eventDispatcher= */ null, /* eventDispatcher= */ null,
/* firstSampleTimeUs= */ 0, /* firstSampleTimeUs= */ 0,
/* timeUsIncrement= */ 50, /* timeUsIncrement= */ 50,
...@@ -367,6 +376,7 @@ public class MediaCodecVideoRendererTest { ...@@ -367,6 +376,7 @@ public class MediaCodecVideoRendererTest {
FakeSampleStream fakeSampleStream2 = FakeSampleStream fakeSampleStream2 =
new FakeSampleStream( new FakeSampleStream(
/* format= */ VIDEO_H264, /* format= */ VIDEO_H264,
DrmSessionManager.DUMMY,
/* eventDispatcher= */ null, /* eventDispatcher= */ null,
/* firstSampleTimeUs= */ 0, /* firstSampleTimeUs= */ 0,
/* timeUsIncrement= */ 50, /* timeUsIncrement= */ 50,
...@@ -401,6 +411,7 @@ public class MediaCodecVideoRendererTest { ...@@ -401,6 +411,7 @@ public class MediaCodecVideoRendererTest {
FakeSampleStream fakeSampleStream1 = FakeSampleStream fakeSampleStream1 =
new FakeSampleStream( new FakeSampleStream(
/* format= */ VIDEO_H264, /* format= */ VIDEO_H264,
DrmSessionManager.DUMMY,
/* eventDispatcher= */ null, /* eventDispatcher= */ null,
/* firstSampleTimeUs= */ 0, /* firstSampleTimeUs= */ 0,
/* timeUsIncrement= */ 50, /* timeUsIncrement= */ 50,
...@@ -409,6 +420,7 @@ public class MediaCodecVideoRendererTest { ...@@ -409,6 +420,7 @@ public class MediaCodecVideoRendererTest {
FakeSampleStream fakeSampleStream2 = FakeSampleStream fakeSampleStream2 =
new FakeSampleStream( new FakeSampleStream(
/* format= */ VIDEO_H264, /* format= */ VIDEO_H264,
DrmSessionManager.DUMMY,
/* eventDispatcher= */ null, /* eventDispatcher= */ null,
/* firstSampleTimeUs= */ 0, /* firstSampleTimeUs= */ 0,
/* timeUsIncrement= */ 50, /* timeUsIncrement= */ 50,
...@@ -450,6 +462,7 @@ public class MediaCodecVideoRendererTest { ...@@ -450,6 +462,7 @@ public class MediaCodecVideoRendererTest {
FakeSampleStream fakeSampleStream = FakeSampleStream fakeSampleStream =
new FakeSampleStream( new FakeSampleStream(
/* format= */ mp4Uhd, /* format= */ mp4Uhd,
DrmSessionManager.DUMMY,
/* eventDispatcher= */ null, /* eventDispatcher= */ null,
/* firstSampleTimeUs= */ 0, /* firstSampleTimeUs= */ 0,
/* timeUsIncrement= */ 50, /* timeUsIncrement= */ 50,
......
...@@ -68,14 +68,6 @@ public class FakeAdaptiveMediaPeriod extends FakeMediaPeriod ...@@ -68,14 +68,6 @@ public class FakeAdaptiveMediaPeriod extends FakeMediaPeriod
} }
@Override @Override
public void release() {
for (ChunkSampleStream<FakeChunkSource> sampleStream : sampleStreams) {
sampleStream.release();
}
super.release();
}
@Override
public synchronized void prepare(Callback callback, long positionUs) { public synchronized void prepare(Callback callback, long positionUs) {
super.prepare(callback, positionUs); super.prepare(callback, positionUs);
this.callback = callback; this.callback = callback;
...@@ -141,8 +133,11 @@ public class FakeAdaptiveMediaPeriod extends FakeMediaPeriod ...@@ -141,8 +133,11 @@ public class FakeAdaptiveMediaPeriod extends FakeMediaPeriod
} }
@Override @Override
protected SampleStream createSampleStream( protected final SampleStream createSampleStream(
long positionUs, TrackSelection trackSelection, EventDispatcher eventDispatcher) { long positionUs,
TrackSelection trackSelection,
DrmSessionManager drmSessionManager,
EventDispatcher eventDispatcher) {
FakeChunkSource chunkSource = FakeChunkSource chunkSource =
chunkSourceFactory.createChunkSource(trackSelection, durationUs, transferListener); chunkSourceFactory.createChunkSource(trackSelection, durationUs, transferListener);
return new ChunkSampleStream<>( return new ChunkSampleStream<>(
...@@ -159,12 +154,20 @@ public class FakeAdaptiveMediaPeriod extends FakeMediaPeriod ...@@ -159,12 +154,20 @@ public class FakeAdaptiveMediaPeriod extends FakeMediaPeriod
} }
@Override @Override
// sampleStream is created by createSampleStream() above.
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
protected void seekSampleStream(SampleStream sampleStream, long positionUs) { protected void seekSampleStream(SampleStream sampleStream, long positionUs) {
((ChunkSampleStream<FakeChunkSource>) sampleStream).seekToUs(positionUs); ((ChunkSampleStream<FakeChunkSource>) sampleStream).seekToUs(positionUs);
} }
@Override @Override
// sampleStream is created by createSampleStream() above.
@SuppressWarnings("unchecked")
protected void releaseSampleStream(SampleStream sampleStream) {
((ChunkSampleStream<FakeChunkSource>) sampleStream).release();
}
@Override
public void onContinueLoadingRequested(ChunkSampleStream<FakeChunkSource> source) { public void onContinueLoadingRequested(ChunkSampleStream<FakeChunkSource> source) {
Assertions.checkStateNotNull(callback).onContinueLoadingRequested(this); Assertions.checkStateNotNull(callback).onContinueLoadingRequested(this);
} }
......
...@@ -18,6 +18,7 @@ package com.google.android.exoplayer2.testutil; ...@@ -18,6 +18,7 @@ package com.google.android.exoplayer2.testutil;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.Timeline.Period; import com.google.android.exoplayer2.Timeline.Period;
import com.google.android.exoplayer2.drm.DrmSessionManager;
import com.google.android.exoplayer2.source.MediaSource; import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispatcher; import com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispatcher;
import com.google.android.exoplayer2.source.TrackGroupArray; import com.google.android.exoplayer2.source.TrackGroupArray;
...@@ -37,7 +38,7 @@ public class FakeAdaptiveMediaSource extends FakeMediaSource { ...@@ -37,7 +38,7 @@ public class FakeAdaptiveMediaSource extends FakeMediaSource {
Timeline timeline, Timeline timeline,
TrackGroupArray trackGroupArray, TrackGroupArray trackGroupArray,
FakeChunkSource.Factory chunkSourceFactory) { FakeChunkSource.Factory chunkSourceFactory) {
super(timeline, trackGroupArray); super(timeline, DrmSessionManager.DUMMY, trackGroupArray);
this.chunkSourceFactory = chunkSourceFactory; this.chunkSourceFactory = chunkSourceFactory;
} }
...@@ -46,6 +47,7 @@ public class FakeAdaptiveMediaSource extends FakeMediaSource { ...@@ -46,6 +47,7 @@ public class FakeAdaptiveMediaSource extends FakeMediaSource {
MediaPeriodId id, MediaPeriodId id,
TrackGroupArray trackGroupArray, TrackGroupArray trackGroupArray,
Allocator allocator, Allocator allocator,
DrmSessionManager drmSessionManager,
EventDispatcher eventDispatcher, EventDispatcher eventDispatcher,
@Nullable TransferListener transferListener) { @Nullable TransferListener transferListener) {
Period period = Util.castNonNull(getTimeline()).getPeriodByUid(id.periodUid, new Period()); Period period = Util.castNonNull(getTimeline()).getPeriodByUid(id.periodUid, new Period());
......
/*
* Copyright (C) 2020 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.testutil;
import android.media.DeniedByServerException;
import android.media.MediaCryptoException;
import android.media.MediaDrmException;
import android.media.NotProvisionedException;
import android.os.PersistableBundle;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import com.google.android.exoplayer2.drm.DrmInitData;
import com.google.android.exoplayer2.drm.ExoMediaCrypto;
import com.google.android.exoplayer2.drm.ExoMediaDrm;
import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.Util;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
/** A fake implementation of {@link ExoMediaDrm} for use in tests. */
@RequiresApi(18)
public class FakeExoMediaDrm implements ExoMediaDrm {
private static final KeyRequest DUMMY_KEY_REQUEST =
new KeyRequest(TestUtil.createByteArray(4, 5, 6), "foo.test");
private static final ProvisionRequest DUMMY_PROVISION_REQUEST =
new ProvisionRequest(TestUtil.createByteArray(7, 8, 9), "bar.test");
private final Map<String, byte[]> byteProperties;
private final Map<String, String> stringProperties;
private final Set<List<Byte>> openSessionIds;
private final AtomicInteger sessionIdGenerator;
private int referenceCount;
/**
* Constructs an instance that returns random and unique {@code sessionIds} for subsequent calls
* to {@link #openSession()}.
*/
public FakeExoMediaDrm() {
byteProperties = new HashMap<>();
stringProperties = new HashMap<>();
openSessionIds = new HashSet<>();
sessionIdGenerator = new AtomicInteger();
referenceCount = 1;
}
@Override
public void setOnEventListener(@Nullable OnEventListener listener) {
// Do nothing.
}
@Override
public void setOnKeyStatusChangeListener(@Nullable OnKeyStatusChangeListener listener) {
// Do nothing.
}
@Override
public void setOnExpirationUpdateListener(@Nullable OnExpirationUpdateListener listener) {
// Do nothing.
}
@Override
public byte[] openSession() throws MediaDrmException {
Assertions.checkState(referenceCount > 0);
byte[] sessionId =
TestUtil.buildTestData(/* length= */ 10, sessionIdGenerator.incrementAndGet());
if (!openSessionIds.add(toByteList(sessionId))) {
throw new MediaDrmException(
Util.formatInvariant(
"Generated sessionId[%s] clashes with already-open session",
sessionIdGenerator.get()));
}
return sessionId;
}
@Override
public void closeSession(byte[] sessionId) {
Assertions.checkState(referenceCount > 0);
Assertions.checkState(openSessionIds.remove(toByteList(sessionId)));
}
@Override
public KeyRequest getKeyRequest(
byte[] scope,
@Nullable List<DrmInitData.SchemeData> schemeDatas,
int keyType,
@Nullable HashMap<String, String> optionalParameters)
throws NotProvisionedException {
Assertions.checkState(referenceCount > 0);
return DUMMY_KEY_REQUEST;
}
@Nullable
@Override
public byte[] provideKeyResponse(byte[] scope, byte[] response)
throws NotProvisionedException, DeniedByServerException {
Assertions.checkState(referenceCount > 0);
return null;
}
@Override
public ProvisionRequest getProvisionRequest() {
Assertions.checkState(referenceCount > 0);
return DUMMY_PROVISION_REQUEST;
}
@Override
public void provideProvisionResponse(byte[] response) throws DeniedByServerException {
Assertions.checkState(referenceCount > 0);
}
@Override
public Map<String, String> queryKeyStatus(byte[] sessionId) {
Assertions.checkState(referenceCount > 0);
return Collections.emptyMap();
}
@Override
public void acquire() {
Assertions.checkState(referenceCount > 0);
referenceCount++;
}
@Override
public void release() {
referenceCount--;
}
@Override
public void restoreKeys(byte[] sessionId, byte[] keySetId) {
throw new UnsupportedOperationException();
}
@Nullable
@Override
public PersistableBundle getMetrics() {
Assertions.checkState(referenceCount > 0);
return null;
}
@Override
public String getPropertyString(String propertyName) {
Assertions.checkState(referenceCount > 0);
@Nullable String value = stringProperties.get(propertyName);
if (value == null) {
throw new IllegalArgumentException("Unrecognized propertyName: " + propertyName);
}
return value;
}
@Override
public byte[] getPropertyByteArray(String propertyName) {
Assertions.checkState(referenceCount > 0);
@Nullable byte[] value = byteProperties.get(propertyName);
if (value == null) {
throw new IllegalArgumentException("Unrecognized propertyName: " + propertyName);
}
return value;
}
@Override
public void setPropertyString(String propertyName, String value) {
Assertions.checkState(referenceCount > 0);
stringProperties.put(propertyName, value);
}
@Override
public void setPropertyByteArray(String propertyName, byte[] value) {
Assertions.checkState(referenceCount > 0);
byteProperties.put(propertyName, value);
}
@Override
public ExoMediaCrypto createMediaCrypto(byte[] sessionId) throws MediaCryptoException {
Assertions.checkState(referenceCount > 0);
Assertions.checkState(openSessionIds.contains(toByteList(sessionId)));
return new FakeExoMediaCrypto();
}
@Nullable
@Override
public Class<? extends ExoMediaCrypto> getExoMediaCryptoType() {
return FakeExoMediaCrypto.class;
}
private static List<Byte> toByteList(byte[] byteArray) {
List<Byte> result = new ArrayList<>(byteArray.length);
for (byte b : byteArray) {
result.add(b);
}
return result;
}
private static class FakeExoMediaCrypto implements ExoMediaCrypto {}
}
...@@ -23,6 +23,7 @@ import android.os.SystemClock; ...@@ -23,6 +23,7 @@ import android.os.SystemClock;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.SeekParameters; import com.google.android.exoplayer2.SeekParameters;
import com.google.android.exoplayer2.drm.DrmSessionManager;
import com.google.android.exoplayer2.source.LoadEventInfo; import com.google.android.exoplayer2.source.LoadEventInfo;
import com.google.android.exoplayer2.source.MediaPeriod; import com.google.android.exoplayer2.source.MediaPeriod;
import com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispatcher; import com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispatcher;
...@@ -49,6 +50,7 @@ public class FakeMediaPeriod implements MediaPeriod { ...@@ -49,6 +50,7 @@ public class FakeMediaPeriod implements MediaPeriod {
private final TrackGroupArray trackGroupArray; private final TrackGroupArray trackGroupArray;
private final List<SampleStream> sampleStreams; private final List<SampleStream> sampleStreams;
private final DrmSessionManager drmSessionManager;
private final EventDispatcher eventDispatcher; private final EventDispatcher eventDispatcher;
private final long fakePreparationLoadTaskId; private final long fakePreparationLoadTaskId;
...@@ -62,23 +64,46 @@ public class FakeMediaPeriod implements MediaPeriod { ...@@ -62,23 +64,46 @@ public class FakeMediaPeriod implements MediaPeriod {
private long discontinuityPositionUs; private long discontinuityPositionUs;
/** /**
* Constructs a FakeMediaPeriod.
*
* @param trackGroupArray The track group array. * @param trackGroupArray The track group array.
* @param eventDispatcher A dispatcher for media source events. * @param eventDispatcher A dispatcher for media source events.
*/ */
public FakeMediaPeriod(TrackGroupArray trackGroupArray, EventDispatcher eventDispatcher) { public FakeMediaPeriod(TrackGroupArray trackGroupArray, EventDispatcher eventDispatcher) {
this(trackGroupArray, eventDispatcher, /* deferOnPrepared */ false); this(trackGroupArray, DrmSessionManager.DUMMY, eventDispatcher, /* deferOnPrepared */ false);
} }
/** /**
* Constructs a FakeMediaPeriod.
*
* @param trackGroupArray The track group array. * @param trackGroupArray The track group array.
* @param drmSessionManager The {@link DrmSessionManager} used for DRM interactions.
* @param eventDispatcher A dispatcher for media source events.
*/
public FakeMediaPeriod(
TrackGroupArray trackGroupArray,
DrmSessionManager drmSessionManager,
EventDispatcher eventDispatcher) {
this(trackGroupArray, drmSessionManager, eventDispatcher, /* deferOnPrepared */ false);
}
/**
* Constructs a FakeMediaPeriod.
*
* @param trackGroupArray The track group array.
* @param drmSessionManager The DrmSessionManager used for DRM interactions.
* @param eventDispatcher A dispatcher for media source events. * @param eventDispatcher A dispatcher for media source events.
* @param deferOnPrepared Whether {@link MediaPeriod.Callback#onPrepared(MediaPeriod)} should be * @param deferOnPrepared Whether {@link MediaPeriod.Callback#onPrepared(MediaPeriod)} should be
* called only after {@link #setPreparationComplete()} has been called. If {@code false} * called only after {@link #setPreparationComplete()} has been called. If {@code false}
* preparation completes immediately. * preparation completes immediately.
*/ */
public FakeMediaPeriod( public FakeMediaPeriod(
TrackGroupArray trackGroupArray, EventDispatcher eventDispatcher, boolean deferOnPrepared) { TrackGroupArray trackGroupArray,
DrmSessionManager drmSessionManager,
EventDispatcher eventDispatcher,
boolean deferOnPrepared) {
this.trackGroupArray = trackGroupArray; this.trackGroupArray = trackGroupArray;
this.drmSessionManager = drmSessionManager;
this.eventDispatcher = eventDispatcher; this.eventDispatcher = eventDispatcher;
this.deferOnPrepared = deferOnPrepared; this.deferOnPrepared = deferOnPrepared;
discontinuityPositionUs = C.TIME_UNSET; discontinuityPositionUs = C.TIME_UNSET;
...@@ -118,6 +143,9 @@ public class FakeMediaPeriod implements MediaPeriod { ...@@ -118,6 +143,9 @@ public class FakeMediaPeriod implements MediaPeriod {
public void release() { public void release() {
prepared = false; prepared = false;
for (int i = 0; i < sampleStreams.size(); i++) {
releaseSampleStream(sampleStreams.get(i));
}
eventDispatcher.mediaPeriodReleased(); eventDispatcher.mediaPeriodReleased();
} }
...@@ -173,7 +201,7 @@ public class FakeMediaPeriod implements MediaPeriod { ...@@ -173,7 +201,7 @@ public class FakeMediaPeriod implements MediaPeriod {
int indexInTrackGroup = selection.getIndexInTrackGroup(selection.getSelectedIndex()); int indexInTrackGroup = selection.getIndexInTrackGroup(selection.getSelectedIndex());
assertThat(indexInTrackGroup).isAtLeast(0); assertThat(indexInTrackGroup).isAtLeast(0);
assertThat(indexInTrackGroup).isLessThan(trackGroup.length); assertThat(indexInTrackGroup).isLessThan(trackGroup.length);
streams[i] = createSampleStream(positionUs, selection, eventDispatcher); streams[i] = createSampleStream(positionUs, selection, drmSessionManager, eventDispatcher);
sampleStreams.add(streams[i]); sampleStreams.add(streams[i]);
streamResetFlags[i] = true; streamResetFlags[i] = true;
} }
...@@ -245,13 +273,18 @@ public class FakeMediaPeriod implements MediaPeriod { ...@@ -245,13 +273,18 @@ public class FakeMediaPeriod implements MediaPeriod {
* *
* @param positionUs The position at which the tracks were selected, in microseconds. * @param positionUs The position at which the tracks were selected, in microseconds.
* @param selection A selection of tracks. * @param selection A selection of tracks.
* @param drmSessionManager The DRM session manager.
* @param eventDispatcher A dispatcher for events that should be used by the sample stream. * @param eventDispatcher A dispatcher for events that should be used by the sample stream.
* @return A {@link SampleStream} for this selection. * @return A {@link SampleStream} for this selection.
*/ */
protected SampleStream createSampleStream( protected SampleStream createSampleStream(
long positionUs, TrackSelection selection, EventDispatcher eventDispatcher) { long positionUs,
TrackSelection selection,
DrmSessionManager drmSessionManager,
EventDispatcher eventDispatcher) {
return new FakeSampleStream( return new FakeSampleStream(
selection.getSelectedFormat(), selection.getSelectedFormat(),
drmSessionManager,
eventDispatcher, eventDispatcher,
positionUs, positionUs,
/* timeUsIncrement= */ 0, /* timeUsIncrement= */ 0,
...@@ -262,7 +295,7 @@ public class FakeMediaPeriod implements MediaPeriod { ...@@ -262,7 +295,7 @@ public class FakeMediaPeriod implements MediaPeriod {
* Seeks inside the given sample stream. * Seeks inside the given sample stream.
* *
* @param sampleStream A sample stream that was created by a call to {@link * @param sampleStream A sample stream that was created by a call to {@link
* #createSampleStream(long, TrackSelection, EventDispatcher)}. * #createSampleStream(long, TrackSelection, DrmSessionManager, EventDispatcher)}.
* @param positionUs The position to seek to, in microseconds. * @param positionUs The position to seek to, in microseconds.
*/ */
protected void seekSampleStream(SampleStream sampleStream, long positionUs) { protected void seekSampleStream(SampleStream sampleStream, long positionUs) {
...@@ -271,6 +304,16 @@ public class FakeMediaPeriod implements MediaPeriod { ...@@ -271,6 +304,16 @@ public class FakeMediaPeriod implements MediaPeriod {
.resetSampleStreamItems(positionUs, FakeSampleStream.SINGLE_SAMPLE_THEN_END_OF_STREAM); .resetSampleStreamItems(positionUs, FakeSampleStream.SINGLE_SAMPLE_THEN_END_OF_STREAM);
} }
/**
* Releases the given sample stream.
*
* @param sampleStream A sample stream that was created by a call to {@link
* #createSampleStream(long, TrackSelection, DrmSessionManager, EventDispatcher)}.
*/
protected void releaseSampleStream(SampleStream sampleStream) {
((FakeSampleStream) sampleStream).release();
}
private void finishPreparation() { private void finishPreparation() {
prepared = true; prepared = true;
Util.castNonNull(prepareCallback).onPrepared(this); Util.castNonNull(prepareCallback).onPrepared(this);
......
...@@ -25,6 +25,7 @@ import com.google.android.exoplayer2.C; ...@@ -25,6 +25,7 @@ import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.Timeline.Period; import com.google.android.exoplayer2.Timeline.Period;
import com.google.android.exoplayer2.drm.DrmSessionManager;
import com.google.android.exoplayer2.source.BaseMediaSource; import com.google.android.exoplayer2.source.BaseMediaSource;
import com.google.android.exoplayer2.source.ForwardingTimeline; import com.google.android.exoplayer2.source.ForwardingTimeline;
import com.google.android.exoplayer2.source.LoadEventInfo; import com.google.android.exoplayer2.source.LoadEventInfo;
...@@ -73,6 +74,7 @@ public class FakeMediaSource extends BaseMediaSource { ...@@ -73,6 +74,7 @@ public class FakeMediaSource extends BaseMediaSource {
private final TrackGroupArray trackGroupArray; private final TrackGroupArray trackGroupArray;
private final ArrayList<FakeMediaPeriod> activeMediaPeriods; private final ArrayList<FakeMediaPeriod> activeMediaPeriods;
private final ArrayList<MediaPeriodId> createdMediaPeriods; private final ArrayList<MediaPeriodId> createdMediaPeriods;
private final DrmSessionManager drmSessionManager;
private @MonotonicNonNull Timeline timeline; private @MonotonicNonNull Timeline timeline;
private boolean preparedSource; private boolean preparedSource;
...@@ -87,7 +89,19 @@ public class FakeMediaSource extends BaseMediaSource { ...@@ -87,7 +89,19 @@ public class FakeMediaSource extends BaseMediaSource {
* can be manually set later using {@link #setNewSourceInfo(Timeline)}. * can be manually set later using {@link #setNewSourceInfo(Timeline)}.
*/ */
public FakeMediaSource(@Nullable Timeline timeline, Format... formats) { public FakeMediaSource(@Nullable Timeline timeline, Format... formats) {
this(timeline, buildTrackGroupArray(formats)); this(timeline, DrmSessionManager.DUMMY, formats);
}
/**
* Creates a {@link FakeMediaSource}. This media source creates {@link FakeMediaPeriod}s with a
* {@link TrackGroupArray} using the given {@link Format}s. It passes {@code drmSessionManager}
* into the created periods. The provided {@link Timeline} may be null to prevent an immediate
* source info refresh message when preparing the media source. It can be manually set later using
* {@link #setNewSourceInfo(Timeline)}.
*/
public FakeMediaSource(
@Nullable Timeline timeline, DrmSessionManager drmSessionManager, Format... formats) {
this(timeline, drmSessionManager, buildTrackGroupArray(formats));
} }
/** /**
...@@ -96,13 +110,17 @@ public class FakeMediaSource extends BaseMediaSource { ...@@ -96,13 +110,17 @@ public class FakeMediaSource extends BaseMediaSource {
* immediate source info refresh message when preparing the media source. It can be manually set * immediate source info refresh message when preparing the media source. It can be manually set
* later using {@link #setNewSourceInfo(Timeline)}. * later using {@link #setNewSourceInfo(Timeline)}.
*/ */
public FakeMediaSource(@Nullable Timeline timeline, TrackGroupArray trackGroupArray) { public FakeMediaSource(
@Nullable Timeline timeline,
DrmSessionManager drmSessionManager,
TrackGroupArray trackGroupArray) {
if (timeline != null) { if (timeline != null) {
this.timeline = timeline; this.timeline = timeline;
} }
this.trackGroupArray = trackGroupArray; this.trackGroupArray = trackGroupArray;
this.activeMediaPeriods = new ArrayList<>(); this.activeMediaPeriods = new ArrayList<>();
this.createdMediaPeriods = new ArrayList<>(); this.createdMediaPeriods = new ArrayList<>();
this.drmSessionManager = drmSessionManager;
} }
@Nullable @Nullable
...@@ -136,6 +154,7 @@ public class FakeMediaSource extends BaseMediaSource { ...@@ -136,6 +154,7 @@ public class FakeMediaSource extends BaseMediaSource {
public synchronized void prepareSourceInternal(@Nullable TransferListener mediaTransferListener) { public synchronized void prepareSourceInternal(@Nullable TransferListener mediaTransferListener) {
assertThat(preparedSource).isFalse(); assertThat(preparedSource).isFalse();
transferListener = mediaTransferListener; transferListener = mediaTransferListener;
drmSessionManager.prepare();
preparedSource = true; preparedSource = true;
releasedSource = false; releasedSource = false;
sourceInfoRefreshHandler = Util.createHandler(); sourceInfoRefreshHandler = Util.createHandler();
...@@ -159,7 +178,8 @@ public class FakeMediaSource extends BaseMediaSource { ...@@ -159,7 +178,8 @@ public class FakeMediaSource extends BaseMediaSource {
EventDispatcher eventDispatcher = EventDispatcher eventDispatcher =
createEventDispatcher(period.windowIndex, id, period.getPositionInWindowMs()); createEventDispatcher(period.windowIndex, id, period.getPositionInWindowMs());
FakeMediaPeriod mediaPeriod = FakeMediaPeriod mediaPeriod =
createFakeMediaPeriod(id, trackGroupArray, allocator, eventDispatcher, transferListener); createFakeMediaPeriod(
id, trackGroupArray, allocator, drmSessionManager, eventDispatcher, transferListener);
activeMediaPeriods.add(mediaPeriod); activeMediaPeriods.add(mediaPeriod);
createdMediaPeriods.add(id); createdMediaPeriods.add(id);
return mediaPeriod; return mediaPeriod;
...@@ -179,6 +199,7 @@ public class FakeMediaSource extends BaseMediaSource { ...@@ -179,6 +199,7 @@ public class FakeMediaSource extends BaseMediaSource {
assertThat(preparedSource).isTrue(); assertThat(preparedSource).isTrue();
assertThat(releasedSource).isFalse(); assertThat(releasedSource).isFalse();
assertThat(activeMediaPeriods.isEmpty()).isTrue(); assertThat(activeMediaPeriods.isEmpty()).isTrue();
drmSessionManager.release();
releasedSource = true; releasedSource = true;
preparedSource = false; preparedSource = false;
Util.castNonNull(sourceInfoRefreshHandler).removeCallbacksAndMessages(null); Util.castNonNull(sourceInfoRefreshHandler).removeCallbacksAndMessages(null);
...@@ -242,9 +263,11 @@ public class FakeMediaSource extends BaseMediaSource { ...@@ -242,9 +263,11 @@ public class FakeMediaSource extends BaseMediaSource {
MediaPeriodId id, MediaPeriodId id,
TrackGroupArray trackGroupArray, TrackGroupArray trackGroupArray,
Allocator allocator, Allocator allocator,
DrmSessionManager drmSessionManager,
EventDispatcher eventDispatcher, EventDispatcher eventDispatcher,
@Nullable TransferListener transferListener) { @Nullable TransferListener transferListener) {
return new FakeMediaPeriod(trackGroupArray, eventDispatcher); return new FakeMediaPeriod(
trackGroupArray, drmSessionManager, eventDispatcher, /* deferOnPrepared= */ false);
} }
private void finishSourcePreparation() { private void finishSourcePreparation() {
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
*/ */
package com.google.android.exoplayer2.testutil; package com.google.android.exoplayer2.testutil;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.BaseRenderer; import com.google.android.exoplayer2.BaseRenderer;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ExoPlaybackException; import com.google.android.exoplayer2.ExoPlaybackException;
...@@ -24,6 +24,7 @@ import com.google.android.exoplayer2.FormatHolder; ...@@ -24,6 +24,7 @@ import com.google.android.exoplayer2.FormatHolder;
import com.google.android.exoplayer2.Renderer; import com.google.android.exoplayer2.Renderer;
import com.google.android.exoplayer2.RendererCapabilities; import com.google.android.exoplayer2.RendererCapabilities;
import com.google.android.exoplayer2.decoder.DecoderInputBuffer; import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
import com.google.android.exoplayer2.drm.DrmSession;
import com.google.android.exoplayer2.source.SampleStream; import com.google.android.exoplayer2.source.SampleStream;
import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.MimeTypes;
...@@ -49,6 +50,8 @@ public class FakeRenderer extends BaseRenderer { ...@@ -49,6 +50,8 @@ public class FakeRenderer extends BaseRenderer {
private final DecoderInputBuffer buffer; private final DecoderInputBuffer buffer;
@Nullable private DrmSession currentDrmSession;
private long playbackPositionUs; private long playbackPositionUs;
private long lastSamplePositionUs; private long lastSamplePositionUs;
private boolean hasPendingBuffer; private boolean hasPendingBuffer;
...@@ -91,7 +94,10 @@ public class FakeRenderer extends BaseRenderer { ...@@ -91,7 +94,10 @@ public class FakeRenderer extends BaseRenderer {
buffer.clear(); buffer.clear();
@SampleStream.ReadDataResult @SampleStream.ReadDataResult
int result = readSource(formatHolder, buffer, /* formatRequired= */ false); int result = readSource(formatHolder, buffer, /* formatRequired= */ false);
if (result == C.RESULT_FORMAT_READ) { if (result == C.RESULT_FORMAT_READ) {
DrmSession.replaceSession(currentDrmSession, formatHolder.drmSession);
currentDrmSession = formatHolder.drmSession;
Format format = Assertions.checkNotNull(formatHolder.format); Format format = Assertions.checkNotNull(formatHolder.format);
if (MimeTypes.getTrackType(format.sampleMimeType) != getTrackType()) { if (MimeTypes.getTrackType(format.sampleMimeType) != getTrackType()) {
throw ExoPlaybackException.createForRenderer( throw ExoPlaybackException.createForRenderer(
...@@ -147,6 +153,14 @@ public class FakeRenderer extends BaseRenderer { ...@@ -147,6 +153,14 @@ public class FakeRenderer extends BaseRenderer {
: RendererCapabilities.create(FORMAT_UNSUPPORTED_TYPE); : RendererCapabilities.create(FORMAT_UNSUPPORTED_TYPE);
} }
@Override
protected void onReset() {
if (currentDrmSession != null) {
currentDrmSession.release(/* eventDispatcher= */ null);
currentDrmSession = null;
}
}
/** Called when the renderer reads a new format. */ /** Called when the renderer reads a new format. */
protected void onFormatChanged(Format format) {} protected void onFormatChanged(Format format) {}
......
...@@ -15,16 +15,24 @@ ...@@ -15,16 +15,24 @@
*/ */
package com.google.android.exoplayer2.testutil; package com.google.android.exoplayer2.testutil;
import android.os.Looper;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.FormatHolder; import com.google.android.exoplayer2.FormatHolder;
import com.google.android.exoplayer2.decoder.DecoderInputBuffer; import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
import com.google.android.exoplayer2.drm.DrmInitData;
import com.google.android.exoplayer2.drm.DrmSession;
import com.google.android.exoplayer2.drm.DrmSessionManager;
import com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispatcher; import com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispatcher;
import com.google.android.exoplayer2.source.SampleStream; import com.google.android.exoplayer2.source.SampleStream;
import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.MimeTypes;
import com.google.android.exoplayer2.util.Util;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayDeque; import java.util.ArrayDeque;
import java.util.Arrays; import java.util.Arrays;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
/** /**
* Fake {@link SampleStream} that outputs a given {@link Format}, any amount of {@link * Fake {@link SampleStream} that outputs a given {@link Format}, any amount of {@link
...@@ -85,15 +93,16 @@ public class FakeSampleStream implements SampleStream { ...@@ -85,15 +93,16 @@ public class FakeSampleStream implements SampleStream {
new FakeSampleStreamItem(new byte[] {0}), FakeSampleStreamItem.END_OF_STREAM_ITEM new FakeSampleStreamItem(new byte[] {0}), FakeSampleStreamItem.END_OF_STREAM_ITEM
}; };
private final Format initialFormat;
private final ArrayDeque<FakeSampleStreamItem> fakeSampleStreamItems; private final ArrayDeque<FakeSampleStreamItem> fakeSampleStreamItems;
private final int timeUsIncrement; private final int timeUsIncrement;
private final DrmSessionManager drmSessionManager;
@Nullable private final EventDispatcher eventDispatcher; @Nullable private final EventDispatcher eventDispatcher;
private Format format; private @MonotonicNonNull Format downstreamFormat;
private long timeUs; private long timeUs;
private boolean readFormat;
private boolean readEOSBuffer; private boolean readEOSBuffer;
@Nullable private DrmSession currentDrmSession;
/** /**
* Creates fake sample stream which outputs the given {@link Format}, optionally one sample with * Creates fake sample stream which outputs the given {@link Format}, optionally one sample with
...@@ -107,6 +116,7 @@ public class FakeSampleStream implements SampleStream { ...@@ -107,6 +116,7 @@ public class FakeSampleStream implements SampleStream {
Format format, @Nullable EventDispatcher eventDispatcher, boolean shouldOutputSample) { Format format, @Nullable EventDispatcher eventDispatcher, boolean shouldOutputSample) {
this( this(
format, format,
DrmSessionManager.DUMMY,
eventDispatcher, eventDispatcher,
/* firstSampleTimeUs= */ 0, /* firstSampleTimeUs= */ 0,
/* timeUsIncrement= */ 0, /* timeUsIncrement= */ 0,
...@@ -120,6 +130,7 @@ public class FakeSampleStream implements SampleStream { ...@@ -120,6 +130,7 @@ public class FakeSampleStream implements SampleStream {
* FakeSampleStreamItem items}, then end of stream. * FakeSampleStreamItem items}, then end of stream.
* *
* @param format The {@link Format} to output. * @param format The {@link Format} to output.
* @param drmSessionManager A {@link DrmSessionManager} for DRM interactions.
* @param eventDispatcher An {@link EventDispatcher} to notify of read events. * @param eventDispatcher An {@link EventDispatcher} to notify of read events.
* @param firstSampleTimeUs The time at which samples will start being output, in microseconds. * @param firstSampleTimeUs The time at which samples will start being output, in microseconds.
* @param timeUsIncrement The time each sample should increase by, in microseconds. * @param timeUsIncrement The time each sample should increase by, in microseconds.
...@@ -129,11 +140,13 @@ public class FakeSampleStream implements SampleStream { ...@@ -129,11 +140,13 @@ public class FakeSampleStream implements SampleStream {
*/ */
public FakeSampleStream( public FakeSampleStream(
Format format, Format format,
DrmSessionManager drmSessionManager,
@Nullable EventDispatcher eventDispatcher, @Nullable EventDispatcher eventDispatcher,
long firstSampleTimeUs, long firstSampleTimeUs,
int timeUsIncrement, int timeUsIncrement,
FakeSampleStreamItem... fakeSampleStreamItems) { FakeSampleStreamItem... fakeSampleStreamItems) {
this.format = format; this.initialFormat = format;
this.drmSessionManager = drmSessionManager;
this.eventDispatcher = eventDispatcher; this.eventDispatcher = eventDispatcher;
this.fakeSampleStreamItems = new ArrayDeque<>(Arrays.asList(fakeSampleStreamItems)); this.fakeSampleStreamItems = new ArrayDeque<>(Arrays.asList(fakeSampleStreamItems));
this.timeUs = firstSampleTimeUs; this.timeUs = firstSampleTimeUs;
...@@ -164,16 +177,21 @@ public class FakeSampleStream implements SampleStream { ...@@ -164,16 +177,21 @@ public class FakeSampleStream implements SampleStream {
@Override @Override
public boolean isReady() { public boolean isReady() {
return !readFormat || readEOSBuffer || !fakeSampleStreamItems.isEmpty(); if (fakeSampleStreamItems.isEmpty()) {
return readEOSBuffer || downstreamFormat == null;
}
if (fakeSampleStreamItems.peek().format != null) {
// A format can be read.
return true;
}
return mayReadSample();
} }
@Override @Override
public int readData( public int readData(
FormatHolder formatHolder, DecoderInputBuffer buffer, boolean formatRequired) { FormatHolder formatHolder, DecoderInputBuffer buffer, boolean formatRequired) {
if (!readFormat || formatRequired) { if (downstreamFormat == null || formatRequired) {
readFormat = true; onFormatResult(downstreamFormat == null ? initialFormat : downstreamFormat, formatHolder);
formatHolder.format = format;
notifyEventDispatcher(formatHolder);
return C.RESULT_FORMAT_READ; return C.RESULT_FORMAT_READ;
} }
// Once an EOS buffer has been read, send EOS every time. // Once an EOS buffer has been read, send EOS every time.
...@@ -181,33 +199,79 @@ public class FakeSampleStream implements SampleStream { ...@@ -181,33 +199,79 @@ public class FakeSampleStream implements SampleStream {
buffer.setFlags(C.BUFFER_FLAG_END_OF_STREAM); buffer.setFlags(C.BUFFER_FLAG_END_OF_STREAM);
return C.RESULT_BUFFER_READ; return C.RESULT_BUFFER_READ;
} }
if (!fakeSampleStreamItems.isEmpty()) { if (!fakeSampleStreamItems.isEmpty()) {
FakeSampleStreamItem fakeSampleStreamItem = fakeSampleStreamItems.remove(); FakeSampleStreamItem fakeSampleStreamItem = fakeSampleStreamItems.remove();
if (fakeSampleStreamItem.format != null) { if (fakeSampleStreamItem.format != null) {
format = fakeSampleStreamItem.format; onFormatResult(fakeSampleStreamItem.format, formatHolder);
formatHolder.format = format;
notifyEventDispatcher(formatHolder);
return C.RESULT_FORMAT_READ; return C.RESULT_FORMAT_READ;
} } else {
if (fakeSampleStreamItem.sampleData != null) { byte[] sampleData = Assertions.checkNotNull(fakeSampleStreamItem.sampleData);
byte[] sampleData = fakeSampleStreamItem.sampleData; if (fakeSampleStreamItem.flags != 0) {
buffer.setFlags(fakeSampleStreamItem.flags);
if (buffer.isEndOfStream()) {
readEOSBuffer = true;
return C.RESULT_BUFFER_READ;
}
}
if (!mayReadSample()) {
// Put the item back so we can consume it next time.
fakeSampleStreamItems.addFirst(fakeSampleStreamItem);
return C.RESULT_NOTHING_READ;
}
buffer.timeUs = timeUs; buffer.timeUs = timeUs;
timeUs += timeUsIncrement; timeUs += timeUsIncrement;
buffer.ensureSpaceForWrite(sampleData.length); buffer.ensureSpaceForWrite(sampleData.length);
buffer.data.put(sampleData); buffer.data.put(sampleData);
if (fakeSampleStreamItem.flags != 0) {
buffer.setFlags(fakeSampleStreamItem.flags);
readEOSBuffer = buffer.isEndOfStream();
}
return C.RESULT_BUFFER_READ; return C.RESULT_BUFFER_READ;
} }
} }
return C.RESULT_NOTHING_READ; return C.RESULT_NOTHING_READ;
} }
private void onFormatResult(Format newFormat, FormatHolder outputFormatHolder) {
outputFormatHolder.format = newFormat;
@Nullable
DrmInitData oldDrmInitData = downstreamFormat == null ? null : downstreamFormat.drmInitData;
boolean isFirstFormat = downstreamFormat == null;
downstreamFormat = newFormat;
@Nullable DrmInitData newDrmInitData = newFormat.drmInitData;
outputFormatHolder.drmSession = currentDrmSession;
notifyEventDispatcher(outputFormatHolder);
if (!isFirstFormat && Util.areEqual(oldDrmInitData, newDrmInitData)) {
// Nothing to do.
return;
}
// Ensure we acquire the new session before releasing the previous one in case the same session
// is being used for both DrmInitData.
@Nullable DrmSession previousSession = currentDrmSession;
Looper playbackLooper = Assertions.checkNotNull(Looper.myLooper());
currentDrmSession =
newDrmInitData != null
? drmSessionManager.acquireSession(playbackLooper, eventDispatcher, newDrmInitData)
: drmSessionManager.acquirePlaceholderSession(
playbackLooper, MimeTypes.getTrackType(newFormat.sampleMimeType));
outputFormatHolder.drmSession = currentDrmSession;
if (previousSession != null) {
previousSession.release(eventDispatcher);
}
}
private boolean mayReadSample() {
@Nullable DrmSession drmSession = this.currentDrmSession;
return drmSession == null
|| drmSession.getState() == DrmSession.STATE_OPENED_WITH_KEYS
|| (!fakeSampleStreamItems.isEmpty()
&& (fakeSampleStreamItems.peek().flags & C.BUFFER_FLAG_ENCRYPTED) == 0
&& drmSession.playClearSamplesWithoutKeys());
}
@Override @Override
public void maybeThrowError() throws IOException { public void maybeThrowError() throws IOException {
// Do nothing. if (currentDrmSession != null && currentDrmSession.getState() == DrmSession.STATE_ERROR) {
throw Assertions.checkNotNull(currentDrmSession.getError());
}
} }
@Override @Override
...@@ -215,6 +279,14 @@ public class FakeSampleStream implements SampleStream { ...@@ -215,6 +279,14 @@ public class FakeSampleStream implements SampleStream {
return 0; return 0;
} }
/** Release this SampleStream and all underlying resources. */
public void release() {
if (currentDrmSession != null) {
currentDrmSession.release(eventDispatcher);
currentDrmSession = null;
}
}
private void notifyEventDispatcher(FormatHolder formatHolder) { private void notifyEventDispatcher(FormatHolder formatHolder) {
if (eventDispatcher != null) { if (eventDispatcher != null) {
eventDispatcher.downstreamFormatChanged( eventDispatcher.downstreamFormatChanged(
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment