shaka-player 4.0.2 → 4.1.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.
Files changed (86) hide show
  1. package/AUTHORS +1 -0
  2. package/CHANGELOG.md +36 -16
  3. package/CONTRIBUTORS +2 -0
  4. package/build/test.py +1 -1
  5. package/demo/common/assets.js +1 -1
  6. package/demo/common/message_ids.js +1 -0
  7. package/demo/config.js +3 -1
  8. package/demo/locales/en.json +1 -0
  9. package/demo/locales/source.json +4 -0
  10. package/demo/main.js +3 -3
  11. package/dist/demo.compiled.debug.js +7 -7
  12. package/dist/demo.compiled.debug.map +2 -2
  13. package/dist/demo.compiled.js +7 -7
  14. package/dist/demo.compiled.map +2 -2
  15. package/dist/deps.js +2 -2
  16. package/dist/locales.js +30 -30
  17. package/dist/receiver.compiled.debug.js +3 -3
  18. package/dist/receiver.compiled.debug.map +2 -2
  19. package/dist/receiver.compiled.js +3 -3
  20. package/dist/receiver.compiled.map +2 -2
  21. package/dist/shaka-player.compiled.d.ts +14 -8
  22. package/dist/shaka-player.compiled.debug.d.ts +14 -8
  23. package/dist/shaka-player.compiled.debug.externs.js +13 -4
  24. package/dist/shaka-player.compiled.debug.js +296 -282
  25. package/dist/shaka-player.compiled.debug.map +4 -4
  26. package/dist/shaka-player.compiled.externs.js +13 -4
  27. package/dist/shaka-player.compiled.js +781 -773
  28. package/dist/shaka-player.compiled.map +4 -4
  29. package/dist/shaka-player.ui.d.ts +15 -9
  30. package/dist/shaka-player.ui.debug.d.ts +15 -9
  31. package/dist/shaka-player.ui.debug.externs.js +13 -4
  32. package/dist/shaka-player.ui.debug.js +345 -326
  33. package/dist/shaka-player.ui.debug.map +4 -4
  34. package/dist/shaka-player.ui.externs.js +13 -4
  35. package/dist/shaka-player.ui.js +955 -949
  36. package/dist/shaka-player.ui.map +4 -4
  37. package/docs/design/chromecast.md +3 -1
  38. package/docs/tutorials/drm-config.md +16 -0
  39. package/docs/tutorials/ui.md +26 -0
  40. package/externs/chromecast.js +9 -2
  41. package/externs/shaka/manifest.js +7 -0
  42. package/externs/shaka/player.js +25 -4
  43. package/externs/shaka/text.js +7 -0
  44. package/lib/cast/cast_proxy.js +19 -8
  45. package/lib/cast/cast_receiver.js +3 -3
  46. package/lib/cast/cast_sender.js +12 -2
  47. package/lib/hls/hls_parser.js +189 -69
  48. package/lib/media/drm_engine.js +17 -8
  49. package/lib/media/gap_jumping_controller.js +23 -1
  50. package/lib/media/playhead.js +47 -4
  51. package/lib/media/segment_index.js +26 -1
  52. package/lib/media/segment_reference.js +10 -3
  53. package/lib/media/stall_detector.js +19 -2
  54. package/lib/media/streaming_engine.js +9 -2
  55. package/lib/offline/manifest_converter.js +1 -0
  56. package/lib/player.js +175 -69
  57. package/lib/text/cue.js +6 -0
  58. package/lib/text/ui_text_displayer.js +1 -0
  59. package/lib/text/vtt_text_parser.js +4 -0
  60. package/lib/util/error.js +6 -0
  61. package/lib/util/fake_event.js +39 -0
  62. package/lib/util/player_configuration.js +2 -0
  63. package/lib/util/stats.js +28 -1
  64. package/lib/util/stream_utils.js +8 -0
  65. package/package.json +2 -2
  66. package/test/cast/cast_proxy_unit.js +3 -1
  67. package/test/cast/cast_sender_unit.js +21 -6
  68. package/test/demo/demo_unit.js +2 -1
  69. package/test/hls/hls_parser_unit.js +102 -8
  70. package/test/media/adaptation_set_unit.js +1 -0
  71. package/test/media/playhead_unit.js +114 -25
  72. package/test/media/stall_detector_unit.js +20 -2
  73. package/test/media/streaming_engine_integration.js +2 -1
  74. package/test/media/streaming_engine_unit.js +1 -0
  75. package/test/player_integration.js +3 -0
  76. package/test/player_unit.js +142 -1
  77. package/test/test/util/manifest_generator.js +2 -0
  78. package/test/test/util/simple_fakes.js +14 -0
  79. package/test/test/util/streaming_engine_util.js +1 -0
  80. package/test/text/vtt_text_parser_unit.js +4 -0
  81. package/test/ui/ui_unit.js +18 -5
  82. package/test/util/stream_utils_unit.js +108 -0
  83. package/ui/controls.js +12 -8
  84. package/ui/externs/ui.js +10 -1
  85. package/ui/statistics_button.js +10 -0
  86. package/ui/ui.js +12 -1
@@ -26,11 +26,13 @@ the `Player` and `HTMLMediaElement` objects. Receiver apps only have to worry
26
26
  about their UI, while the `CastReceiver` takes care of playback and
27
27
  communication.
28
28
 
29
+ To enable an Android (TV) receiver apps set `androidReceiverCompatible` to true.
30
+
29
31
 
30
32
  #### `CastProxy` API sketch
31
33
 
32
34
  ```js
33
- new shaka.cast.CastProxy(video, player, receiverAppId)
35
+ new shaka.cast.CastProxy(video, player, receiverAppId, androidReceiverCompatible)
34
36
 
35
37
  // Also destroys the underlying local Player object
36
38
  shaka.cast.CastProxy.prototype.destroy() => Promise
@@ -75,6 +75,22 @@ player.configure({
75
75
  If the browser supports it and you configured a license server URL for it, we'll
76
76
  use it.
77
77
 
78
+ Alternative there are a config for make a mapping of keysystem if you know that
79
+ is broadly supported. For example, `com.microsoft.playready.recommendation`:
80
+
81
+ ```js
82
+ player.configure({
83
+ drm: {
84
+ keySystemsMapping: {
85
+ 'com.microsoft.playready': 'com.microsoft.playready.recommendation',
86
+ }
87
+ }
88
+ });
89
+ ```
90
+
91
+ With the previous configuration you will choose the `recommendation` keySystem
92
+ when your manifest (HLS or DASH) uses PlayReady.
93
+
78
94
 
79
95
  #### Clear Key
80
96
 
@@ -130,6 +130,23 @@ Next, let's add a listener to the 'caststatuschanged' event in myapp.js:
130
130
  }
131
131
  ```
132
132
 
133
+
134
+ #### Enabling Android Receiver Apps
135
+
136
+ If you'd like to take advantage of Android Receiver App support,
137
+ you will need to provide a boolean flag to enable support for
138
+ casting to an Android receiver app.
139
+
140
+ ```html
141
+ <div data-shaka-player-container style="max-width:40em"
142
+ data-shaka-player-cast-receiver-id="E7271BEC"
143
+ data-shaka-player-cast-android-receiver-compatible="true">
144
+ <!-- The manifest url in the src attribute will be automatically loaded -->
145
+ <video autoplay data-shaka-player id="video" style="width:100%;height:100%"
146
+ src="https://storage.googleapis.com/shaka-demo-assets/angel-one/dash.mpd"></video>
147
+ </div
148
+
149
+
133
150
  #### Providing source(s) for auto load.
134
151
 
135
152
  It's also possible to provide the `src` attribute on the `<video>` element
@@ -200,6 +217,15 @@ const controls = ui.getControls();
200
217
  // your API calls will be routed to the remote playback session.
201
218
  const player = controls.getPlayer();
202
219
  const video = controls.getVideo();
220
+
221
+ // Programatically configure the Chromecast Receiver App Id and Android
222
+ // Receiver Compatability.
223
+ ui.configure({
224
+ // Set the castReceiverAppId
225
+ 'castReceiverAppId': 'BBED8D28',
226
+ // Enable casting to native Android Apps (e.g. Android TV Apps)
227
+ 'castAndroidReceiverCompatible': true,
228
+ });
203
229
  ```
204
230
 
205
231
 
@@ -270,6 +270,13 @@ chrome.cast.Session = class {
270
270
 
271
271
 
272
272
  chrome.cast.SessionRequest = class {
273
- /** @param {string} appId */
274
- constructor(appId) {}
273
+ /**
274
+ * @param {string} appId
275
+ * @param {Array.<Object>} capabilities
276
+ * @param {?number} timeout
277
+ * @param {boolean} androidReceiverCompatible
278
+ * @param {Object} credentialsData
279
+ */
280
+ constructor(appId, capabilities, timeout, androidReceiverCompatible,
281
+ credentialsData) {}
275
282
  };
@@ -176,6 +176,7 @@ shaka.extern.DrmInfo;
176
176
  * @typedef {{
177
177
  * id: number,
178
178
  * language: string,
179
+ * disabledUntilTime: number,
179
180
  * primary: boolean,
180
181
  * audio: ?shaka.extern.Stream,
181
182
  * video: ?shaka.extern.Stream,
@@ -198,6 +199,12 @@ shaka.extern.DrmInfo;
198
199
  * The Variant's language, specified as a language code. <br>
199
200
  * See {@link https://tools.ietf.org/html/rfc5646} <br>
200
201
  * See {@link http://www.iso.org/iso/home/standards/language_codes.htm}
202
+ * @property {number} disabledUntilTime
203
+ * <i>Defaults to 0.</i> <br>
204
+ * 0 means the variant is enabled. The Player will set this value to
205
+ * "(Date.now() / 1000) + config.streaming.maxDisabledTime" and once this
206
+ * maxDisabledTime has passed Player will set the value to 0 in order to
207
+ * reenable the variant.
201
208
  * @property {boolean} primary
202
209
  * <i>Defaults to false.</i> <br>
203
210
  * True indicates that the player should use this Variant over others if user
@@ -82,6 +82,9 @@ shaka.extern.StateChange;
82
82
  *
83
83
  * maxSegmentDuration: number,
84
84
  *
85
+ * gapsJumped: number,
86
+ * stallsDetected: number,
87
+ *
85
88
  * switchHistory: !Array.<shaka.extern.TrackChoice>,
86
89
  * stateHistory: !Array.<shaka.extern.StateChange>
87
90
  * }}
@@ -112,6 +115,11 @@ shaka.extern.StateChange;
112
115
  * @property {number} estimatedBandwidth
113
116
  * The current estimated network bandwidth (in bit/sec).
114
117
  *
118
+ * @property {number} gapsJumped
119
+ * The total number of playback gaps jumped by the GapJumpingController.
120
+ * @property {number} stallsDetected
121
+ * The total number of playback stalls detected by the StallDetector.
122
+ *
115
123
  * @property {number} completionPercent
116
124
  * This is the greatest completion percent that the user has experienced in
117
125
  * playback. Also known as the "high water mark". Is NaN when there is no
@@ -623,7 +631,8 @@ shaka.extern.AdvancedDrmConfiguration;
623
631
  * undefined),
624
632
  * logLicenseExchange: boolean,
625
633
  * updateExpirationTime: number,
626
- * preferredKeySystems: !Array.<string>
634
+ * preferredKeySystems: !Array.<string>,
635
+ * keySystemsMapping: !Object.<string, string>
627
636
  * }}
628
637
  *
629
638
  * @property {shaka.extern.RetryParameters} retryParameters
@@ -664,6 +673,8 @@ shaka.extern.AdvancedDrmConfiguration;
664
673
  * @property {!Array.<string>} preferredKeySystems
665
674
  * <i>Defaults to an empty array. </i> <br>
666
675
  * Specifies the priorties of available DRM key systems.
676
+ * @property {Object.<string, string>} keySystemsMapping
677
+ * A map of key system name to key system name.
667
678
  *
668
679
  * @exportDoc
669
680
  */
@@ -766,8 +777,10 @@ shaka.extern.DashManifestConfiguration;
766
777
  * <i>Defaults to <code>'avc1.42E01E'</code>.</i>
767
778
  * @property {boolean} ignoreManifestProgramDateTime
768
779
  * If <code>true</code>, the HLS parser will ignore the
769
- * <code>EXT-X-PROGRAM-DATE-TIME</code> tags in the manifest.
770
- * Meant for tags that are incorrect or malformed.
780
+ * <code>EXT-X-PROGRAM-DATE-TIME</code> tags in the manifest and use media
781
+ * sequence numbers instead.
782
+ * Meant for streams where <code>EXT-X-PROGRAM-DATE-TIME</code> is incorrect
783
+ * or malformed.
771
784
  * <i>Defaults to <code>false</code>.</i>
772
785
  * @property {string} mediaPlaylistFullMimeType
773
786
  * A string containing a full mime type, including both the basic mime type
@@ -863,7 +876,8 @@ shaka.extern.ManifestConfiguration;
863
876
  * preferNativeHls: boolean,
864
877
  * updateIntervalSeconds: number,
865
878
  * dispatchAllEmsgBoxes: boolean,
866
- * observeQualityChanges: boolean
879
+ * observeQualityChanges: boolean,
880
+ * maxDisabledTime: number
867
881
  * }}
868
882
  *
869
883
  * @description
@@ -968,6 +982,10 @@ shaka.extern.ManifestConfiguration;
968
982
  * @property {boolean} observeQualityChanges
969
983
  * If true, monitor media quality changes and emit
970
984
  * <code.shaka.Player.MediaQualityChangedEvent</code>.
985
+ * @property {number} maxDisabledTime
986
+ * The maximum time a variant can be disabled when NETWORK HTTP_ERROR
987
+ * is reached, in seconds.
988
+ * If all variants are disabled this way, NETWORK HTTP_ERROR will be thrown.
971
989
  * @exportDoc
972
990
  */
973
991
  shaka.extern.StreamingConfiguration;
@@ -1264,11 +1282,14 @@ shaka.extern.Thumbnail;
1264
1282
 
1265
1283
  /**
1266
1284
  * @typedef {{
1285
+ * id: string,
1267
1286
  * title: string,
1268
1287
  * startTime: number,
1269
1288
  * endTime: number
1270
1289
  * }}
1271
1290
  *
1291
+ * @property {string} id
1292
+ * The id of the chapter.
1272
1293
  * @property {string} title
1273
1294
  * The title of the chapter.
1274
1295
  * @property {number} startTime
@@ -297,6 +297,13 @@ shaka.extern.Cue = class {
297
297
  */
298
298
  this.fontFamily;
299
299
 
300
+ /**
301
+ * Text shadow color as a CSS text-shadow value.
302
+ * @type {string}
303
+ * @exportDoc
304
+ */
305
+ this.textShadow = '';
306
+
300
307
  /**
301
308
  * Text stroke color as a CSS color, e.g. "#FFFFFF" or "white".
302
309
  * @type {string}
@@ -43,8 +43,11 @@ shaka.cast.CastProxy = class extends shaka.util.FakeEventTarget {
43
43
  * @param {string} receiverAppId The ID of the cast receiver application.
44
44
  * If blank, casting will not be available, but the proxy will still
45
45
  * function otherwise.
46
+ * @param {boolean} androidReceiverCompatible Indicates if the app is
47
+ * compatible with an Android Receiver.
46
48
  */
47
- constructor(video, player, receiverAppId) {
49
+ constructor(video, player, receiverAppId,
50
+ androidReceiverCompatible = false) {
48
51
  super();
49
52
 
50
53
  /** @private {HTMLMediaElement} */
@@ -71,6 +74,9 @@ shaka.cast.CastProxy = class extends shaka.util.FakeEventTarget {
71
74
  /** @private {string} */
72
75
  this.receiverAppId_ = receiverAppId;
73
76
 
77
+ /** @private {boolean} */
78
+ this.androidReceiverCompatible_ = androidReceiverCompatible;
79
+
74
80
  /** @private {!Map} */
75
81
  this.compiledToExternNames_ = new Map();
76
82
 
@@ -81,7 +87,8 @@ shaka.cast.CastProxy = class extends shaka.util.FakeEventTarget {
81
87
  () => this.onFirstCastStateUpdate_(),
82
88
  (targetName, event) => this.onRemoteEvent_(targetName, event),
83
89
  () => this.onResumeLocal_(),
84
- () => this.getInitState_());
90
+ () => this.getInitState_(),
91
+ androidReceiverCompatible);
85
92
 
86
93
 
87
94
  this.init_();
@@ -225,15 +232,18 @@ shaka.cast.CastProxy = class extends shaka.util.FakeEventTarget {
225
232
 
226
233
  /**
227
234
  * @param {string} newAppId
235
+ * @param {boolean=} newCastAndroidReceiver
228
236
  * @export
229
237
  */
230
- async changeReceiverId(newAppId) {
231
- if (newAppId == this.receiverAppId_) {
238
+ async changeReceiverId(newAppId, newCastAndroidReceiver = false) {
239
+ if (newAppId == this.receiverAppId_ &&
240
+ newCastAndroidReceiver == this.androidReceiverCompatible_) {
232
241
  // Nothing to change
233
242
  return;
234
243
  }
235
244
 
236
245
  this.receiverAppId_ = newAppId;
246
+ this.androidReceiverCompatible_ = newCastAndroidReceiver;
237
247
 
238
248
  // Destroy the old sender
239
249
  this.sender_.forceDisconnect();
@@ -248,7 +258,8 @@ shaka.cast.CastProxy = class extends shaka.util.FakeEventTarget {
248
258
  () => this.onFirstCastStateUpdate_(),
249
259
  (targetName, event) => this.onRemoteEvent_(targetName, event),
250
260
  () => this.onResumeLocal_(),
251
- () => this.getInitState_());
261
+ () => this.getInitState_(),
262
+ newCastAndroidReceiver);
252
263
 
253
264
  this.sender_.init();
254
265
  }
@@ -267,8 +278,8 @@ shaka.cast.CastProxy = class extends shaka.util.FakeEventTarget {
267
278
  (event) => this.videoProxyLocalEvent_(event));
268
279
  }
269
280
 
270
- for (const key in shaka.Player.EventName) {
271
- const name = shaka.Player.EventName[key];
281
+ for (const key in shaka.util.FakeEvent.EventName) {
282
+ const name = shaka.util.FakeEvent.EventName[key];
272
283
  this.eventManager_.listen(this.localPlayer_, name,
273
284
  (event) => this.playerProxyLocalEvent_(event));
274
285
  }
@@ -526,7 +537,7 @@ shaka.cast.CastProxy = class extends shaka.util.FakeEventTarget {
526
537
  // Pass any errors through to the app.
527
538
  goog.asserts.assert(error instanceof shaka.util.Error,
528
539
  'Wrong error type!');
529
- const eventType = shaka.Player.EventName.Error;
540
+ const eventType = shaka.util.FakeEvent.EventName.Error;
530
541
  const data = (new Map()).set('detail', error);
531
542
  const event = new shaka.util.FakeEvent(eventType, data);
532
543
  this.localPlayer_.dispatchEvent(event);
@@ -281,8 +281,8 @@ shaka.cast.CastReceiver = class extends shaka.util.FakeEventTarget {
281
281
  this.video_, name, (event) => this.proxyEvent_('video', event));
282
282
  }
283
283
 
284
- for (const key in shaka.Player.EventName) {
285
- const name = shaka.Player.EventName[key];
284
+ for (const key in shaka.util.FakeEvent.EventName) {
285
+ const name = shaka.util.FakeEvent.EventName[key];
286
286
  this.eventManager_.listen(
287
287
  this.player_, name, (event) => this.proxyEvent_('player', event));
288
288
  }
@@ -409,7 +409,7 @@ shaka.cast.CastReceiver = class extends shaka.util.FakeEventTarget {
409
409
  // Pass any errors through to the app.
410
410
  goog.asserts.assert(error instanceof shaka.util.Error,
411
411
  'Wrong error type!');
412
- const eventType = shaka.Player.EventName.Error;
412
+ const eventType = shaka.util.FakeEvent.EventName.Error;
413
413
  const data = (new Map()).set('detail', error);
414
414
  const event = new shaka.util.FakeEvent(eventType, data);
415
415
  // Only dispatch the event if the player still exists.
@@ -32,12 +32,18 @@ shaka.cast.CastSender = class {
32
32
  * should resume playback. Called before the cached remote state is wiped.
33
33
  * @param {function()} onInitStateRequired A callback to get local player's.
34
34
  * state. Invoked when casting is initiated from Chrome's cast button.
35
+ * @param {boolean} androidReceiverCompatible Indicates if the app is
36
+ * compatible with an Android Receiver.
35
37
  */
36
38
  constructor(receiverAppId, onStatusChanged, onFirstCastStateUpdate,
37
- onRemoteEvent, onResumeLocal, onInitStateRequired) {
39
+ onRemoteEvent, onResumeLocal, onInitStateRequired,
40
+ androidReceiverCompatible) {
38
41
  /** @private {string} */
39
42
  this.receiverAppId_ = receiverAppId;
40
43
 
44
+ /** @private {boolean} */
45
+ this.androidReceiverCompatible_ = androidReceiverCompatible;
46
+
41
47
  /** @private {shaka.util.Timer} */
42
48
  this.statusChangeTimer_ = new shaka.util.Timer(onStatusChanged);
43
49
 
@@ -211,7 +217,11 @@ shaka.cast.CastSender = class {
211
217
  // Use static versions of the API callbacks, since the ChromeCast API is
212
218
  // static. If we used local versions, we might end up retaining references
213
219
  // to destroyed players here.
214
- const sessionRequest = new chrome.cast.SessionRequest(this.receiverAppId_);
220
+ const sessionRequest = new chrome.cast.SessionRequest(this.receiverAppId_,
221
+ /* capabilities= */ [],
222
+ /* timeout= */ null,
223
+ this.androidReceiverCompatible_,
224
+ /* credentialsData= */null);
215
225
  const apiConfig = new chrome.cast.ApiConfig(sessionRequest,
216
226
  (session) => CastSender.onExistingSessionJoined_(session),
217
227
  (availability) => CastSender.onReceiverStatusChanged_(availability),