Plumb DrmSessionManager into DashMediaSource

PiperOrigin-RevId: 257576791
This commit is contained in:
aquilescanta 2019-07-11 11:16:54 +01:00 committed by Oliver Woodman
parent 6796b179a6
commit 91750b8009
9 changed files with 87 additions and 20 deletions

View file

@ -39,6 +39,7 @@ import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.RenderersFactory;
import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.drm.DefaultDrmSessionManager;
import com.google.android.exoplayer2.drm.DrmSessionManager;
import com.google.android.exoplayer2.drm.FrameworkMediaCrypto;
import com.google.android.exoplayer2.drm.FrameworkMediaDrm;
import com.google.android.exoplayer2.drm.HttpMediaDrmCallback;
@ -358,7 +359,7 @@ public class PlayerActivity extends AppCompatActivity
return;
}
DefaultDrmSessionManager<FrameworkMediaCrypto> drmSessionManager = null;
DrmSessionManager<FrameworkMediaCrypto> drmSessionManager = null;
if (intent.hasExtra(DRM_SCHEME_EXTRA) || intent.hasExtra(DRM_SCHEME_UUID_EXTRA)) {
String drmLicenseUrl = intent.getStringExtra(DRM_LICENSE_URL_EXTRA);
String[] keyRequestPropertiesArray =
@ -389,6 +390,8 @@ public class PlayerActivity extends AppCompatActivity
finish();
return;
}
} else {
drmSessionManager = DrmSessionManager.getDummyDrmSessionManager();
}
TrackSelection.Factory trackSelectionFactory;
@ -425,7 +428,7 @@ public class PlayerActivity extends AppCompatActivity
MediaSource[] mediaSources = new MediaSource[uris.length];
for (int i = 0; i < uris.length; i++) {
mediaSources[i] = buildMediaSource(uris[i], extensions[i]);
mediaSources[i] = buildMediaSource(uris[i], extensions[i], drmSessionManager);
}
mediaSource =
mediaSources.length == 1 ? mediaSources[0] : new ConcatenatingMediaSource(mediaSources);
@ -455,10 +458,16 @@ public class PlayerActivity extends AppCompatActivity
}
private MediaSource buildMediaSource(Uri uri) {
return buildMediaSource(uri, null);
return buildMediaSource(
uri,
/* overrideExtension= */ null,
/* drmSessionManager= */ DrmSessionManager.getDummyDrmSessionManager());
}
private MediaSource buildMediaSource(Uri uri, @Nullable String overrideExtension) {
private MediaSource buildMediaSource(
Uri uri,
@Nullable String overrideExtension,
DrmSessionManager<FrameworkMediaCrypto> drmSessionManager) {
DownloadRequest downloadRequest =
((DemoApplication) getApplication()).getDownloadTracker().getDownloadRequest(uri);
if (downloadRequest != null) {
@ -467,7 +476,9 @@ public class PlayerActivity extends AppCompatActivity
@ContentType int type = Util.inferContentType(uri, overrideExtension);
switch (type) {
case C.TYPE_DASH:
return new DashMediaSource.Factory(dataSourceFactory).createMediaSource(uri);
return new DashMediaSource.Factory(dataSourceFactory)
.setDrmSessionManager(drmSessionManager)
.createMediaSource(uri);
case C.TYPE_SS:
return new SsMediaSource.Factory(dataSourceFactory).createMediaSource(uri);
case C.TYPE_HLS:

View file

@ -172,6 +172,7 @@ public final class DecryptableSampleQueueReader {
*/
private void onFormat(Format format, FormatHolder outputFormatHolder) {
outputFormatHolder.format = format;
DrmInitData oldDrmInitData = currentFormat != null ? currentFormat.drmInitData : null;
currentFormat = format;
if (sessionManager == DrmSessionManager.DUMMY) {
// Avoid attempting to acquire a session using the dummy DRM session manager. It's likely that
@ -182,12 +183,10 @@ public final class DecryptableSampleQueueReader {
}
outputFormatHolder.includesDrmSession = true;
outputFormatHolder.drmSession = currentSession;
DrmInitData oldDrmInitData = currentFormat != null ? currentFormat.drmInitData : null;
if (Util.areEqual(oldDrmInitData, format.drmInitData)) {
// Nothing to do.
return;
}
// Ensure we acquire the new session before releasing the previous one in case the same session
// can be used for both DrmInitData.
DrmSession<?> previousSession = currentSession;

View file

@ -21,6 +21,9 @@ import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.FormatHolder;
import com.google.android.exoplayer2.SeekParameters;
import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
import com.google.android.exoplayer2.drm.DrmSession;
import com.google.android.exoplayer2.drm.DrmSessionManager;
import com.google.android.exoplayer2.source.DecryptableSampleQueueReader;
import com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispatcher;
import com.google.android.exoplayer2.source.SampleQueue;
import com.google.android.exoplayer2.source.SampleStream;
@ -71,6 +74,7 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
private final ArrayList<BaseMediaChunk> mediaChunks;
private final List<BaseMediaChunk> readOnlyMediaChunks;
private final SampleQueue primarySampleQueue;
private final DecryptableSampleQueueReader primarySampleQueueReader;
private final SampleQueue[] embeddedSampleQueues;
private final BaseMediaChunkOutput mediaChunkOutput;
@ -94,6 +98,8 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
* @param callback An {@link Callback} for the stream.
* @param allocator An {@link Allocator} from which allocations can be obtained.
* @param positionUs The position from which to start loading media.
* @param drmSessionManager The {@link DrmSessionManager} to obtain {@link DrmSession DrmSessions}
* from.
* @param loadErrorHandlingPolicy The {@link LoadErrorHandlingPolicy}.
* @param eventDispatcher A dispatcher to notify of events.
*/
@ -105,6 +111,7 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
Callback<ChunkSampleStream<T>> callback,
Allocator allocator,
long positionUs,
DrmSessionManager<?> drmSessionManager,
LoadErrorHandlingPolicy loadErrorHandlingPolicy,
EventDispatcher eventDispatcher) {
this.primaryTrackType = primaryTrackType;
@ -126,6 +133,8 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
SampleQueue[] sampleQueues = new SampleQueue[1 + embeddedTrackCount];
primarySampleQueue = new SampleQueue(allocator);
primarySampleQueueReader =
new DecryptableSampleQueueReader(primarySampleQueue, drmSessionManager);
trackTypes[0] = primaryTrackType;
sampleQueues[0] = primarySampleQueue;
@ -328,6 +337,7 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
this.releaseCallback = callback;
// Discard as much as we can synchronously.
primarySampleQueue.discardToEnd();
primarySampleQueueReader.release();
for (SampleQueue embeddedSampleQueue : embeddedSampleQueues) {
embeddedSampleQueue.discardToEnd();
}
@ -349,12 +359,13 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
@Override
public boolean isReady() {
return loadingFinished || (!isPendingReset() && primarySampleQueue.hasNextSample());
return !isPendingReset() && primarySampleQueueReader.isReady(loadingFinished);
}
@Override
public void maybeThrowError() throws IOException {
loader.maybeThrowError();
primarySampleQueueReader.maybeThrowError();
if (!loader.isLoading()) {
chunkSource.maybeThrowError();
}
@ -367,13 +378,9 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
return C.RESULT_NOTHING_READ;
}
maybeNotifyPrimaryTrackFormatChanged();
return primarySampleQueue.read(
formatHolder,
buffer,
formatRequired,
/* allowOnlyClearBuffers= */ false,
loadingFinished,
decodeOnlyUntilPositionUs);
return primarySampleQueueReader.read(
formatHolder, buffer, formatRequired, loadingFinished, decodeOnlyUntilPositionUs);
}
@Override

View file

@ -22,6 +22,8 @@ import android.util.SparseIntArray;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.SeekParameters;
import com.google.android.exoplayer2.drm.DrmInitData;
import com.google.android.exoplayer2.drm.DrmSessionManager;
import com.google.android.exoplayer2.offline.StreamKey;
import com.google.android.exoplayer2.source.CompositeSequenceableLoaderFactory;
import com.google.android.exoplayer2.source.EmptySampleStream;
@ -70,6 +72,7 @@ import java.util.regex.Pattern;
/* package */ final int id;
private final DashChunkSource.Factory chunkSourceFactory;
@Nullable private final TransferListener transferListener;
private final DrmSessionManager<?> drmSessionManager;
private final LoadErrorHandlingPolicy loadErrorHandlingPolicy;
private final long elapsedRealtimeOffsetMs;
private final LoaderErrorThrower manifestLoaderErrorThrower;
@ -97,6 +100,7 @@ import java.util.regex.Pattern;
int periodIndex,
DashChunkSource.Factory chunkSourceFactory,
@Nullable TransferListener transferListener,
DrmSessionManager<?> drmSessionManager,
LoadErrorHandlingPolicy loadErrorHandlingPolicy,
EventDispatcher eventDispatcher,
long elapsedRealtimeOffsetMs,
@ -109,6 +113,7 @@ import java.util.regex.Pattern;
this.periodIndex = periodIndex;
this.chunkSourceFactory = chunkSourceFactory;
this.transferListener = transferListener;
this.drmSessionManager = drmSessionManager;
this.loadErrorHandlingPolicy = loadErrorHandlingPolicy;
this.eventDispatcher = eventDispatcher;
this.elapsedRealtimeOffsetMs = elapsedRealtimeOffsetMs;
@ -123,8 +128,8 @@ import java.util.regex.Pattern;
compositeSequenceableLoaderFactory.createCompositeSequenceableLoader(sampleStreams);
Period period = manifest.getPeriod(periodIndex);
eventStreams = period.eventStreams;
Pair<TrackGroupArray, TrackGroupInfo[]> result = buildTrackGroups(period.adaptationSets,
eventStreams);
Pair<TrackGroupArray, TrackGroupInfo[]> result =
buildTrackGroups(drmSessionManager, period.adaptationSets, eventStreams);
trackGroups = result.first;
trackGroupInfos = result.second;
eventDispatcher.mediaPeriodCreated();
@ -455,7 +460,9 @@ import java.util.regex.Pattern;
}
private static Pair<TrackGroupArray, TrackGroupInfo[]> buildTrackGroups(
List<AdaptationSet> adaptationSets, List<EventStream> eventStreams) {
DrmSessionManager<?> drmSessionManager,
List<AdaptationSet> adaptationSets,
List<EventStream> eventStreams) {
int[][] groupedAdaptationSetIndices = getGroupedAdaptationSetIndices(adaptationSets);
int primaryGroupCount = groupedAdaptationSetIndices.length;
@ -475,6 +482,7 @@ import java.util.regex.Pattern;
int trackGroupCount =
buildPrimaryAndEmbeddedTrackGroupInfos(
drmSessionManager,
adaptationSets,
groupedAdaptationSetIndices,
primaryGroupCount,
@ -569,6 +577,7 @@ import java.util.regex.Pattern;
}
private static int buildPrimaryAndEmbeddedTrackGroupInfos(
DrmSessionManager<?> drmSessionManager,
List<AdaptationSet> adaptationSets,
int[][] groupedAdaptationSetIndices,
int primaryGroupCount,
@ -585,7 +594,14 @@ import java.util.regex.Pattern;
}
Format[] formats = new Format[representations.size()];
for (int j = 0; j < formats.length; j++) {
formats[j] = representations.get(j).format;
Format format = representations.get(j).format;
DrmInitData drmInitData = format.drmInitData;
if (drmInitData != null) {
format =
format.copyWithExoMediaCryptoType(
drmSessionManager.getExoMediaCryptoType(drmInitData));
}
formats[j] = format;
}
AdaptationSet firstAdaptationSet = adaptationSets.get(adaptationSetIndices[0]);
@ -692,6 +708,7 @@ import java.util.regex.Pattern;
this,
allocator,
positionUs,
drmSessionManager,
loadErrorHandlingPolicy,
eventDispatcher);
synchronized (this) {

View file

@ -25,6 +25,8 @@ import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ExoPlayerLibraryInfo;
import com.google.android.exoplayer2.ParserException;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.drm.DrmSession;
import com.google.android.exoplayer2.drm.DrmSessionManager;
import com.google.android.exoplayer2.offline.FilteringManifestParser;
import com.google.android.exoplayer2.offline.StreamKey;
import com.google.android.exoplayer2.source.BaseMediaSource;
@ -79,6 +81,7 @@ public final class DashMediaSource extends BaseMediaSource {
private final DashChunkSource.Factory chunkSourceFactory;
@Nullable private final DataSource.Factory manifestDataSourceFactory;
private DrmSessionManager<?> drmSessionManager;
@Nullable private ParsingLoadable.Parser<? extends DashManifest> manifestParser;
@Nullable private List<StreamKey> streamKeys;
private CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory;
@ -112,6 +115,7 @@ public final class DashMediaSource extends BaseMediaSource {
@Nullable DataSource.Factory manifestDataSourceFactory) {
this.chunkSourceFactory = Assertions.checkNotNull(chunkSourceFactory);
this.manifestDataSourceFactory = manifestDataSourceFactory;
drmSessionManager = DrmSessionManager.getDummyDrmSessionManager();
loadErrorHandlingPolicy = new DefaultLoadErrorHandlingPolicy();
livePresentationDelayMs = DEFAULT_LIVE_PRESENTATION_DELAY_MS;
compositeSequenceableLoaderFactory = new DefaultCompositeSequenceableLoaderFactory();
@ -132,6 +136,20 @@ public final class DashMediaSource extends BaseMediaSource {
return this;
}
/**
* Sets the {@link DrmSessionManager} to use for acquiring {@link DrmSession DrmSessions}. The
* default value is {@link DrmSessionManager#DUMMY}.
*
* @param drmSessionManager The {@link DrmSessionManager}.
* @return This factory, for convenience.
* @throws IllegalStateException If one of the {@code create} methods has already been called.
*/
public Factory setDrmSessionManager(DrmSessionManager<?> drmSessionManager) {
Assertions.checkState(!isCreateCalled);
this.drmSessionManager = drmSessionManager;
return this;
}
/**
* Sets the minimum number of times to retry if a loading error occurs. See {@link
* #setLoadErrorHandlingPolicy} for the default value.
@ -253,6 +271,7 @@ public final class DashMediaSource extends BaseMediaSource {
/* manifestParser= */ null,
chunkSourceFactory,
compositeSequenceableLoaderFactory,
drmSessionManager,
loadErrorHandlingPolicy,
livePresentationDelayMs,
livePresentationDelayOverridesManifest,
@ -313,6 +332,7 @@ public final class DashMediaSource extends BaseMediaSource {
manifestParser,
chunkSourceFactory,
compositeSequenceableLoaderFactory,
drmSessionManager,
loadErrorHandlingPolicy,
livePresentationDelayMs,
livePresentationDelayOverridesManifest,
@ -361,6 +381,7 @@ public final class DashMediaSource extends BaseMediaSource {
private final DataSource.Factory manifestDataSourceFactory;
private final DashChunkSource.Factory chunkSourceFactory;
private final CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory;
private final DrmSessionManager<?> drmSessionManager;
private final LoadErrorHandlingPolicy loadErrorHandlingPolicy;
private final long livePresentationDelayMs;
private final boolean livePresentationDelayOverridesManifest;
@ -443,6 +464,7 @@ public final class DashMediaSource extends BaseMediaSource {
/* manifestParser= */ null,
chunkSourceFactory,
new DefaultCompositeSequenceableLoaderFactory(),
DrmSessionManager.getDummyDrmSessionManager(),
new DefaultLoadErrorHandlingPolicy(minLoadableRetryCount),
DEFAULT_LIVE_PRESENTATION_DELAY_MS,
/* livePresentationDelayOverridesManifest= */ false,
@ -556,6 +578,7 @@ public final class DashMediaSource extends BaseMediaSource {
manifestParser,
chunkSourceFactory,
new DefaultCompositeSequenceableLoaderFactory(),
DrmSessionManager.getDummyDrmSessionManager(),
new DefaultLoadErrorHandlingPolicy(minLoadableRetryCount),
livePresentationDelayMs == DEFAULT_LIVE_PRESENTATION_DELAY_PREFER_MANIFEST_MS
? DEFAULT_LIVE_PRESENTATION_DELAY_MS
@ -574,6 +597,7 @@ public final class DashMediaSource extends BaseMediaSource {
ParsingLoadable.Parser<? extends DashManifest> manifestParser,
DashChunkSource.Factory chunkSourceFactory,
CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory,
DrmSessionManager<?> drmSessionManager,
LoadErrorHandlingPolicy loadErrorHandlingPolicy,
long livePresentationDelayMs,
boolean livePresentationDelayOverridesManifest,
@ -584,6 +608,7 @@ public final class DashMediaSource extends BaseMediaSource {
this.manifestDataSourceFactory = manifestDataSourceFactory;
this.manifestParser = manifestParser;
this.chunkSourceFactory = chunkSourceFactory;
this.drmSessionManager = drmSessionManager;
this.loadErrorHandlingPolicy = loadErrorHandlingPolicy;
this.livePresentationDelayMs = livePresentationDelayMs;
this.livePresentationDelayOverridesManifest = livePresentationDelayOverridesManifest;
@ -660,6 +685,7 @@ public final class DashMediaSource extends BaseMediaSource {
periodIndex,
chunkSourceFactory,
mediaTransferListener,
drmSessionManager,
loadErrorHandlingPolicy,
periodEventDispatcher,
elapsedRealtimeOffsetMs,

View file

@ -22,6 +22,7 @@ import androidx.annotation.Nullable;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.drm.DrmSessionManager;
import com.google.android.exoplayer2.source.CompositeSequenceableLoaderFactory;
import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
import com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispatcher;
@ -116,6 +117,7 @@ public final class DashMediaPeriodTest {
periodIndex,
mock(DashChunkSource.Factory.class),
mock(TransferListener.class),
DrmSessionManager.getDummyDrmSessionManager(),
mock(LoadErrorHandlingPolicy.class),
new EventDispatcher()
.withParameters(

View file

@ -18,6 +18,7 @@ package com.google.android.exoplayer2.source.dash.offline;
import android.net.Uri;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.android.exoplayer2.Renderer;
import com.google.android.exoplayer2.drm.DrmSessionManager;
import com.google.android.exoplayer2.offline.DownloadHelper;
import com.google.android.exoplayer2.testutil.FakeDataSource;
import org.junit.Test;
@ -37,7 +38,7 @@ public final class DownloadHelperTest {
Uri.parse("http://uri"),
new FakeDataSource.Factory(),
(handler, videoListener, audioListener, text, metadata, drm) -> new Renderer[0],
/* drmSessionManager= */ null,
/* drmSessionManager= */ DrmSessionManager.getDummyDrmSessionManager(),
DownloadHelper.DEFAULT_TRACK_SELECTOR_PARAMETERS);
}
}

View file

@ -18,6 +18,7 @@ package com.google.android.exoplayer2.source.smoothstreaming;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.SeekParameters;
import com.google.android.exoplayer2.drm.DrmSessionManager;
import com.google.android.exoplayer2.offline.StreamKey;
import com.google.android.exoplayer2.source.CompositeSequenceableLoaderFactory;
import com.google.android.exoplayer2.source.MediaPeriod;
@ -237,6 +238,7 @@ import java.util.List;
this,
allocator,
positionUs,
DrmSessionManager.getDummyDrmSessionManager(),
loadErrorHandlingPolicy,
eventDispatcher);
}

View file

@ -16,6 +16,7 @@
package com.google.android.exoplayer2.testutil;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.drm.DrmSessionManager;
import com.google.android.exoplayer2.source.CompositeSequenceableLoader;
import com.google.android.exoplayer2.source.MediaPeriod;
import com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispatcher;
@ -149,6 +150,7 @@ public class FakeAdaptiveMediaPeriod extends FakeMediaPeriod
/* callback= */ this,
allocator,
/* positionUs= */ 0,
/* drmSessionManager= */ DrmSessionManager.getDummyDrmSessionManager(),
new DefaultLoadErrorHandlingPolicy(/* minimumLoadableRetryCount= */ 3),
eventDispatcher);
}