ExoPlayer
1. Giới thiệu
Thông tin tích hợp:
License URL:
Thông tin khách hàng:
2. Yêu cầu
Yêu cầu
Phiên bản hệ thống: Android 16+
Cài đặt Exoplayer2:
Thêm thông tin về kho chứa thư viện vào tệp build.gradle trong thư mục app.
javarepositories{ maven { url "https://maven.sigmadrm.com" } } }
Các thông tin được sử dụng trong tài liệu
Trường | Kiểu | Mô tả |
---|---|---|
LICENSE_URL | String | Địa chỉ hệ thống máy chủ DRM. Bạn có thể tìm thấy ở đây |
MERCHANT_ID | String | Định danh khách hàng. Bạn có thể tìm thấy ở đây |
APP_ID | String | Định danh của ứng dụng. Bạn có thể tìm thấy ở đây |
USER_ID | String | Định danh của người dung trong hệ thống của khách hàng |
SESSION_ID | String | Mã xác thực được cấp cho người dùng bởi hệ thống của khách hàng |
Chú ý: "Nếu bạn sử dụng cả hai loại Sigma MultiDRM và Sigma DRM, vù lòng thêm thư viện phụ thuộc Sigma DRM"
3. Hỗ trợ các phiên bản của Exoplayer
4. Khởi tạo MediaDrmCallback
Chú ý:
- Phiên bản Exoplayer trước 2.12.x: Vui lòng thay những nơi có dòng chữ EXCEPTION thành IOException
- Phiên bản Exoplayer từ 2.12.x: Vui lòng thay những nơi có dòng chữ EXCEPTION thành MediaDrmCallbackException
java
import android.annotation.TargetApi;
import android.net.Uri;
import android.text.TextUtils;
import android.util.Base64;
import android.util.Log;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.drm.ExoMediaDrm.KeyRequest;
import com.google.android.exoplayer2.drm.ExoMediaDrm.ProvisionRequest;
import com.google.android.exoplayer2.drm.MediaDrmCallback;
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.util.Assertions;
import com.google.android.exoplayer2.util.Util;
import com.sigma.packer.RequestInfo;
// FIXME: If you user license encrypt feature then please uncomment line below
// import com.sigma.packer.SigmaDrmPacker;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
/**
* A {@link MediaDrmCallback} that makes requests using {@link HttpDataSource} instances.
*/
@TargetApi(18)
public final class WidevineMediaDrmCallback implements MediaDrmCallback {
private final HttpDataSource.Factory dataSourceFactory;
private final String defaultLicenseUrl;
private final boolean forceDefaultLicenseUrl;
private final Map<String, String> keyRequestProperties;
/**
* @param defaultLicenseUrl The default license URL. Used for key requests that do not specify
* their own license URL.
* @param dataSourceFactory A factory from which to obtain {@link HttpDataSource} instances.
*/
public WidevineMediaDrmCallback(String defaultLicenseUrl, HttpDataSource.Factory dataSourceFactory) {
this(defaultLicenseUrl, false, dataSourceFactory);
}
/**
* @param defaultLicenseUrl The default license URL. Used for key requests that do not specify
* their own license URL, or for all key requests if {@code forceDefaultLicenseUrl} is
* set to true.
* @param forceDefaultLicenseUrl Whether to use {@code defaultLicenseUrl} for key requests that
* include their own license URL.
* @param dataSourceFactory A factory from which to obtain {@link HttpDataSource} instances.
*/
public WidevineMediaDrmCallback(String defaultLicenseUrl, boolean forceDefaultLicenseUrl,
HttpDataSource.Factory dataSourceFactory) {
this.dataSourceFactory = dataSourceFactory;
this.defaultLicenseUrl = defaultLicenseUrl;
this.forceDefaultLicenseUrl = forceDefaultLicenseUrl;
this.keyRequestProperties = new HashMap<>();
}
/**
* Sets a header for key requests made by the callback.
*
* @param name The name of the header field.
* @param value The value of the field.
*/
public void setKeyRequestProperty(String name, String value) {
Assertions.checkNotNull(name);
Assertions.checkNotNull(value);
synchronized (keyRequestProperties) {
keyRequestProperties.put(name, value);
}
}
/**
* Clears a header for key requests made by the callback.
*
* @param name The name of the header field.
*/
public void clearKeyRequestProperty(String name) {
Assertions.checkNotNull(name);
synchronized (keyRequestProperties) {
keyRequestProperties.remove(name);
}
}
/**
* Clears all headers for key requests made by the callback.
*/
public void clearAllKeyRequestProperties() {
synchronized (keyRequestProperties) {
keyRequestProperties.clear();
}
}
@Override
public byte[] executeProvisionRequest(UUID uuid, ProvisionRequest request) throws EXCEPTION {
String url =
request.getDefaultUrl() + "&signedRequest=" + Util.fromUtf8Bytes(request.getData());
return executePost(dataSourceFactory, url, Util.EMPTY_BYTE_ARRAY, null);
}
@Override
public byte[] executeKeyRequest(UUID uuid, KeyRequest request) throws EXCEPTION {
try {
String url = request.getLicenseServerUrl();
if (forceDefaultLicenseUrl || TextUtils.isEmpty(url)) {
url = defaultLicenseUrl;
}
Map<String, String> requestProperties = new HashMap<>();
// Add standard request properties for supported schemes.
String contentType = "application/octet-stream";
requestProperties.put("Content-Type", contentType);
JSONObject customData = new JSONObject();
requestProperties.put("custom-data", getCustomData(request));
// Add additional request properties.
synchronized (keyRequestProperties) {
requestProperties.putAll(keyRequestProperties);
}
String base64Encoded = Base64.encodeToString(request.getData(), Base64.NO_WRAP);
byte[] bytes = executePost(dataSourceFactory, url, request.getData(), requestProperties);
JSONObject jsonObject = new JSONObject(new String(bytes));
String licenseEncrypted = jsonObject.getString("license");
return Base64.decode(licenseEncrypted, Base64.DEFAULT);
} catch (JSONException e) {
throw new RuntimeException("Error while parsing response", e);
} catch (Exception e) {
throw new RuntimeException("Error while parsing response", e);
}
}
private static byte[] executePost(HttpDataSource.Factory dataSourceFactory, String url,
byte[] data, Map<String, String> requestProperties) throws IOException {
HttpDataSource dataSource = dataSourceFactory.createDataSource();
if (requestProperties != null) {
for (Map.Entry<String, String> requestProperty : requestProperties.entrySet()) {
dataSource.setRequestProperty(requestProperty.getKey(), requestProperty.getValue());
}
}
while (true) {
DataSpec dataSpec =
new DataSpec(
Uri.parse(url),
data,
/* absoluteStreamPosition= */ 0,
/* position= */ 0,
/* length= */ C.LENGTH_UNSET,
/* key= */ null,
DataSpec.FLAG_ALLOW_GZIP);
DataSourceInputStream inputStream = new DataSourceInputStream(dataSource, dataSpec);
try {
return Util.toByteArray(inputStream);
} catch (Exception e) {
throw e;
} finally {
Util.closeQuietly(inputStream);
}
}
}
private String getCustomData(KeyRequest keyRequest) throws Exception {
JSONObject customData = new JSONObject();
customData.put("userId", USER_ID);
customData.put("sessionId", SESSION_ID);
customData.put("merchantId", MERCHANT_ID);
customData.put("appId", APP_ID);
// FIXME: If you user license encrypt feature then please uncomment 3 line below
// RequestInfo requestInfo = SigmaDrmPacker.requestInfo(keyRequest.getData());
// customData.put("reqId", requestInfo.requestId);
// customData.put("deviceInfo", requestInfo.deviceInfo);
String customHeader = Base64.encodeToString(customData.toString().getBytes(), Base64.NO_WRAP);
Log.e("Custom Data: ", customHeader);
return customHeader;
}
}
5. Mã nguồn mẫu
Mã nguồn mẫu