Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add modern EME support for FairPlay #3776

Merged
merged 30 commits into from Feb 7, 2022
Merged
Show file tree
Hide file tree
Changes from 28 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
2710251
feat: add support for HLS EME com.apple.fps keySystem
valotvince Nov 29, 2021
6be7725
revert
valotvince Nov 30, 2021
f20bd58
enhance hls parser and add a unit test
valotvince Dec 1, 2021
70133e6
add rule on setting media keys if polyfilled
valotvince Dec 1, 2021
4e9a3e0
update docs
valotvince Dec 2, 2021
3b43e34
detect sinf data from legacy media keys implementation
valotvince Dec 15, 2021
421b0b8
prevent playback when using TS w/ MSE or MSE w/ legacy Apple Media Keys
valotvince Dec 20, 2021
7ed4c43
fixup doc
valotvince Dec 20, 2021
c37fb46
add error test in hls parser
valotvince Dec 20, 2021
bac1ca8
fixup drm engine tests
valotvince Dec 21, 2021
06d8482
remove useless test
valotvince Dec 23, 2021
c7ea708
rename platform polyfill detect will => should
valotvince Jan 21, 2022
1f60cb0
remove eslint disable on drm engine
valotvince Jan 21, 2022
854d6eb
documentation adjustements
valotvince Jan 21, 2022
e03cae7
fixes conccurence on attachMediaKeys "gets a license and can play enc…
valotvince Jan 21, 2022
d6e8aee
fix offline session loading
valotvince Jan 21, 2022
e9be15d
fixup clearkey playback
valotvince Jan 21, 2022
1f659a7
prevent clearkey test to run on Safari (like before)
valotvince Jan 24, 2022
df1cee7
revert comment
valotvince Jan 25, 2022
1ca5399
add hint to webkit bug tracker for clearkey
valotvince Jan 25, 2022
acf47d9
change how we detect polyfill MediaKeys
valotvince Jan 25, 2022
a3b9ec7
enhance comment on useNativeHlsOnSafari
valotvince Jan 25, 2022
f6fbcf1
remove useless method in platform util
valotvince Jan 25, 2022
ed532c5
make fps work with dash
valotvince Jan 26, 2022
4bcd860
remove reference to HLS
valotvince Jan 26, 2022
971987e
fixup doc
valotvince Jan 26, 2022
7f018a8
fixup test with a new key system uid
valotvince Jan 27, 2022
159ea32
fixup documentation
valotvince Jan 27, 2022
b1d78d8
rename nonEmptyInitData to manifestInitData
valotvince Feb 7, 2022
9d313ed
remove DASH-related code
valotvince Feb 7, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 4 additions & 2 deletions README.md
Expand Up @@ -167,11 +167,13 @@ NOTES:

|Manifest |Widevine |PlayReady|FairPlay |ClearKey |
|:--------:|:--------:|:-------:|:-------:|:--------:|
|DASH |**Y** |**Y** | - |**Y** |
|DASH |**Y** |**Y** |**Y** |**Y** |
joeyparrish marked this conversation as resolved.
Show resolved Hide resolved
|HLS |**Y** |**Y** |**Y** ¹ | - |

NOTES:
- ¹: We support FairPlay through Apple's native HLS player.
- ¹: By default, FairPlay is handled using Apple's native HLS player, when on
Safari. We do support FairPlay through MSE/EME, however. See the
`streaming.useNativeHlsOnSafari` configuration value.


## Media container and subtitle support
Expand Down
5 changes: 5 additions & 0 deletions docs/tutorials/drm-config.md
Expand Up @@ -184,6 +184,11 @@ Microsoft Documentation: https://docs.microsoft.com/en-us/playready/overview/sec

NB: Audio Hardware DRM is not supported (PlayReady limitation)

##### FairPlay

Based on [Apple's Documentation](https://developer.apple.com/streaming/fps/),
you should provide an empty string as robustness

##### Other key-systems

Values for other key systems are not known to us at this time.
Expand Down
16 changes: 11 additions & 5 deletions docs/tutorials/fairplay.md
@@ -1,25 +1,31 @@
# FairPlay Support

When using native `src=` playback, we support using FairPlay on Safari.
We support FairPlay with EME on compatible environments or native `src=`.
joeyparrish marked this conversation as resolved.
Show resolved Hide resolved
Adding FairPlay support involves a bit more work than other key systems.


## Server certificate

All FairPlay content requires setting a server certificate. This is set in the
Player configuration:
All FairPlay content requires setting a server certificate. You can either
provide it directly or set a serverCertificateUri for Shaka to fetch it for
you.

```js
const req = await fetch('https://example.com/cert.der');
const cert = await req.arrayBuffer();

player.configure('drm.advanced.com\\.apple\\.fps\\.1_0.serverCertificate',
player.configure('drm.advanced.com\\.apple\\.fps\\.serverCertificate',
new Uint8Array(cert));
```

```js
player.configure('drm.advanced.com\\.apple\\.fps\\.serverCertificateUri',
'https://example.com/cert.der');
```

## Content ID

Note: This only applies when legacy Apple Media Keys is used.

Some FairPlay content use custom signaling for the content ID. The content ID
is used by the browser to generate the license request. If you don't use the
default content ID derivation, you need to specify a custom init data transform:
Expand Down
15 changes: 15 additions & 0 deletions externs/polyfill.js
@@ -0,0 +1,15 @@
/*! @license
* Shaka Player
* Copyright 2016 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/

/**
* @fileoverview Externs for Shaka polyfills
*
* @externs
*/


/** @type {boolean} */
window.shakaMediaKeysPolyfill;
5 changes: 3 additions & 2 deletions externs/shaka/player.js
Expand Up @@ -934,8 +934,9 @@ shaka.extern.ManifestConfiguration;
* @property {boolean} useNativeHlsOnSafari
* Desktop Safari has both MediaSource and their native HLS implementation.
* Depending on the application's needs, it may prefer one over the other.
* Examples: FairPlay is only supported via Safari's native HLS, but it
* doesn't have an API for selecting specific tracks.
* Warning when disabled: Where single-key DRM streams work fine, multi-keys
* streams is showing unexpected behaviours (stall, audio playing with video
* freezes, ...). Use with care.
* @property {number} inaccurateManifestTolerance
* The maximum difference, in seconds, between the times in the manifest and
* the times in the segments. Larger values allow us to compensate for more
Expand Down
72 changes: 53 additions & 19 deletions lib/hls/hls_parser.js
Expand Up @@ -40,6 +40,7 @@ goog.require('shaka.util.Networking');
goog.require('shaka.util.OperationManager');
goog.require('shaka.util.Pssh');
goog.require('shaka.util.Timer');
goog.require('shaka.util.Platform');
goog.requireType('shaka.hls.Segment');


Expand Down Expand Up @@ -1391,6 +1392,21 @@ shaka.hls.HlsParser = class {
shaka.util.Error.Code.HLS_INVALID_PLAYLIST_HIERARCHY);
}

/** @type {!Array.<!shaka.hls.Tag>} */
const variablesTags = shaka.hls.Utils.filterTagsByName(playlist.tags,
'EXT-X-DEFINE');

const mediaVariables = this.parseMediaVariables_(variablesTags);

goog.asserts.assert(playlist.segments != null,
'Media playlist should have segments!');

this.determinePresentationType_(playlist);

/** @type {string} */
const mimeType = await this.guessMimeType_(type, codecs, playlist,
mediaVariables);

/** @type {!Array.<!shaka.hls.Tag>} */
const drmTags = [];
if (playlist.segments) {
Expand Down Expand Up @@ -1425,7 +1441,7 @@ shaka.hls.HlsParser = class {
const drmParser =
shaka.hls.HlsParser.KEYFORMATS_TO_DRM_PARSERS_[keyFormat];

const drmInfo = drmParser ? drmParser(drmTag) : null;
const drmInfo = drmParser ? drmParser(drmTag, mimeType) : null;
if (drmInfo) {
if (drmInfo.keyIds) {
for (const keyId of drmInfo.keyIds) {
Expand All @@ -1446,21 +1462,6 @@ shaka.hls.HlsParser = class {
shaka.util.Error.Code.HLS_KEYFORMATS_NOT_SUPPORTED);
}

/** @type {!Array.<!shaka.hls.Tag>} */
const variablesTags = shaka.hls.Utils.filterTagsByName(playlist.tags,
'EXT-X-DEFINE');

const mediaVariables = this.parseMediaVariables_(variablesTags);

goog.asserts.assert(playlist.segments != null,
'Media playlist should have segments!');

this.determinePresentationType_(playlist);

/** @type {string} */
const mimeType = await this.guessMimeType_(type, codecs, playlist,
mediaVariables);

// MediaSource expects no codec strings combined with raw formats.
// TODO(#2337): Instead, create a Stream flag indicating a raw format.
if (shaka.hls.HlsParser.RAW_FORMATS_.includes(mimeType)) {
Expand Down Expand Up @@ -2807,6 +2808,41 @@ shaka.hls.HlsParser = class {
return op.promise;
}

/**
* @param {!shaka.hls.Tag} drmTag
* @param {string} mimeType
* @return {?shaka.extern.DrmInfo}
* @private
*/
static fairplayDrmParser_(drmTag, mimeType) {
if (mimeType == 'video/mp2t') {
throw new shaka.util.Error(
shaka.util.Error.Severity.CRITICAL,
shaka.util.Error.Category.MANIFEST,
shaka.util.Error.Code.HLS_MSE_ENCRYPTED_MP2T_NOT_SUPPORTED);
}

if (shaka.util.Platform.isMediaKeysPolyfilled()) {
joeyparrish marked this conversation as resolved.
Show resolved Hide resolved
throw new shaka.util.Error(
shaka.util.Error.Severity.CRITICAL,
shaka.util.Error.Category.MANIFEST,
shaka.util.Error.Code
.HLS_MSE_ENCRYPTED_LEGACY_APPLE_MEDIA_KEYS_NOT_SUPPORTED);
}

/*
* Even if we're not able to construct initData through the HLS tag, adding
* a DRMInfo will allow DRM Engine to request a media key system access
* with the correct keySystem and initDataType
*/
const drmInfo = shaka.util.ManifestParserUtils.createDrmInfo(
'com.apple.fps', [
{initDataType: 'sinf', initData: new Uint8Array(0)},
]);

return drmInfo;
}

/**
* @param {!shaka.hls.Tag} drmTag
* @return {?shaka.extern.DrmInfo}
Expand Down Expand Up @@ -3029,7 +3065,7 @@ shaka.hls.HlsParser.EXTENSION_MAP_BY_CONTENT_TYPE_ = {


/**
* @typedef {function(!shaka.hls.Tag):?shaka.extern.DrmInfo}
* @typedef {function(!shaka.hls.Tag, string):?shaka.extern.DrmInfo}
* @private
*/
shaka.hls.HlsParser.DrmParser_;
Expand All @@ -3040,10 +3076,8 @@ shaka.hls.HlsParser.DrmParser_;
* @private
*/
shaka.hls.HlsParser.KEYFORMATS_TO_DRM_PARSERS_ = {
/* TODO: https://github.com/google/shaka-player/issues/382
'com.apple.streamingkeydelivery':
shaka.hls.HlsParser.fairplayDrmParser_,
*/
'urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed':
shaka.hls.HlsParser.widevineDrmParser_,
'com.microsoft.playready':
Expand Down