Bitmovin Player Web
1. Introduction
This section will provide information on integrating SigmaMultiDRM into Bitmovin Player on Web platform:
Information
- Widevine:
- Playready:
- FairPlay:
- Staging:
- Production:
- Certificate URL: https://cert.sigmadrm.com/app/fairplay/{MERCHANT_ID}/{APP_ID}
- License URL: https://license.sigmadrm.com/license/verify/fairplay
In which, MERCHANT_ID
and APP_ID
will be obtained from Dashboard.
2. Require
Prerequisite
- Html 5 Browsers:
Html 5 browsers | Widevine | PlayReady | FairPlay | License encryption support |
---|---|---|---|---|
Chrome (Window, MacOS, Android, ChromeOS, Linux) | Yes | No | No | Yes |
Firefox (Window, MacOS, Linux) | Yes | No | No | Yes |
Microsoft Edge (Window, MacOS, Android) | Yes | Yes | No | No |
Safari (Safari 8+ on MacOS, Safari on iOS 11.2+) | No | No | Yes | No |
iOS Browser (Chrome, Cốc Cốc, Microsoft Edge, Firefox, Opera) | No | No | Yes | No |
Opera (Window, MacOS) | Yes | No | No | Yes |
Internet Explorer (Window 8.1+) | No | Yes | Yes | No |
- Smart TVs:
Smart TVs | Widevine | PlayReady | FairPlay | License encryption support |
---|---|---|---|---|
SamSung Tizen (2016-2017, 2018+ Models) | Yes | Yes | No | No |
SamSung Tizen&Orsay (2010-2015 Models) | No | Yes | No | No |
LG (WebOS 3.0+) | Yes | Yes | No | No |
LG (WebOS 1.2 & Netcast) | No | Yes | No | No |
Smart TV Alliance (LG, Philips, Toshiba, Panasonic) | Yes | Yes | No | No |
Android TV | Yes | Yes | No | No |
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,
},
},
};
Props | Type | Description |
---|---|---|
DASH_MANIFEST_URL | String | Dash URL of the content you want to view |
HLS_MANIFEST_URL | String | HLS URL of the content you want to view |
LICENSE_WIDEVINE_URL | String | See heading 1. Introduction |
LICENSE_PLAYREADY_URL | String | See heading 1. Introduction |
LICENSE_FAIRPLAY_URL | String | See heading 1. Introduction |
FAIRPLAY_CERTIFICATE_URL | String | See heading 1. Introduction |
3.4 License request handler
Configuration information:
Props | Type | Description |
---|---|---|
MERCHANT_ID | String | Id of merchant's user |
APP_ID | String | Id of application |
USER_ID | String | UserId of merchant's client |
SESSION_ID | String | SessionId 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);