Skip to content

Commit

Permalink
feat: Add support for Modern EME and legacy Apple Media Keys for Fair…
Browse files Browse the repository at this point in the history
  • Loading branch information
Álvaro Velad Galván committed Jun 29, 2022
1 parent 7f670d4 commit 5441f93
Show file tree
Hide file tree
Showing 11 changed files with 997 additions and 6 deletions.
1 change: 1 addition & 0 deletions build/types/complete
Expand Up @@ -2,6 +2,7 @@

+@ads
+@cast
+@fairplay
+@networking
+@manifests
+@polyfill
Expand Down
1 change: 0 additions & 1 deletion build/types/core
Expand Up @@ -68,7 +68,6 @@
+../../lib/util/ebml_parser.js
+../../lib/util/error.js
+../../lib/util/event_manager.js
+../../lib/util/fairplay_utils.js
+../../lib/util/fake_event.js
+../../lib/util/fake_event_target.js
+../../lib/util/functional.js
Expand Down
3 changes: 3 additions & 0 deletions build/types/fairplay
@@ -0,0 +1,3 @@
# FairPlay

+../../lib/util/fairplay_utils.js
1 change: 1 addition & 0 deletions build/types/polyfill
Expand Up @@ -7,6 +7,7 @@
+../../lib/polyfill/mediasource.js
+../../lib/polyfill/media_capabilities.js
+../../lib/polyfill/orientation.js
+../../lib/polyfill/patchedmediakeys_apple.js
+../../lib/polyfill/patchedmediakeys_nop.js
+../../lib/polyfill/patchedmediakeys_webkit.js
+../../lib/polyfill/pip_webkit.js
Expand Down
149 changes: 149 additions & 0 deletions docs/tutorials/fairplay.md
@@ -1,8 +1,41 @@
# FairPlay Support

We support FairPlay with EME on compatible environments or native `src=`.

By default Shaka Player supports Modern EME, if your provider doesn't support
Modern EME yet, you can use legacy Apple Media Keys with:
```js
shaka.polyfill.PatchedMediaKeysApple.install();
```

The support in each case would be the following:

| |Modern EME |legacy Apple Media Keys|
|:----------:|:---------:|:---------------------:|
|src= (CMAF) |**Y** |**Y** |
|src= (TS) |**Y** |**Y** |
|MSE (CMAF) |**Y** | - |
|MSE (TS) | - | - |


Adding FairPlay support involves a bit more work than other key systems.


## Keysystem used in EME

Depending on the EME implementation that is being used, the Fairplay keysystem
varies.

For Modern EME:
```
com.apple.fps
```

For legacy Apple Media Keys:
```
com.apple.fps.1_0
```

## Server certificate

All FairPlay content requires setting a server certificate. You can either
Expand All @@ -22,6 +55,27 @@ player.configure('drm.advanced.com\\.apple\\.fps\\.serverCertificateUri',
'https://example.com/cert.der');
```

## Content ID

Note: Normally only applies to legacy Apple Media Keys but some providers also
need it in Modern EME.

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:

```js
player.configure('drm.initDataTransform', (initData, initDataType) => {
if (initDataType != 'skd')
return initData;
// 'initData' is a buffer containing an 'skd://' URL as a UTF-8 string.
const skdUri = shaka.util.StringUtils.fromBytesAutoDetect(initData);
const contentId = getMyContentId(skdUri);
const cert = player.drmInfo().serverCertificate;
return shaka.util.FairPlayUtils.initDataTransform(initData, contentId, cert);
});
```

## License wrapping

Some FairPlay servers need to accept the license request in a different format
Expand Down Expand Up @@ -61,3 +115,98 @@ player.getNetworkingEngine().registerResponseFilter((type, response) => {
response.data = shaka.util.Uint8ArrayUtils.fromBase64(responseText).buffer;
});
```

### Integration with some DRMs providers

Note: Some providers support both Modern EME and legacy Apple Media Keys.

#### EZDRM (Modern EME)

For integration with EZDRM the following can be used:

```js
const FairPlayUtils = shaka.util.FairPlayUtils;
player.getNetworkingEngine()
.registerRequestFilter(FairPlayUtils.ezdrmFairPlayRequest);
player.getNetworkingEngine()
.registerResponseFilter(FairPlayUtils.commonFairPlayResponse);
```

Note: If the url of the license server has to undergo any transformation
(eg: add the contentId), you would have to create your filter manually.

```js
player.getNetworkingEngine().registerRequestFilter((type, request) => {
if (type != shaka.net.NetworkingEngine.RequestType.LICENSE) {
return;
}
const uri = request.uris[0];
const FairPlayUtils = shaka.util.FairPlayUtils;
const contentId = FairPlayUtils.defaultGetContentId(request.initData);
const newUri = uri.replace('^assetId^', contentId);
request.uris = [newUri];
request.headers['Content-Type'] = 'application/octet-stream'
});
```

#### EZDRM (legacy Apple Media Keys)

For integration with EZDRM the following can be used:

```js
shaka.polyfill.PatchedMediaKeysApple.install();
const FairPlayUtils = shaka.util.FairPlayUtils;
player.getNetworkingEngine()
.registerRequestFilter(FairPlayUtils.ezdrmFairPlayRequest);
player.getNetworkingEngine()
.registerResponseFilter(FairPlayUtils.commonFairPlayResponse);
player.configure('drm.initDataTransform',
FairPlayUtils.ezdrmInitDataTransform);
```

Note: If the url of the license server has to undergo any transformation
(eg: add the contentId), you would have to create your filter manually.

```js
player.getNetworkingEngine().registerRequestFilter((type, request) => {
if (type != shaka.net.NetworkingEngine.RequestType.LICENSE) {
return;
}
const uri = request.uris[0];
const FairPlayUtils = shaka.util.FairPlayUtils;
const contentId = FairPlayUtils.defaultGetContentId(request.initData);
const newUri = uri.replace('^assetId^', contentId);
request.uris = [newUri];
request.headers['Content-Type'] = 'application/octet-stream'
});
```

#### Verimatrix (legacy Apple Media Keys)

For integration with Verimatrix the following can be used:

```js
shaka.polyfill.PatchedMediaKeysApple.install();
const FairPlayUtils = shaka.util.FairPlayUtils;
player.getNetworkingEngine()
.registerRequestFilter(FairPlayUtils.verimatrixFairPlayRequest);
player.getNetworkingEngine()
.registerResponseFilter(FairPlayUtils.commonFairPlayResponse);
player.configure('drm.initDataTransform',
FairPlayUtils.verimatrixInitDataTransform);
```

#### Conax (legacy Apple Media Keys)

For integration with Conax the following can be used:

```js
shaka.polyfill.PatchedMediaKeysApple.install();
const FairPlayUtils = shaka.util.FairPlayUtils;
player.getNetworkingEngine()
.registerRequestFilter(FairPlayUtils.conaxFairPlayRequest);
player.getNetworkingEngine()
.registerResponseFilter(FairPlayUtils.commonFairPlayResponse);
player.configure('drm.initDataTransform',
FairPlayUtils.conaxInitDataTransform);
```
8 changes: 8 additions & 0 deletions lib/hls/hls_parser.js
Expand Up @@ -2607,6 +2607,14 @@ shaka.hls.HlsParser = class {
shaka.util.Error.Code.HLS_MSE_ENCRYPTED_MP2T_NOT_SUPPORTED);
}

if (shaka.util.Platform.isMediaKeysPolyfilled()) {
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
Expand Down
2 changes: 0 additions & 2 deletions lib/media/drm_engine.js
Expand Up @@ -1668,8 +1668,6 @@ shaka.media.DrmEngine = class {
'com.widevine.alpha',
'com.microsoft.playready',
'com.microsoft.playready.recommendation',
'com.apple.fps.3_0',
'com.apple.fps.2_0',
'com.apple.fps.1_0',
'com.apple.fps',
'com.adobe.primetime',
Expand Down

0 comments on commit 5441f93

Please sign in to comment.