Skip to content
On this page

Bitmovin Player Web ​

1. Introduction ​

This section will provide information on integrating SigmaMultiDRM into Bitmovin Player on Web platform:

Information ​

In which, MERCHANT_ID and APP_ID will be obtained from Dashboard.

get_customer_info

2. Require ​

Prerequisite ​

  • Html 5 Browsers:
Html 5 browsersWidevinePlayReadyFairPlayLicense encryption support
Chrome (Window, MacOS, Android, ChromeOS, Linux)YesNoNoYes
Firefox (Window, MacOS, Linux)YesNoNoYes
Microsoft Edge (Window, MacOS, Android)YesYesNoNo
Safari (Safari 8+ on MacOS, Safari on iOS 11.2+)NoNoYesNo
iOS Browser (Chrome, Cốc Cốc, Microsoft Edge, Firefox, Opera)NoNoYesNo
Opera (Window, MacOS)YesNoNoYes
Internet Explorer (Window 8.1+)NoYesYesNo
  • Smart TVs:
Smart TVsWidevinePlayReadyFairPlayLicense encryption support
SamSung Tizen (2016-2017, 2018+ Models)YesYesNoNo
SamSung Tizen&Orsay (2010-2015 Models)NoYesNoNo
LG (WebOS 3.0+)YesYesNoNo
LG (WebOS 1.2 & Netcast)NoYesNoNo
Smart TV Alliance (LG, Philips, Toshiba, Panasonic)YesYesNoNo
Android TVYesYesNoNo

3. Integrate license into Bitmovin Player Web ​

3.1. License encryption feature with Sigma Packer SDK ​

To use the license encryption feature, you need to install the Sigma Packer SDK into your application

Installing the SDK

  • Source: sigma_packer.js

  • Add script:

    html
    <script src="sigma_packer.js"></script>

Note: The implementation will be presented in the following sections

3.2 Init application ​

  • If you use the license encryption feature: You need to instantiate an object of the SigmaPacker class:
javascript
document.addEventListener('DOMContentLoaded', function () {
  window.sigmaPacker = new SigmaPacker();
  window.sigmaPacker.onload = () => {
    console.log('SigmaPacker loaded');
  };
  window.sigmaPacker.init();
});

Note: If you are using ReactJS, place this code snippet in the src/App.js file immediately after importing the utilities used to initialize the SigmaPacker.

javascript
// src/App.js
import ... from "...";
import ... from "...";

window.sigmaPacker = new SigmaPacker();
window.sigmaPacker.onload = () => {
  console.log('SigmaPacker loaded');
};
window.sigmaPacker.init();

// do something

3.3 Configure the player to use this license server ​

javascript
// SourceConfig object to be passed to Bitmovin Player instance
const source = {
  dash: DASH_MANIFEST_URL,
  hls: HLS_MANIFEST_URL,
  drm: {
    widevine: {
      LA_URL: LICENSE_WIDEVINE_URL,
    },
    playready: {
      LA_URL: LICENSE_PLAYREADY_URL,
    },
    fairplay: {
      LA_URL: LICENSE_FAIRPLAY_URL,
      certificateURL: FAIRPLAY_CERTIFICATE_URL,
    },
  },
};
PropsTypeDescription
DASH_MANIFEST_URLStringDash URL of the content you want to view
HLS_MANIFEST_URLStringHLS URL of the content you want to view
LICENSE_WIDEVINE_URLStringSee heading 1. Introduction
LICENSE_PLAYREADY_URLStringSee heading 1. Introduction
LICENSE_FAIRPLAY_URLStringSee heading 1. Introduction
FAIRPLAY_CERTIFICATE_URLStringSee heading 1. Introduction

3.4 License request handler ​

Configuration information:

PropsTypeDescription
MERCHANT_IDStringId of merchant's user
APP_IDStringId of application
USER_IDStringUserId of merchant's client
SESSION_IDStringSessionId of merchant's client

3.4.1 FairPlay ​

javascript
let licenseURL = ''; // The variable to store license request url
// SourceConfig object to be passed to Bitmovin Player instance
const source = {
  hls: HLS_MANIFEST_URL,
  drm: {
    fairplay: {
      LA_URL: LICENSE_FAIRPLAY_URL,
      certificateURL: FAIRPLAY_CERTIFICATE_URL,
      prepareLicense: (license) => {
        return new Uint8Array(license);
      },
      prepareMessage: (event, session) => {
        return JSON.stringify({
          spc: event.messageBase64Encoded,
          assetId: session.contentId,
        });
      },
      prepareContentId: (contentId) => {
        const pattern = 'skd://';
        const idx = contentId.indexOf(pattern);

        if (idx > -1) {
          licenseURL = contentId.substring(idx + pattern.length);
          licenseURL = 'https://' + licenseURL;
          return new URL(licenseURL).searchParams.get('assetId');
        }
        return '';
      },
    },
  },
};

// The configuration object is used to initialize the Bitmovin Player instance
const config = {
  network: {
    preprocessHttpRequest: function (type, request) {
      const HttpRequestType = bitmovin.player.HttpRequestType;
      if (type === HttpRequestType.DRM_LICENSE_FAIRPLAY) {
        const customData = {
          merchantId,
          appId,
          userId,
          sessionId,
        };
        request.url = licenseURL;
        request.headers['Content-Type'] = 'application/json';
        request.headers['custom-data'] = btoa(JSON.stringify(customData));
      }
      return Promise.resolve(request);
    },
  },
};

3.4.2. Widevine or PlayReady ​

  • Default case:
javascript
// The configuration object using init bitmovin player instance
const config = {
  network: {
    preprocessHttpRequest: function (type, request) {
      const HttpRequestType = bitmovin.player.HttpRequestType;
      if (
        type === HttpRequestType.DRM_LICENSE_WIDEVINE ||
        type === HttpRequestType.DRM_LICENSE_PLAYREADY
      ) {
        const customData = {
          merchantId: MERCHANT_ID,
          appId: APP_ID,
          userId: USER_ID,
          sessionId: SESSION_ID,
        };
        request.headers['Content-Type'] = 'application/octet-stream';
        request.headers['custom-data'] = btoa(JSON.stringify(customData));
      }
      return Promise.resolve(request);
    },
  },
};
  • If you use license encryption feature, you need to add some fields to the header:
javascript
const config = {
  network: {
    preprocessHttpRequest: function (type, request) {
      const HttpRequestType = bitmovin.player.HttpRequestType;
      if (
        type === HttpRequestType.DRM_LICENSE_WIDEVINE ||
        type === HttpRequestType.DRM_LICENSE_PLAYREADY
      ) {
        const packInfo = window.sigmaPacker.getDataPacker(request.body) || {};
        const customData = {
          merchantId: MERCHANT_ID,
          appId: APP_ID,
          userId: USER_ID,
          sessionId: SESSION_ID,
          reqId: packInfo.requestId,
          deviceInfo: packInfo.deviceInfo,
        };
        request.headers['Content-Type'] = 'application/octet-stream';
        request.headers['custom-data'] = btoa(JSON.stringify(customData));
      }
      return Promise.resolve(request);
    },
  },
};

3.5 License response handler ​

3.5.1 FairPlay ​

javascript
const config = {
  network: {
    preprocessHttpResponse: function (type, response) {
      const HttpRequestType = bitmovin.player.HttpRequestType;
      if (type === HttpRequestType.DRM_LICENSE_FAIRPLAY) {
        // This is the wrapped license, which is a JSON string.
        try {
          const wrapped = JSON.parse(response.body);
          // Parse the JSON string into an object.
          // This is a base64-encoded version of the raw license.
          const rawLicenseBase64 = wrapped.license;
          // Decode that base64 string into a Uint8Array and replace the response
          // data.  The raw license will be fed to the FairPlay.
          response.body = Uint8Array.from(atob(rawLicenseBase64), (c) =>
            c.charCodeAt(0)
          );
          // Read additional fields from the server.
          // The server we are using in this tutorial does not send anything useful.
          // In practice, you could send any license metadata the client might need.
          // Here we log what the server sent to the JavaScript console for inspection.
        } catch (error) {}
      }
    },
  },
};

3.5.2 Widevine or PlayReady ​

  • Default case:
javascript
const config = {
  network: {
    preprocessHttpResponse: function (type, response) {
      const HttpRequestType = bitmovin.player.HttpRequestType;
      if (
        type === HttpRequestType.DRM_LICENSE_WIDEVINE ||
        type === HttpRequestType.DRM_LICENSE_PLAYREADY
      ) {
        // This is the wrapped license, which is a JSON string.
        try {
          const wrappedString = new TextDecoder().decode(response.body);
          // Parse the JSON string into an object.
          const wrapped = JSON.parse(wrappedString);
          // This is a base64-encoded version of the raw license.
          const rawLicenseBase64 = wrapped.license;
          // Decode that base64 string into a Uint8Array and replace the response
          // data.  The raw license will be fed to the Widevine CDM.
          response.body = Uint8Array.from(atob(rawLicenseBase64), (c) =>
            c.charCodeAt(0)
          );
          // Read additional fields from the server.
          // The server we are using in this tutorial does not send anything useful.
          // In practice, you could send any license metadata the client might need.
          // Here we log what the server sent to the JavaScript console for inspection.
        } catch (error) {}
      }
    },
  },
};
  • If you use license encryption feature, you need a few more handling;
javascript
const config = {
  network: {
    preprocessHttpResponse: function (type, response) {
      const HttpRequestType = bitmovin.player.HttpRequestType;
      if (
        type === HttpRequestType.DRM_LICENSE_WIDEVINE ||
        type === HttpRequestType.DRM_LICENSE_PLAYREADY
      ) {
        // This is the wrapped license, which is a JSON string.
        try {
          const wrappedString = new TextDecoder().decode(response.body);
          // Parse the JSON string into an object.
          const wrapped = JSON.parse(wrappedString);

          if (response.headers['client-info']) {
            window.sigmaPacker.update(atob(response.headers['client-info']));
          } else if (wrapped.clientInfo) {
            window.sigmaPacker.update(JSON.stringify(wrapped.clientInfo));
          }

          // This is a base64-encoded version of the raw license.
          const rawLicenseBase64 = wrapped.license;
          // Decode that base64 string into a Uint8Array and replace the response
          // data.  The raw license will be fed to the Widevine CDM.
          response.body = Uint8Array.from(atob(rawLicenseBase64), (c) =>
            c.charCodeAt(0)
          );
          // Read additional fields from the server.
          // The server we are using in this tutorial does not send anything useful.
          // In practice, you could send any license metadata the client might need.
          // Here we log what the server sent to the JavaScript console for inspection.
        } catch (error) {}
      }
    },
  },
};

4. Play ​

javascript
const player = new bitmovin.player.Player(
  document.getElementById('VIDEO_CONTAINER_ELEMENT'),
  config
);
player.load(source);