components_drm-support.js
import videojs from 'video.js';
/** @import Component from 'video.js/dist/types/component' */
/** @import Player from 'video.js/dist/types/player' */
/**
* @ignore
* @type {typeof Component}
*/
const Component = videojs.getComponent('Component');
/**
* A component that provides DRM support detection.
*
* @class DrmSupport
*
* @extends {Component}
*/
class DrmSupport extends Component {
/**
* Creates an instance of DrmSupport.
*
* @param {Player} player the player instance
* @param {Object} [options={}] the component options
*/
constructor(player, options = {}) {
const opts = videojs.obj.merge(options, { createEl: false });
super(player, opts);
}
/**
* Checks DRM and HDCP capabilities.
*
* @param {Object} [options={}] configuration options
* @param {string} [options.contentType='video/mp4; codecs="avc1.42E01E"'] video content type to test
* @param {string[]} [options.initDataTypes=['cenc']] initialization data types
*
* @returns {Promise<Object>} object containing supported levels and HDCP per vendor
*
* @example
* player.drmSupport.check().then((results) => {
* console.log('DRM Support Results:', results);
* // Example output:
* // {
* // widevine: { level: 'L1', hdcp: '2.2' },
* // playReady: null,
* // fairPlay: null,
* // clearKey: { level: 'Supported', hdcp: null }
* // }
* });
*
* @example
* player.drmSupport().check({
* contentType: 'video/mp4; codecs="avc1.4d401e"',
* initDataTypes: ['cenc', 'keyids']
* }).then((results) => {
* console.log('DRM Support Results:', results)
* });
*/
async check({
contentType = 'video/mp4; codecs="avc1.42E01E"',
initDataTypes = ['cenc']
} = {}) {
const results = {};
const promises = Object.entries(DrmSupport.DRM_CONFIG).map(
async ([key, { vendor, levels }]) => {
results[key] =
await this.checkVendor(vendor, levels, initDataTypes, contentType);
}
);
await Promise.all(promises);
return results;
}
/**
* Tests robustness levels and HDCP for specific DRM vendor.
*
* @param {string} vendor key system identifier
* @param {Array<{robustness: string, label: string}>} levels array of robustness levels to test
* @param {string[]} initDataTypes initialization data types
* @param {string} contentType video content type
*
* @returns {Promise<{level: string, hdcp: string|null}|null>} supported level and HDCP or null
*/
async checkVendor(vendor, levels, initDataTypes, contentType) {
for (const { robustness, label } of levels) {
try {
const config = [{
initDataTypes,
videoCapabilities: [{ contentType, robustness }]
}];
const access =
await navigator.requestMediaKeySystemAccess(vendor, config);
const mediaKeys = await access.createMediaKeys();
const hdcp = await this.findMaxHdcp(mediaKeys);
return { level: label, hdcp };
} catch (e) {
videojs.log.debug(
'DrmSupport',
`checkVendor failed (vendor=${vendor}, level=${label}, contentType=${contentType}, robustness=${robustness})`,
e
);
}
}
return null;
}
/**
* Iterates through HDCP versions to find maximum supported version.
*
* @param {MediaKeys} mediaKeys instantiated MediaKeys object
*
* @returns {Promise<string|null>} maximum usable HDCP version or null
*/
async findMaxHdcp(mediaKeys) {
if (!mediaKeys.getStatusForPolicy) {
return null;
}
const versions = ['2.3', '2.2', '2.1', '2.0', '1.4', '1.3', '1.2', '1.1', '1.0'];
for (const version of versions) {
const status = await mediaKeys
.getStatusForPolicy({ minHdcpVersion: version })
.catch(() => null);
if (status === 'usable') {
return version;
}
}
return null;
}
/**
* Returns static DRM configuration matrix.
*
* @returns {Object} DRM configuration
*/
static get DRM_CONFIG() {
return {
widevine: {
vendor: 'com.widevine.alpha',
levels: [
{ robustness: 'HW_SECURE_ALL', label: 'L1' },
{ robustness: 'SW_SECURE_CRYPTO', label: 'L3' }
]
},
playReady: {
vendor: 'com.microsoft.playready',
levels: [
{ robustness: '3000', label: 'SL3000' },
{ robustness: '2000', label: 'SL2000' }
]
},
fairPlay: {
vendor: 'com.apple.fps',
levels: [
{ robustness: '', label: 'Supported' }
]
},
clearKey: {
vendor: 'org.w3.clearkey',
levels: [
{ robustness: '', label: 'Supported' }
]
}
};
}
}
videojs.registerComponent('DrmSupport', DrmSupport);
export default DrmSupport;