Skip to content
On this page

ExoPlayer

1. Giới thiệu

Thông tin tích hợp:

get_customer_info

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.

      java
      repositories{
      		maven
      			{
      				url "https://maven.sigmadrm.com"
      			}
      		}
      	}
  • Các thông tin được sử dụng trong tài liệu

TrườngKiểuMô tả
LICENSE_URLStringĐịa chỉ hệ thống máy chủ DRM. Bạn có thể tìm thấy ở đây
MERCHANT_IDStringĐịnh danh khách hàng. Bạn có thể tìm thấy ở đây
APP_IDStringĐịnh danh của ứng dụng. Bạn có thể tìm thấy ở đây
USER_IDStringĐịnh danh của người dung trong hệ thống của khách hàng
SESSION_IDStringMã 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 MultiDRMSigma 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;
  }
}