Wednesday 4 November 2020

EME with Clear key is not working with Pre-Signed URL of an encrypted audio file stored in S3

I have implemented EME using clear key, following practical guide at: https://www.html5rocks.com/tutorials/eme/basics/

I have encrypted an audio using webm-encrypt npm package, by providing it a key and webm audio file. Same key I'm using in my clear key code to decrypt the audio. It works fine when I use the encrypted audio file locally, setting the src as:

audio.src = './encrypted.webm'

on the other hand I'm storing the same encrypted file in s3. Problem is, when I points the audio src to my server api which in turns redirect to pre-signed s3 url of encrypted audio file, audio is not playing and I see following error in console:

Failed to generate a license request TypeError: Failed to execute 'generateRequest' on 'MediaKeySession': The initDataType parameter is empty.

audio element is not null and encrypted event is also fired, but both event.initData and event.initDataType are empty. Not sure what I'm missing here.

main.js

    "use strict";

var KEY = new Uint8Array([
  0xeb,0xdd,0x62,0xf1,0x68,0x14,0xd2,0x7b,
  0x68,0xef,0x12,0x2a,0xfc,0xe4,0xae,0x3c,
]);

var config = [
  {
    initDataTypes: ["webm"],
    videoCapabilities: [
      {
        contentType: 'video/webm; codecs="vp8"',
      },
    ],
    audioCapabilities: [
      { contentType: 'audio/webm; codecs="opus"' },
      { contentType: 'audio/webm; codecs="vorbis"' },
    ],
  },
];

var audio = document.querySelector("audio");

audio.addEventListener("encrypted", handleEncrypted, false);

createMediaKeys().then(() => {
    //src points to server api
  audio.src = "/api/audio?file=encrypted1.webm";
});

function createMediaKeys() {
  return navigator
    .requestMediaKeySystemAccess("org.w3.clearkey", config)
    .then((keySystemAccess) => {
      return keySystemAccess.createMediaKeys();
    })
    .then((mediaKeys) => {
      return audio.setMediaKeys(mediaKeys);
    })
    .catch(function (error) {
      console.error("Failed to set up MediaKeys", error);
    });
}

function handleEncrypted(event) {
  var session = audio.mediaKeys.createSession();
  session.addEventListener("message", handleMessage, false);
  // error occurs at this line
  session
    .generateRequest(event.initDataType, event.initData)
    .catch(function (error) {
      console.error("Failed to generate a license request", error);
    });
}

function handleMessage(event) {
  var license = generateLicense(event.message);
  var session = event.target;
  session.update(license).catch(function (error) {
    console.error("Failed to update the session", error);
  });
}

function toBase64(u8arr) {
  return btoa(String.fromCharCode.apply(null, u8arr))
    .replace(/\+/g, "-")
    .replace(/\//g, "_")
    .replace(/=*$/, "");
}

function generateLicense(message) {
  var request = JSON.parse(new TextDecoder().decode(message));
  console.assert(request.kids.length === 1);

  var keyObj = {
    kty: "oct",
    alg: "A128KW",
    kid: request.kids[0],
    k: toBase64(KEY),
  };
  return new TextEncoder().encode(
    JSON.stringify({
      keys: [keyObj],
    })
  );
}

index.html

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <title>EME with Clear Key</title>
</head>

<body>

    <div id="audio-player">
        <audio controls>
            <p>This browser does not support the audio element.</p>
        </audio>
    </div>

    <script src="./main.js"></script>
</body>

</html>

server.js

app.get("/api/audio", (req, res) => {
  
  const params = {
    Bucket: "test",
    Key: req.query.file,
  };
  const url = AWSS3.getSignedUrl("getObject", params);
  res.setHeader("Cache-Control", "public, max-age=0");

  return res.redirect(302, url);
});


from EME with Clear key is not working with Pre-Signed URL of an encrypted audio file stored in S3

No comments:

Post a Comment