Make MediaDrmCallback surface more error information

Issue:#7309
PiperOrigin-RevId: 311324242
This commit is contained in:
aquilescanta 2020-05-13 15:28:21 +01:00 committed by Oliver Woodman
parent 1c3c7c58ab
commit 025a2c2b62
4 changed files with 123 additions and 40 deletions

View file

@ -24,9 +24,9 @@ import com.google.android.exoplayer2.upstream.DataSourceInputStream;
import com.google.android.exoplayer2.upstream.DataSpec;
import com.google.android.exoplayer2.upstream.HttpDataSource;
import com.google.android.exoplayer2.upstream.HttpDataSource.InvalidResponseCodeException;
import com.google.android.exoplayer2.upstream.StatsDataSource;
import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.Util;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
@ -104,14 +104,19 @@ public final class HttpMediaDrmCallback implements MediaDrmCallback {
}
@Override
public byte[] executeProvisionRequest(UUID uuid, ProvisionRequest request) throws IOException {
public byte[] executeProvisionRequest(UUID uuid, ProvisionRequest request)
throws MediaDrmCallbackException {
String url =
request.getDefaultUrl() + "&signedRequest=" + Util.fromUtf8Bytes(request.getData());
return executePost(dataSourceFactory, url, /* httpBody= */ null, /* requestProperties= */ null);
return executePost(
dataSourceFactory,
url,
/* httpBody= */ null,
/* requestProperties= */ Collections.emptyMap());
}
@Override
public byte[] executeKeyRequest(UUID uuid, KeyRequest request) throws Exception {
public byte[] executeKeyRequest(UUID uuid, KeyRequest request) throws MediaDrmCallbackException {
String url = request.getLicenseServerUrl();
if (forceDefaultLicenseUrl || TextUtils.isEmpty(url)) {
url = defaultLicenseUrl;
@ -136,41 +141,56 @@ public final class HttpMediaDrmCallback implements MediaDrmCallback {
HttpDataSource.Factory dataSourceFactory,
String url,
@Nullable byte[] httpBody,
@Nullable Map<String, String> requestProperties)
throws IOException {
HttpDataSource dataSource = dataSourceFactory.createDataSource();
Map<String, String> requestProperties)
throws MediaDrmCallbackException {
StatsDataSource dataSource = new StatsDataSource(dataSourceFactory.createDataSource());
int manualRedirectCount = 0;
while (true) {
DataSpec dataSpec =
new DataSpec.Builder()
.setUri(url)
.setHttpRequestHeaders(
requestProperties != null ? requestProperties : Collections.emptyMap())
.setHttpMethod(DataSpec.HTTP_METHOD_POST)
.setHttpBody(httpBody)
.setFlags(DataSpec.FLAG_ALLOW_GZIP)
.build();
DataSourceInputStream inputStream = new DataSourceInputStream(dataSource, dataSpec);
try {
return Util.toByteArray(inputStream);
} catch (InvalidResponseCodeException e) {
// For POST requests, the underlying network stack will not normally follow 307 or 308
// redirects automatically. Do so manually here.
boolean manuallyRedirect =
(e.responseCode == 307 || e.responseCode == 308)
&& manualRedirectCount++ < MAX_MANUAL_REDIRECTS;
@Nullable String redirectUrl = manuallyRedirect ? getRedirectUrl(e) : null;
if (redirectUrl == null) {
throw e;
DataSpec dataSpec =
new DataSpec.Builder()
.setUri(url)
.setHttpRequestHeaders(requestProperties)
.setHttpMethod(DataSpec.HTTP_METHOD_POST)
.setHttpBody(httpBody)
.setFlags(DataSpec.FLAG_ALLOW_GZIP)
.build();
DataSpec originalDataSpec = dataSpec;
try {
while (true) {
DataSourceInputStream inputStream = new DataSourceInputStream(dataSource, dataSpec);
try {
return Util.toByteArray(inputStream);
} catch (InvalidResponseCodeException e) {
@Nullable String redirectUrl = getRedirectUrl(e, manualRedirectCount);
if (redirectUrl == null) {
throw e;
}
manualRedirectCount++;
dataSpec = dataSpec.buildUpon().setUri(redirectUrl).build();
} finally {
Util.closeQuietly(inputStream);
}
url = redirectUrl;
} finally {
Util.closeQuietly(inputStream);
}
} catch (Exception e) {
throw new MediaDrmCallbackException(
originalDataSpec,
Assertions.checkNotNull(dataSource.getLastOpenedUri()),
dataSource.getResponseHeaders(),
dataSource.getBytesRead(),
/* cause= */ e);
}
}
private static @Nullable String getRedirectUrl(InvalidResponseCodeException exception) {
@Nullable
private static String getRedirectUrl(
InvalidResponseCodeException exception, int manualRedirectCount) {
// For POST requests, the underlying network stack will not normally follow 307 or 308
// redirects automatically. Do so manually here.
boolean manuallyRedirect =
(exception.responseCode == 307 || exception.responseCode == 308)
&& manualRedirectCount < MAX_MANUAL_REDIRECTS;
if (!manuallyRedirect) {
return null;
}
Map<String, List<String>> headerFields = exception.headerFields;
if (headerFields != null) {
@Nullable List<String> locationHeaders = headerFields.get("Location");

View file

@ -18,7 +18,6 @@ package com.google.android.exoplayer2.drm;
import com.google.android.exoplayer2.drm.ExoMediaDrm.KeyRequest;
import com.google.android.exoplayer2.drm.ExoMediaDrm.ProvisionRequest;
import com.google.android.exoplayer2.util.Assertions;
import java.io.IOException;
import java.util.UUID;
/**
@ -39,12 +38,12 @@ public final class LocalMediaDrmCallback implements MediaDrmCallback {
}
@Override
public byte[] executeProvisionRequest(UUID uuid, ProvisionRequest request) throws IOException {
public byte[] executeProvisionRequest(UUID uuid, ProvisionRequest request) {
throw new UnsupportedOperationException();
}
@Override
public byte[] executeKeyRequest(UUID uuid, KeyRequest request) throws Exception {
public byte[] executeKeyRequest(UUID uuid, KeyRequest request) {
return keyResponse;
}

View file

@ -30,9 +30,10 @@ public interface MediaDrmCallback {
* @param uuid The UUID of the content protection scheme.
* @param request The request.
* @return The response data.
* @throws Exception If an error occurred executing the request.
* @throws MediaDrmCallbackException If an error occurred executing the request.
*/
byte[] executeProvisionRequest(UUID uuid, ProvisionRequest request) throws Exception;
byte[] executeProvisionRequest(UUID uuid, ProvisionRequest request)
throws MediaDrmCallbackException;
/**
* Executes a key request.
@ -40,7 +41,7 @@ public interface MediaDrmCallback {
* @param uuid The UUID of the content protection scheme.
* @param request The request.
* @return The response data.
* @throws Exception If an error occurred executing the request.
* @throws MediaDrmCallbackException If an error occurred executing the request.
*/
byte[] executeKeyRequest(UUID uuid, KeyRequest request) throws Exception;
byte[] executeKeyRequest(UUID uuid, KeyRequest request) throws MediaDrmCallbackException;
}

View file

@ -0,0 +1,63 @@
/*
* Copyright 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.drm;
import android.net.Uri;
import com.google.android.exoplayer2.upstream.DataSpec;
import java.io.IOException;
import java.util.List;
import java.util.Map;
/**
* Thrown when an error occurs while executing a DRM {@link MediaDrmCallback#executeKeyRequest key}
* or {@link MediaDrmCallback#executeProvisionRequest provisioning} request.
*/
public final class MediaDrmCallbackException extends IOException {
/** The {@link DataSpec} associated with the request. */
public final DataSpec dataSpec;
/**
* The {@link Uri} after redirections, or {@link #dataSpec dataSpec.uri} if no redirection
* occurred.
*/
public final Uri uriAfterRedirects;
/** The HTTP request headers included in the response. */
public final Map<String, List<String>> responseHeaders;
/** The number of bytes obtained from the server. */
public final long bytesLoaded;
/**
* Creates a new instance with the given values.
*
* @param dataSpec See {@link #dataSpec}.
* @param uriAfterRedirects See {@link #uriAfterRedirects}.
* @param responseHeaders See {@link #responseHeaders}.
* @param bytesLoaded See {@link #bytesLoaded}.
* @param cause The cause of the exception.
*/
public MediaDrmCallbackException(
DataSpec dataSpec,
Uri uriAfterRedirects,
Map<String, List<String>> responseHeaders,
long bytesLoaded,
Throwable cause) {
super(cause);
this.dataSpec = dataSpec;
this.uriAfterRedirects = uriAfterRedirects;
this.responseHeaders = responseHeaders;
this.bytesLoaded = bytesLoaded;
}
}