shaka-player 4.0.4 → 4.1.2

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 (79) hide show
  1. package/CHANGELOG.md +41 -34
  2. package/CONTRIBUTORS +1 -0
  3. package/demo/common/message_ids.js +1 -0
  4. package/demo/config.js +3 -1
  5. package/demo/locales/en.json +1 -0
  6. package/demo/locales/source.json +4 -0
  7. package/dist/demo.compiled.debug.js +4 -4
  8. package/dist/demo.compiled.debug.map +2 -2
  9. package/dist/demo.compiled.js +4 -4
  10. package/dist/demo.compiled.map +2 -2
  11. package/dist/deps.js +2 -2
  12. package/dist/locales.js +30 -30
  13. package/dist/receiver.compiled.debug.js +2 -2
  14. package/dist/receiver.compiled.debug.map +2 -2
  15. package/dist/receiver.compiled.js +2 -2
  16. package/dist/receiver.compiled.map +2 -2
  17. package/dist/shaka-player.compiled.d.ts +14 -8
  18. package/dist/shaka-player.compiled.debug.d.ts +14 -8
  19. package/dist/shaka-player.compiled.debug.externs.js +10 -2
  20. package/dist/shaka-player.compiled.debug.js +168 -160
  21. package/dist/shaka-player.compiled.debug.map +3 -3
  22. package/dist/shaka-player.compiled.externs.js +10 -2
  23. package/dist/shaka-player.compiled.js +767 -764
  24. package/dist/shaka-player.compiled.map +3 -3
  25. package/dist/shaka-player.ui.d.ts +15 -9
  26. package/dist/shaka-player.ui.debug.d.ts +15 -9
  27. package/dist/shaka-player.ui.debug.externs.js +10 -2
  28. package/dist/shaka-player.ui.debug.js +201 -189
  29. package/dist/shaka-player.ui.debug.map +3 -3
  30. package/dist/shaka-player.ui.externs.js +10 -2
  31. package/dist/shaka-player.ui.js +934 -931
  32. package/dist/shaka-player.ui.map +3 -3
  33. package/docs/design/chromecast.md +3 -1
  34. package/docs/tutorials/drm-config.md +16 -0
  35. package/docs/tutorials/ui.md +26 -0
  36. package/externs/chromecast.js +9 -2
  37. package/externs/shaka/manifest.js +7 -0
  38. package/externs/shaka/player.js +21 -2
  39. package/externs/shaka/text.js +7 -0
  40. package/lib/cast/cast_proxy.js +19 -8
  41. package/lib/cast/cast_receiver.js +3 -3
  42. package/lib/cast/cast_sender.js +12 -2
  43. package/lib/hls/hls_parser.js +12 -1
  44. package/lib/media/drm_engine.js +17 -8
  45. package/lib/media/gap_jumping_controller.js +23 -1
  46. package/lib/media/playhead.js +47 -4
  47. package/lib/media/stall_detector.js +19 -2
  48. package/lib/media/streaming_engine.js +8 -1
  49. package/lib/offline/manifest_converter.js +1 -0
  50. package/lib/player.js +175 -69
  51. package/lib/text/cue.js +6 -0
  52. package/lib/text/ui_text_displayer.js +1 -0
  53. package/lib/text/vtt_text_parser.js +4 -0
  54. package/lib/util/error.js +6 -0
  55. package/lib/util/fake_event.js +39 -0
  56. package/lib/util/player_configuration.js +2 -0
  57. package/lib/util/stats.js +28 -1
  58. package/lib/util/stream_utils.js +7 -0
  59. package/package.json +1 -1
  60. package/test/cast/cast_proxy_unit.js +3 -1
  61. package/test/cast/cast_sender_unit.js +21 -6
  62. package/test/demo/demo_unit.js +2 -1
  63. package/test/media/adaptation_set_unit.js +1 -0
  64. package/test/media/playhead_unit.js +114 -25
  65. package/test/media/stall_detector_unit.js +20 -2
  66. package/test/media/streaming_engine_integration.js +2 -1
  67. package/test/media/streaming_engine_unit.js +1 -0
  68. package/test/player_integration.js +3 -0
  69. package/test/player_unit.js +142 -1
  70. package/test/test/util/manifest_generator.js +2 -0
  71. package/test/test/util/simple_fakes.js +14 -0
  72. package/test/test/util/streaming_engine_util.js +1 -0
  73. package/test/text/vtt_text_parser_unit.js +4 -0
  74. package/test/ui/ui_unit.js +18 -5
  75. package/test/util/stream_utils_unit.js +108 -0
  76. package/ui/controls.js +12 -8
  77. package/ui/externs/ui.js +10 -1
  78. package/ui/statistics_button.js +10 -0
  79. package/ui/ui.js +12 -1
@@ -144,3 +144,42 @@ shaka.util.FakeEvent = class {
144
144
  */
145
145
  stopPropagation() {}
146
146
  };
147
+
148
+
149
+ /**
150
+ * An internal enum that contains the string values of all of the player events.
151
+ * This exists primarily to act as an implicit list of events, for tests.
152
+ *
153
+ * @enum {string}
154
+ */
155
+ shaka.util.FakeEvent.EventName = {
156
+ AbrStatusChanged: 'abrstatuschanged',
157
+ Adaptation: 'adaptation',
158
+ Buffering: 'buffering',
159
+ DownloadFailed: 'downloadfailed',
160
+ DownloadHeadersReceived: 'downloadheadersreceived',
161
+ DrmSessionUpdate: 'drmsessionupdate',
162
+ Emsg: 'emsg',
163
+ Error: 'error',
164
+ ExpirationUpdated: 'expirationupdated',
165
+ GapJumped: 'gapjumped',
166
+ Loaded: 'loaded',
167
+ Loading: 'loading',
168
+ ManifestParsed: 'manifestparsed',
169
+ MediaQualityChanged: 'mediaqualitychanged',
170
+ Metadata: 'metadata',
171
+ OnStateChange: 'onstatechange',
172
+ OnStateIdle: 'onstateidle',
173
+ RateChange: 'ratechange',
174
+ SessionDataEvent: 'sessiondata',
175
+ StallDetected: 'stalldetected',
176
+ Streaming: 'streaming',
177
+ TextChanged: 'textchanged',
178
+ TextTrackVisibility: 'texttrackvisibility',
179
+ TimelineRegionAdded: 'timelineregionadded',
180
+ TimelineRegionEnter: 'timelineregionenter',
181
+ TimelineRegionExit: 'timelineregionexit',
182
+ TracksChanged: 'trackschanged',
183
+ Unloading: 'unloading',
184
+ VariantChanged: 'variantchanged',
185
+ };
@@ -74,6 +74,7 @@ shaka.util.PlayerConfiguration = class {
74
74
  logLicenseExchange: false,
75
75
  updateExpirationTime: 1,
76
76
  preferredKeySystems: [],
77
+ keySystemsMapping: {},
77
78
  };
78
79
 
79
80
  const manifest = {
@@ -169,6 +170,7 @@ shaka.util.PlayerConfiguration = class {
169
170
  updateIntervalSeconds: 1,
170
171
  dispatchAllEmsgBoxes: false,
171
172
  observeQualityChanges: false,
173
+ maxDisabledTime: 30,
172
174
  };
173
175
 
174
176
  // Some browsers will stop earlier than others before a gap (e.g., Edge
package/lib/util/stats.js CHANGED
@@ -31,6 +31,11 @@ shaka.util.Stats = class {
31
31
  /** @private {number} */
32
32
  this.totalCorruptedFrames_ = NaN;
33
33
 
34
+ /** @private {number} */
35
+ this.totalStallsDetected_ = NaN;
36
+ /** @private {number} */
37
+ this.totalGapsJumped_ = NaN;
38
+
34
39
  /** @private {number} */
35
40
  this.completionPercent_ = NaN;
36
41
 
@@ -76,7 +81,6 @@ shaka.util.Stats = class {
76
81
  this.totalDecodedFrames_ = decoded;
77
82
  }
78
83
 
79
-
80
84
  /**
81
85
  * Update corrupted frames. This will replace the previous values.
82
86
  *
@@ -86,6 +90,25 @@ shaka.util.Stats = class {
86
90
  this.totalCorruptedFrames_ = corrupted;
87
91
  }
88
92
 
93
+ /**
94
+ * Update number of stalls detected. This will replace the previous value.
95
+ *
96
+ * @param {number} stallsDetected
97
+ */
98
+ setStallsDetected(stallsDetected) {
99
+ this.totalStallsDetected_ = stallsDetected;
100
+ }
101
+
102
+ /**
103
+ * Update number of playback gaps jumped over. This will replace the previous
104
+ * value.
105
+ *
106
+ * @param {number} gapsJumped
107
+ */
108
+ setGapsJumped(gapsJumped) {
109
+ this.totalGapsJumped_ = gapsJumped;
110
+ }
111
+
89
112
  /**
90
113
  * Set the width and height of the video we are currently playing.
91
114
  *
@@ -208,6 +231,8 @@ shaka.util.Stats = class {
208
231
  decodedFrames: this.totalDecodedFrames_,
209
232
  droppedFrames: this.totalDroppedFrames_,
210
233
  corruptedFrames: this.totalCorruptedFrames_,
234
+ stallsDetected: this.totalStallsDetected_,
235
+ gapsJumped: this.totalGapsJumped_,
211
236
  estimatedBandwidth: this.bandwidthEstimate_,
212
237
  completionPercent: this.completionPercent_,
213
238
  loadLatency: this.loadLatencySeconds_,
@@ -238,6 +263,8 @@ shaka.util.Stats = class {
238
263
  decodedFrames: NaN,
239
264
  droppedFrames: NaN,
240
265
  corruptedFrames: NaN,
266
+ stallsDetected: NaN,
267
+ gapsJumped: NaN,
241
268
  estimatedBandwidth: NaN,
242
269
  completionPercent: NaN,
243
270
  loadLatency: NaN,
@@ -329,6 +329,13 @@ shaka.util.StreamUtils = class {
329
329
 
330
330
  const video = variant.video;
331
331
 
332
+ if (variant.disabledUntilTime != 0) {
333
+ if (variant.disabledUntilTime > Date.now() / 1000) {
334
+ return false;
335
+ }
336
+ variant.disabledUntilTime = 0;
337
+ }
338
+
332
339
  // |video.width| and |video.height| can be undefined, which breaks
333
340
  // the math, so make sure they are there first.
334
341
  if (video && video.width && video.height) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "shaka-player",
3
3
  "description": "DASH/EME video player library",
4
- "version": "4.0.4",
4
+ "version": "4.1.2",
5
5
  "homepage": "https://github.com/shaka-project/shaka-player",
6
6
  "author": "Google",
7
7
  "maintainers": [
@@ -11,6 +11,7 @@ describe('CastProxy', () => {
11
11
 
12
12
  const originalCastSender = shaka.cast.CastSender;
13
13
  const fakeAppId = 'fake app ID';
14
+ const fakeAndroidReceiverCompatible = false;
14
15
 
15
16
  let mockPlayer;
16
17
  let mockSender;
@@ -31,7 +32,8 @@ describe('CastProxy', () => {
31
32
  mockPlayer = createMockPlayer();
32
33
  mockSender = null;
33
34
 
34
- proxy = new CastProxy(mockVideo, mockPlayer, fakeAppId);
35
+ proxy = new CastProxy(mockVideo, mockPlayer, fakeAppId,
36
+ fakeAndroidReceiverCompatible);
35
37
  });
36
38
 
37
39
  afterEach(async () => {
@@ -13,6 +13,7 @@ describe('CastSender', () => {
13
13
  const originalStatusDelay = shaka.cast.CastSender.STATUS_DELAY;
14
14
 
15
15
  const fakeAppId = 'asdf';
16
+ const fakeAndroidReceiverCompatible = false;
16
17
  const fakeInitState = {
17
18
  manifest: null,
18
19
  player: null,
@@ -52,7 +53,8 @@ describe('CastSender', () => {
52
53
  sender = new CastSender(
53
54
  fakeAppId, Util.spyFunc(onStatusChanged),
54
55
  Util.spyFunc(onFirstCastStateUpdate), Util.spyFunc(onRemoteEvent),
55
- Util.spyFunc(onResumeLocal), Util.spyFunc(onInitStateRequired));
56
+ Util.spyFunc(onResumeLocal), Util.spyFunc(onInitStateRequired),
57
+ fakeAndroidReceiverCompatible);
56
58
  });
57
59
 
58
60
  afterEach(async () => {
@@ -87,7 +89,12 @@ describe('CastSender', () => {
87
89
  expect(sender.apiReady()).toBe(true);
88
90
  expect(sender.hasReceivers()).toBe(false);
89
91
  expect(onStatusChanged).toHaveBeenCalled();
90
- expect(mockCastApi.SessionRequest).toHaveBeenCalledWith(fakeAppId);
92
+ expect(mockCastApi.SessionRequest).toHaveBeenCalledWith(
93
+ fakeAppId,
94
+ /* capabilities= */ [],
95
+ /* timeout= */ null,
96
+ fakeAndroidReceiverCompatible,
97
+ /* credentialsData= */ null);
91
98
  expect(mockCastApi.initialize).toHaveBeenCalled();
92
99
  });
93
100
 
@@ -97,7 +104,12 @@ describe('CastSender', () => {
97
104
  expect(sender.apiReady()).toBe(true);
98
105
  expect(sender.hasReceivers()).toBe(false);
99
106
  expect(onStatusChanged).toHaveBeenCalled();
100
- expect(mockCastApi.SessionRequest).toHaveBeenCalledWith(fakeAppId);
107
+ expect(mockCastApi.SessionRequest).toHaveBeenCalledWith(
108
+ fakeAppId,
109
+ /* capabilities= */ [],
110
+ /* timeout= */ null,
111
+ fakeAndroidReceiverCompatible,
112
+ /* credentialsData= */ null);
101
113
  expect(mockCastApi.initialize).toHaveBeenCalled();
102
114
  });
103
115
  });
@@ -122,7 +134,8 @@ describe('CastSender', () => {
122
134
  sender = new CastSender(
123
135
  fakeAppId, Util.spyFunc(onStatusChanged),
124
136
  Util.spyFunc(onFirstCastStateUpdate), Util.spyFunc(onRemoteEvent),
125
- Util.spyFunc(onResumeLocal), Util.spyFunc(onInitStateRequired));
137
+ Util.spyFunc(onResumeLocal), Util.spyFunc(onInitStateRequired),
138
+ /* androidReceiverCompatible= */ false);
126
139
  sender.init();
127
140
  // You get an initial call to onStatusChanged when it initializes.
128
141
  expect(onStatusChanged).toHaveBeenCalledTimes(3);
@@ -256,7 +269,8 @@ describe('CastSender', () => {
256
269
  sender = new CastSender(
257
270
  fakeAppId, Util.spyFunc(onStatusChanged),
258
271
  Util.spyFunc(onFirstCastStateUpdate), Util.spyFunc(onRemoteEvent),
259
- Util.spyFunc(onResumeLocal), Util.spyFunc(onInitStateRequired));
272
+ Util.spyFunc(onResumeLocal), Util.spyFunc(onInitStateRequired),
273
+ /* androidReceiverCompatible= */ false);
260
274
  sender.init();
261
275
 
262
276
  // The sender should automatically rejoin the session, without needing
@@ -288,7 +302,8 @@ describe('CastSender', () => {
288
302
  sender = new CastSender(
289
303
  fakeAppId, Util.spyFunc(onStatusChanged),
290
304
  Util.spyFunc(onFirstCastStateUpdate), Util.spyFunc(onRemoteEvent),
291
- Util.spyFunc(onResumeLocal), Util.spyFunc(onInitStateRequired));
305
+ Util.spyFunc(onResumeLocal), Util.spyFunc(onInitStateRequired),
306
+ /* androidReceiverCompatible= */ false);
292
307
  sender.init();
293
308
 
294
309
  expect(sender.isCasting()).toBe(false);
@@ -94,7 +94,8 @@ describe('Demo', () => {
94
94
  .add('playRangeStart')
95
95
  .add('playRangeEnd')
96
96
  .add('manifest.dash.keySystemsByURI')
97
- .add('manifest.hls.mediaPlaylistFullMimeType');
97
+ .add('manifest.hls.mediaPlaylistFullMimeType')
98
+ .add('drm.keySystemsMapping');
98
99
 
99
100
  /**
100
101
  * @param {!Object} section
@@ -179,6 +179,7 @@ describe('AdaptationSet', () => {
179
179
  audio: audio,
180
180
  bandwidth: 1024,
181
181
  id: id,
182
+ disabledUntilTime: 0,
182
183
  language: '',
183
184
  primary: false,
184
185
  video: video,