下面列出了android.media.MediaCrypto#com.google.android.exoplayer2.drm.DrmSession 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
@SuppressWarnings("PMD.AvoidCatchingGenericException") // We are forced to catch Exception as ResourceBusyException is minSdk 19
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
@Override
public DrmSession<FrameworkMediaCrypto> acquireSession(Looper playbackLooper, DrmInitData drmInitData) {
DrmSession<FrameworkMediaCrypto> drmSession;
try {
SessionId sessionId = SessionId.of(mediaDrm.openSession());
FrameworkMediaCrypto mediaCrypto = mediaDrm.createMediaCrypto(sessionId.asBytes());
mediaDrm.restoreKeys(sessionId.asBytes(), keySetIdToRestore.asBytes());
drmSession = new LocalDrmSession(mediaCrypto, keySetIdToRestore, sessionId);
} catch (Exception exception) {
drmSession = new InvalidDrmSession(new DrmSession.DrmSessionException(exception));
notifyErrorListener(drmSession);
}
return drmSession;
}
/** Returns a {@link DrmSession} ready for assignment, handling resource management. */
@Nullable
protected final <T extends ExoMediaCrypto> DrmSession<T> getUpdatedSourceDrmSession(
@Nullable Format oldFormat,
Format newFormat,
@Nullable DrmSessionManager<T> drmSessionManager,
@Nullable DrmSession<T> existingSourceSession)
throws ExoPlaybackException {
boolean drmInitDataChanged =
!Util.areEqual(newFormat.drmInitData, oldFormat == null ? null : oldFormat.drmInitData);
if (!drmInitDataChanged) {
return existingSourceSession;
}
@Nullable DrmSession<T> newSourceDrmSession = null;
if (newFormat.drmInitData != null) {
if (drmSessionManager == null) {
throw createRendererException(
new IllegalStateException("Media requires a DrmSessionManager"), newFormat);
}
newSourceDrmSession =
drmSessionManager.acquireSession(
Assertions.checkNotNull(Looper.myLooper()), newFormat.drmInitData);
}
if (existingSourceSession != null) {
existingSourceSession.release();
}
return newSourceDrmSession;
}
/**
* Throws an error that's preventing data from being read. Does nothing if no such error exists.
*
* @throws IOException The underlying error.
*/
public void maybeThrowError() throws IOException {
// TODO: Avoid throwing if the DRM error is not preventing a read operation.
if (currentDrmSession != null && currentDrmSession.getState() == DrmSession.STATE_ERROR) {
throw Assertions.checkNotNull(currentDrmSession.getError());
}
}
/**
* Sets the downstream format, performs DRM resource management, and populates the {@code
* outputFormatHolder}.
*
* @param newFormat The new downstream format.
* @param outputFormatHolder The output {@link FormatHolder}.
*/
private void onFormatResult(Format newFormat, FormatHolder outputFormatHolder) {
outputFormatHolder.format = newFormat;
boolean isFirstFormat = downstreamFormat == null;
DrmInitData oldDrmInitData = isFirstFormat ? null : downstreamFormat.drmInitData;
downstreamFormat = newFormat;
if (drmSessionManager == DrmSessionManager.DUMMY) {
// Avoid attempting to acquire a session using the dummy DRM session manager. It's likely that
// the media source creation has not yet been migrated and the renderer can acquire the
// session for the read DRM init data.
// TODO: Remove once renderers are migrated [Internal ref: b/122519809].
return;
}
DrmInitData newDrmInitData = newFormat.drmInitData;
outputFormatHolder.includesDrmSession = true;
outputFormatHolder.drmSession = currentDrmSession;
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.
DrmSession<?> previousSession = currentDrmSession;
Looper playbackLooper = Assertions.checkNotNull(Looper.myLooper());
currentDrmSession =
newDrmInitData != null
? drmSessionManager.acquireSession(playbackLooper, newDrmInitData)
: drmSessionManager.acquirePlaceholderSession(
playbackLooper, MimeTypes.getTrackType(newFormat.sampleMimeType));
outputFormatHolder.drmSession = currentDrmSession;
if (previousSession != null) {
previousSession.release();
}
}
/**
* Returns whether it's possible to read the next sample.
*
* @param relativeReadIndex The relative read index of the next sample.
* @return Whether it's possible to read the next sample.
*/
private boolean mayReadSample(int relativeReadIndex) {
if (drmSessionManager == DrmSessionManager.DUMMY) {
// TODO: Remove once renderers are migrated [Internal ref: b/122519809].
// For protected content it's likely that the DrmSessionManager is still being injected into
// the renderers. We assume that the renderers will be able to acquire a DrmSession if needed.
return true;
}
return currentDrmSession == null
|| currentDrmSession.getState() == DrmSession.STATE_OPENED_WITH_KEYS
|| ((flags[relativeReadIndex] & C.BUFFER_FLAG_ENCRYPTED) == 0
&& currentDrmSession.playClearSamplesWithoutKeys());
}
private boolean shouldWaitForKeys(boolean bufferEncrypted) throws ExoPlaybackException {
if (codecDrmSession == null
|| (!bufferEncrypted
&& (playClearSamplesWithoutKeys || codecDrmSession.playClearSamplesWithoutKeys()))) {
return false;
}
@DrmSession.State int drmSessionState = codecDrmSession.getState();
if (drmSessionState == DrmSession.STATE_ERROR) {
throw createRendererException(codecDrmSession.getError(), inputFormat);
}
return drmSessionState != DrmSession.STATE_OPENED_WITH_KEYS;
}
private boolean shouldWaitForKeys(boolean bufferEncrypted) throws ExoPlaybackException {
if (decoderDrmSession == null
|| (!bufferEncrypted
&& (playClearSamplesWithoutKeys || decoderDrmSession.playClearSamplesWithoutKeys()))) {
return false;
}
@DrmSession.State int drmSessionState = decoderDrmSession.getState();
if (drmSessionState == DrmSession.STATE_ERROR) {
throw createRendererException(decoderDrmSession.getError(), inputFormat);
}
return drmSessionState != DrmSession.STATE_OPENED_WITH_KEYS;
}
@SuppressWarnings("unchecked")
private void onInputFormatChanged(FormatHolder formatHolder) throws ExoPlaybackException {
Format newFormat = Assertions.checkNotNull(formatHolder.format);
if (formatHolder.includesDrmSession) {
setSourceDrmSession((DrmSession<ExoMediaCrypto>) formatHolder.drmSession);
} else {
sourceDrmSession =
getUpdatedSourceDrmSession(inputFormat, newFormat, drmSessionManager, sourceDrmSession);
}
Format oldFormat = inputFormat;
inputFormat = newFormat;
if (!canKeepCodec(oldFormat, inputFormat)) {
if (decoderReceivedBuffers) {
// Signal end of stream and wait for any final output buffers before re-initialization.
decoderReinitializationState = REINITIALIZATION_STATE_SIGNAL_END_OF_STREAM;
} else {
// There aren't any final output buffers, so release the decoder immediately.
releaseDecoder();
maybeInitDecoder();
audioTrackNeedsConfigure = true;
}
}
encoderDelay = inputFormat.encoderDelay;
encoderPadding = inputFormat.encoderPadding;
eventDispatcher.inputFormatChanged(inputFormat);
}
/**
* Called when a new format is read from the upstream source.
*
* @param formatHolder A {@link FormatHolder} that holds the new {@link Format}.
* @throws ExoPlaybackException If an error occurs (re-)initializing the decoder.
*/
@CallSuper
@SuppressWarnings("unchecked")
protected void onInputFormatChanged(FormatHolder formatHolder) throws ExoPlaybackException {
waitingForFirstSampleInFormat = true;
Format newFormat = Assertions.checkNotNull(formatHolder.format);
if (formatHolder.includesDrmSession) {
setSourceDrmSession((DrmSession<ExoMediaCrypto>) formatHolder.drmSession);
} else {
sourceDrmSession =
getUpdatedSourceDrmSession(inputFormat, newFormat, drmSessionManager, sourceDrmSession);
}
inputFormat = newFormat;
if (sourceDrmSession != decoderDrmSession) {
if (decoderReceivedBuffers) {
// Signal end of stream and wait for any final output buffers before re-initialization.
decoderReinitializationState = REINITIALIZATION_STATE_SIGNAL_END_OF_STREAM;
} else {
// There aren't any final output buffers, so release the decoder immediately.
releaseDecoder();
maybeInitDecoder();
}
}
eventDispatcher.inputFormatChanged(inputFormat);
}
private boolean shouldWaitForKeys(boolean bufferEncrypted) throws ExoPlaybackException {
if (decoderDrmSession == null
|| (!bufferEncrypted
&& (playClearSamplesWithoutKeys || decoderDrmSession.playClearSamplesWithoutKeys()))) {
return false;
}
@DrmSession.State int drmSessionState = decoderDrmSession.getState();
if (drmSessionState == DrmSession.STATE_ERROR) {
throw createRendererException(decoderDrmSession.getError(), inputFormat);
}
return drmSessionState != DrmSession.STATE_OPENED_WITH_KEYS;
}
private boolean shouldWaitForKeys(boolean bufferEncrypted) throws ExoPlaybackException {
if (drmSession == null || (!bufferEncrypted && playClearSamplesWithoutKeys)) {
return false;
}
@DrmSession.State int drmSessionState = drmSession.getState();
if (drmSessionState == DrmSession.STATE_ERROR) {
throw ExoPlaybackException.createForRenderer(drmSession.getError(), getIndex());
}
return drmSessionState != DrmSession.STATE_OPENED_WITH_KEYS;
}
private boolean shouldWaitForKeys(boolean bufferEncrypted) throws ExoPlaybackException {
if (drmSession == null || (!bufferEncrypted && playClearSamplesWithoutKeys)) {
return false;
}
@DrmSession.State int drmSessionState = drmSession.getState();
if (drmSessionState == DrmSession.STATE_ERROR) {
throw ExoPlaybackException.createForRenderer(drmSession.getError(), getIndex());
}
return drmSessionState != DrmSession.STATE_OPENED_WITH_KEYS;
}
private boolean shouldWaitForKeys(boolean bufferEncrypted) throws ExoPlaybackException {
if (drmSession == null || (!bufferEncrypted && playClearSamplesWithoutKeys)) {
return false;
}
@DrmSession.State int drmSessionState = drmSession.getState();
if (drmSessionState == DrmSession.STATE_ERROR) {
throw ExoPlaybackException.createForRenderer(drmSession.getError(), getIndex());
}
return drmSessionState != DrmSession.STATE_OPENED_WITH_KEYS;
}
private boolean shouldWaitForKeys(boolean bufferEncrypted) throws ExoPlaybackException {
if (drmSession == null || (!bufferEncrypted && playClearSamplesWithoutKeys)) {
return false;
}
@DrmSession.State int drmSessionState = drmSession.getState();
if (drmSessionState == DrmSession.STATE_ERROR) {
throw ExoPlaybackException.createForRenderer(drmSession.getError(), getIndex());
}
return drmSessionState != DrmSession.STATE_OPENED_WITH_KEYS;
}
private boolean shouldWaitForKeys(boolean bufferEncrypted) throws ExoPlaybackException {
if (drmSession == null || (!bufferEncrypted && playClearSamplesWithoutKeys)) {
return false;
}
@DrmSession.State int drmSessionState = drmSession.getState();
if (drmSessionState == DrmSession.STATE_ERROR) {
throw ExoPlaybackException.createForRenderer(drmSession.getError(), getIndex());
}
return drmSessionState != DrmSession.STATE_OPENED_WITH_KEYS;
}
private void notifyErrorListener(DrmSession<FrameworkMediaCrypto> drmSession) {
final DrmSession.DrmSessionException error = drmSession.getError();
handler.post(new Runnable() {
@Override
public void run() {
eventListener.onDrmSessionManagerError(error);
}
});
}
@Test
public void givenValidMediaDrm_whenAcquiringSession_thenReturnsLocalDrmSession() throws MediaCryptoException {
given(mediaDrm.createMediaCrypto(SESSION_ID.asBytes())).willReturn(frameworkMediaCrypto);
DrmSession<FrameworkMediaCrypto> drmSession = localDrmSessionManager.acquireSession(IGNORED_LOOPER, IGNORED_DRM_DATA);
LocalDrmSession localDrmSession = new LocalDrmSession(frameworkMediaCrypto, KEY_SET_ID_TO_RESTORE, SESSION_ID);
assertThat(drmSession).isEqualTo(localDrmSession);
}
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
@Test
public void givenOpeningSessionError_whenAcquiringSession_thenNotifiesErrorEventListenerOnHandler() throws MediaDrmException {
given(mediaDrm.openSession()).willThrow(new ResourceBusyException("resource is busy"));
localDrmSessionManager.acquireSession(IGNORED_LOOPER, IGNORED_DRM_DATA);
ArgumentCaptor<Runnable> argumentCaptor = ArgumentCaptor.forClass(Runnable.class);
verify(handler).post(argumentCaptor.capture());
argumentCaptor.getValue().run();
verify(eventListener).onDrmSessionManagerError(any(DrmSession.DrmSessionException.class));
}
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
@Test
public void givenOpeningSessionError_whenAcquiringSession_thenReturnsInvalidDrmSession() throws MediaDrmException {
ResourceBusyException resourceBusyException = new ResourceBusyException("resource is busy");
given(mediaDrm.openSession()).willThrow(resourceBusyException);
DrmSession<FrameworkMediaCrypto> drmSession = localDrmSessionManager.acquireSession(IGNORED_LOOPER, IGNORED_DRM_DATA);
assertThat(drmSession).isInstanceOf(InvalidDrmSession.class);
assertThat(drmSession.getError().getCause()).isEqualTo(resourceBusyException);
}
@Test
public void givenAcquiredSession_whenReleasingSession_thenClosesCurrentSession() {
DrmSession<FrameworkMediaCrypto> drmSession = new LocalDrmSession(frameworkMediaCrypto, KEY_SET_ID_TO_RESTORE, SESSION_ID);
localDrmSessionManager.releaseSession(drmSession);
verify(mediaDrm).closeSession(SESSION_ID.asBytes());
}
private boolean shouldWaitForKeys(boolean bufferEncrypted) throws ExoPlaybackException {
if (drmSession == null) {
return false;
}
@DrmSession.State int drmSessionState = drmSession.getState();
if (drmSessionState == DrmSession.STATE_ERROR) {
throw ExoPlaybackException.createForRenderer(drmSession.getError(), getIndex());
}
return drmSessionState != DrmSession.STATE_OPENED_WITH_KEYS
&& (bufferEncrypted || !playClearSamplesWithoutKeys);
}
private boolean shouldWaitForKeys(boolean bufferEncrypted) throws ExoPlaybackException {
if (drmSession == null) {
return false;
}
@DrmSession.State int drmSessionState = drmSession.getState();
if (drmSessionState == DrmSession.STATE_ERROR) {
throw ExoPlaybackException.createForRenderer(drmSession.getError(), getIndex());
}
return drmSessionState != DrmSession.STATE_OPENED_WITH_KEYS
&& (bufferEncrypted || !playClearSamplesWithoutKeys);
}
private void maybeInitDecoder() throws ExoPlaybackException {
if (decoder != null) {
return;
}
drmSession = pendingDrmSession;
ExoMediaCrypto mediaCrypto = null;
if (drmSession != null) {
@DrmSession.State int drmSessionState = drmSession.getState();
if (drmSessionState == DrmSession.STATE_ERROR) {
throw ExoPlaybackException.createForRenderer(drmSession.getError(), getIndex());
} else if (drmSessionState == DrmSession.STATE_OPENED
|| drmSessionState == DrmSession.STATE_OPENED_WITH_KEYS) {
mediaCrypto = drmSession.getMediaCrypto();
} else {
// The drm session isn't open yet.
return;
}
}
try {
long codecInitializingTimestamp = SystemClock.elapsedRealtime();
TraceUtil.beginSection("createAudioDecoder");
decoder = createDecoder(inputFormat, mediaCrypto);
TraceUtil.endSection();
long codecInitializedTimestamp = SystemClock.elapsedRealtime();
eventDispatcher.decoderInitialized(decoder.getName(), codecInitializedTimestamp,
codecInitializedTimestamp - codecInitializingTimestamp);
decoderCounters.decoderInitCount++;
} catch (AudioDecoderException e) {
throw ExoPlaybackException.createForRenderer(e, getIndex());
}
}
private boolean shouldWaitForKeys(boolean bufferEncrypted) throws ExoPlaybackException {
if (codecDrmSession == null || (!bufferEncrypted && playClearSamplesWithoutKeys)) {
return false;
}
@DrmSession.State int drmSessionState = codecDrmSession.getState();
if (drmSessionState == DrmSession.STATE_ERROR) {
throw ExoPlaybackException.createForRenderer(codecDrmSession.getError(), getIndex());
}
return drmSessionState != DrmSession.STATE_OPENED_WITH_KEYS;
}
private boolean shouldWaitForKeys(boolean bufferEncrypted) throws ExoPlaybackException {
if (decoderDrmSession == null || (!bufferEncrypted && playClearSamplesWithoutKeys)) {
return false;
}
@DrmSession.State int drmSessionState = decoderDrmSession.getState();
if (drmSessionState == DrmSession.STATE_ERROR) {
throw ExoPlaybackException.createForRenderer(decoderDrmSession.getError(), getIndex());
}
return drmSessionState != DrmSession.STATE_OPENED_WITH_KEYS;
}
private void onInputFormatChanged(Format newFormat) throws ExoPlaybackException {
Format oldFormat = inputFormat;
inputFormat = newFormat;
boolean drmInitDataChanged = !Util.areEqual(inputFormat.drmInitData, oldFormat == null ? null
: oldFormat.drmInitData);
if (drmInitDataChanged) {
if (inputFormat.drmInitData != null) {
if (drmSessionManager == null) {
throw ExoPlaybackException.createForRenderer(
new IllegalStateException("Media requires a DrmSessionManager"), getIndex());
}
DrmSession<ExoMediaCrypto> session =
drmSessionManager.acquireSession(Looper.myLooper(), newFormat.drmInitData);
if (session == decoderDrmSession || session == sourceDrmSession) {
// We already had this session. The manager must be reference counting, so release it once
// to get the count attributed to this renderer back down to 1.
drmSessionManager.releaseSession(session);
}
setSourceDrmSession(session);
} else {
setSourceDrmSession(null);
}
}
if (decoderReceivedBuffers) {
// Signal end of stream and wait for any final output buffers before re-initialization.
decoderReinitializationState = REINITIALIZATION_STATE_SIGNAL_END_OF_STREAM;
} else {
// There aren't any final output buffers, so release the decoder immediately.
releaseDecoder();
maybeInitDecoder();
audioTrackNeedsConfigure = true;
}
encoderDelay = newFormat.encoderDelay;
encoderPadding = newFormat.encoderPadding;
eventDispatcher.inputFormatChanged(newFormat);
}
private boolean shouldWaitForKeys(boolean bufferEncrypted) throws ExoPlaybackException {
if (codecDrmSession == null || (!bufferEncrypted && playClearSamplesWithoutKeys)) {
return false;
}
@DrmSession.State int drmSessionState = codecDrmSession.getState();
if (drmSessionState == DrmSession.STATE_ERROR) {
throw ExoPlaybackException.createForRenderer(codecDrmSession.getError(), getIndex());
}
return drmSessionState != DrmSession.STATE_OPENED_WITH_KEYS;
}
private boolean shouldWaitForKeys(boolean bufferEncrypted) throws ExoPlaybackException {
if (decoderDrmSession == null || (!bufferEncrypted && playClearSamplesWithoutKeys)) {
return false;
}
@DrmSession.State int drmSessionState = decoderDrmSession.getState();
if (drmSessionState == DrmSession.STATE_ERROR) {
throw ExoPlaybackException.createForRenderer(decoderDrmSession.getError(), getIndex());
}
return drmSessionState != DrmSession.STATE_OPENED_WITH_KEYS;
}
private void onInputFormatChanged(Format newFormat) throws ExoPlaybackException {
Format oldFormat = inputFormat;
inputFormat = newFormat;
boolean drmInitDataChanged = !Util.areEqual(inputFormat.drmInitData, oldFormat == null ? null
: oldFormat.drmInitData);
if (drmInitDataChanged) {
if (inputFormat.drmInitData != null) {
if (drmSessionManager == null) {
throw ExoPlaybackException.createForRenderer(
new IllegalStateException("Media requires a DrmSessionManager"), getIndex());
}
DrmSession<ExoMediaCrypto> session =
drmSessionManager.acquireSession(Looper.myLooper(), newFormat.drmInitData);
if (session == decoderDrmSession || session == sourceDrmSession) {
// We already had this session. The manager must be reference counting, so release it once
// to get the count attributed to this renderer back down to 1.
drmSessionManager.releaseSession(session);
}
setSourceDrmSession(session);
} else {
setSourceDrmSession(null);
}
}
if (decoderReceivedBuffers) {
// Signal end of stream and wait for any final output buffers before re-initialization.
decoderReinitializationState = REINITIALIZATION_STATE_SIGNAL_END_OF_STREAM;
} else {
// There aren't any final output buffers, so release the decoder immediately.
releaseDecoder();
maybeInitDecoder();
audioTrackNeedsConfigure = true;
}
encoderDelay = newFormat.encoderDelay;
encoderPadding = newFormat.encoderPadding;
eventDispatcher.inputFormatChanged(newFormat);
}
private void setSourceDrmSession(@Nullable DrmSession<FrameworkMediaCrypto> session) {
DrmSession.replaceSession(sourceDrmSession, session);
sourceDrmSession = session;
}