Abe Estrada

ShakaPlayer + FairPlay

Ahora toca el turno para configurar FairPlay (DRM) en el ShakaPlayer .

Al inicio debemos obtener el certificado de FairPlay proporcionado por el servidor de DRM al cual debemos tener acceso, el certificado puede ser descargado con fetch algo asi:

fetch("FAIRPLAY_CERT_URL")
  .then((res) => res.arrayBuffer())
  .then((buffer) => setCert(buffer))
  .catch((error) => console.log(error));

Una vez obtenido el certificado, hay que configurar ShakaPlayer con dos filtros, primero en el Request para poder mandar con un formato especial el spc= y otro filtro en el Response para poder convertir la respuesta en un formato que pueda ser leĆ­do por el ShakaPlayer.

// TODO: Fetch FairPlay certificate
const cert = "<CERT_BUFFER>";

// Detect type of DRM supported
const isFairPlaySupported = async () => {
  const config = {
    initDataTypes: ["cenc", "sinf", "skd"],
    videoCapabilities: [{ contentType: 'video/mp4; codecs="avc1.42E01E"' }],
  };
  try {
    await navigator.requestMediaKeySystemAccess("com.apple.fps", [config]);
    return true;
  } catch (error) {
    return false;
  }
};

const videoEl = document.getElementById("video");
const player = new shaka.Player(videoEl);

// WideVine and PlayReady
player.configure({
  drm: {
    servers: {
      "com.widevine.alpha": "https://<DRM_SERVER>/WideVine/",
      "com.microsoft.playready": "https://<DRM_SERVER>/PlayReady/",
      "com.apple.fps.1_0": "skd://<DRM_SERVER>/FairPlay".replace("skd://", "https://"),
    },
    advanced: {
      "com.widevine.alpha": {
        videoRobustness: "SW_SECURE_CRYPTO",
        audioRobustness: "SW_SECURE_CRYPTO",
      },
    },
  },
});

// FairPlay
player.configure("drm.advanced.com\\.apple\\.fps\\.1_0.serverCertificate", shaka.util.BufferUtils.toUint8(cert));

player.getNetworkingEngine().registerRequestFilter((type, request) => {
  if (type !== shaka.net.NetworkingEngine.RequestType.LICENSE) {
    return;
  }
  request.headers["Authorization"] = "<DRM_TOKEN>";
  if (isFairPlaySupported) {
    const originalPayload = shaka.util.BufferUtils.toUint8(request.body);
    const base64Payload = encodeURI(btoa(String.fromCharCode(...originalPayload)));
    request.headers["Content-Type"] = "application/x-www-form-urlencoded";
    request.body = shaka.util.StringUtils.toUTF8(`spc=${base64Payload}`);
  }
});

player.getNetworkingEngine().registerResponseFilter((type, response) => {
  if (type !== shaka.net.NetworkingEngine.RequestType.LICENSE) {
    return;
  }
  if (isFairPlaySupported) {
    const responseText = shaka.util.StringUtils.fromUTF8(response.data);
    const b64key = responseText.trim().slice(5, -6);
    const key = new Uint8Array(atob(b64key).split("").map((c) => c.charCodeAt(0)));
    response.data = key;
  }
});

const play = async () => {
  try {
    await player.load(isFairPlaySupported ? "<HSL_VIDEO_URL>" : "<MPEG_DASH_URL>");
    videoEl.play();
  } catch (error) {
    console.log("Error:", error);
  }
};
play();

Relacionados: