shaka-player 2.5.1 → 2.5.5

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 (166) hide show
  1. package/.csslintrc +13 -0
  2. package/AUTHORS +3 -0
  3. package/CHANGELOG.md +156 -0
  4. package/CONTRIBUTORS +3 -0
  5. package/README.md +3 -0
  6. package/build/README.md +5 -5
  7. package/build/apps.py +3 -1
  8. package/build/build.py +5 -2
  9. package/build/check.py +17 -0
  10. package/build/compiler.py +49 -0
  11. package/build/conformance.textproto +1 -0
  12. package/build/docs.py +0 -6
  13. package/build/generateExterns.js +72 -20
  14. package/build/install-linux-prereqs.sh +4 -4
  15. package/build/shakaBuildHelpers.py +7 -8
  16. package/build/test.py +21 -9
  17. package/build/types/core +1 -0
  18. package/build/types/ui +6 -1
  19. package/demo/asset_card.js +129 -41
  20. package/demo/cast_receiver/receiver_app.css +27 -13
  21. package/demo/close_button.js +10 -15
  22. package/demo/common/asset.js +6 -6
  23. package/demo/common/assets.js +72 -14
  24. package/demo/config.js +28 -25
  25. package/demo/custom.js +20 -16
  26. package/demo/demo.less +107 -16
  27. package/demo/demo_uncompiled.js +33 -0
  28. package/demo/demo_utils.js +4 -3
  29. package/demo/front.js +12 -8
  30. package/demo/index.html +14 -17
  31. package/demo/input.js +30 -23
  32. package/demo/input_container.js +15 -11
  33. package/demo/load.js +5 -7
  34. package/demo/main.js +138 -49
  35. package/demo/search.js +40 -36
  36. package/demo/service_worker.js +1 -1
  37. package/demo/tooltip.js +16 -24
  38. package/dist/.csslintstamp +0 -0
  39. package/dist/controls.css +1 -1
  40. package/dist/controls.css.map +1 -1
  41. package/dist/demo.compiled.debug.js +165 -152
  42. package/dist/demo.compiled.debug.map +4 -4
  43. package/dist/demo.compiled.js +165 -152
  44. package/dist/demo.compiled.map +4 -4
  45. package/dist/demo.css +1 -1
  46. package/dist/demo.css.map +1 -1
  47. package/dist/deps.js +28 -11
  48. package/dist/receiver.compiled.debug.js +11 -11
  49. package/dist/receiver.compiled.debug.map +3 -3
  50. package/dist/receiver.compiled.js +11 -11
  51. package/dist/receiver.compiled.map +3 -3
  52. package/dist/shaka-player.compiled.debug.externs.js +232 -102
  53. package/dist/shaka-player.compiled.debug.js +189 -165
  54. package/dist/shaka-player.compiled.debug.map +4 -4
  55. package/dist/shaka-player.compiled.externs.js +232 -102
  56. package/dist/shaka-player.compiled.js +567 -553
  57. package/dist/shaka-player.compiled.map +4 -4
  58. package/dist/shaka-player.ui.debug.externs.js +338 -113
  59. package/dist/shaka-player.ui.debug.js +296 -276
  60. package/dist/shaka-player.ui.debug.map +4 -4
  61. package/dist/shaka-player.ui.externs.js +338 -113
  62. package/dist/shaka-player.ui.js +685 -671
  63. package/dist/shaka-player.ui.map +4 -4
  64. package/docs/tutorials/drm-config.md +1 -0
  65. package/docs/tutorials/fairplay.md +77 -0
  66. package/docs/tutorials/index.json +1 -0
  67. package/docs/tutorials/manifest-parser.md +1 -1
  68. package/docs/tutorials/ui-customization.md +5 -2
  69. package/docs/tutorials/ui.md +10 -4
  70. package/docs/tutorials/welcome.md +2 -2
  71. package/externs/mediasession.js +16 -1
  72. package/externs/shaka/net.js +14 -4
  73. package/externs/shaka/player.js +136 -90
  74. package/externs/tippy.js +30 -0
  75. package/externs/webkitmediakeys.js +4 -0
  76. package/karma.conf.js +30 -24
  77. package/lib/cast/cast_proxy.js +94 -23
  78. package/lib/cast/cast_receiver.js +8 -1
  79. package/lib/dash/content_protection.js +33 -1
  80. package/lib/dash/dash_parser.js +13 -5
  81. package/lib/hls/hls_parser.js +20 -4
  82. package/lib/media/drm_engine.js +29 -2
  83. package/lib/media/media_source_engine.js +9 -6
  84. package/lib/media/play_rate_controller.js +14 -3
  85. package/lib/media/playhead.js +8 -3
  86. package/lib/media/streaming_engine.js +68 -20
  87. package/lib/media/transmuxer.js +2 -2
  88. package/lib/media/video_wrapper.js +8 -3
  89. package/lib/net/data_uri_plugin.js +5 -2
  90. package/lib/net/http_fetch_plugin.js +3 -3
  91. package/lib/net/http_plugin_utils.js +2 -4
  92. package/lib/net/http_xhr_plugin.js +2 -2
  93. package/lib/net/networking_engine.js +1 -0
  94. package/lib/offline/offline_scheme.js +7 -2
  95. package/lib/player.js +18 -8
  96. package/lib/polyfill/input_event.js +7 -11
  97. package/lib/polyfill/mediasource.js +1 -1
  98. package/lib/polyfill/patchedmediakeys_apple.js +2 -72
  99. package/lib/text/cue.js +1 -1
  100. package/lib/text/ttml_text_parser.js +1 -1
  101. package/lib/util/config_utils.js +1 -0
  102. package/lib/util/error.js +45 -11
  103. package/lib/util/event_manager.js +211 -100
  104. package/lib/util/fairplay_utils.js +122 -0
  105. package/lib/util/i_releasable.js +1 -0
  106. package/lib/util/player_configuration.js +7 -0
  107. package/lib/util/pssh.js +41 -0
  108. package/lib/util/string_utils.js +42 -6
  109. package/lib/util/timer.js +1 -1
  110. package/package.json +33 -33
  111. package/roadmap.md +96 -0
  112. package/shaka-player.uncompiled.js +5 -1
  113. package/test/dash/dash_parser_content_protection_unit.js +35 -1
  114. package/test/dash/dash_parser_manifest_unit.js +60 -0
  115. package/test/hls/hls_live_unit.js +7 -1
  116. package/test/hls/hls_parser_unit.js +50 -0
  117. package/test/media/drm_engine_unit.js +10 -4
  118. package/test/media/media_source_engine_integration.js +12 -0
  119. package/test/media/media_source_engine_unit.js +3 -1
  120. package/test/media/playhead_unit.js +7 -5
  121. package/test/media/streaming_engine_unit.js +46 -1
  122. package/test/media/transmuxer_integration.js +13 -0
  123. package/test/net/data_uri_plugin_unit.js +13 -2
  124. package/test/net/http_plugin_unit.js +17 -12
  125. package/test/net/networking_engine_unit.js +17 -8
  126. package/test/offline/offline_scheme_unit.js +18 -8
  127. package/test/player_external.js +3 -2
  128. package/test/player_integration.js +94 -3
  129. package/test/player_src_equals_integration.js +2 -2
  130. package/test/player_unit.js +21 -8
  131. package/test/test/boot.js +20 -5
  132. package/test/test/externs/jasmine.js +48 -0
  133. package/test/test/util/expect_async_polyfill.js +145 -0
  134. package/test/test/util/fake_networking_engine.js +1 -0
  135. package/test/test/util/manifest_generator.js +2 -1
  136. package/test/test/util/test_scheme.js +34 -2
  137. package/test/test/util/ui_utils.js +41 -0
  138. package/test/test/util/util.js +16 -8
  139. package/test/ui/ui_unit.js +130 -4
  140. package/ui/audio_language_selection.js +17 -96
  141. package/ui/big_play_button.js +61 -0
  142. package/ui/controls.js +226 -335
  143. package/ui/controls.less +3 -5
  144. package/ui/element.js +24 -6
  145. package/ui/externs/ui.js +62 -9
  146. package/ui/fullscreen_button.js +2 -52
  147. package/ui/less/buttons.less +10 -16
  148. package/ui/less/containers.less +75 -20
  149. package/ui/less/general.less +18 -2
  150. package/ui/less/other_elements.less +2 -1
  151. package/ui/less/overflow_menu.less +11 -10
  152. package/ui/less/range_elements.less +12 -10
  153. package/ui/less/spinner.less +2 -0
  154. package/ui/overflow_menu.js +1 -1
  155. package/ui/pip_button.js +1 -1
  156. package/ui/{play_pause_button.js → play_button.js} +17 -47
  157. package/ui/presentation_time.js +17 -12
  158. package/ui/range_element.js +176 -0
  159. package/ui/resolution_selection.js +43 -106
  160. package/ui/seek_bar.js +204 -0
  161. package/ui/settings_menu.js +113 -0
  162. package/ui/small_play_button.js +73 -0
  163. package/ui/text_displayer.js +17 -14
  164. package/ui/text_selection.js +42 -107
  165. package/ui/ui.js +17 -40
  166. package/ui/volume_bar.js +40 -68
@@ -17,6 +17,7 @@
17
17
 
18
18
  goog.provide('shaka.util.StringUtils');
19
19
 
20
+ goog.require('goog.asserts');
20
21
  goog.require('shaka.log');
21
22
  goog.require('shaka.util.Error');
22
23
 
@@ -212,12 +213,47 @@ shaka.util.StringUtils.toUTF16 = function(str, littleEndian) {
212
213
  * @return {string}
213
214
  */
214
215
  shaka.util.StringUtils.fromCharCode = function(array) {
215
- let max = 16000;
216
- let ret = '';
217
- for (let i = 0; i < array.length; i += max) {
218
- let subArray = array.subarray(i, i + max);
219
- ret += String.fromCharCode.apply(null, subArray);
216
+ // Check the browser for what chunk sizes it supports. Cache the result
217
+ // in an impl method to avoid checking several times.
218
+ if (!shaka.util.StringUtils.fromCharCodeImpl_) {
219
+ const supportsChunkSize = (size) => {
220
+ try {
221
+ const buffer = new Uint8Array(size);
222
+ // The compiler will complain about suspicious value if this isn't
223
+ // stored in a variable and used.
224
+ const foo = String.fromCharCode(...buffer);
225
+ goog.asserts.assert(foo, 'Should get value');
226
+ return true;
227
+ } catch (error) {
228
+ return false;
229
+ }
230
+ };
231
+
232
+ // Different browsers support different chunk sizes; find out the largest
233
+ // this browser supports so we can use larger chunks on supported browsers
234
+ // but still support lower-end devices that require small chunks.
235
+ // 64k is supported on all major desktop browsers.
236
+ for (let size = 64 * 1024; size > 0; size /= 2) {
237
+ if (supportsChunkSize(size)) {
238
+ shaka.util.StringUtils.fromCharCodeImpl_ = (buffer) => {
239
+ let ret = '';
240
+ for (let i = 0; i < buffer.length; i += size) {
241
+ const subArray = buffer.subarray(i, i + size);
242
+ ret += String.fromCharCode(...subArray);
243
+ }
244
+ return ret;
245
+ };
246
+ break;
247
+ }
248
+ }
220
249
  }
221
250
 
222
- return ret;
251
+ goog.asserts.assert(
252
+ shaka.util.StringUtils.fromCharCodeImpl_,
253
+ 'Unable to create a fromCharCode method');
254
+ return shaka.util.StringUtils.fromCharCodeImpl_(array);
223
255
  };
256
+
257
+
258
+ /** @private {?function(!TypedArray):string} */
259
+ shaka.util.StringUtils.fromCharCodeImpl_ = null;
package/lib/util/timer.js CHANGED
@@ -62,7 +62,7 @@ shaka.util.Timer = class {
62
62
  }
63
63
 
64
64
  /**
65
- * Have the timer call |onTick| after |seconds| has elasped unless |stop| is
65
+ * Have the timer call |onTick| after |seconds| has elapsed unless |stop| is
66
66
  * called first.
67
67
  *
68
68
  * @param {number} seconds
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": "2.5.1",
4
+ "version": "2.5.5",
5
5
  "homepage": "https://github.com/google/shaka-player",
6
6
  "author": "Google",
7
7
  "maintainers": [
@@ -11,47 +11,47 @@
11
11
  }
12
12
  ],
13
13
  "devDependencies": {
14
- "array-includes": "~3.0.3",
15
- "awesomplete": "~1.1.1",
16
- "babel-core": "^6.26.0",
14
+ "awesomplete": "^1.1.4",
15
+ "babel-core": "^6.26.3",
16
+ "babel-plugin-istanbul": "^4.1.6",
17
17
  "babel-polyfill": "^6.26.0",
18
- "babel-preset-env": "^1.6.1",
18
+ "babel-preset-env": "^1.7.0",
19
19
  "cajon": "^0.4.4",
20
- "dialog-polyfill": "^0.4.10",
20
+ "dialog-polyfill": "^0.5.0",
21
21
  "es6-promise-polyfill": "^1.2.0",
22
- "es6-shim": "~0.35.3",
23
- "eslint": "^4.14.0",
22
+ "eslint": "^5.16.0",
24
23
  "eslint-config-google": "^0.9.1",
25
- "esprima": "^4.0.0",
26
- "htmlhint": "yaniswang/HTMLHint#152a114f",
27
- "in-publish": "~2.0.0",
28
- "jasmine-ajax": "~3.3.1",
24
+ "esprima": "^4.0.1",
25
+ "htmlhint": "^0.11.0",
26
+ "jasmine-ajax": "^3.3.1",
29
27
  "jasmine-core": "^2.8.0",
30
- "jsdoc": "joeyparrish/jsdoc#c2fe066a",
31
- "karma": "~1.6.0",
28
+ "jsdoc": "github:joeyparrish/jsdoc#45c271fa",
29
+ "karma": "^4.1.0",
32
30
  "karma-babel-preprocessor": "^7.0.0",
33
- "karma-chrome-launcher": "~2.0.0",
34
- "karma-coverage": "~1.1.1",
35
- "karma-edge-launcher": "~0.4.1",
36
- "karma-firefox-launcher": "~1.0.1",
37
- "karma-ie-launcher": "~1.0.0",
38
- "karma-jasmine": "~1.1.0",
39
- "karma-jasmine-ajax": "~0.1.13",
40
- "karma-opera-launcher": "~1.0.0",
41
- "karma-safari-launcher": "~1.0.0",
42
- "karma-source-map-support": "^1.2.0",
43
- "karma-spec-reporter": "~0.0.31",
44
- "karma-webdriver-launcher": "~1.0.5",
45
- "less": "^3.8.1",
31
+ "karma-chrome-launcher": "^2.2.0",
32
+ "karma-coverage": "^1.1.2",
33
+ "karma-edge-launcher": "^0.4.2",
34
+ "karma-firefox-launcher": "^1.1.0",
35
+ "karma-ie-launcher": "^1.0.0",
36
+ "karma-jasmine": "^1.1.0",
37
+ "karma-jasmine-ajax": "^0.1.13",
38
+ "karma-opera-launcher": "^1.0.0",
39
+ "karma-safari-launcher": "^1.0.0",
40
+ "karma-sourcemap-loader": "^0.3.7",
41
+ "karma-spec-reporter": "0.0.32",
42
+ "karma-webdriver-launcher": "^1.0.7",
43
+ "less": "^3.9.0",
46
44
  "less-plugin-clean-css": "^1.5.1",
47
45
  "material-design-lite": "^1.3.0",
48
46
  "mux.js": "^5.1.3",
49
47
  "promise-mock": "^2.1.0",
50
- "rimraf": "~2.6.1",
51
- "sprintf-js": "~1.0.3",
52
- "useragent": "~2.1.13",
53
- "wd": "^1.8.0 <1.11.0",
54
- "which": "~1.3.0"
48
+ "promise-polyfill": "<8.1.1",
49
+ "rimraf": "^2.6.3",
50
+ "sprintf-js": "^1.1.2",
51
+ "stylelint": "github:theodab/stylelint",
52
+ "stylelint-config-standard": "^18.3.0",
53
+ "tippy.js": "^4.3.1",
54
+ "which": "^1.3.1"
55
55
  },
56
56
  "main": "dist/shaka-player.compiled.js",
57
57
  "repository": {
@@ -63,6 +63,6 @@
63
63
  },
64
64
  "license": "Apache-2.0",
65
65
  "scripts": {
66
- "prepublish": "in-publish && python build/checkversion.py && python build/all.py --force || not-in-publish"
66
+ "prepublishOnly": "python build/checkversion.py && python build/all.py --force"
67
67
  }
68
68
  }
package/roadmap.md ADDED
@@ -0,0 +1,96 @@
1
+ # Shaka Player Roadmap
2
+
3
+ This doc shows all past and planned future milestones for Shaka Player, with
4
+ brief details about the goals and rough dates of each milestone. This is not a
5
+ comprehensive list of features or fixes for each release. For that, see
6
+ CHANGELOG.md.
7
+
8
+ The goals of future milestones are fluid until we begin that development cycle,
9
+ so the exact milestone for future features is not pre-determined.
10
+
11
+ Candidate features for future release cycles
12
+ - HLS discontinuity support
13
+ - Low-latency live (LHLS, equivalent for DASH)
14
+ - MediaCapabilities to make performance-based decisions
15
+ - Codec-switching
16
+ - Background fetch for offline storage
17
+ - Preload API
18
+ - Thumbnail tracks
19
+ - Own CEA parser, use mux.js only for TS
20
+ - Smaller, more modular binary
21
+ - IMA SDK ad integration demo
22
+ - Ad controls in the UI
23
+
24
+ v2.6 - 2019 Q3 (estimated)
25
+ - Code health release
26
+ - Finish conversion to ES6
27
+ - Isolate DASH periods to the DASH parser
28
+
29
+ =====
30
+
31
+ v2.5 - 2019 Q2
32
+ - Video controls UI API
33
+ - FairPlay & iOS support
34
+ - CEA captions in HLS/CMAF and DASH w/ mux.js
35
+ - Single-file playback
36
+ - DASH drift tolerance
37
+
38
+ v2.4 - 2018 Q2
39
+ - TTML and VTT regions
40
+ - CEA captions in HLS/TS
41
+ - Attach/detach API
42
+
43
+ v2.3 - 2017 Q4
44
+ - HLS live
45
+ - Transmux TS w/ mux.js
46
+ - NetworkInformation API to improve bandwidth estimates
47
+ - ES6 transition begins
48
+
49
+ v2.2 - 2017 Q3
50
+ - HLS event-type playlists
51
+ - TextDisplayer interface
52
+ - DASH xlink support
53
+
54
+ v2.1 - 2017 Q2
55
+ - HLS VOD, clear & Widevine only, no CEA
56
+ - DASH trick mode tracks
57
+ - Async network filters
58
+
59
+ v2.0 - 2016 Q3
60
+ - Multi-period DASH
61
+ - Chromecast API
62
+ - TTML, VTT-in-MP4, and TTML-in-MP4
63
+ - Safari, Firefox, & Opera support
64
+ - Plugin system (manifest parsers, network filters, text parsers)
65
+ - DASH emsg box support
66
+ - DASH IPR support
67
+
68
+ v1.6 - 2015 Q4
69
+ - IE11, Edge, & PlayReady support
70
+ - Chromecast added to demo app
71
+
72
+ v1.5 - 2015 Q3
73
+ - Unified configuration system
74
+ - Multiple DASH BaseURL elements for failover
75
+ - Side-loaded text streams
76
+
77
+ v1.4 - 2015 Q3
78
+ - Code health release
79
+ - DASH Location element support
80
+ - Buffering config API
81
+ - License preprocessing API
82
+
83
+ v1.3 - 2015 Q2
84
+ - DASH live
85
+ - Offline playback
86
+
87
+ v1.2 - 2015 Q1
88
+ - DASH Role element support
89
+
90
+ v1.1 - 2015 Q1
91
+ - EME API updates
92
+
93
+ v1.0 - 2014 Q4
94
+ - DASH VOD (MP4 & WebM)
95
+ - VTT subtitles, rendered by the browser
96
+ - Widevine support
@@ -64,8 +64,11 @@ goog.require('shaka.text.TextEngine');
64
64
  goog.require('shaka.text.TtmlTextParser');
65
65
  goog.require('shaka.text.VttTextParser');
66
66
  goog.require('shaka.ui.Controls');
67
+ goog.require('shaka.ui.PlayButton');
68
+ goog.require('shaka.ui.SettingsMenu');
67
69
  goog.require('shaka.ui.OverflowMenu');
68
70
  goog.require('shaka.ui.AudioLanguageSelection');
71
+ goog.require('shaka.ui.BigPlayButton');
69
72
  goog.require('shaka.ui.CastButton');
70
73
  goog.require('shaka.ui.Element');
71
74
  goog.require('shaka.ui.FastForwardButton');
@@ -74,7 +77,7 @@ goog.require('shaka.ui.Localization');
74
77
  goog.require('shaka.ui.MuteButton');
75
78
  goog.require('shaka.ui.Overlay');
76
79
  goog.require('shaka.ui.PipButton');
77
- goog.require('shaka.ui.PlayPauseButton');
80
+ goog.require('shaka.ui.SmallPlayButton');
78
81
  goog.require('shaka.ui.PresentationTimeTracker');
79
82
  goog.require('shaka.ui.ResolutionSelection');
80
83
  goog.require('shaka.ui.RewindButton');
@@ -83,4 +86,5 @@ goog.require('shaka.ui.TextSelection');
83
86
  goog.require('shaka.ui.VolumeBar');
84
87
  goog.require('shaka.util.Dom');
85
88
  goog.require('shaka.util.Error');
89
+ goog.require('shaka.util.FairPlayUtils');
86
90
  goog.require('shaka.util.Iterables');
@@ -68,7 +68,8 @@ describe('DashParser ContentProtection', function() {
68
68
  adaptationSetLines, representation1Lines, representation2Lines) {
69
69
  let template = [
70
70
  '<MPD xmlns="urn:mpeg:DASH:schema:MPD:2011"',
71
- ' xmlns:cenc="urn:mpeg:cenc:2013">',
71
+ ' xmlns:cenc="urn:mpeg:cenc:2013"',
72
+ ' xmlns:mspr="urn:microsoft:playready">',
72
73
  ' <Period duration="PT30S">',
73
74
  ' <SegmentTemplate media="s.mp4" duration="2" />',
74
75
  ' <AdaptationSet mimeType="video/mp4" codecs="avc1.4d401f">',
@@ -298,6 +299,39 @@ describe('DashParser ContentProtection', function() {
298
299
  await testDashParser(source, expected);
299
300
  });
300
301
 
302
+ it('extracts embedded PSSHs with mspr:pro', async () => {
303
+ const source = buildManifestText([
304
+ // AdaptationSet lines
305
+ '<ContentProtection',
306
+ ' schemeIdUri="urn:uuid:9a04f079-9840-4286-ab92-e65be0885f95">',
307
+ ' <mspr:pro>UGxheXJlYWR5</mspr:pro>',
308
+ '</ContentProtection>',
309
+ ], [], []);
310
+ const expected = buildExpectedManifest([
311
+ buildDrmInfo('com.microsoft.playready', [], [
312
+ 'AAAAKXBzc2gAAAAAmgTweZhAQoarkuZb4IhflQAAAAlQbGF5cmVhZHk=',
313
+ ]),
314
+ ]);
315
+ await testDashParser(source, expected);
316
+ });
317
+
318
+ it('extracts embedded PSSHs and prefer cenc:pssh over mspr:pro', async () => {
319
+ const source = buildManifestText([
320
+ // AdaptationSet lines
321
+ '<ContentProtection',
322
+ ' schemeIdUri="urn:uuid:9a04f079-9840-4286-ab92-e65be0885f95">',
323
+ ' <cenc:pssh>bm8gaHVtYW4gY2FuIHJlYWQgYmFzZTY0IGRpcmVjdGx5</cenc:pssh>',
324
+ ' <mspr:pro>ZmFrZSBQbGF5cmVhZHkgUFJP</mspr:pro>',
325
+ '</ContentProtection>',
326
+ ], [], []);
327
+ const expected = buildExpectedManifest([
328
+ buildDrmInfo('com.microsoft.playready', [], [
329
+ 'bm8gaHVtYW4gY2FuIHJlYWQgYmFzZTY0IGRpcmVjdGx5',
330
+ ]),
331
+ ]);
332
+ await testDashParser(source, expected);
333
+ });
334
+
301
335
  it('assumes all known key systems for generic CENC', async () => {
302
336
  let source = buildManifestText([
303
337
  // AdaptationSet lines
@@ -1215,4 +1215,64 @@ describe('DashParser Manifest', function() {
1215
1215
  const minBufferTime = manifest.minBufferTime;
1216
1216
  expect(minBufferTime).toEqual(75);
1217
1217
  });
1218
+
1219
+ it('does not set presentationDelay to NaN', async () => {
1220
+ // NOTE: This is a regression test for #2015. It ensures that, if
1221
+ // ignoreMinBufferTime is true and there is no suggestedPresentationDelay,
1222
+ // we do not erroneously set presentationDelay to NaN.
1223
+ const manifestText = [
1224
+ '<MPD minBufferTime="PT75S">',
1225
+ ' <Period id="1" duration="PT30S">',
1226
+ ' <AdaptationSet id="1" mimeType="video/mp4">',
1227
+ ' <Representation id="video-sd" width="640" height="480">',
1228
+ ' <BaseURL>v-sd.mp4</BaseURL>',
1229
+ ' <SegmentBase indexRange="100-200" />',
1230
+ ' </Representation>',
1231
+ ' </AdaptationSet>',
1232
+ ' </Period>',
1233
+ '</MPD>',
1234
+ ].join('\n');
1235
+
1236
+ fakeNetEngine.setResponseText('dummy://foo', manifestText);
1237
+ const config = shaka.util.PlayerConfiguration.createDefault().manifest;
1238
+ config.dash.ignoreMinBufferTime = true;
1239
+ parser.configure(config);
1240
+
1241
+ const manifest = await parser.start('dummy://foo', playerInterface);
1242
+ const presentationTimeline = manifest.presentationTimeline;
1243
+ const presentationDelay = presentationTimeline.getDelay();
1244
+ expect(presentationDelay).not.toBeNaN();
1245
+ expect(presentationDelay).toBe(config.dash.defaultPresentationDelay);
1246
+ });
1247
+
1248
+ it('converts Accessibility element to "kind"', async () => {
1249
+ const manifestText = [
1250
+ '<MPD minBufferTime="PT75S">',
1251
+ ' <Period id="1" duration="PT30S">',
1252
+ ' <AdaptationSet id="1" contentType="text">',
1253
+ ' <Accessibility schemeIdUri="urn:mpeg:dash:role:2011" ',
1254
+ ' value="captions" />',
1255
+ ' <Accessibility schemeIdUri="urn:mpeg:dash:role:2011" ',
1256
+ ' value="foo" />',
1257
+ ' <Accessibility schemeIdUri="foobar" value="bar" />',
1258
+ ' <Representation id="text-en" mimeType="text/webvtt">',
1259
+ ' <BaseURL>t-en.vtt</BaseURL>',
1260
+ ' </Representation>',
1261
+ ' </AdaptationSet>',
1262
+ ' <AdaptationSet id="1" mimeType="video/mp4">',
1263
+ ' <Representation id="video-sd" width="640" height="480">',
1264
+ ' <BaseURL>v-sd.mp4</BaseURL>',
1265
+ ' <SegmentBase indexRange="100-200" />',
1266
+ ' </Representation>',
1267
+ ' </AdaptationSet>',
1268
+ ' </Period>',
1269
+ '</MPD>',
1270
+ ].join('\n');
1271
+
1272
+ fakeNetEngine.setResponseText('dummy://foo', manifestText);
1273
+ const manifest = await parser.start('dummy://foo', playerInterface);
1274
+ const textStream = manifest.periods[0].textStreams[0];
1275
+ expect(textStream.roles).toEqual(['captions', 'foo']);
1276
+ expect(textStream.kind).toBe('caption');
1277
+ });
1218
1278
  });
@@ -273,12 +273,18 @@ describe('HlsParser live', function() {
273
273
  });
274
274
 
275
275
  it('updates all streams', function(done) {
276
+ const masterlist = [
277
+ '#EXTM3U\n',
278
+ '#EXT-X-STREAM-INF:BANDWIDTH=200,CODECS="avc1",AUDIO="aud1",',
279
+ 'RESOLUTION=960x540,FRAME-RATE=60\n',
280
+ 'video\n',
281
+ ].join('');
276
282
  const audio = [
277
283
  '#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="aud1",LANGUAGE="eng",',
278
284
  'URI="audio"\n',
279
285
  ].join('');
280
286
 
281
- let masterWithAudio = master + audio;
287
+ let masterWithAudio = masterlist + audio;
282
288
  let ref1 = ManifestParser.makeReference('test:/main.mp4',
283
289
  0, 2, 4);
284
290
  let ref2 = ManifestParser.makeReference('test:/main2.mp4',
@@ -1107,6 +1107,56 @@ describe('HlsParser', function() {
1107
1107
  .catch(fail).then(done);
1108
1108
  });
1109
1109
 
1110
+ it('drops failed text streams when configured to', async () => {
1111
+ const master = [
1112
+ '#EXTM3U\n',
1113
+ '#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="sub1",LANGUAGE="eng",',
1114
+ 'URI="text"\n',
1115
+ '#EXT-X-STREAM-INF:BANDWIDTH=200,CODECS="avc1,vtt",',
1116
+ 'RESOLUTION=960x540,FRAME-RATE=60,SUBTITLES="sub1"\n',
1117
+ 'video\n',
1118
+ ].join('');
1119
+
1120
+ const media = [
1121
+ '#EXTM3U\n',
1122
+ '#EXT-X-PLAYLIST-TYPE:VOD\n',
1123
+ '#EXT-X-MAP:URI="init.mp4",BYTERANGE="616@0"\n',
1124
+ '#EXTINF:5,\n',
1125
+ '#EXT-X-BYTERANGE:121090@616\n',
1126
+ 'main.mp4',
1127
+ ].join('');
1128
+
1129
+ const textMedia = [
1130
+ '#EXTM3U\n',
1131
+ '#EXT-X-PLAYLIST-TYPE:VOD\n',
1132
+ '#EXTINF:5,\n',
1133
+ '#EXT-X-BYTERANGE:121090@616\n',
1134
+ 'main.foo',
1135
+ ].join('');
1136
+
1137
+ /* eslint-disable indent */
1138
+ const manifest = new shaka.test.ManifestGenerator()
1139
+ .anyTimeline()
1140
+ .addPeriod(0)
1141
+ .addPartialVariant()
1142
+ .addPartialStream(ContentType.VIDEO)
1143
+ .build();
1144
+ /* eslint-enable indent */
1145
+
1146
+ fakeNetEngine
1147
+ .setResponseText('test:/master', master)
1148
+ .setResponseText('test:/audio', media)
1149
+ .setResponseText('test:/video', media)
1150
+ .setResponseText('test:/text', textMedia)
1151
+ .setResponseText('test:/main.foo', '')
1152
+ .setResponseValue('test:/init.mp4', initSegmentData)
1153
+ .setResponseValue('test:/main.mp4', segmentData);
1154
+
1155
+ config.hls.ignoreTextStreamFailures = true;
1156
+ const actual = await parser.start('test:/master', playerInterface);
1157
+ expect(actual).toEqual(manifest);
1158
+ });
1159
+
1110
1160
  it('parses video described by a media tag', async () => {
1111
1161
  const master = [
1112
1162
  '#EXTM3U\n',
@@ -829,7 +829,7 @@ describe('DrmEngine', function() {
829
829
  it('is listened for', async () => {
830
830
  await initAndAttach();
831
831
  expect(mockVideo.addEventListener).toHaveBeenCalledWith(
832
- 'encrypted', jasmine.any(Function), false);
832
+ 'encrypted', jasmine.any(Function), jasmine.anything());
833
833
  });
834
834
 
835
835
  it('triggers the creation of a session', async () => {
@@ -924,7 +924,7 @@ describe('DrmEngine', function() {
924
924
  {initDataType: 'webm', initData: initData, keyId: null});
925
925
 
926
926
  expect(session1.addEventListener).toHaveBeenCalledWith(
927
- 'message', jasmine.any(Function), false);
927
+ 'message', jasmine.any(Function), jasmine.anything());
928
928
  });
929
929
 
930
930
  it('triggers a license request', async () => {
@@ -1027,7 +1027,7 @@ describe('DrmEngine', function() {
1027
1027
  {initDataType: 'webm', initData: initData, keyId: null});
1028
1028
 
1029
1029
  expect(session1.addEventListener).toHaveBeenCalledWith(
1030
- 'keystatuseschange', jasmine.any(Function), false);
1030
+ 'keystatuseschange', jasmine.any(Function), jasmine.anything());
1031
1031
  });
1032
1032
 
1033
1033
  it('triggers callback', function(done) {
@@ -1262,8 +1262,14 @@ describe('DrmEngine', function() {
1262
1262
  // Not mocked. Run data through real data URI parser to ensure that it is
1263
1263
  // correctly formatted.
1264
1264
  fakeNetEngine.request.and.callFake(function(type, request) {
1265
+ const requestType = shaka.net.NetworkingEngine.RequestType.LICENSE;
1266
+
1267
+ // A dummy progress callback.
1268
+ const progressUpdated = (elapsedMs, bytes, bytesRemaining) => {};
1269
+
1265
1270
  // eslint-disable-next-line new-cap
1266
- return shaka.net.DataUriPlugin(request.uris[0], request);
1271
+ return shaka.net.DataUriPlugin(
1272
+ request.uris[0], request, requestType, progressUpdated);
1267
1273
  });
1268
1274
 
1269
1275
  await initAndAttach();
@@ -193,6 +193,18 @@ describe('MediaSourceEngine', function() {
193
193
  expect(mediaSource.duration).toBeCloseTo(30);
194
194
  });
195
195
 
196
+ it('does not throw if endOfStrem called more than once', async () => {
197
+ const initObject = new Map();
198
+ initObject.set(ContentType.VIDEO, getFakeStream(metadata.video));
199
+ await mediaSourceEngine.init(initObject, false);
200
+ await mediaSourceEngine.setDuration(presentationDuration);
201
+ await appendInit(ContentType.VIDEO);
202
+ await append(ContentType.VIDEO, 1);
203
+ // Call endOfStream twice. There should be no exception.
204
+ await mediaSourceEngine.endOfStream();
205
+ await mediaSourceEngine.endOfStream();
206
+ });
207
+
196
208
  it('queues operations', function(done) {
197
209
  let resolutionOrder = [];
198
210
  let requests = [];
@@ -1066,6 +1066,8 @@ describe('MediaSourceEngine', function() {
1066
1066
  new shaka.test.StatusPromise(mediaSourceEngine.appendBuffer(
1067
1067
  ContentType.AUDIO, buffer2, null, null,
1068
1068
  /* hasClosedCaptions */ false));
1069
+ // Create the expectation first so we don't get unhandled rejection errors
1070
+ const expected = expectAsync(rejected).toBeRejected();
1069
1071
 
1070
1072
  expect(audioSourceBuffer.appendBuffer).toHaveBeenCalledWith(buffer);
1071
1073
  expect(audioSourceBuffer.appendBuffer).not.toHaveBeenCalledWith(buffer2);
@@ -1076,7 +1078,7 @@ describe('MediaSourceEngine', function() {
1076
1078
  expect(p.status).toBe('pending');
1077
1079
  await Util.delay(0.1);
1078
1080
  expect(p.status).toBe('pending');
1079
- expect(rejected.status).toBe('rejected');
1081
+ await expected;
1080
1082
  expect(audioSourceBuffer.appendBuffer).toHaveBeenCalledWith(buffer);
1081
1083
  expect(audioSourceBuffer.appendBuffer).not.toHaveBeenCalledWith(buffer2);
1082
1084
  audioSourceBuffer.updateend();
@@ -200,9 +200,9 @@ describe('Playhead', function() {
200
200
  Util.spyFunc(onEvent));
201
201
 
202
202
  expect(video.addEventListener).toHaveBeenCalledWith(
203
- 'loadedmetadata', jasmine.any(Function), false);
203
+ 'loadedmetadata', jasmine.any(Function), jasmine.anything());
204
204
  expect(video.addEventListener).not.toHaveBeenCalledWith(
205
- 'seeking', jasmine.any(Function), jasmine.any(Boolean));
205
+ 'seeking', jasmine.any(Function), jasmine.anything());
206
206
 
207
207
  expect(playhead.getTime()).toBe(5);
208
208
  expect(video.currentTime).toBe(0);
@@ -211,7 +211,8 @@ describe('Playhead', function() {
211
211
  video.on['loadedmetadata']();
212
212
 
213
213
  expect(video.addEventListener).toHaveBeenCalledWith(
214
- 'seeking', jasmine.any(Function), false);
214
+ 'seeking', jasmine.any(Function), jasmine.anything());
215
+ video.on['seeking']();
215
216
 
216
217
  expect(playhead.getTime()).toBe(5);
217
218
  expect(video.currentTime).toBe(5);
@@ -239,6 +240,7 @@ describe('Playhead', function() {
239
240
  Util.spyFunc(onSeek),
240
241
  Util.spyFunc(onEvent));
241
242
 
243
+ video.on['seeking']();
242
244
  expect(playhead.getTime()).toBe(5);
243
245
  expect(video.currentTime).toBe(5);
244
246
 
@@ -314,7 +316,7 @@ describe('Playhead', function() {
314
316
  Util.spyFunc(onEvent));
315
317
 
316
318
  expect(video.addEventListener).toHaveBeenCalledWith(
317
- 'loadedmetadata', jasmine.any(Function), false);
319
+ 'loadedmetadata', jasmine.any(Function), jasmine.anything());
318
320
 
319
321
  expect(playhead.getTime()).toBe(5);
320
322
  expect(video.currentTime).toBe(0);
@@ -347,7 +349,7 @@ describe('Playhead', function() {
347
349
  Util.spyFunc(onEvent));
348
350
 
349
351
  expect(video.addEventListener).toHaveBeenCalledWith(
350
- 'loadedmetadata', jasmine.any(Function), false);
352
+ 'loadedmetadata', jasmine.any(Function), jasmine.anything());
351
353
 
352
354
  expect(playhead.getTime()).toBe(60);
353
355
  expect(video.currentTime).toBe(0);