{"id":13510291,"url":"https://github.com/videojs/videojs-contrib-eme","last_synced_at":"2025-06-29T18:04:31.963Z","repository":{"id":10340202,"uuid":"65419087","full_name":"videojs/videojs-contrib-eme","owner":"videojs","description":"Supports Encrypted Media Extensions for playback of encrypted content in Video.js","archived":false,"fork":false,"pushed_at":"2024-08-27T15:47:23.000Z","size":2851,"stargazers_count":215,"open_issues_count":73,"forks_count":72,"subscribers_count":24,"default_branch":"main","last_synced_at":"2025-06-08T07:44:09.492Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/videojs.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-08-10T21:56:15.000Z","updated_at":"2025-05-21T13:43:54.000Z","dependencies_parsed_at":"2023-01-13T15:53:04.891Z","dependency_job_id":"dd16ac9e-64ae-405f-8be6-3c071ae741b9","html_url":"https://github.com/videojs/videojs-contrib-eme","commit_stats":null,"previous_names":[],"tags_count":43,"template":false,"template_full_name":null,"purl":"pkg:github/videojs/videojs-contrib-eme","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/videojs%2Fvideojs-contrib-eme","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/videojs%2Fvideojs-contrib-eme/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/videojs%2Fvideojs-contrib-eme/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/videojs%2Fvideojs-contrib-eme/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/videojs","download_url":"https://codeload.github.com/videojs/videojs-contrib-eme/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/videojs%2Fvideojs-contrib-eme/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":262642958,"owners_count":23341817,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-01T02:01:32.262Z","updated_at":"2025-06-29T18:04:31.938Z","avatar_url":"https://github.com/videojs.png","language":"JavaScript","funding_links":[],"categories":["JavaScript","HarmonyOS","others"],"sub_categories":["Windows Manager"],"readme":"# videojs-contrib-eme\n\n\n[![Build Status](https://travis-ci.org/videojs/videojs-contrib-eme.svg?branch=master)](https://travis-ci.org/videojs/videojs-contrib-eme)\n[![Greenkeeper badge](https://badges.greenkeeper.io/videojs/videojs-contrib-eme.svg)](https://greenkeeper.io/)\n[![Slack Status](http://slack.videojs.com/badge.svg)](http://slack.videojs.com)\n\n[![NPM](https://nodei.co/npm/videojs-contrib-eme.png?downloads=true\u0026downloadRank=true)](https://nodei.co/npm/videojs-contrib-eme/)\n\nSupports Encrypted Media Extensions for playback of encrypted content in Video.js\n\nMaintenance Status: Stable\n\n\u003c!-- START doctoc generated TOC please keep comment here to allow auto update --\u003e\n\u003c!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --\u003e\n\n- [Using](#using)\n  - [Initialization](#initialization)\n  - [FairPlay](#fairplay)\n    - [Get Certificate/License by URL](#get-certificatelicense-by-url)\n    - [Get Certificate/Content ID/License by Functions](#get-certificatecontent-idlicense-by-functions)\n  - [PlayReady for IE11 (Windows 8.1+)](#playready-for-ie11-windows-81)\n    - [Get License by Default](#get-license-by-default)\n    - [Get Key by URL](#get-key-by-url)\n    - [Get Key by Function](#get-key-by-function)\n  - [Other DRM Systems](#other-drm-systems)\n    - [Get License By URL](#get-license-by-url)\n    - [Get License By Function](#get-license-by-function)\n    - [Get Certificate by function](#get-certificate-by-function)\n  - [audioContentType/videoContentType](#audiocontenttypevideocontenttype)\n  - [audioRobustness/videoRobustness](#audiorobustnessvideorobustness)\n  - [MediaKeySystemConfiguration and supportedConfigurations](#mediakeysystemconfiguration-and-supportedconfigurations)\n  - [Get License Errors](#get-license-errors)\n- [API](#api)\n  - [Available Options](#available-options)\n    - [`keySystems`](#keysystems)\n    - [`emeHeaders`](#emeheaders)\n    - [`firstWebkitneedkeyTimeout`](#firstwebkitneedkeytimeout)\n    - [`limitRenewalsMaxPauseDuration`](#limitrenewalsmaxpauseduration)\n    - [`limitRenewalsBeforePlay`](#limitrenewalsbeforeplay)\n  - [Setting Options per Source](#setting-options-per-source)\n  - [Setting Options for All Sources](#setting-options-for-all-sources)\n  - [Header Hierarchy and Removal](#header-hierarchy-and-removal)\n  - [`emeOptions`](#emeoptions)\n  - [`initializeMediaKeys()`](#initializemediakeys)\n  - [`detectSupportedCDMs()`](#detectsupportedcdms)\n  - [`initLegacyFairplay()`](#initlegacyfairplay)\n  - [Events](#events)\n    - [`licenserequestattempted`](#licenserequestattempted)\n    - [`keystatuschange`](#keystatuschange)\n  - [`keysessioncreated`](#keysessioncreated)\n- [License](#license)\n\n\u003c!-- END doctoc generated TOC please keep comment here to allow auto update --\u003e\n\n## Using\n\nBy default, videojs-contrib-eme is not able to decrypt any audio/video.\n\nIn 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.\n\nIf you're new to DRM on the web, read [about how EME is used to play protected content on the web](https://developers.google.com/web/fundamentals/media/eme).\n\n### Initialization\n\nThe videojs-contrib-eme plugin must be initialized before a source is loaded into the player:\n\n```js\nplayer.eme();\nplayer.src({\n  src: '\u003cyour url here\u003e',\n  type: 'application/dash+xml',\n  keySystems: {\n    'com.widevine.alpha': '\u003cYOUR URL HERE\u003e'\n  }\n});\n```\n\n### FairPlay\n\nFor FairPlay, only `keySystems` is used from the options passed into videojs-contrib-eme or provided as part of the source object.\n\nThere are two ways to configure FairPlay.\n\n#### Get Certificate/License by URL\n\nIn this simpler implementation, you can provide URLs and allow videojs-contrib-eme to make the requests internally via default mechanisms.\n\nWhen using this method, there are two required properties of the `keySystems` object:\n\n* `certificateUri`\n* `licenseUri`\n\nAnd there are two _optional_ properties:\n\n* `certificateHeaders`\n* `licenseHeaders`\n\nWith this configuration, videojs-contrib-eme will behave in the following ways:\n\n* 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.\n* The content ID will be interpreted from the `initData`.\n* 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`.\n\n\nBelow are examples of FairPlay configurations of this type:\n\n```js\n{\n  keySystems: {\n    'com.apple.fps.1_0': {\n      certificateUri: '\u003cCERTIFICATE_URL\u003e',\n      licenseUri: '\u003cLICENSE_URL\u003e'\n    }\n  }\n}\n```\n\nor\n\n```javascript\n{\n  keySystems: {\n    'com.apple.fps.1_0': {\n      certificateUri: '\u003cCERTIFICATE_URL\u003e',\n      certificateHeaders: {\n        'Some-Header': 'value'\n      },\n      licenseUri: '\u003cLICENSE_URL\u003e',\n      licenseHeaders: {\n        'Some-Header': 'value'\n      }\n    }\n  }\n}\n```\n\n#### Get Certificate/Content ID/License by Functions\n\nYou can control the license and certificate request processes by providing the following methods instead of the properties discussed above:\n\n* `getCertificate()` - Allows asynchronous retrieval of a certificate.\n* `getContentId()` - Allows synchronous retrieval of a content ID. It takes `emeOptions`, as well as the `initData` converted into a String.\n* `getLicense()` - Allows asynchronous retrieval of a license.\n\n```js\n{\n  keySystems: {\n    'com.apple.fps.1_0': {\n      getCertificate: function(emeOptions, callback) {\n        // request certificate\n        // if err, callback(err)\n        // if success, callback(null, certificate)\n      },\n      getContentId: function(emeOptions, contentId) {\n        // return content ID\n      },\n      getLicense: function(emeOptions, contentId, keyMessage, callback) {\n        // request key\n        // if err, callback(err)\n        // if success, callback(null, key) as arraybuffer\n      }\n    }\n  }\n}\n```\n\n### PlayReady for IE11 (Windows 8.1+)\n\nPlayReady for IE11 (Windows 8.1+) only requires `keySystems` from the options passed into videojs-contrib-eme or provided as part of the source object.\n\nThere are three ways to configure PlayReady for IE11 (Windows 8.1+).\n\n#### Get License by Default\n\nIf 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.\n\n```js\nkeySystems: {\n  'com.microsoft.playready': true\n}\n```\n\n#### Get Key by URL\n\nIf 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:\n\n```js\nkeySystems: {\n  'com.microsoft.playready': '\u003cYOUR_KEY_URL\u003e'\n}\n```\n\nor\n\n```js\n  keySystems: {\n    'com.microsoft.playready': {\n      url: '\u003cYOUR_KEY_URL\u003e',\n      licenseHeaders: {\n        'Some-Header': 'value'\n      }\n    }\n  }\n```\n\n#### Get Key by Function\n\nIf 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:\n\n```js\n{\n  keySystems: {\n    'com.microsoft.playready': {\n      getKey: function(emeOptions, destinationURI, buffer, callback) {\n        // request key\n        // if err, callback(err)\n        // if success, callback(null, key), where key is a Uint8Array\n      }\n    }\n  }\n}\n```\n\n### Other DRM Systems\n\nFor DRM systems that use the W3C EME specification as of 5 July 2016, only `keySystems` and a way of obtaining the license are required.\n\nObtaining a license can be done in two ways.\n\n#### Get License By URL\n\nFor simple use-cases, you may use a string as the license URL or a URL as a property of in the `keySystems` entry:\n\n```js\n{\n  keySystems: {\n    'org.w3.clearkey': '\u003cYOUR_LICENSE_URL\u003e',\n    'com.widevine.alpha': {\n      url: '\u003cYOUR_LICENSE_URL\u003e'\n    }\n  }\n}\n```\n\n#### Get License By Function\n\nFor more complex integrations, you may pass a `getLicense` function to fully control the license retrieval process:\n\n```js\n{\n  keySystems: {\n    'org.w3.clearkey': {\n      getLicense: function(emeOptions, keyMessage, callback) {\n        // request license\n        // if err, callback(err)\n        // if success, callback(null, license)\n      }\n    }\n  }\n}\n```\n\n\n#### Get Certificate by function\nAlthough the license acquisition is the only required configuration, `getCertificate()` is also supported if your source needs to retrieve a certificate, similar to the [FairPlay](#fairplay) implementation above.\n\nExample:\n```js\n{\n  'org.w3.clearkey': {\n    getCertificate: function(emeOptions, callback) {\n      // request certificate\n      // if err, callback(err)\n      // if success, callback(null, certificate)\n    },\n  }\n}\n```\n\n\n### audioContentType/videoContentType\n\nThe `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.\n\nexample:\n```js\n{\n  keySystems: {\n    'org.w3.clearkey': {\n      audioContentType: 'audio/webm; codecs=\"vorbis\"',\n      videoContentType: 'video/webm; codecs=\"vp9\"',\n    }\n  }\n}\n```\n\n### audioRobustness/videoRobustness\n\u003e 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`\n\nThe `audioRobustness` and `videoRobustness` properties for non-FairPlay sources are used to determine the robustness level of the DRM you are using.\n\nExample:\n\n```js\n{\n  keySystems: {\n    'com.widevine.alpha': {\n      audioRobustness: 'SW_SECURE_CRYPTO',\n      videoRobustness: 'SW_SECURE_CRYPTO'\n    }\n  }\n}\n```\n\n### MediaKeySystemConfiguration and supportedConfigurations\n\nIn 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.\n\nNote that if `supportedConfigurations` is provided, it will override `audioContentType`, `videoContentType`, `audioRobustness`, `videoRobustness`, and `persistentState`.\n\nExample:\n\n```js\n{\n  keySystems: {\n    'org.w3.clearkey': {\n      supportedConfigurations: [{\n        videoCapabilities: [{\n          contentType: 'video/webm; codecs=\"vp9\"',\n          robustness: 'SW_SECURE_CRYPTO'\n        }],\n        audioCapabilities: [{\n          contentType: 'audio/webm; codecs=\"vorbis\"',\n          robustness: 'SW_SECURE_CRYPTO'\n        }]\n      }],\n      'org.w3.clearkey': '\u003cYOUR_LICENSE_URL\u003e'\n    }\n  }\n}\n```\n\n### Get License Errors\n\nThe 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.\n\n## API\n\n### Available Options\n\n#### `keySystems`\n\nThis 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.\n\n#### `emeHeaders`\n\nThis 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`).\n\nAn `emeHeaders` object should look like this:\n\n```js\nemeHeaders: {\n  'Common-Header': 'value'\n}\n```\n\n#### `firstWebkitneedkeyTimeout`\n\u003e Default: 1000\n\nThe 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.\n\n#### `limitRenewalsMaxPauseDuration`\n\nThe duration, in seconds, to wait in paused state before license-renewals are rejected and session is closed. This option limits excess license requests when using limited-duration licenses.\n\n#### `limitRenewalsBeforePlay`\n\u003e Boolean\n\nIf set to true, license renewal is rejected if license expires before play when player is idle. This option limits excess license requests when using limited-duration licenses.\n\n### Setting Options per Source\n\nThis 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.\n\nTo do this, attach the options to the source object you pass to `player.src()`:\n\n```js\nplayer.src({\n\n  // normal Video.js src and type options\n  src: '\u003cURL\u003e',\n  type: 'video/webm',\n\n  // eme options\n  emeHeaders: {\n    'Common-Header': 'value'\n  },\n  keySystems: {\n    'org.w3.clearkey': {\n      initDataTypes: ['cenc', 'webm'],\n      audioContentType: 'audio/webm; codecs=\"vorbis\"',\n      videoContentType: 'video/webm; codecs=\"vp9\"',\n      getCertificate: function(emeOptions, callback) {\n        // request certificate\n        // if err, callback(err)\n        // if success, callback(null, certificate)\n      },\n      getLicense: function(emeOptions, keyMessage, callback) {\n        // request license\n        // if err, callback(err)\n        // if success, callback(null, license)\n      }\n    }\n  }\n});\n```\n\n### Setting Options for All Sources\n\nWhile [setting options per source](#setting-options-per-source) is recommended, some implementations may want to use plugin-level options.\n\nThese can be set during plugin invocation:\n\n```js\nplayer.eme({\n\n  // Set Common-Header on ALL requests for ALL key systems.\n  emeHeaders: {\n    'Common-Header': 'value'\n  }\n});\n```\n\nPlugin-level options may also be set after plugin initialization by assigning to the options property on the `eme` object itself:\n\n```js\nplayer.eme();\n\nplayer.eme.options.emeHeaders = {\n  'Common-Header': 'value'\n};\n```\n\nor\n\n```js\nplayer.eme();\n\nplayer.eme.options = {\n  emeHeaders: {\n    'Common-Header': 'value'\n  }\n};\n```\n\n### Header Hierarchy and Removal\n\nHeaders 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`.\n\nThe hierarchy of header definitions is:\n\n```\nlicenseHeaders/certificateHeaders \u003e emeHeaders \u003e internal defaults\n```\n\nIn 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.\n\nHere's an example:\n\n```js\nplayer.eme({\n  emeHeaders: {\n\n    // Remove the internal default Content-Type\n    'Content-Type': null,\n    'Custom-Foo': '\u003cCUSTOM_FOO_VALUE\u003e'\n  }\n});\n\nplayer.src({\n  src: '\u003cURL\u003e',\n  type: '\u003cMIME_TYPE\u003e',\n  keySystems: {\n    'com.apple.fps.1_0': {\n      certificateUri: '\u003cCERTIFICATE_URL\u003e',\n      certificateHeaders: {\n        'Custom-Foo': '\u003cANOTHER_CUSTOM_FOO_VALUE\u003e'\n      },\n      licenseUri: '\u003cLICENSE_URL\u003e',\n      licenseHeaders: {\n        'License-Bar': '\u003cLICENSE_BAR_VALUE\u003e'\n      }\n    }\n  }\n})\n```\n\nThis will result in the following headers for the certificate request:\n\n```\nCustom-Foo: \u003cANOTHER_CUSTOM_FOO_VALUE\u003e\n```\n\nAnd for the license request:\n\n```\nCustom-Foo: \u003cCUSTOM_FOO_VALUE\u003e\nLicense-Bar: \u003cLICENSE_BAR_VALUE\u003e\n```\n\n### `emeOptions`\n\nAll methods in a key system receive `emeOptions` as their first argument.\n\nThe `emeOptions` are an object which merges source-level options with plugin-level options.\n\n\u003e **NOTE:** In these cases, plugin-level options will **override** the source-level options. This is used by libraries like [VHS](https://github.com/videojs/http-streaming), but could be unintuitive. This is another reason to prefer source-level options in all cases!\n\nIt 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.\n\nFor example, if you needed to use a `userId` for the `getCertificate()` request, you could:\n\n```js\nplayer.eme();\n\nplayer.src({\n  keySystems: {\n    'org.w3.clearkey': {\n      getCertificate: function(emeOptions, callback) {\n        var userId = emeOptions.userId; // 'user-id'\n        // ...\n      },\n      getLicense: function(emeOptions, keyMessage, callback) {\n        var userId = emeOptions.userId; // 'user-id'\n        // ...\n      }\n    }\n  },\n  userId: 'user-id'\n});\n```\n\n### `initializeMediaKeys()`\n\n`player.eme.initializeMediaKeys()` sets up MediaKeys immediately on demand.\n\nThis 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.\n\n```js\n// additional plugin options\nvar emeOptions = {\n  keySystems: {\n    'org.w3.clearkey': {...}\n  }\n};\n\nvar emeCallback = function(error) {\n  if (error) {\n    // do something with error\n  }\n\n  // do something else\n};\n\nvar suppressErrorsIfPossible = true;\n\nplayer.eme.initializeMediaKeys(emeOptions, emeCallback, suppressErrorsIfPossible);\n```\n\nWhen `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.\n\n### `detectSupportedCDMs()`\n\n`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.\n\nPlease 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()](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/requestMediaKeySystemAccess) documentation for more information.\n\n```js\nplayer.eme.detectSupportedCDMs()\n  .then(supportedCDMs =\u003e {\n    // Sample output: {fairplay: false, playready: false, widevine: true, clearkey: true}\n    console.log(supportedCDMs);\n  });\n```\n\n### `initLegacyFairplay()`\n\n`player.eme.initLegacyFairplay()` is used to init the `'webkitneedskey'` listener when using `WebKitMediaKeys` in Safari. This is useful because Safari currently supports both the modern `com.apple.fps` keysystem through `MediaKeys` and the legacy `com.apple.fps.1_0` keysystem through `WebKitMediaKeys`. Since this plugin will prefer using modern `MediaKeys` over `WebkitMediaKeys` initializing legacy fairplay can be necessary for media using the legacy `1_0` keysystem.\n\n```js\nplayer.eme.initLegacyFairplay();\n```\n_________________________________________________________\n\n### Events\n\nThere are some events that are specific to this plugin.\n\n#### `licenserequestattempted`\n\nThis event is triggered on the Video.js playback tech on the callback of every license request made by videojs-contrib-eme.\n\n```\nplayer.tech(true).on('licenserequestattempted', function(event) {\n  // Act on event\n});\n```\n\n#### `keystatuschange`\n\nWhen the status of a key changes, an event of type `keystatuschange` will\nbe 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.\n\n```\nplayer.tech(true).on('keystatuschange', function(event) {\n  // Event data:\n  // keyId\n  // status: usable, output-restricted, etc\n  // target: the MediaKeySession object that caused this event\n});\n```\n\nThis event is triggered directly from the underlying `keystatuseschange` event, so the statuses should correspond to [those listed in the spec](https://www.w3.org/TR/encrypted-media/#dom-mediakeystatus).\n\n### `keysessioncreated`\n\nWhen the key session is created, an event of type `keysessioncreated` will be triggered on the Video.js playback tech.\n\n```\nplayer.tech().on('keysessioncreated', function(keySession) {\n  // Event data:\n  // keySession: the mediaKeySession object\n  // https://www.w3.org/TR/encrypted-media/#mediakeysession-interface\n});\n```\n\n## License\n\nApache License, Version 2.0. [View the license file](LICENSE)\n\n[MediaKeySystemConfiguration]: https://www.w3.org/TR/encrypted-media/#dom-mediakeysystemconfiguration\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvideojs%2Fvideojs-contrib-eme","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvideojs%2Fvideojs-contrib-eme","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvideojs%2Fvideojs-contrib-eme/lists"}