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);