• Stars
    star
    192
  • Rank 194,689 (Top 4 %)
  • Language
    JavaScript
  • License
    Other
  • Created over 7 years ago
  • Updated about 1 month ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Supports Encrypted Media Extensions for playback of encrypted content in Video.js

videojs-contrib-eme

Build Status Greenkeeper badge Slack Status

NPM

Supports Encrypted Media Extensions for playback of encrypted content in Video.js

Maintenance Status: Stable

Using

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.

If you're new to DRM on the web, read about how EME is used to play protected content on the web.

Initialization

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

FairPlay

For FairPlay, only keySystems is used from the options passed into videojs-contrib-eme or provided as part of the source object.

There are two ways to configure FairPlay.

Get Certificate/License by URL

In this simpler implementation, you can provide URLs and allow videojs-contrib-eme to make the requests internally via default mechanisms.

When using this method, there are two required properties of the keySystems object:

  • certificateUri
  • licenseUri

And there are two optional properties:

  • certificateHeaders
  • licenseHeaders

With this configuration, videojs-contrib-eme will behave in the following ways:

  • It will fetch the certificate by making a GET request to your certificateUri with an expected response type of arraybuffer. Headers can be defined for this request via the certificateHeaders object.
  • The content ID will be interpreted from the initData.
  • It will fetch the license by making a POST request to your licenseUri with an expected response type of arraybuffer. This will have one default header of Content-type: application/octet-stream, but this can be overridden (or other headers added) using licenseHeaders.

Below are examples of FairPlay configurations of this type:

{
  keySystems: {
    'com.apple.fps.1_0': {
      certificateUri: '<CERTIFICATE_URL>',
      licenseUri: '<LICENSE_URL>'
    }
  }
}

or

{
  keySystems: {
    'com.apple.fps.1_0': {
      certificateUri: '<CERTIFICATE_URL>',
      certificateHeaders: {
        'Some-Header': 'value'
      },
      licenseUri: '<LICENSE_URL>',
      licenseHeaders: {
        'Some-Header': 'value'
      }
    }
  }
}

Get Certificate/Content ID/License by Functions

You can control the license and certificate request processes by providing the following methods instead of the properties discussed above:

  • getCertificate() - Allows asynchronous retrieval of a certificate.
  • getContentId() - Allows synchronous retrieval of a content ID. It takes emeOptions, as well as the initData converted into a String.
  • getLicense() - Allows asynchronous retrieval of a license.
{
  keySystems: {
    'com.apple.fps.1_0': {
      getCertificate: function(emeOptions, callback) {
        // request certificate
        // if err, callback(err)
        // if success, callback(null, certificate)
      },
      getContentId: function(emeOptions, contentId) {
        // return content ID
      },
      getLicense: function(emeOptions, contentId, keyMessage, callback) {
        // request key
        // if err, callback(err)
        // if success, callback(null, key) as arraybuffer
      }
    }
  }
}

PlayReady for IE11 (Windows 8.1+)

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 three ways to configure PlayReady for IE11 (Windows 8.1+).

Get License by Default

If the value of true is provided, then a POST request will be made to the destinationURI passed by the message from the browser, with the headers and body specified in the message.

keySystems: {
  'com.microsoft.playready': true
}

Get Key by URL

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. Additionally, a licenseHeaders object may be provided, if additional headers are required:

keySystems: {
  'com.microsoft.playready': '<YOUR_KEY_URL>'
}

or

  keySystems: {
    'com.microsoft.playready': {
      url: '<YOUR_KEY_URL>',
      licenseHeaders: {
        'Some-Header': 'value'
      }
    }
  }

Get Key by Function

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:

{
  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
      }
    }
  }
}

Other DRM Systems

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.

Obtaining a license can be done in two ways.

Get License By URL

For simple use-cases, you may use a string as the license URL or a URL as a property of in the keySystems entry:

{
  keySystems: {
    'org.w3.clearkey': '<YOUR_LICENSE_URL>',
    'com.widevine.alpha': {
      url: '<YOUR_LICENSE_URL>'
    }
  }
}

Get License By Function

For more complex integrations, you may pass a getLicense function to fully control the license retrieval process:

{
  keySystems: {
    'org.w3.clearkey': {
      getLicense: function(emeOptions, keyMessage, callback) {
        // request license
        // if err, callback(err)
        // if success, callback(null, license)
      }
    }
  }
}

Get Certificate by function

Although the license acquisition is the only required configuration, getCertificate() is also supported if your source needs to retrieve a certificate, similar to the FairPlay implementation above.

Example:

{
  'org.w3.clearkey': {
    getCertificate: function(emeOptions, callback) {
      // request certificate
      // if err, callback(err)
      // if success, callback(null, certificate)
    },
  }
}

audioContentType/videoContentType

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.

example:

{
  keySystems: {
    'org.w3.clearkey': {
      audioContentType: 'audio/webm; codecs="vorbis"',
      videoContentType: 'video/webm; codecs="vp9"',
    }
  }
}

audioRobustness/videoRobustness

If audioRobustness/videoRobustness is not passed in for widevine, you will see a warning similar to: It is recommended that a robustness level be specified. Not specifying the robustness level could result in unexpected behavior. Possible Options for widevine: SW_SECURE_CRYPTO, SW_SECURE_DECODE, HW_SECURE_CRYPTO, HW_SECURE_DECODE, HW_SECURE_ALL

The audioRobustness and videoRobustness properties for non-FairPlay sources are used to determine the robustness level of the DRM you are using.

Example:

{
  keySystems: {
    'com.widevine.alpha': {
      audioRobustness: 'SW_SECURE_CRYPTO',
      videoRobustness: 'SW_SECURE_CRYPTO'
    }
  }
}

MediaKeySystemConfiguration and supportedConfigurations

In addition to key systems options provided above, it is possible to directly provide the supportedConfigurations array to use for the requestMediaKeySystemAccess call. This allows for the entire range of options specified by the MediaKeySystemConfiguration object.

Note that if supportedConfigurations is provided, it will override audioContentType, videoContentType, audioRobustness, videoRobustness, and persistentState.

Example:

{
  keySystems: {
    'org.w3.clearkey': {
      supportedConfigurations: [{
        videoCapabilities: [{
          contentType: 'video/webm; codecs="vp9"',
          robustness: 'SW_SECURE_CRYPTO'
        }],
        audioCapabilities: [{
          contentType: 'audio/webm; codecs="vorbis"',
          robustness: 'SW_SECURE_CRYPTO'
        }]
      }],
      'org.w3.clearkey': '<YOUR_LICENSE_URL>'
    }
  }
}

Get License Errors

The default getLicense() functions pass an error to the callback if the license request returns a 4xx or 5xx response code. Depending on how the license server is configured, it is possible in some cases that a valid license could still be returned even if the response code is in that range. If you wish not to pass an error for 4xx and 5xx response codes, you may pass your own getLicense() function with the keySystems as described above.

API

Available Options

keySystems

This is the main option through which videojs-contrib-eme can be configured. It maps key systems by name (e.g. 'org.w3.clearkey') to an object for configuring that key system.

emeHeaders

This object can be a convenient way to specify default headers for all requests that are made by videojs-contrib-eme. These headers will override any headers that are set by videojs-contrib-eme internally, but can be further overridden by headers specified in keySystems objects (e.g., certificateHeaders or licenseHeaders).

An emeHeaders object should look like this:

emeHeaders: {
  'Common-Header': 'value'
}

firstWebkitneedkeyTimeout

Default: 1000

The amount of time in milliseconds to wait on the first webkitneedkey event before making the key request. This was implemented due to a bug in Safari where rendition switches at the start of playback can cause webkitneedkey to fire multiple times, with only the last one being valid.

Setting Options per Source

This is the recommended way of setting most options. Each source may have a different set of requirements; so, it is best to define options on a per source basis.

To do this, attach the options to the source object you pass to player.src():

player.src({

  // normal Video.js src and type options
  src: '<URL>',
  type: 'video/webm',

  // eme options
  emeHeaders: {
    'Common-Header': 'value'
  },
  keySystems: {
    'org.w3.clearkey': {
      initDataTypes: ['cenc', 'webm'],
      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)
      }
    }
  }
});

Setting Options for All Sources

While setting options per source is recommended, some implementations may want to use plugin-level options.

These can be set during plugin invocation:

player.eme({

  // Set Common-Header on ALL requests for ALL key systems.
  emeHeaders: {
    'Common-Header': 'value'
  }
});

Plugin-level options may also be set after plugin initialization by assigning to the options property on the eme object itself:

player.eme();

player.eme.options.emeHeaders = {
  'Common-Header': 'value'
};

or

player.eme();

player.eme.options = {
  emeHeaders: {
    'Common-Header': 'value'
  }
};

Header Hierarchy and Removal

Headers defined in the emeHeaders option or in licenseHeaders/certificateHeaders objects within keySystems can remove headers defined at lower levels without defining a new value. This can be done by setting their value to null.

The hierarchy of header definitions is:

licenseHeaders/certificateHeaders > emeHeaders > internal defaults

In most cases, the header {'Content-type': 'application/octet-stream'} is a default and cannot be overridden without writing your own getLicense() function. This internal default can be overridden by either of the user-provided options.

Here's an example:

player.eme({
  emeHeaders: {

    // Remove the internal default Content-Type
    'Content-Type': null,
    'Custom-Foo': '<CUSTOM_FOO_VALUE>'
  }
});

player.src({
  src: '<URL>',
  type: '<MIME_TYPE>',
  keySystems: {
    'com.apple.fps.1_0': {
      certificateUri: '<CERTIFICATE_URL>',
      certificateHeaders: {
        'Custom-Foo': '<ANOTHER_CUSTOM_FOO_VALUE>'
      },
      licenseUri: '<LICENSE_URL>',
      licenseHeaders: {
        'License-Bar': '<LICENSE_BAR_VALUE>'
      }
    }
  }
})

This will result in the following headers for the certificate request:

Custom-Foo: <ANOTHER_CUSTOM_FOO_VALUE>

And for the license request:

Custom-Foo: <CUSTOM_FOO_VALUE>
License-Bar: <LICENSE_BAR_VALUE>

emeOptions

All methods in a key system receive emeOptions as their first argument.

The emeOptions are an object which merges source-level options with plugin-level options.

NOTE: In these cases, plugin-level options will override the source-level options. This is used by libraries like VHS, but could be unintuitive. This is another reason to prefer source-level options in all cases!

It is available to make it easier to access options in custom key systems methods, so that you don't have to maintain your own references.

For example, if you needed to use a userId for the getCertificate() request, you could:

player.eme();

player.src({
  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'
});

initializeMediaKeys()

player.eme.initializeMediaKeys() sets up MediaKeys immediately on demand.

This is useful for setting up the video element for DRM before loading any content. Otherwise, the video element is set up for DRM on encrypted events. This is not supported in Safari.

// additional plugin options
var emeOptions = {
  keySystems: {
    'org.w3.clearkey': {...}
  }
};

var emeCallback = function(error) {
  if (error) {
    // do something with error
  }

  // do something else
};

var suppressErrorsIfPossible = true;

player.eme.initializeMediaKeys(emeOptions, emeCallback, suppressErrorsIfPossible);

When suppressErrorsIfPossible is set to false (the default) and an error occurs, the error handler will be invoked after the callback finishes and error() will be called on the player. When set to true and an error occurs, the error handler will not be invoked with the exception of mskeyerror errors in IE11 since they cannot be suppressed asynchronously.

detectSupportedCDMs()

player.eme.detectSupportedCDMs() is used to asynchronously detect and return a list of supported Content Decryption Modules (CDMs) in the current browser. It uses the EME API to request access to each key system and determine its availability. This function checks for the support of the following key systems: FairPlay, PlayReady, Widevine, and ClearKey.

Please use this function sparingly, as side-effects (namely calling navigator.requestMediaKeySystemAccess()) can have user-visible effects, such as prompting for system resource permissions, which could be disruptive if invoked at inappropriate times. See requestMediaKeySystemAccess() documentation for more information.

player.eme.detectSupportedCDMs()
  .then(supportedCDMs => {
    // Sample output: {fairplay: false, playready: false, widevine: true, clearkey: true}
    console.log(supportedCDMs);
  });

Events

There are some events that are specific to this plugin.

licenserequestattempted

This event is triggered on the Video.js playback tech on the callback of every license request made by videojs-contrib-eme.

player.tech(true).on('licenserequestattempted', function(event) {
  // Act on event
});

keystatuschange

When the status of a key changes, an event of type keystatuschange will be triggered on the Video.js playback tech. This helps you handle feedback to the user for situations like trying to play DRM-protected media on restricted devices.

player.tech(true).on('keystatuschange', function(event) {
  // Event data:
  // keyId
  // status: usable, output-restricted, etc
  // target: the MediaKeySession object that caused this event
});

This event is triggered directly from the underlying keystatuseschange event, so the statuses should correspond to those listed in the spec.

keysessioncreated

When the key session is created, an event of type keysessioncreated will be triggered on the Video.js playback tech.

player.tech().on('keysessioncreated', function(event) {
  // note that there is no event data for keysessioncreated
});

License

Apache License, Version 2.0. View the license file

More Repositories

1

video.js

Video.js - open source HTML5 video player
JavaScript
37,092
star
2

videojs-contrib-hls

HLS library for video.js
JavaScript
2,835
star
3

http-streaming

HLS, DASH, and future HTTP streaming protocols library for video.js
JavaScript
2,410
star
4

videojs-youtube

YouTube playback technology for Video.js
JavaScript
1,097
star
5

mux.js

Lightweight utilities for inspecting and manipulating video container formats.
JavaScript
1,057
star
6

videojs-vr

A plugin to add 360 and VR video support to video.js.
JavaScript
522
star
7

m3u8-parser

An m3u8 parser.
JavaScript
444
star
8

videojs-contrib-ads

A Tool for Building Video.js Ad Plugins
JavaScript
376
star
9

videojs-playlist

Playlist plugin for videojs
JavaScript
352
star
10

video-js-swf

Custom Flash Player for VideoJS
JavaScript
338
star
11

videojs-contrib-dash

Video.js plugin for supporting the MPEG-DASH playback through a video.js player
JavaScript
293
star
12

videojs-overlay

A video.js plugin to display simple overlays during playback.
JavaScript
239
star
13

videojs-flash

The Flash tech for video.js
JavaScript
214
star
14

videojs-vimeo

Support Vimeo source for Video.js
JavaScript
195
star
15

hls-fetcher

JavaScript
163
star
16

videojs-contrib-quality-levels

JavaScript
155
star
17

videojs-contrib-media-sources

Code for working with the media source extensions API and video.js
JavaScript
145
star
18

themes

Videojs themes πŸ’…
CSS
130
star
19

videojs-playlist-ui

A playlist video picker for video.js
JavaScript
127
star
20

thumbcoil

Tools for inspecting MPEG2TS, fMP4, and FLV files and the codec bitstreams therein
JavaScript
121
star
21

videojs-errors

A video.js plugin that displays error messages to video viewers.
JavaScript
85
star
22

generator-videojs-plugin

Yeoman generator for video.js plugins.
JavaScript
81
star
23

mpd-parser

JavaScript
77
star
24

vtt.js

A JavaScript implementation of the WebVTT specification, forked from vtt.js for use with Video.js
JavaScript
68
star
25

font

Icon font used for Video.js
CSS
59
star
26

videojs.com

The Video.js Website
MDX
57
star
27

designer

A video.js player skin editor using a live CSS editor
JavaScript
42
star
28

aes-decrypter

JavaScript
32
star
29

videojs-playbackrate-adjuster

A Video.js middleware that adjusts controls based on playback rate
JavaScript
28
star
30

videojs-contextmenu-ui

A cross-device context menu UI for video.js players.
JavaScript
28
star
31

cdn

The video.js CDN
JavaScript
24
star
32

ie8

Video.js files for IE8 compatibility
JavaScript
23
star
33

video.js-component

Video.js - HTML5 Video Player - Component
JavaScript
15
star
34

docs

videojs docs
JavaScript
14
star
35

plugin-concat

Concatenate videos for playback by videojs/http-streaming in a Video.js player
JavaScript
10
star
36

videojs-adaptive

Building support for adaptive streaming video formats into video.js
JavaScript
10
star
37

doc-generator

Auto-generate API docs for the video.js codebase and plugins
JavaScript
8
star
38

videojs-settings-menu

A place to incubate a new settings menu for videojs.
JavaScript
8
star
39

videojs-media-session

Media Session API plugin
JavaScript
8
star
40

videojs-4to5

Tools to ease the transition from video.js 4.x to 5.x.
JavaScript
7
star
41

thumb.co.il

The fancy front-end for Thumbcoil!
JavaScript
7
star
42

standard

JavaScript Standard Style β€” One Style to Rule Them All
JavaScript
6
star
43

vhs-utils

Objects and functions shared throughout @videojs/http-streaming code
JavaScript
6
star
44

remark-preset-lint-videojs

A remark linting preset for Video.js
JavaScript
5
star
45

videojs-placeholder

A placeholder for videojs packages
5
star
46

web-media-box

TypeScript
5
star
47

blog

The video.js blog
Stylus
4
star
48

videojs-languages

JavaScript
4
star
49

grunt-videojs-languages

A grunt task to convert video.js language JSON files in to includable scripts.
JavaScript
4
star
50

videojs-generate-rollup-config

Generate a standard rollup config, so that plugins don't need the same script in every repository.
JavaScript
3
star
51

eslint-config-videojs

JavaScript
3
star
52

webwackify

launch a web worker that can require() in the browser with browserify and webpack
JavaScript
3
star
53

autoplay-tests

Autoplay test examples
HTML
2
star
54

tooling

A monorepo for all videojs project and plugin tooling
JavaScript
2
star
55

spellbook

JavaScript
2
star
56

ffrwd

ffrwd is an extensible HTML5 streaming media player capable of playing HLS, MPEG-DASH and more!
1
star
57

generator-helpers

A package to keep all of our generator helpers packages, so everything can be updated more easily.
1
star
58

.github

1
star
59

xhr

A small xhr wrapper
JavaScript
1
star
60

babel-config

A standard babel config, so that plugins don't need the same script in every repository.
JavaScript
1
star
61

rfcs

RFCs for changes to Video.js
1
star
62

videojs-bundler-sample

sample and test project for using Video.js with various bundler configurations
JavaScript
1
star
63

videojs-contrib-quality-menu

Adds a quality selector button to the Video.js control bar for Video.js 8+
JavaScript
1
star