shaka-player 4.1.3 → 4.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/selenium-lab-tests.yaml +158 -53
- package/CHANGELOG.md +39 -29
- package/demo/common/assets.js +25 -0
- package/demo/common/message_ids.js +2 -0
- package/demo/config.js +5 -1
- package/demo/index.html +1 -1
- package/demo/locales/en.json +2 -0
- package/demo/locales/source.json +8 -0
- package/dist/controls.css +1 -1
- package/dist/controls.css.map +1 -1
- package/dist/demo.compiled.debug.js +25 -23
- package/dist/demo.compiled.debug.map +3 -3
- package/dist/demo.compiled.js +25 -23
- package/dist/demo.compiled.map +3 -3
- package/dist/deps.js +3 -2
- package/dist/locales.js +32 -32
- package/dist/receiver.compiled.debug.js +24 -22
- package/dist/receiver.compiled.debug.map +3 -3
- package/dist/receiver.compiled.js +24 -22
- package/dist/receiver.compiled.map +3 -3
- package/dist/shaka-player.compiled.d.ts +57 -6
- package/dist/shaka-player.compiled.debug.d.ts +57 -6
- package/dist/shaka-player.compiled.debug.externs.js +62 -6
- package/dist/shaka-player.compiled.debug.js +305 -262
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +62 -6
- package/dist/shaka-player.compiled.js +817 -801
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.d.ts +57 -6
- package/dist/shaka-player.ui.debug.d.ts +57 -6
- package/dist/shaka-player.ui.debug.externs.js +62 -6
- package/dist/shaka-player.ui.debug.js +308 -265
- package/dist/shaka-player.ui.debug.map +4 -4
- package/dist/shaka-player.ui.externs.js +62 -6
- package/dist/shaka-player.ui.js +942 -925
- package/dist/shaka-player.ui.map +4 -4
- package/docs/tutorials/fairplay.md +149 -0
- package/docs/tutorials/ui.md +6 -6
- package/externs/shaka/abr_manager.js +8 -0
- package/externs/shaka/manifest.js +43 -0
- package/externs/shaka/player.js +13 -2
- package/lib/abr/simple_abr_manager.js +72 -4
- package/lib/hls/hls_parser.js +138 -96
- package/lib/media/drm_engine.js +0 -2
- package/lib/media/segment_index.js +8 -0
- package/lib/media/segment_reference.js +7 -1
- package/lib/media/streaming_engine.js +38 -2
- package/lib/net/networking_engine.js +1 -0
- package/lib/player.js +20 -1
- package/lib/polyfill/patchedmediakeys_apple.js +729 -0
- package/lib/text/ui_text_displayer.js +8 -0
- package/lib/text/vtt_text_parser.js +61 -4
- package/lib/util/error.js +23 -11
- package/lib/util/fairplay_utils.js +100 -2
- package/lib/util/platform.js +12 -1
- package/lib/util/player_configuration.js +4 -10
- package/package.json +1 -1
- package/shaka-player.uncompiled.js +1 -0
- package/test/hls/hls_parser_unit.js +101 -34
- package/test/media/drm_engine_unit.js +29 -0
- package/test/media/streaming_engine_unit.js +79 -5
- package/test/player_src_equals_integration.js +2 -0
- package/test/player_unit.js +39 -1
- package/test/test/assets/small.mp4 +0 -0
- package/test/test/util/simple_fakes.js +4 -0
- package/test/test/util/streaming_engine_util.js +10 -2
- package/test/text/vtt_text_parser_unit.js +26 -0
- package/ui/less/ad_controls.less +4 -0
|
@@ -1,8 +1,41 @@
|
|
|
1
1
|
# FairPlay Support
|
|
2
2
|
|
|
3
3
|
We support FairPlay with EME on compatible environments or native `src=`.
|
|
4
|
+
|
|
5
|
+
By default Shaka Player supports Modern EME, if your provider doesn't support
|
|
6
|
+
Modern EME yet, you can use legacy Apple Media Keys with:
|
|
7
|
+
```js
|
|
8
|
+
shaka.polyfill.PatchedMediaKeysApple.install();
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
The support in each case would be the following:
|
|
12
|
+
|
|
13
|
+
| |Modern EME |legacy Apple Media Keys|
|
|
14
|
+
|:----------:|:---------:|:---------------------:|
|
|
15
|
+
|src= (CMAF) |**Y** |**Y** |
|
|
16
|
+
|src= (TS) |**Y** |**Y** |
|
|
17
|
+
|MSE (CMAF) |**Y** | - |
|
|
18
|
+
|MSE (TS) | - | - |
|
|
19
|
+
|
|
20
|
+
|
|
4
21
|
Adding FairPlay support involves a bit more work than other key systems.
|
|
5
22
|
|
|
23
|
+
|
|
24
|
+
## Keysystem used in EME
|
|
25
|
+
|
|
26
|
+
Depending on the EME implementation that is being used, the Fairplay keysystem
|
|
27
|
+
varies.
|
|
28
|
+
|
|
29
|
+
For Modern EME:
|
|
30
|
+
```
|
|
31
|
+
com.apple.fps
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
For legacy Apple Media Keys:
|
|
35
|
+
```
|
|
36
|
+
com.apple.fps.1_0
|
|
37
|
+
```
|
|
38
|
+
|
|
6
39
|
## Server certificate
|
|
7
40
|
|
|
8
41
|
All FairPlay content requires setting a server certificate. You can either
|
|
@@ -22,6 +55,27 @@ player.configure('drm.advanced.com\\.apple\\.fps\\.serverCertificateUri',
|
|
|
22
55
|
'https://example.com/cert.der');
|
|
23
56
|
```
|
|
24
57
|
|
|
58
|
+
## Content ID
|
|
59
|
+
|
|
60
|
+
Note: Normally only applies to legacy Apple Media Keys but some providers also
|
|
61
|
+
need it in Modern EME.
|
|
62
|
+
|
|
63
|
+
Some FairPlay content use custom signaling for the content ID. The content ID
|
|
64
|
+
is used by the browser to generate the license request. If you don't use the
|
|
65
|
+
default content ID derivation, you need to specify a custom init data transform:
|
|
66
|
+
|
|
67
|
+
```js
|
|
68
|
+
player.configure('drm.initDataTransform', (initData, initDataType) => {
|
|
69
|
+
if (initDataType != 'skd')
|
|
70
|
+
return initData;
|
|
71
|
+
// 'initData' is a buffer containing an 'skd://' URL as a UTF-8 string.
|
|
72
|
+
const skdUri = shaka.util.StringUtils.fromBytesAutoDetect(initData);
|
|
73
|
+
const contentId = getMyContentId(skdUri);
|
|
74
|
+
const cert = player.drmInfo().serverCertificate;
|
|
75
|
+
return shaka.util.FairPlayUtils.initDataTransform(initData, contentId, cert);
|
|
76
|
+
});
|
|
77
|
+
```
|
|
78
|
+
|
|
25
79
|
## License wrapping
|
|
26
80
|
|
|
27
81
|
Some FairPlay servers need to accept the license request in a different format
|
|
@@ -61,3 +115,98 @@ player.getNetworkingEngine().registerResponseFilter((type, response) => {
|
|
|
61
115
|
response.data = shaka.util.Uint8ArrayUtils.fromBase64(responseText).buffer;
|
|
62
116
|
});
|
|
63
117
|
```
|
|
118
|
+
|
|
119
|
+
### Integration with some DRMs providers
|
|
120
|
+
|
|
121
|
+
Note: Some providers support both Modern EME and legacy Apple Media Keys.
|
|
122
|
+
|
|
123
|
+
#### EZDRM (Modern EME)
|
|
124
|
+
|
|
125
|
+
For integration with EZDRM the following can be used:
|
|
126
|
+
|
|
127
|
+
```js
|
|
128
|
+
const FairPlayUtils = shaka.util.FairPlayUtils;
|
|
129
|
+
player.getNetworkingEngine()
|
|
130
|
+
.registerRequestFilter(FairPlayUtils.ezdrmFairPlayRequest);
|
|
131
|
+
player.getNetworkingEngine()
|
|
132
|
+
.registerResponseFilter(FairPlayUtils.commonFairPlayResponse);
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Note: If the url of the license server has to undergo any transformation
|
|
136
|
+
(eg: add the contentId), you would have to create your filter manually.
|
|
137
|
+
|
|
138
|
+
```js
|
|
139
|
+
player.getNetworkingEngine().registerRequestFilter((type, request) => {
|
|
140
|
+
if (type != shaka.net.NetworkingEngine.RequestType.LICENSE) {
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
const uri = request.uris[0];
|
|
144
|
+
const FairPlayUtils = shaka.util.FairPlayUtils;
|
|
145
|
+
const contentId = FairPlayUtils.defaultGetContentId(request.initData);
|
|
146
|
+
const newUri = uri.replace('^assetId^', contentId);
|
|
147
|
+
request.uris = [newUri];
|
|
148
|
+
request.headers['Content-Type'] = 'application/octet-stream'
|
|
149
|
+
});
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
#### EZDRM (legacy Apple Media Keys)
|
|
153
|
+
|
|
154
|
+
For integration with EZDRM the following can be used:
|
|
155
|
+
|
|
156
|
+
```js
|
|
157
|
+
shaka.polyfill.PatchedMediaKeysApple.install();
|
|
158
|
+
const FairPlayUtils = shaka.util.FairPlayUtils;
|
|
159
|
+
player.getNetworkingEngine()
|
|
160
|
+
.registerRequestFilter(FairPlayUtils.ezdrmFairPlayRequest);
|
|
161
|
+
player.getNetworkingEngine()
|
|
162
|
+
.registerResponseFilter(FairPlayUtils.commonFairPlayResponse);
|
|
163
|
+
player.configure('drm.initDataTransform',
|
|
164
|
+
FairPlayUtils.ezdrmInitDataTransform);
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Note: If the url of the license server has to undergo any transformation
|
|
168
|
+
(eg: add the contentId), you would have to create your filter manually.
|
|
169
|
+
|
|
170
|
+
```js
|
|
171
|
+
player.getNetworkingEngine().registerRequestFilter((type, request) => {
|
|
172
|
+
if (type != shaka.net.NetworkingEngine.RequestType.LICENSE) {
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
const uri = request.uris[0];
|
|
176
|
+
const FairPlayUtils = shaka.util.FairPlayUtils;
|
|
177
|
+
const contentId = FairPlayUtils.defaultGetContentId(request.initData);
|
|
178
|
+
const newUri = uri.replace('^assetId^', contentId);
|
|
179
|
+
request.uris = [newUri];
|
|
180
|
+
request.headers['Content-Type'] = 'application/octet-stream'
|
|
181
|
+
});
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
#### Verimatrix (legacy Apple Media Keys)
|
|
185
|
+
|
|
186
|
+
For integration with Verimatrix the following can be used:
|
|
187
|
+
|
|
188
|
+
```js
|
|
189
|
+
shaka.polyfill.PatchedMediaKeysApple.install();
|
|
190
|
+
const FairPlayUtils = shaka.util.FairPlayUtils;
|
|
191
|
+
player.getNetworkingEngine()
|
|
192
|
+
.registerRequestFilter(FairPlayUtils.verimatrixFairPlayRequest);
|
|
193
|
+
player.getNetworkingEngine()
|
|
194
|
+
.registerResponseFilter(FairPlayUtils.commonFairPlayResponse);
|
|
195
|
+
player.configure('drm.initDataTransform',
|
|
196
|
+
FairPlayUtils.verimatrixInitDataTransform);
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
#### Conax (legacy Apple Media Keys)
|
|
200
|
+
|
|
201
|
+
For integration with Conax the following can be used:
|
|
202
|
+
|
|
203
|
+
```js
|
|
204
|
+
shaka.polyfill.PatchedMediaKeysApple.install();
|
|
205
|
+
const FairPlayUtils = shaka.util.FairPlayUtils;
|
|
206
|
+
player.getNetworkingEngine()
|
|
207
|
+
.registerRequestFilter(FairPlayUtils.conaxFairPlayRequest);
|
|
208
|
+
player.getNetworkingEngine()
|
|
209
|
+
.registerResponseFilter(FairPlayUtils.commonFairPlayResponse);
|
|
210
|
+
player.configure('drm.initDataTransform',
|
|
211
|
+
FairPlayUtils.conaxInitDataTransform);
|
|
212
|
+
```
|
package/docs/tutorials/ui.md
CHANGED
|
@@ -30,7 +30,7 @@ Set up controls with HTML data attributes:
|
|
|
30
30
|
The data-shaka-player-cast-receiver-id tag allows you to provide a Cast Application ID that
|
|
31
31
|
the cast button will cast to; the value provided here is the sample cast receiver. -->
|
|
32
32
|
<div data-shaka-player-container style="max-width:40em"
|
|
33
|
-
data-shaka-player-cast-receiver-id="
|
|
33
|
+
data-shaka-player-cast-receiver-id="07AEE832">
|
|
34
34
|
<!-- The data-shaka-player tag will make the UI library use this video element.
|
|
35
35
|
If no video is provided, the UI will automatically make one inside the container div. -->
|
|
36
36
|
<video autoplay data-shaka-player id="video" style="width:100%;height:100%"></video>
|
|
@@ -111,7 +111,7 @@ set up a listener for the 'caststatuschanged' events.
|
|
|
111
111
|
<!-- Add a data-shaka-player-cast-receiver-id tag to provide a Cast Application ID that
|
|
112
112
|
the cast button will cast to; the value provided here is the sample cast receiver. -->
|
|
113
113
|
<div data-shaka-player-container style="max-width:40em"
|
|
114
|
-
data-shaka-player-cast-receiver-id="
|
|
114
|
+
data-shaka-player-cast-receiver-id="07AEE832">
|
|
115
115
|
</div>
|
|
116
116
|
```
|
|
117
117
|
|
|
@@ -154,7 +154,7 @@ or a `<source>` tag inside it to enable auto loading of the specified content.
|
|
|
154
154
|
|
|
155
155
|
```html
|
|
156
156
|
<div data-shaka-player-container style="max-width:40em"
|
|
157
|
-
data-shaka-player-cast-receiver-id="
|
|
157
|
+
data-shaka-player-cast-receiver-id="07AEE832">
|
|
158
158
|
<!-- The manifest url in the src attribute will be automatically loaded -->
|
|
159
159
|
<video autoplay data-shaka-player id="video" style="width:100%;height:100%"
|
|
160
160
|
src="https://storage.googleapis.com/shaka-demo-assets/angel-one/dash.mpd"></video>
|
|
@@ -165,7 +165,7 @@ or
|
|
|
165
165
|
|
|
166
166
|
```html
|
|
167
167
|
<div data-shaka-player-container style="max-width:40em"
|
|
168
|
-
data-shaka-player-cast-receiver-id="
|
|
168
|
+
data-shaka-player-cast-receiver-id="07AEE832">
|
|
169
169
|
<video autoplay data-shaka-player id="video" style="width:100%;height:100%">
|
|
170
170
|
<!-- The manifest url in the src attribute will be auto loaded -->
|
|
171
171
|
<source src="https://storage.googleapis.com/shaka-demo-assets/angel-one/dash.mpd"/>
|
|
@@ -178,7 +178,7 @@ call to the first one fails.
|
|
|
178
178
|
|
|
179
179
|
```html
|
|
180
180
|
<div data-shaka-player-container style="max-width:40em"
|
|
181
|
-
data-shaka-player-cast-receiver-id="
|
|
181
|
+
data-shaka-player-cast-receiver-id="07AEE832">
|
|
182
182
|
<video autoplay data-shaka-player id="video" style="width:100%;height:100%">
|
|
183
183
|
<!-- Try this first -->
|
|
184
184
|
<source src="https://storage.googleapis.com/shaka-demo-assets/angel-one/dash.mpd"/>
|
|
@@ -222,7 +222,7 @@ const video = controls.getVideo();
|
|
|
222
222
|
// Receiver Compatability.
|
|
223
223
|
ui.configure({
|
|
224
224
|
// Set the castReceiverAppId
|
|
225
|
-
'castReceiverAppId': '
|
|
225
|
+
'castReceiverAppId': '07AEE832',
|
|
226
226
|
// Enable casting to native Android Apps (e.g. Android TV Apps)
|
|
227
227
|
'castAndroidReceiverCompatible': true,
|
|
228
228
|
});
|
|
@@ -103,6 +103,14 @@ shaka.extern.AbrManager = class {
|
|
|
103
103
|
*/
|
|
104
104
|
playbackRateChanged(rate) {}
|
|
105
105
|
|
|
106
|
+
/**
|
|
107
|
+
* Set media element.
|
|
108
|
+
*
|
|
109
|
+
* @param {HTMLMediaElement} mediaElement
|
|
110
|
+
* @exportDoc
|
|
111
|
+
*/
|
|
112
|
+
setMediaElement(mediaElement) {}
|
|
113
|
+
|
|
106
114
|
/**
|
|
107
115
|
* Sets the ABR configuration.
|
|
108
116
|
*
|
|
@@ -244,6 +244,49 @@ shaka.extern.Variant;
|
|
|
244
244
|
shaka.extern.CreateSegmentIndexFunction;
|
|
245
245
|
|
|
246
246
|
|
|
247
|
+
/**
|
|
248
|
+
* @typedef {{
|
|
249
|
+
* method: string,
|
|
250
|
+
* cryptoKey: (webCrypto.CryptoKey|undefined),
|
|
251
|
+
* fetchKey: (shaka.extern.CreateSegmentIndexFunction|undefined),
|
|
252
|
+
* iv: (!Uint8Array|undefined),
|
|
253
|
+
* firstMediaSequenceNumber: number
|
|
254
|
+
* }}
|
|
255
|
+
*
|
|
256
|
+
* @description
|
|
257
|
+
* AES-128 key and iv info from the HLS manifest.
|
|
258
|
+
*
|
|
259
|
+
* @property {string} method
|
|
260
|
+
* The key method defined in the HLS manifest.
|
|
261
|
+
* @property {webCrypto.CryptoKey|undefined} cryptoKey
|
|
262
|
+
* Web crypto key object of the AES-128 CBC key. If unset, the "fetchKey"
|
|
263
|
+
* property should be provided.
|
|
264
|
+
* @property {shaka.extern.FetchCryptoKeysFunction|undefined} fetchKey
|
|
265
|
+
* A function that fetches the key.
|
|
266
|
+
* Should be provided if the "cryptoKey" property is unset.
|
|
267
|
+
* Should update this object in-place, to set "cryptoKey".
|
|
268
|
+
* @property {(!Uint8Array|undefined)} iv
|
|
269
|
+
* The IV in the HLS manifest, if defined. See HLS RFC 8216 Section 5.2 for
|
|
270
|
+
* handling undefined IV.
|
|
271
|
+
* @property {number} firstMediaSequenceNumber
|
|
272
|
+
* The starting Media Sequence Number of the playlist, used when IV is
|
|
273
|
+
* undefined.
|
|
274
|
+
*
|
|
275
|
+
* @exportDoc
|
|
276
|
+
*/
|
|
277
|
+
shaka.extern.HlsAes128Key;
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* A function that fetches the crypto keys for AES-128.
|
|
282
|
+
* Returns a promise that resolves when the keys have been fetched.
|
|
283
|
+
*
|
|
284
|
+
* @typedef {function(): !Promise}
|
|
285
|
+
* @exportDoc
|
|
286
|
+
*/
|
|
287
|
+
shaka.extern.FetchCryptoKeysFunction;
|
|
288
|
+
|
|
289
|
+
|
|
247
290
|
/**
|
|
248
291
|
* @typedef {{
|
|
249
292
|
* id: number,
|
package/externs/shaka/player.js
CHANGED
|
@@ -1000,7 +1000,9 @@ shaka.extern.StreamingConfiguration;
|
|
|
1000
1000
|
* switchInterval: number,
|
|
1001
1001
|
* bandwidthUpgradeTarget: number,
|
|
1002
1002
|
* bandwidthDowngradeTarget: number,
|
|
1003
|
-
* advanced: shaka.extern.AdvancedAbrConfiguration
|
|
1003
|
+
* advanced: shaka.extern.AdvancedAbrConfiguration,
|
|
1004
|
+
* restrictToElementSize: boolean,
|
|
1005
|
+
* ignoreDevicePixelRatio: boolean
|
|
1004
1006
|
* }}
|
|
1005
1007
|
*
|
|
1006
1008
|
* @property {boolean} enabled
|
|
@@ -1029,7 +1031,16 @@ shaka.extern.StreamingConfiguration;
|
|
|
1029
1031
|
* The largest fraction of the estimated bandwidth we should use. We should
|
|
1030
1032
|
* downgrade to avoid this.
|
|
1031
1033
|
* @property {shaka.extern.AdvancedAbrConfiguration} advanced
|
|
1032
|
-
* Advanced ABR configuration
|
|
1034
|
+
* Advanced ABR configuration
|
|
1035
|
+
* @property {boolean} restrictToElementSize
|
|
1036
|
+
* If true, restrict the quality to media element size.
|
|
1037
|
+
* Note: The use of ResizeObserver is required for it to work properly. If
|
|
1038
|
+
* true without ResizeObserver, it behaves as false.
|
|
1039
|
+
* Defaults false.
|
|
1040
|
+
* @property {boolean} ignoreDevicePixelRatio
|
|
1041
|
+
* If true,device pixel ratio is ignored when restricting the quality to
|
|
1042
|
+
* media element size.
|
|
1043
|
+
* Defaults false.
|
|
1033
1044
|
* @exportDoc
|
|
1034
1045
|
*/
|
|
1035
1046
|
shaka.extern.AbrConfiguration;
|
|
@@ -10,6 +10,7 @@ goog.require('goog.asserts');
|
|
|
10
10
|
goog.require('shaka.abr.EwmaBandwidthEstimator');
|
|
11
11
|
goog.require('shaka.log');
|
|
12
12
|
goog.require('shaka.util.StreamUtils');
|
|
13
|
+
goog.require('shaka.util.Timer');
|
|
13
14
|
|
|
14
15
|
|
|
15
16
|
/**
|
|
@@ -85,6 +86,22 @@ shaka.abr.SimpleAbrManager = class {
|
|
|
85
86
|
|
|
86
87
|
/** @private {?shaka.extern.AbrConfiguration} */
|
|
87
88
|
this.config_ = null;
|
|
89
|
+
|
|
90
|
+
/** @private {HTMLMediaElement} */
|
|
91
|
+
this.mediaElement_ = null;
|
|
92
|
+
|
|
93
|
+
/** @private {ResizeObserver} */
|
|
94
|
+
this.resizeObserver_ = null;
|
|
95
|
+
|
|
96
|
+
/** @private {shaka.util.Timer} */
|
|
97
|
+
this.resizeObserverTimer_ = new shaka.util.Timer(() => {
|
|
98
|
+
if (this.config_.restrictToElementSize) {
|
|
99
|
+
const chosenVariant = this.chooseVariant();
|
|
100
|
+
if (chosenVariant) {
|
|
101
|
+
this.switch_(chosenVariant);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
});
|
|
88
105
|
}
|
|
89
106
|
|
|
90
107
|
|
|
@@ -98,6 +115,14 @@ shaka.abr.SimpleAbrManager = class {
|
|
|
98
115
|
this.variants_ = [];
|
|
99
116
|
this.playbackRate_ = 1;
|
|
100
117
|
this.lastTimeChosenMs_ = null;
|
|
118
|
+
this.mediaElement_ = null;
|
|
119
|
+
|
|
120
|
+
if (this.resizeObserver_) {
|
|
121
|
+
this.resizeObserver_.disconnect();
|
|
122
|
+
this.resizeObserver_ = null;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
this.resizeObserverTimer_.stop();
|
|
101
126
|
|
|
102
127
|
// Don't reset |startupComplete_|: if we've left the startup interval, we
|
|
103
128
|
// can start using bandwidth estimates right away after init() is called.
|
|
@@ -120,9 +145,19 @@ shaka.abr.SimpleAbrManager = class {
|
|
|
120
145
|
chooseVariant() {
|
|
121
146
|
const SimpleAbrManager = shaka.abr.SimpleAbrManager;
|
|
122
147
|
|
|
148
|
+
let maxHeight = Infinity;
|
|
149
|
+
let maxWidth = Infinity;
|
|
150
|
+
|
|
151
|
+
if (this.resizeObserver_ && this.config_.restrictToElementSize) {
|
|
152
|
+
const devicePixelRatio =
|
|
153
|
+
this.config_.ignoreDevicePixelRatio ? 1 : window.devicePixelRatio;
|
|
154
|
+
maxHeight = this.mediaElement_.clientWidth * devicePixelRatio;
|
|
155
|
+
maxWidth = this.mediaElement_.clientHeight * devicePixelRatio;
|
|
156
|
+
}
|
|
157
|
+
|
|
123
158
|
// Get sorted Variants.
|
|
124
159
|
let sortedVariants = SimpleAbrManager.filterAndSortVariants_(
|
|
125
|
-
this.config_.restrictions, this.variants_);
|
|
160
|
+
this.config_.restrictions, this.variants_, maxHeight, maxWidth);
|
|
126
161
|
|
|
127
162
|
const defaultBandwidthEstimate = this.getDefaultBandwidth_();
|
|
128
163
|
const currentBandwidth = this.bandwidthEstimator_.getBandwidthEstimate(
|
|
@@ -137,7 +172,8 @@ shaka.abr.SimpleAbrManager = class {
|
|
|
137
172
|
shaka.log.warning('No variants met the ABR restrictions. ' +
|
|
138
173
|
'Choosing a variant by lowest bandwidth.');
|
|
139
174
|
sortedVariants = SimpleAbrManager.filterAndSortVariants_(
|
|
140
|
-
/* restrictions= */ null, this.variants_
|
|
175
|
+
/* restrictions= */ null, this.variants_,
|
|
176
|
+
/* maxHeight= */ Infinity, /* maxWidth= */ Infinity);
|
|
141
177
|
sortedVariants = [sortedVariants[0]];
|
|
142
178
|
}
|
|
143
179
|
|
|
@@ -243,6 +279,28 @@ shaka.abr.SimpleAbrManager = class {
|
|
|
243
279
|
}
|
|
244
280
|
|
|
245
281
|
|
|
282
|
+
/**
|
|
283
|
+
* @override
|
|
284
|
+
* @export
|
|
285
|
+
*/
|
|
286
|
+
setMediaElement(mediaElement) {
|
|
287
|
+
this.mediaElement_ = mediaElement;
|
|
288
|
+
if (this.resizeObserver_) {
|
|
289
|
+
this.resizeObserver_.disconnect();
|
|
290
|
+
this.resizeObserver_ = null;
|
|
291
|
+
}
|
|
292
|
+
if (this.mediaElement_ && 'ResizeObserver' in window) {
|
|
293
|
+
this.resizeObserver_ = new ResizeObserver(() => {
|
|
294
|
+
const SimpleAbrManager = shaka.abr.SimpleAbrManager;
|
|
295
|
+
// Batch up resize changes before checking them.
|
|
296
|
+
this.resizeObserverTimer_.tickAfter(
|
|
297
|
+
/* seconds= */ SimpleAbrManager.RESIZE_OBSERVER_BATCH_TIME);
|
|
298
|
+
});
|
|
299
|
+
this.resizeObserver_.observe(this.mediaElement_);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
|
|
246
304
|
/**
|
|
247
305
|
* @override
|
|
248
306
|
* @export
|
|
@@ -320,11 +378,13 @@ shaka.abr.SimpleAbrManager = class {
|
|
|
320
378
|
/**
|
|
321
379
|
* @param {?shaka.extern.Restrictions} restrictions
|
|
322
380
|
* @param {!Array.<shaka.extern.Variant>} variants
|
|
381
|
+
* @param {!number} maxHeight
|
|
382
|
+
* @param {!number} maxWidth
|
|
323
383
|
* @return {!Array.<shaka.extern.Variant>} variants filtered according to
|
|
324
384
|
* |restrictions| and sorted in ascending order of bandwidth.
|
|
325
385
|
* @private
|
|
326
386
|
*/
|
|
327
|
-
static filterAndSortVariants_(restrictions, variants) {
|
|
387
|
+
static filterAndSortVariants_(restrictions, variants, maxHeight, maxWidth) {
|
|
328
388
|
if (restrictions) {
|
|
329
389
|
variants = variants.filter((variant) => {
|
|
330
390
|
// This was already checked in another scope, but the compiler doesn't
|
|
@@ -333,7 +393,7 @@ shaka.abr.SimpleAbrManager = class {
|
|
|
333
393
|
|
|
334
394
|
return shaka.util.StreamUtils.meetsRestrictions(
|
|
335
395
|
variant, restrictions,
|
|
336
|
-
/* maxHwRes= */ {width:
|
|
396
|
+
/* maxHwRes= */ {width: maxWidth, height: maxHeight});
|
|
337
397
|
});
|
|
338
398
|
}
|
|
339
399
|
|
|
@@ -342,3 +402,11 @@ shaka.abr.SimpleAbrManager = class {
|
|
|
342
402
|
});
|
|
343
403
|
}
|
|
344
404
|
};
|
|
405
|
+
|
|
406
|
+
|
|
407
|
+
/**
|
|
408
|
+
* The amount of time, in seconds, we wait to batch up rapid resize changes.
|
|
409
|
+
* This allows us to avoid multiple resize events in most cases.
|
|
410
|
+
* @type {number}
|
|
411
|
+
*/
|
|
412
|
+
shaka.abr.SimpleAbrManager.RESIZE_OBSERVER_BATCH_TIME = 1;
|