Drm configuration "preprocessHttpRequest"

Product

Player

Question

async function initPlayer(packageId = "123fzgAAfEwpCX1A", contentId = "123fzgAAfEwpCX1A", providerId = "vLiveProvider", drmToken = 1234) {
  // Create a Player instance using the HTML video element.
  var video = document.getElementById('video');
  var player = new shaka.Player(video);

  // Define the manifest URI for the video content and the license server URL.
  let manifestUri = 'https://cdn.noorplay.com/RuB69qNY_GNzBKXZk1a4TUgVr_enc.mpd';
  let licenseServerUrl = 'https://vdrm.mobiotics.com/betav1/proxy/v1/license';

  // Expose the player instance globally for potential debugging.
  window.player = player;

  // Listen for error events and handle them with the onErrorEvent function.
  player.addEventListener('error', onErrorEvent);

  // Configure the player for DRM and adaptive bitrate (ABR).
  player.configure({
      drm: {
          servers: {
              'com.widevine.alpha': licenseServerUrl // Set the Widevine license server.
          },
      },
      abr: { enabled: true } // Enable adaptive bitrate streaming.
  });

  // Register a request filter to modify license requests before sending.
  player.getNetworkingEngine().registerRequestFilter(function(type, request) {
      if (type == window.shaka.net.NetworkingEngine.RequestType.LICENSE) {
          // Create a Uint8Array from the raw license request body.
          var rawLicenseRequest = new Uint8Array(request.body);

          // Set the request headers for the license request.
          request.headers['Content-Type'] = "application/json";
          var wrapped = {};  
          wrapped.payload = btoa(String.fromCharCode.apply(null, rawLicenseRequest)); // Encode the payload in Base64.

          // Add DRM scheme and custom data to the wrapped request.
          wrapped.drmscheme = "WIDEVINE";

          customData = {};
          customData.packageid = packageId; // Add package ID.
          customData.drmtoken = drmToken;    // Add DRM token.
          wrapped.customdata = customData;    // Wrap custom data.
          wrapped.contentid = contentId;      // Add content ID.
          wrapped.providerid = providerId;    // Add provider ID.

          // Convert the wrapped object to a JSON string.
          var wrappedJson = JSON.stringify(wrapped);

          // Convert the JSON string back to a Uint8Array for the request body.
          request.body = new Uint8Array(wrappedJson.length);
          for (var i = 0; i < wrappedJson.length; ++i) {
              request.body[i] = wrappedJson.charCodeAt(i);
          }
      }
  });

  // Register a response filter to modify license responses before processing.
  player.getNetworkingEngine().registerResponseFilter(function(type, response) {
      if (type == window.shaka.net.NetworkingEngine.RequestType.LICENSE) {
          // Convert the response data to a Uint8Array.
          var wrappedArray = new Uint8Array(response.data);
          var wrappedString = String.fromCharCode.apply(null, wrappedArray);
          var wrapped = JSON.parse(wrappedString); // Parse the wrapped response.

          // Get the raw license from the wrapped response.
          var rawLicenseBase64 = wrapped.body;
          console.log(wrapped.body); // Log the wrapped body for debugging.

          // Decode the Base64 license to a string.
          var rawLicenseString = atob(rawLicenseBase64);
          // Convert the decoded string to a Uint8Array and set it as the response data.
          response.data = new Uint8Array(rawLicenseString.length);
          for (var i = 0; i < rawLicenseString.length; ++i) {
              response.data[i] = rawLicenseString.charCodeAt(i);
          }
      }
  });

  // Load the video manifest and play the video if successful.
  player.load(manifestUri).then(function() {
      console.log('The video has now been loaded !!'); // Success message.
      player.play(); // Start playback.
  }).catch(onError); // Handle any errors that occur during loading.

}

// Handle error events by forwarding the error details to the onError function.
function onErrorEvent(event) {
  onError(event.detail);
}

// Function to log errors with error code.
function onError(error) {
  console.log('Error code', error.code);
}

// Set up event listeners once the DOM is fully loaded.
document.addEventListener('DOMContentLoaded', () => {
  // Make the play button visible and style it.
  document.getElementById("play").style.display = "block";
  document.getElementById("play").style.fontSize = "30px"; // Corrected property to "fontSize" from "fontsize".

  // Focus on the play button for user convenience.
  document.getElementById("play").focus();
});

How to implement the above for bitmovin player, I have used preprocessHttpRequest and implemented but i was not getting proper results.

preprocessHttpRequest(type, request)

here the request.body getting as “CAQ=” where as in shaka player getting a license key

Hi @madhuy1729,

The request with this specific Widevine body (CAQ=) is a request for a Widevine Server Certificate. This is initiated by the Widevine CDM in the browser if it needs the server certificate.

I’ve run your code with Shaka player and see the same request happening, and the request fails with an HTTP status 502 and the following response:

{
  "errorcode": 401,
  "message": "Access Denied"
}

Now this might be due to incorrect or expired tokens. Can you please share a way for us to play this content in Shaka (send me a private message if you’re not willing to share the token/details publicly)?

FWIW, I usually prefer to successfully test before sharing code, but based on your code snippet from Shaka, it could look like this using the Bitmovin Player:

  const source = {
    dash: 'https://cdn.noorplay.com/RuB69qNY_GNzBKXZk1a4TUgVr_enc.mpd',
    drm: {
      widevine: {
        LA_URL: 'https://vdrm.mobiotics.com/betav1/proxy/v1/license',
        headers: {
          'Content-Type': 'application/json'
        },
        prepareMessage: keyMessageEvent => {
          const wrappedJson = JSON.stringify({
            payload: btoa(String.fromCharCode.apply(null, new Uint8Array(keyMessageEvent.message))),
            drmscheme: 'WIDEVINE',
            customdata: {
              packageid: packageId, // Add package ID.
              drmtoken: drmToken,   // Add DRM token.
            },
            contentid: contentId,      // Add content ID.
            providerid: providerId,    // Add provider ID.
          });

          // Convert the JSON string back to a Uint8Array for the request body.
          const message = new Uint8Array(wrappedJson.length);
          for (let i = 0; i < wrappedJson.length; ++i) {
              message[i] = wrappedJson.charCodeAt(i);
          }

          return message
        },
        prepareLicense: licenseObj => {
          const wrappedString = String.fromCharCode.apply(null, licenseObj.license);
          const wrapped = JSON.parse(wrappedString); // Parse the wrapped response.

          // Get the raw license from the wrapped response.
          const rawLicenseBase64 = wrapped.body;

          // Decode the Base64 license to a string.
          const rawLicenseString = atob(rawLicenseBase64);
          // Convert the decoded string to a Uint8Array and set it as the response data.
          const widevineLicense = new Uint8Array(rawLicenseString.length);
          for (var i = 0; i < rawLicenseString.length; ++i) {
            widevineLicense[i] = rawLicenseString.charCodeAt(i);
          }

          return widevineLicense;
        }
      }
    }

  player.load(source)