Supports Encrypted Media Extensions for playback of encrypted content in Video.js
Maintenance Status: Stable
By default, videojs-contrib-eme is not able to decrypt any audio/video. In order to decrypt audio/video, a user must pass in either relevant license URIs, or methods specific to a source and its combination of key system and codec. These are provided to the plugin via either videojs-contrib-eme's plugin options, or source options.
The videojs-contrib-eme plugin must be initialized before a source is loaded into the player:
player.eme();
player.src({
src: '<your url here>',
type: 'application/dash+xml',
keySystems: {
'com.widevine.alpha': '<your url here>'
}
});
For FairPlay, only keySystems
is used from the options passed into videojs-contrib-eme,
or provided as part of the source object.
The required methods to provide are:
getCertificate
getContentId
getLicense
or, if you are using the default FairPlay methods, the only required parameters are:certificateUri
licenseUri
Below is an example of videojs-contrib-eme options when only using FairPlay:
{
keySystems: {
"com.apple.fps.1_0": {
getCertificate: function(emeOptions, callback) {
// request certificate
// if err, callback(err)
// if success, callback(null, certificate)
},
getContentId: function(emeOptions, initData) {
// return content ID
},
getLicense: function(emeOptions, contentId, keyMessage, callback) {
// request key
// if err, callback(err)
// if success, callback(null, key) as arraybuffer
}
}
}
}
Below is an example of videojs-contrib-eme options when only using FairPlay, and using the default FairPlay methods:
{
keySystems: {
"com.apple.fps.1_0": {
certificateUri: "<CERTIFICATE URI>",
licenseUri: "<LICENSE URI>"
}
}
}
The default methods are defined as follows:
- getCertificate - GET certificateUri with response type of arraybuffer
- getContentId - gets the hostname from the initData URI
- getLicense - POST licenseUri with response type of arraybuffer, header of 'Content-type': 'application/octet-stream', and body of webKitKeyMessage
PlayReady for IE11 (Windows 8.1+) only requires keySystems
from the options passed
into videojs-contrib-eme, or provided as part of the source object.
There are four choices for options that may be passed:
- If the value of
true
is provided, then a POST request will be made to thedetinationURI
passed by the message from the browser, with the headers and body specified in the message.
Example:
keySystems: {
"com.microsoft.playready": true
}
2/3) If a url is provided, either within an object or as a string, then a POST request will be made to the provided url, with the headers and body specified in the message.
Example:
keySystems: {
"com.microsoft.playready": "<your url here>"
}
// or
keySystems: {
"com.microsoft.playready": {
"url": "<your url here>"
}
}
- If a
getKey
function is provided, then the function will be run with the message buffer and destinationURI passed by the browser, and will expect a callback with the key.
Example:
{
keySystems: {
"com.microsoft.playready": {
getKey: function(emeOptions, destinationURI, buffer, callback) {
// request key
// if err, callback(err)
// if success, callback(null, key), where key is a Uint8Array
}
}
}
}
For DRM systems that use the W3C EME specification as of 5 July 2016, only keySystems
and a way of obtaining the license are required.
To obtain a license requires one of a couple different options:
- You may use a string as the license url, or a url as an entry in the options:
{
keySystems: {
'org.w3.clearkey': '<your-license-url>',
'com.widevine.alpha': {
url: '<your-license-url>'
}
}
}
- You may pass a
getLicense
function:
{
keySystems: {
'org.w3.clearkey': {
getLicense: function(emeOptions, keyMessage, callback) {
// request license
// if err, callback(err)
// if success, callback(null, license)
}
}
}
}
Although the license acquisition related config is the only required configuration,
getCertificate
is also supported if your source needs to retrieve a certificate.
The audioContentType
and videoContentType
properties for non-FairPlay sources are
used to determine if the system supports that codec, and to create an appropriate
keySystemAccess
object. If left out, it is possible that the system will create a
keySystemAccess
object for the given key system, but will not be able to play the
source due to the browser's inability to use that codec.
Below is an example of videojs-contrib-eme options when only using one of these DRM
systems, and custom getLicense
and getCertificate
functions:
{
keySystems: {
"org.w3.clearkey": {
audioContentType: 'audio/webm; codecs="vorbis"',
videoContentType: 'video/webm; codecs="vp9"',
getCertificate: function(emeOptions, callback) {
// request certificate
// if err, callback(err)
// if success, callback(null, certificate)
},
getLicense: function(emeOptions, keyMessage, callback) {
// request license
// if err, callback(err)
// if success, callback(null, license)
}
}
}
}
Since each source may have a different set of properties and methods, it is best to use
source options instead of plugin options when specifying key systems. To do that, simply
pass the same options as you would as part of the plugin options, but instead pass them
as part of the source object when specifying player.src(sourceObject)
.
For example:
player.src({
// normal src and type options
src: '<URL>',
type: 'video/webm',
// eme options
keySystems: {
'org.w3.clearkey': {
audioContentType: 'audio/webm; codecs="vorbis"',
videoContentType: 'video/webm; codecs="vp9"',
getCertificate: function(emeOptions, callback) {
// request certificate
// if err, callback(err)
// if success, callback(null, certificate)
},
getLicense: function(emeOptions, keyMessage, callback) {
// request license
// if err, callback(err)
// if success, callback(null, license)
}
}
}
});
Plugin options may be provided in one of two ways. Either they are provided in the standard plugins configuration when setting up video.js itself, or they may be set by assigning to the options property on the eme object itself:
player.eme.options = {
// options you want to pass
};
emeOptions
are provided for all methods. This is a reference to the source options for
the current source merged with (overwritten by) the latest plugin options. It is available
to make it easier to access options so that you don't have to maintain them yourself.
For example. If you need to use a userId for the getCertificate request, you can pass in plugin options that have:
{
keySystems: {
"org.w3.clearkey": {
getCertificate: function(emeOptions, callback) {
var userId = emeOptions.userId; // 'user-id'
// ...
},
getLicense: function(emeOptions, keyMessage, callback) {
var userId = emeOptions.userId; // 'user-id'
// ...
}
}
},
userId: 'user-id'
}
Or, if you need a source-specific userId, you can overwrite it via the source options:
// plugin options
{
keySystems: {
"org.w3.clearkey": {
getCertificate: function(emeOptions, callback) {
var userId = emeOptions.userId; // 'source-specific-user-id'
// ...
},
getLicense: function(emeOptions, keyMessage, callback) {
var userId = emeOptions.userId; // 'source-specific-user-id'
// ...
}
}
},
userId: 'user-id'
}
// source options
player.src({
src: '<URL>',
type: 'video/webm',
userId: 'source-specific-user-id'
});
While simple URLs are supported for many EME implementations, we wanted to provide as much flexibility as possible. This means that if your server has a different structure, you use a different format for FairPlay content IDs, or you want to test something in the browser without making a request, we can support that, since you can control the methods.
There are some events that are specific to this plugin. Once such event is licenserequestattempted
.
This event is triggered on the tech on the callback of every license request.
In order to listen to this event:
player.tech().on('licenserequestattempted', function(event) {
// Act on event
});
Additionally, when the status of a key changes, an event of type keystatuschange
will
be triggered on the tech_
. This helps you handle feedback to the user for situations
like trying to play DRM-protected media on restricted devices.
Just like the above, you can listen to the event like so:
player.tech().on('keystatuschange', function(event) {
// Event data:
// keyId
// status: usable, output-restricted, etc
// target: the MediaKeySession object that caused this event
});
It is triggered directly from the underlying keystatuseschange
event, so the statuses
should correspond to those listed in the spec.
- Clone this repository!
- Install dependencies:
npm install
- Run a development server:
npm start
That's it! Refer to the video.js plugin standards for more detail.
- In all available and supported browsers:
npm test
- In a specific browser:
npm run test:chrome
,npm run test:firefox
, etc. - While development server is running, navigate to
http://localhost:9999/test/
(note: port may vary, check console output)
- Make sure everything is committed.
npm version *
where*
ismajor
,minor
,patch
, etc. Read more about versioning.npm publish
Apache License, Version 2.0. View the license file