shaka-player 3.3.4 → 4.0.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/config.yml +1 -0
- package/.github/workflows/build-and-test.yaml +0 -1
- package/.github/workflows/demo-version-index.yaml +8 -0
- package/.github/workflows/release-please.yaml +19 -3
- package/.github/workflows/selenium-lab-tests.yaml +0 -1
- package/.github/workflows/sync-labels.yaml +33 -0
- package/.github/workflows/update-issues.yaml +29 -0
- package/.github/workflows/validate-pr-title.yaml +35 -0
- package/AUTHORS +1 -0
- package/CHANGELOG.md +209 -28
- package/CONTRIBUTORS +1 -0
- package/README.md +10 -7
- package/app-engine/demo-version-index/README.md +3 -3
- package/app-engine/demo-version-index/app.yaml +27 -1
- package/app-engine/demo-version-index/generate.py +164 -0
- package/app-engine/demo-version-index/main.py +4 -155
- package/app-engine/demo-version-index/requirements.txt +0 -1
- package/build/README.md +2 -2
- package/build/compiler.py +1 -1
- package/build/generateTsDefs.py +0 -2
- package/build/misspellings.txt +1 -0
- package/build/shaka-lab.yaml +0 -2
- package/build/test.py +7 -1
- package/build/types/core +0 -1
- package/build/types/polyfill +0 -3
- package/demo/common/asset.js +17 -1
- package/demo/common/assets.js +29 -0
- package/demo/common/message_ids.js +6 -3
- package/demo/config.js +10 -11
- package/demo/custom.js +39 -0
- package/demo/demo_utils.js +0 -1
- package/demo/locales/en.json +6 -3
- package/demo/locales/source.json +22 -10
- package/demo/main.js +9 -6
- package/demo/search.js +2 -1
- package/dist/controls.css +1 -1
- package/dist/demo.compiled.debug.js +71 -64
- package/dist/demo.compiled.debug.map +3 -3
- package/dist/demo.compiled.js +71 -64
- package/dist/demo.compiled.map +3 -3
- package/dist/demo.css +1 -1
- package/dist/demo.css.map +1 -1
- package/dist/deps.js +16 -20
- package/dist/locales.js +33 -31
- package/dist/receiver.compiled.debug.js +32 -28
- package/dist/receiver.compiled.debug.map +3 -3
- package/dist/receiver.compiled.js +32 -28
- package/dist/receiver.compiled.map +3 -3
- package/dist/shaka-player.compiled.d.ts +78 -82
- package/dist/shaka-player.compiled.debug.d.ts +78 -82
- package/dist/shaka-player.compiled.debug.externs.js +127 -126
- package/dist/shaka-player.compiled.debug.js +471 -523
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +127 -126
- package/dist/shaka-player.compiled.js +844 -858
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.d.ts +80 -82
- package/dist/shaka-player.ui.debug.d.ts +80 -82
- package/dist/shaka-player.ui.debug.externs.js +135 -126
- package/dist/shaka-player.ui.debug.js +531 -581
- package/dist/shaka-player.ui.debug.map +4 -4
- package/dist/shaka-player.ui.externs.js +135 -126
- package/dist/shaka-player.ui.js +991 -1001
- package/dist/shaka-player.ui.map +4 -4
- package/docs/tutorials/config.md +0 -2
- package/docs/tutorials/drm-config.md +5 -0
- package/docs/tutorials/fairplay.md +7 -22
- package/docs/tutorials/faq.md +0 -11
- package/docs/tutorials/index.json +2 -8
- package/docs/tutorials/plugins.md +1 -3
- package/docs/tutorials/upgrade.md +85 -11
- package/externs/polyfill.js +15 -0
- package/externs/shaka/manifest.js +5 -1
- package/externs/shaka/net.js +12 -0
- package/externs/shaka/offline.js +5 -1
- package/externs/shaka/player.js +39 -21
- package/externs/shaka/text.js +12 -12
- package/externs/sourcebuffer.js +15 -0
- package/karma.conf.js +4 -0
- package/lib/ads/client_side_ad.js +13 -2
- package/lib/ads/client_side_ad_manager.js +22 -4
- package/lib/cast/cast_utils.js +0 -1
- package/lib/dash/content_protection.js +85 -5
- package/lib/dash/dash_parser.js +3 -3
- package/lib/hls/hls_parser.js +391 -747
- package/lib/hls/manifest_text_parser.js +2 -3
- package/lib/media/drm_engine.js +102 -37
- package/lib/media/gap_jumping_controller.js +10 -45
- package/lib/media/media_source_engine.js +157 -31
- package/lib/media/playhead.js +2 -5
- package/lib/media/presentation_timeline.js +1 -2
- package/lib/media/segment_index.js +13 -46
- package/lib/media/segment_reference.js +47 -1
- package/lib/media/streaming_engine.js +28 -11
- package/lib/media/time_ranges_utils.js +4 -9
- package/lib/net/networking_engine.js +3 -0
- package/lib/offline/indexeddb/storage_mechanism.js +4 -2
- package/lib/offline/indexeddb/v1_storage_cell.js +1 -0
- package/lib/offline/indexeddb/v2_storage_cell.js +1 -0
- package/lib/offline/manifest_converter.js +1 -0
- package/lib/offline/storage.js +100 -132
- package/lib/player.js +181 -307
- package/lib/polyfill/media_capabilities.js +12 -6
- package/lib/polyfill/mediasource.js +0 -28
- package/lib/polyfill/patchedmediakeys_nop.js +2 -0
- package/lib/polyfill/patchedmediakeys_webkit.js +2 -0
- package/lib/text/cue.js +0 -6
- package/lib/text/lrc_text_parser.js +8 -0
- package/lib/text/mp4_ttml_parser.js +8 -0
- package/lib/text/mp4_vtt_parser.js +8 -0
- package/lib/text/sbv_text_parser.js +8 -0
- package/lib/text/simple_text_displayer.js +1 -7
- package/lib/text/srt_text_parser.js +8 -0
- package/lib/text/ssa_text_parser.js +8 -0
- package/lib/text/text_engine.js +19 -3
- package/lib/text/ttml_text_parser.js +8 -0
- package/lib/text/ui_text_displayer.js +1 -7
- package/lib/text/vtt_text_parser.js +27 -5
- package/lib/text/web_vtt_generator.js +1 -7
- package/lib/util/config_utils.js +25 -0
- package/lib/util/error.js +16 -13
- package/lib/util/fairplay_utils.js +109 -0
- package/lib/util/functional.js +0 -42
- package/lib/util/manifest_parser_utils.js +1 -1
- package/lib/util/mime_utils.js +50 -1
- package/lib/util/periods.js +5 -4
- package/lib/util/platform.js +45 -0
- package/lib/util/player_configuration.js +26 -20
- package/lib/util/pssh.js +23 -4
- package/lib/util/stream_utils.js +96 -24
- package/lib/util/uint8array_utils.js +0 -16
- package/lib/util/xml_utils.js +1 -1
- package/package.json +4 -1
- package/roadmap.md +19 -19
- package/shaka-player.uncompiled.js +0 -3
- package/test/cast/cast_utils_unit.js +1 -0
- package/test/dash/dash_parser_content_protection_unit.js +44 -0
- package/test/dash/dash_parser_manifest_unit.js +0 -24
- package/test/dash/dash_parser_segment_template_unit.js +3 -4
- package/test/demo/demo_unit.js +2 -1
- package/test/hls/hls_live_unit.js +121 -220
- package/test/hls/hls_parser_unit.js +515 -432
- package/test/hls/manifest_text_parser_unit.js +19 -0
- package/test/media/drm_engine_unit.js +86 -120
- package/test/media/media_source_engine_integration.js +26 -3
- package/test/media/media_source_engine_unit.js +7 -6
- package/test/media/playhead_unit.js +27 -191
- package/test/media/segment_index_unit.js +15 -25
- package/test/media/streaming_engine_integration.js +4 -39
- package/test/media/streaming_engine_unit.js +3 -2
- package/test/media/time_ranges_utils_unit.js +0 -5
- package/test/offline/indexeddb_storage_unit.js +1 -1
- package/test/offline/manifest_convert_unit.js +34 -4
- package/test/offline/offline_manifest_parser_unit.js +1 -0
- package/test/offline/storage_compatibility_unit.js +1 -1
- package/test/offline/storage_integration.js +5 -4
- package/test/player_external.js +7 -7
- package/test/player_integration.js +22 -10
- package/test/player_src_equals_integration.js +81 -83
- package/test/player_unit.js +124 -1
- package/test/test/boot.js +9 -0
- package/test/test/externs/filters.js +4 -0
- package/test/test/util/fake_media_source_engine.js +11 -4
- package/test/test/util/manifest_generator.js +3 -1
- package/test/test/util/manifest_parser_util.js +4 -1
- package/test/test/util/offline_utils.js +1 -0
- package/test/test/util/simple_fakes.js +31 -2
- package/test/test/util/streaming_engine_util.js +1 -0
- package/test/test/util/test_scheme.js +24 -1
- package/test/test/util/util.js +4 -4
- package/test/text/cue_integration.js +2 -2
- package/test/text/lrc_text_parser_unit.js +6 -7
- package/test/text/mp4_ttml_parser_unit.js +6 -4
- package/test/text/mp4_vtt_parser_unit.js +6 -5
- package/test/text/sbv_text_parser_unit.js +5 -6
- package/test/text/srt_text_parser_unit.js +5 -6
- package/test/text/ssa_text_parser_unit.js +17 -29
- package/test/text/text_engine_unit.js +45 -5
- package/test/text/ttml_text_parser_unit.js +77 -77
- package/test/text/vtt_text_parser_unit.js +116 -59
- package/test/ui/ui_integration.js +0 -16
- package/test/ui/ui_unit.js +27 -0
- package/test/util/cmcd_manager_unit.js +3 -0
- package/test/util/mime_utils_unit.js +54 -0
- package/test/util/periods_unit.js +79 -0
- package/test/util/stream_utils_unit.js +23 -7
- package/ui/controls.js +65 -40
- package/ui/fullscreen_button.js +26 -6
- package/ui/less/containers.less +3 -3
- package/ui/locales/en.json +1 -0
- package/ui/locales/source.json +5 -0
- package/ui/resolution_selection.js +31 -33
- package/ui/ui.js +0 -17
- package/docs/tutorials/gsoc-ideas-list.md +0 -3
- package/docs/tutorials/upgrade-v2-5.md +0 -441
- package/docs/tutorials/upgrade-v3.md +0 -38
- package/lib/polyfill/mathround.js +0 -49
- package/lib/polyfill/patchedmediakeys_apple.js +0 -744
- package/lib/polyfill/patchedmediakeys_ms.js +0 -698
- package/lib/util/mutex.js +0 -52
- package/test/util/functional_unit.js +0 -82
package/lib/player.js
CHANGED
|
@@ -43,7 +43,6 @@ goog.require('shaka.util.Error');
|
|
|
43
43
|
goog.require('shaka.util.EventManager');
|
|
44
44
|
goog.require('shaka.util.FakeEvent');
|
|
45
45
|
goog.require('shaka.util.FakeEventTarget');
|
|
46
|
-
goog.require('shaka.util.Functional');
|
|
47
46
|
goog.require('shaka.util.IDestroyable');
|
|
48
47
|
goog.require('shaka.util.LanguageUtils');
|
|
49
48
|
goog.require('shaka.util.ManifestParserUtils');
|
|
@@ -301,22 +300,6 @@ goog.requireType('shaka.routing.Payload');
|
|
|
301
300
|
*/
|
|
302
301
|
|
|
303
302
|
|
|
304
|
-
/**
|
|
305
|
-
* @event shaka.Player.LargeGapEvent
|
|
306
|
-
* @description Fired when the playhead enters a large gap. If the
|
|
307
|
-
* <code>streaming.jumpLargeGaps</code> configuration is set, the default
|
|
308
|
-
* action of this event is to jump the gap; this can be prevented by calling
|
|
309
|
-
* <code>preventDefault()</code> on the event object.
|
|
310
|
-
* @property {string} type
|
|
311
|
-
* 'largegap'
|
|
312
|
-
* @property {number} currentTime
|
|
313
|
-
* The current time of the playhead.
|
|
314
|
-
* @property {number} gapSize
|
|
315
|
-
* The size of the gap, in seconds.
|
|
316
|
-
* @exportDoc
|
|
317
|
-
*/
|
|
318
|
-
|
|
319
|
-
|
|
320
303
|
/**
|
|
321
304
|
* @event shaka.Player.ManifestParsedEvent
|
|
322
305
|
* @description Fired after the manifest has been parsed, but before anything
|
|
@@ -440,8 +423,23 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
440
423
|
*/
|
|
441
424
|
this.isTextVisible_ = false;
|
|
442
425
|
|
|
443
|
-
/**
|
|
444
|
-
|
|
426
|
+
/**
|
|
427
|
+
* For listeners scoped to the lifetime of the Player instance.
|
|
428
|
+
* @private {shaka.util.EventManager}
|
|
429
|
+
*/
|
|
430
|
+
this.globalEventManager_ = new shaka.util.EventManager();
|
|
431
|
+
|
|
432
|
+
/**
|
|
433
|
+
* For listeners scoped to the lifetime of the media element attachment.
|
|
434
|
+
* @private {shaka.util.EventManager}
|
|
435
|
+
*/
|
|
436
|
+
this.attachEventManager_ = new shaka.util.EventManager();
|
|
437
|
+
|
|
438
|
+
/**
|
|
439
|
+
* For listeners scoped to the lifetime of the loaded content.
|
|
440
|
+
* @private {shaka.util.EventManager}
|
|
441
|
+
*/
|
|
442
|
+
this.loadEventManager_ = new shaka.util.EventManager();
|
|
445
443
|
|
|
446
444
|
/** @private {shaka.net.NetworkingEngine} */
|
|
447
445
|
this.networkingEngine_ = null;
|
|
@@ -576,13 +574,12 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
576
574
|
this.adManager_ = null;
|
|
577
575
|
|
|
578
576
|
if (shaka.Player.adManagerFactory_) {
|
|
579
|
-
this.adManager_ =
|
|
580
|
-
shaka.util.Functional.callFactory(shaka.Player.adManagerFactory_);
|
|
577
|
+
this.adManager_ = shaka.Player.adManagerFactory_();
|
|
581
578
|
}
|
|
582
579
|
|
|
583
580
|
// If the browser comes back online after being offline, then try to play
|
|
584
581
|
// again.
|
|
585
|
-
this.
|
|
582
|
+
this.globalEventManager_.listen(window, 'online', () => {
|
|
586
583
|
this.retryStreaming();
|
|
587
584
|
});
|
|
588
585
|
|
|
@@ -770,10 +767,18 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
770
767
|
});
|
|
771
768
|
await this.walker_.destroy();
|
|
772
769
|
|
|
773
|
-
// Tear-down the event
|
|
774
|
-
if (this.
|
|
775
|
-
this.
|
|
776
|
-
this.
|
|
770
|
+
// Tear-down the event managers to ensure handlers stop firing.
|
|
771
|
+
if (this.globalEventManager_) {
|
|
772
|
+
this.globalEventManager_.release();
|
|
773
|
+
this.globalEventManager_ = null;
|
|
774
|
+
}
|
|
775
|
+
if (this.attachEventManager_) {
|
|
776
|
+
this.attachEventManager_.release();
|
|
777
|
+
this.attachEventManager_ = null;
|
|
778
|
+
}
|
|
779
|
+
if (this.loadEventManager_) {
|
|
780
|
+
this.loadEventManager_.release();
|
|
781
|
+
this.loadEventManager_ = null;
|
|
777
782
|
}
|
|
778
783
|
|
|
779
784
|
this.abrManagerFactory_ = null;
|
|
@@ -847,10 +852,10 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
847
852
|
return false;
|
|
848
853
|
}
|
|
849
854
|
|
|
850
|
-
// We do not support iOS 9, 10, or
|
|
851
|
-
// Safari.
|
|
855
|
+
// We do not support iOS 9, 10, 11 or 12, nor those same versions of
|
|
856
|
+
// desktop Safari.
|
|
852
857
|
const safariVersion = shaka.util.Platform.safariVersion();
|
|
853
|
-
if (safariVersion && safariVersion <
|
|
858
|
+
if (safariVersion && safariVersion < 13) {
|
|
854
859
|
return false;
|
|
855
860
|
}
|
|
856
861
|
|
|
@@ -1316,7 +1321,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
1316
1321
|
has.mediaElement = wants.mediaElement;
|
|
1317
1322
|
|
|
1318
1323
|
const onError = (error) => this.onVideoError_(error);
|
|
1319
|
-
this.
|
|
1324
|
+
this.attachEventManager_.listen(has.mediaElement, 'error', onError);
|
|
1320
1325
|
}
|
|
1321
1326
|
|
|
1322
1327
|
this.video_ = has.mediaElement;
|
|
@@ -1343,10 +1348,10 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
1343
1348
|
* @private
|
|
1344
1349
|
*/
|
|
1345
1350
|
onDetach_(has, wants) {
|
|
1346
|
-
// If we
|
|
1351
|
+
// If we were going from "detached" to "detached" we wouldn't have
|
|
1347
1352
|
// a media element to detach from.
|
|
1348
1353
|
if (has.mediaElement) {
|
|
1349
|
-
this.
|
|
1354
|
+
this.attachEventManager_.removeAll();
|
|
1350
1355
|
has.mediaElement = null;
|
|
1351
1356
|
}
|
|
1352
1357
|
|
|
@@ -1404,11 +1409,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
1404
1409
|
// In most cases we should have a media element. The one exception would
|
|
1405
1410
|
// be if there was an error and we, by chance, did not have a media element.
|
|
1406
1411
|
if (has.mediaElement) {
|
|
1407
|
-
this.
|
|
1408
|
-
this.eventManager_.unlisten(has.mediaElement, 'playing');
|
|
1409
|
-
this.eventManager_.unlisten(has.mediaElement, 'pause');
|
|
1410
|
-
this.eventManager_.unlisten(has.mediaElement, 'ended');
|
|
1411
|
-
this.eventManager_.unlisten(has.mediaElement, 'ratechange');
|
|
1412
|
+
this.loadEventManager_.removeAll();
|
|
1412
1413
|
}
|
|
1413
1414
|
|
|
1414
1415
|
// Some observers use some playback components, shutting down the observers
|
|
@@ -1560,8 +1561,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
1560
1561
|
// text displayer and streaming engine are always in sync, wait until they
|
|
1561
1562
|
// are both initialized before setting the initial value.
|
|
1562
1563
|
const textDisplayerFactory = this.config_.textDisplayFactory;
|
|
1563
|
-
const textDisplayer =
|
|
1564
|
-
shaka.util.Functional.callFactory(textDisplayerFactory);
|
|
1564
|
+
const textDisplayer = textDisplayerFactory();
|
|
1565
1565
|
this.lastTextFactory_ = textDisplayerFactory;
|
|
1566
1566
|
|
|
1567
1567
|
const mediaSourceEngine = this.createMediaSourceEngine(
|
|
@@ -1571,6 +1571,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
1571
1571
|
(metadata, offset, endTime) => {
|
|
1572
1572
|
this.processTimedMetadataMediaSrc_(metadata, offset, endTime);
|
|
1573
1573
|
});
|
|
1574
|
+
const {segmentRelativeVttTiming} = this.config_.manifest;
|
|
1575
|
+
mediaSourceEngine.setSegmentRelativeVttTiming(segmentRelativeVttTiming);
|
|
1574
1576
|
|
|
1575
1577
|
// Wait for media source engine to finish opening. This promise should
|
|
1576
1578
|
// NEVER be rejected as per the media source engine implementation.
|
|
@@ -1632,7 +1634,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
1632
1634
|
this.config_.manifest.retryParameters,
|
|
1633
1635
|
has.mimeType);
|
|
1634
1636
|
goog.asserts.assert(this.parserFactory_, 'Must have manifest parser');
|
|
1635
|
-
this.parser_ =
|
|
1637
|
+
this.parser_ = this.parserFactory_();
|
|
1636
1638
|
|
|
1637
1639
|
const manifestConfig =
|
|
1638
1640
|
shaka.util.ObjectUtils.cloneObject(this.config_.manifest);
|
|
@@ -1902,29 +1904,23 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
1902
1904
|
this.assetUri_ = assetUri;
|
|
1903
1905
|
|
|
1904
1906
|
this.playRateController_ = new shaka.media.PlayRateController({
|
|
1905
|
-
getRate: () =>
|
|
1906
|
-
getDefaultRate: () =>
|
|
1907
|
-
setRate: (rate) => {
|
|
1908
|
-
movePlayhead: (delta) => {
|
|
1907
|
+
getRate: () => mediaElement.playbackRate,
|
|
1908
|
+
getDefaultRate: () => mediaElement.defaultPlaybackRate,
|
|
1909
|
+
setRate: (rate) => { mediaElement.playbackRate = rate; },
|
|
1910
|
+
movePlayhead: (delta) => { mediaElement.currentTime += delta; },
|
|
1909
1911
|
});
|
|
1910
1912
|
|
|
1911
1913
|
const updateStateHistory = () => this.updateStateHistory_();
|
|
1912
1914
|
const onRateChange = () => this.onRateChange_();
|
|
1913
|
-
this.
|
|
1914
|
-
this.
|
|
1915
|
-
this.
|
|
1916
|
-
this.
|
|
1915
|
+
this.loadEventManager_.listen(mediaElement, 'playing', updateStateHistory);
|
|
1916
|
+
this.loadEventManager_.listen(mediaElement, 'pause', updateStateHistory);
|
|
1917
|
+
this.loadEventManager_.listen(mediaElement, 'ended', updateStateHistory);
|
|
1918
|
+
this.loadEventManager_.listen(mediaElement, 'ratechange', onRateChange);
|
|
1917
1919
|
|
|
1918
1920
|
const abrFactory = this.config_.abrFactory;
|
|
1919
1921
|
if (!this.abrManager_ || this.abrManagerFactory_ != abrFactory) {
|
|
1920
1922
|
this.abrManagerFactory_ = abrFactory;
|
|
1921
|
-
this.abrManager_ =
|
|
1922
|
-
if (typeof this.abrManager_.playbackRateChanged != 'function') {
|
|
1923
|
-
shaka.Deprecate.deprecateFeature(4,
|
|
1924
|
-
'AbrManager',
|
|
1925
|
-
'Please use an AbrManager with playbackRateChanged function.');
|
|
1926
|
-
this.abrManager_.playbackRateChanged = (rate) => {};
|
|
1927
|
-
}
|
|
1923
|
+
this.abrManager_ = abrFactory();
|
|
1928
1924
|
this.abrManager_.configure(this.config_.abr);
|
|
1929
1925
|
}
|
|
1930
1926
|
|
|
@@ -1976,6 +1972,24 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
1976
1972
|
// "streaming" so that they can access internal information.
|
|
1977
1973
|
this.loadMode_ = shaka.Player.LoadMode.MEDIA_SOURCE;
|
|
1978
1974
|
|
|
1975
|
+
if (mediaElement.textTracks) {
|
|
1976
|
+
this.loadEventManager_.listen(
|
|
1977
|
+
mediaElement.textTracks, 'addtrack', (e) => {
|
|
1978
|
+
const trackEvent = /** @type {!TrackEvent} */(e);
|
|
1979
|
+
if (trackEvent.track) {
|
|
1980
|
+
const track = trackEvent.track;
|
|
1981
|
+
goog.asserts.assert(
|
|
1982
|
+
track instanceof TextTrack, 'Wrong track type!');
|
|
1983
|
+
|
|
1984
|
+
switch (track.kind) {
|
|
1985
|
+
case 'chapters':
|
|
1986
|
+
this.activateChaptersTrack_(track);
|
|
1987
|
+
break;
|
|
1988
|
+
}
|
|
1989
|
+
}
|
|
1990
|
+
});
|
|
1991
|
+
}
|
|
1992
|
+
|
|
1979
1993
|
// The event must be fired after we filter by restrictions but before the
|
|
1980
1994
|
// active stream is picked to allow those listening for the "streaming"
|
|
1981
1995
|
// event to make changes before streaming starts.
|
|
@@ -2062,7 +2076,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
2062
2076
|
}
|
|
2063
2077
|
|
|
2064
2078
|
// Wait for the 'loadedmetadata' event to measure load() latency.
|
|
2065
|
-
this.
|
|
2079
|
+
this.loadEventManager_.listenOnce(mediaElement, 'loadedmetadata', () => {
|
|
2066
2080
|
const now = Date.now() / 1000;
|
|
2067
2081
|
const delta = now - wants.startTimeOfLoad;
|
|
2068
2082
|
this.stats_.setLoadLatency(delta);
|
|
@@ -2215,11 +2229,12 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
2215
2229
|
// Save the uri so that it can be used outside of the load-graph.
|
|
2216
2230
|
this.assetUri_ = has.uri;
|
|
2217
2231
|
|
|
2218
|
-
|
|
2232
|
+
const mediaElement = has.mediaElement;
|
|
2233
|
+
|
|
2234
|
+
this.playhead_ = new shaka.media.SrcEqualsPlayhead(mediaElement);
|
|
2219
2235
|
|
|
2220
|
-
// This flag is used below in the language preference setup
|
|
2221
|
-
//
|
|
2222
|
-
// events fired.
|
|
2236
|
+
// This flag is used below in the language preference setup to check if
|
|
2237
|
+
// this load was canceled before the necessary awaits completed.
|
|
2223
2238
|
let unloaded = false;
|
|
2224
2239
|
this.cleanupOnUnload_.push(() => {
|
|
2225
2240
|
unloaded = true;
|
|
@@ -2230,10 +2245,10 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
2230
2245
|
}
|
|
2231
2246
|
|
|
2232
2247
|
this.playRateController_ = new shaka.media.PlayRateController({
|
|
2233
|
-
getRate: () =>
|
|
2234
|
-
getDefaultRate: () =>
|
|
2235
|
-
setRate: (rate) => {
|
|
2236
|
-
movePlayhead: (delta) => {
|
|
2248
|
+
getRate: () => mediaElement.playbackRate,
|
|
2249
|
+
getDefaultRate: () => mediaElement.defaultPlaybackRate,
|
|
2250
|
+
setRate: (rate) => { mediaElement.playbackRate = rate; },
|
|
2251
|
+
movePlayhead: (delta) => { mediaElement.currentTime += delta; },
|
|
2237
2252
|
});
|
|
2238
2253
|
|
|
2239
2254
|
// We need to start the buffer management code near the end because it will
|
|
@@ -2245,17 +2260,17 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
2245
2260
|
// Add all media element listeners.
|
|
2246
2261
|
const updateStateHistory = () => this.updateStateHistory_();
|
|
2247
2262
|
const onRateChange = () => this.onRateChange_();
|
|
2248
|
-
this.
|
|
2249
|
-
this.
|
|
2250
|
-
this.
|
|
2251
|
-
this.
|
|
2263
|
+
this.loadEventManager_.listen(mediaElement, 'playing', updateStateHistory);
|
|
2264
|
+
this.loadEventManager_.listen(mediaElement, 'pause', updateStateHistory);
|
|
2265
|
+
this.loadEventManager_.listen(mediaElement, 'ended', updateStateHistory);
|
|
2266
|
+
this.loadEventManager_.listen(mediaElement, 'ratechange', onRateChange);
|
|
2252
2267
|
|
|
2253
2268
|
// Wait for the 'loadedmetadata' event to measure load() latency, but only
|
|
2254
2269
|
// if preload is set in a way that would result in this event firing
|
|
2255
2270
|
// automatically.
|
|
2256
2271
|
// See https://github.com/shaka-project/shaka-player/issues/2483
|
|
2257
|
-
if (
|
|
2258
|
-
this.
|
|
2272
|
+
if (mediaElement.preload != 'none') {
|
|
2273
|
+
this.loadEventManager_.listenOnce(mediaElement, 'loadedmetadata', () => {
|
|
2259
2274
|
const now = Date.now() / 1000;
|
|
2260
2275
|
const delta = now - wants.startTimeOfLoad;
|
|
2261
2276
|
this.stats_.setLoadLatency(delta);
|
|
@@ -2265,44 +2280,47 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
2265
2280
|
// The audio tracks are only available on Safari at the moment, but this
|
|
2266
2281
|
// drives the tracks API for Safari's native HLS. So when they change,
|
|
2267
2282
|
// fire the corresponding Shaka Player event.
|
|
2268
|
-
if (
|
|
2269
|
-
this.
|
|
2270
|
-
|
|
2271
|
-
this.
|
|
2272
|
-
|
|
2283
|
+
if (mediaElement.audioTracks) {
|
|
2284
|
+
this.loadEventManager_.listen(
|
|
2285
|
+
mediaElement.audioTracks, 'addtrack', () => this.onTracksChanged_());
|
|
2286
|
+
this.loadEventManager_.listen(
|
|
2287
|
+
mediaElement.audioTracks, 'removetrack',
|
|
2273
2288
|
() => this.onTracksChanged_());
|
|
2274
|
-
this.
|
|
2275
|
-
|
|
2276
|
-
}
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2289
|
+
this.loadEventManager_.listen(
|
|
2290
|
+
mediaElement.audioTracks, 'change', () => this.onTracksChanged_());
|
|
2291
|
+
}
|
|
2292
|
+
|
|
2293
|
+
if (mediaElement.textTracks) {
|
|
2294
|
+
this.loadEventManager_.listen(
|
|
2295
|
+
mediaElement.textTracks, 'addtrack', (e) => {
|
|
2296
|
+
const trackEvent = /** @type {!TrackEvent} */(e);
|
|
2297
|
+
if (trackEvent.track) {
|
|
2298
|
+
const track = trackEvent.track;
|
|
2299
|
+
goog.asserts.assert(
|
|
2300
|
+
track instanceof TextTrack, 'Wrong track type!');
|
|
2301
|
+
|
|
2302
|
+
switch (track.kind) {
|
|
2303
|
+
case 'metadata':
|
|
2304
|
+
this.processTimedMetadataSrcEqls_(track);
|
|
2305
|
+
break;
|
|
2306
|
+
|
|
2307
|
+
case 'chapters':
|
|
2308
|
+
this.activateChaptersTrack_(track);
|
|
2309
|
+
break;
|
|
2310
|
+
|
|
2311
|
+
default:
|
|
2312
|
+
this.onTracksChanged_();
|
|
2313
|
+
break;
|
|
2314
|
+
}
|
|
2315
|
+
}
|
|
2316
|
+
});
|
|
2284
2317
|
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
this.processTimedMetadataSrcEqls_(track);
|
|
2292
|
-
break;
|
|
2293
|
-
case 'chapters':
|
|
2294
|
-
this.processChaptersTrack_(track);
|
|
2295
|
-
break;
|
|
2296
|
-
default:
|
|
2297
|
-
this.onTracksChanged_();
|
|
2298
|
-
break;
|
|
2299
|
-
}
|
|
2300
|
-
}
|
|
2301
|
-
});
|
|
2302
|
-
this.eventManager_.listen(
|
|
2303
|
-
this.video_.textTracks, 'removetrack', () => this.onTracksChanged_());
|
|
2304
|
-
this.eventManager_.listen(
|
|
2305
|
-
this.video_.textTracks, 'change', () => this.onTracksChanged_());
|
|
2318
|
+
this.loadEventManager_.listen(
|
|
2319
|
+
mediaElement.textTracks, 'removetrack',
|
|
2320
|
+
() => this.onTracksChanged_());
|
|
2321
|
+
this.loadEventManager_.listen(
|
|
2322
|
+
mediaElement.textTracks, 'change',
|
|
2323
|
+
() => this.onTracksChanged_());
|
|
2306
2324
|
}
|
|
2307
2325
|
|
|
2308
2326
|
const extension = shaka.media.ManifestParser.getExtension(has.uri);
|
|
@@ -2311,14 +2329,14 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
2311
2329
|
|
|
2312
2330
|
// By setting |src| we are done "loading" with src=. We don't need to set
|
|
2313
2331
|
// the current time because |playhead| will do that for us.
|
|
2314
|
-
|
|
2332
|
+
mediaElement.src = this.cmcdManager_.appendSrcData(has.uri, mimeType);
|
|
2315
2333
|
|
|
2316
2334
|
// Tizen 3 / WebOS won't load anything unless you call load() explicitly,
|
|
2317
2335
|
// no matter the value of the preload attribute. This is harmful on some
|
|
2318
2336
|
// other platforms by triggering unbounded loading of media data, but is
|
|
2319
2337
|
// necessary here.
|
|
2320
2338
|
if (shaka.util.Platform.isTizen() || shaka.util.Platform.isWebOS()) {
|
|
2321
|
-
|
|
2339
|
+
mediaElement.load();
|
|
2322
2340
|
}
|
|
2323
2341
|
|
|
2324
2342
|
// Set the load mode last so that we know that all our components are
|
|
@@ -2334,24 +2352,18 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
2334
2352
|
// wait for the full data, that won't happen on Safari until the play button
|
|
2335
2353
|
// is hit.
|
|
2336
2354
|
const fullyLoaded = new shaka.util.PublicPromise();
|
|
2337
|
-
shaka.util.MediaReadyState.waitForReadyState(
|
|
2355
|
+
shaka.util.MediaReadyState.waitForReadyState(mediaElement,
|
|
2338
2356
|
HTMLMediaElement.HAVE_METADATA,
|
|
2339
|
-
this.
|
|
2357
|
+
this.loadEventManager_,
|
|
2340
2358
|
() => {
|
|
2341
2359
|
fullyLoaded.resolve();
|
|
2342
2360
|
});
|
|
2343
2361
|
|
|
2344
2362
|
// We can't switch to preferred languages, though, until the data is loaded.
|
|
2345
|
-
shaka.util.MediaReadyState.waitForReadyState(
|
|
2363
|
+
shaka.util.MediaReadyState.waitForReadyState(mediaElement,
|
|
2346
2364
|
HTMLMediaElement.HAVE_CURRENT_DATA,
|
|
2347
|
-
this.
|
|
2365
|
+
this.loadEventManager_,
|
|
2348
2366
|
async () => {
|
|
2349
|
-
// If we have moved on to another piece of content while waiting for
|
|
2350
|
-
// the above event, we should not change tracks here.
|
|
2351
|
-
if (unloaded) {
|
|
2352
|
-
return;
|
|
2353
|
-
}
|
|
2354
|
-
|
|
2355
2367
|
this.setupPreferredAudioOnSrc_();
|
|
2356
2368
|
|
|
2357
2369
|
// Applying the text preference too soon can result in it being
|
|
@@ -2359,8 +2371,9 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
2359
2371
|
const textTracks = this.getFilteredTextTracks_();
|
|
2360
2372
|
if (!textTracks.find((t) => t.mode != 'disabled')) {
|
|
2361
2373
|
await new Promise((resolve) => {
|
|
2362
|
-
this.
|
|
2363
|
-
|
|
2374
|
+
this.loadEventManager_.listenOnce(
|
|
2375
|
+
mediaElement.textTracks, 'change', resolve);
|
|
2376
|
+
|
|
2364
2377
|
// We expect the event to fire because it does on Safari.
|
|
2365
2378
|
// But in case it doesn't on some other platform or future
|
|
2366
2379
|
// version, move on in 1 second no matter what. This keeps the
|
|
@@ -2379,10 +2392,10 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
2379
2392
|
this.setupPreferredTextOnSrc_();
|
|
2380
2393
|
});
|
|
2381
2394
|
|
|
2382
|
-
if (
|
|
2395
|
+
if (mediaElement.error) {
|
|
2383
2396
|
// Already failed!
|
|
2384
2397
|
fullyLoaded.reject(this.videoErrorToShakaError_());
|
|
2385
|
-
} else if (
|
|
2398
|
+
} else if (mediaElement.preload == 'none') {
|
|
2386
2399
|
shaka.log.alwaysWarn(
|
|
2387
2400
|
'With <video preload="none">, the browser will not load anything ' +
|
|
2388
2401
|
'until play() is called. We are unable to measure load latency in ' +
|
|
@@ -2393,7 +2406,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
2393
2406
|
fullyLoaded.resolve();
|
|
2394
2407
|
}
|
|
2395
2408
|
|
|
2396
|
-
this.
|
|
2409
|
+
this.loadEventManager_.listenOnce(mediaElement, 'error', () => {
|
|
2397
2410
|
fullyLoaded.reject(this.videoErrorToShakaError_());
|
|
2398
2411
|
});
|
|
2399
2412
|
|
|
@@ -2477,7 +2490,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
2477
2490
|
|
|
2478
2491
|
// Hidden mode is required for the cuechange event to launch correctly
|
|
2479
2492
|
track.mode = 'hidden';
|
|
2480
|
-
this.
|
|
2493
|
+
this.loadEventManager_.listen(track, 'cuechange', () => {
|
|
2481
2494
|
if (!track.activeCues) {
|
|
2482
2495
|
return;
|
|
2483
2496
|
}
|
|
@@ -2555,12 +2568,12 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
2555
2568
|
}
|
|
2556
2569
|
|
|
2557
2570
|
/**
|
|
2558
|
-
*
|
|
2571
|
+
* Set the mode on a chapters track so that it loads.
|
|
2559
2572
|
*
|
|
2560
2573
|
* @param {?TextTrack} track
|
|
2561
2574
|
* @private
|
|
2562
2575
|
*/
|
|
2563
|
-
|
|
2576
|
+
activateChaptersTrack_(track) {
|
|
2564
2577
|
if (!track || track.kind != 'chapters') {
|
|
2565
2578
|
return;
|
|
2566
2579
|
}
|
|
@@ -2573,10 +2586,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
2573
2586
|
// this process to be repeated several times to ensure that it has been put
|
|
2574
2587
|
// in the correct mode.
|
|
2575
2588
|
const timer = new shaka.util.Timer(() => {
|
|
2576
|
-
|
|
2577
|
-
for (const chaptersTrack of chaptersTracks) {
|
|
2578
|
-
chaptersTrack.mode = 'hidden';
|
|
2579
|
-
}
|
|
2589
|
+
track.mode = 'hidden';
|
|
2580
2590
|
}).tickNow().tickAfter(0.5);
|
|
2581
2591
|
|
|
2582
2592
|
this.cleanupOnUnload_.push(() => {
|
|
@@ -2683,8 +2693,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
2683
2693
|
this.manifest_,
|
|
2684
2694
|
this.config_.streaming,
|
|
2685
2695
|
startTime,
|
|
2686
|
-
() => this.onSeek_()
|
|
2687
|
-
(event) => this.dispatchEvent(event));
|
|
2696
|
+
() => this.onSeek_());
|
|
2688
2697
|
}
|
|
2689
2698
|
|
|
2690
2699
|
/**
|
|
@@ -2943,17 +2952,6 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
2943
2952
|
|
|
2944
2953
|
goog.asserts.assert(typeof(config) == 'object', 'Should be an object!');
|
|
2945
2954
|
|
|
2946
|
-
// Deprecate 'manifest.dash.defaultPresentationDelay' configuration.
|
|
2947
|
-
if (config['manifest'] && config['manifest']['dash'] &&
|
|
2948
|
-
'defaultPresentationDelay' in config['manifest']['dash']) {
|
|
2949
|
-
shaka.Deprecate.deprecateFeature(4,
|
|
2950
|
-
'manifest.dash.defaultPresentationDelay configuration',
|
|
2951
|
-
'Please Use manifest.defaultPresentationDelay instead.');
|
|
2952
|
-
config['manifest']['defaultPresentationDelay'] =
|
|
2953
|
-
config['manifest']['dash']['defaultPresentationDelay'];
|
|
2954
|
-
delete config['manifest']['dash']['defaultPresentationDelay'];
|
|
2955
|
-
}
|
|
2956
|
-
|
|
2957
2955
|
// If lowLatencyMode is enabled, and inaccurateManifestTolerance and
|
|
2958
2956
|
// rebufferingGoal are not specified, set inaccurateManifestTolerance to 0
|
|
2959
2957
|
// and rebufferingGoal to 0.01 by default for low latency streaming.
|
|
@@ -3020,10 +3018,13 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
3020
3018
|
}
|
|
3021
3019
|
|
|
3022
3020
|
if (this.mediaSourceEngine_) {
|
|
3021
|
+
const {segmentRelativeVttTiming} = this.config_.manifest;
|
|
3022
|
+
this.mediaSourceEngine_.setSegmentRelativeVttTiming(
|
|
3023
|
+
segmentRelativeVttTiming);
|
|
3024
|
+
|
|
3023
3025
|
const textDisplayerFactory = this.config_.textDisplayFactory;
|
|
3024
3026
|
if (this.lastTextFactory_ != textDisplayerFactory) {
|
|
3025
|
-
const displayer =
|
|
3026
|
-
shaka.util.Functional.callFactory(textDisplayerFactory);
|
|
3027
|
+
const displayer = textDisplayerFactory();
|
|
3027
3028
|
this.mediaSourceEngine_.setTextDisplayer(displayer);
|
|
3028
3029
|
this.lastTextFactory_ = textDisplayerFactory;
|
|
3029
3030
|
|
|
@@ -4408,158 +4409,6 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
4408
4409
|
return this.stats_.getBlob();
|
|
4409
4410
|
}
|
|
4410
4411
|
|
|
4411
|
-
/**
|
|
4412
|
-
* Adds the given text track to the loaded manifest. <code>load()</code> must
|
|
4413
|
-
* resolve before calling. The presentation must have a duration.
|
|
4414
|
-
*
|
|
4415
|
-
* This returns the created track, which can immediately be selected by the
|
|
4416
|
-
* application. The track will not be automatically selected.
|
|
4417
|
-
*
|
|
4418
|
-
* @param {string} uri
|
|
4419
|
-
* @param {string} language
|
|
4420
|
-
* @param {string} kind
|
|
4421
|
-
* @param {string=} mimeType
|
|
4422
|
-
* @param {string=} codec
|
|
4423
|
-
* @param {string=} label
|
|
4424
|
-
* @param {boolean=} forced
|
|
4425
|
-
* @return {shaka.extern.Track}
|
|
4426
|
-
* @export
|
|
4427
|
-
*/
|
|
4428
|
-
addTextTrack(uri, language, kind, mimeType, codec, label, forced = false) {
|
|
4429
|
-
shaka.Deprecate.deprecateFeature(4,
|
|
4430
|
-
'addTextTrack',
|
|
4431
|
-
'Please use an addTextTrackAsync.');
|
|
4432
|
-
if (this.loadMode_ != shaka.Player.LoadMode.MEDIA_SOURCE &&
|
|
4433
|
-
this.loadMode_ != shaka.Player.LoadMode.SRC_EQUALS) {
|
|
4434
|
-
shaka.log.error(
|
|
4435
|
-
'Must call load() and wait for it to resolve before adding text ' +
|
|
4436
|
-
'tracks.');
|
|
4437
|
-
throw new shaka.util.Error(
|
|
4438
|
-
shaka.util.Error.Severity.RECOVERABLE,
|
|
4439
|
-
shaka.util.Error.Category.PLAYER,
|
|
4440
|
-
shaka.util.Error.Code.CONTENT_NOT_LOADED);
|
|
4441
|
-
}
|
|
4442
|
-
|
|
4443
|
-
if (!mimeType) {
|
|
4444
|
-
// Try using the uri extension.
|
|
4445
|
-
const extension = shaka.media.ManifestParser.getExtension(uri);
|
|
4446
|
-
mimeType = shaka.Player.TEXT_EXTENSIONS_TO_MIME_TYPES_[extension];
|
|
4447
|
-
|
|
4448
|
-
if (!mimeType) {
|
|
4449
|
-
shaka.log.error(
|
|
4450
|
-
'The mimeType has not been provided and it could not be deduced ' +
|
|
4451
|
-
'from its extension.');
|
|
4452
|
-
throw new shaka.util.Error(
|
|
4453
|
-
shaka.util.Error.Severity.RECOVERABLE,
|
|
4454
|
-
shaka.util.Error.Category.TEXT,
|
|
4455
|
-
shaka.util.Error.Code.TEXT_COULD_NOT_GUESS_MIME_TYPE,
|
|
4456
|
-
extension);
|
|
4457
|
-
}
|
|
4458
|
-
}
|
|
4459
|
-
|
|
4460
|
-
if (this.loadMode_ == shaka.Player.LoadMode.SRC_EQUALS) {
|
|
4461
|
-
if (mimeType != 'text/vtt') {
|
|
4462
|
-
shaka.log.error('Only WebVTT is supported when using src=');
|
|
4463
|
-
throw new shaka.util.Error(
|
|
4464
|
-
shaka.util.Error.Severity.RECOVERABLE,
|
|
4465
|
-
shaka.util.Error.Category.TEXT,
|
|
4466
|
-
shaka.util.Error.Code.TEXT_ONLY_WEBVTT_SRC_EQUALS,
|
|
4467
|
-
mimeType);
|
|
4468
|
-
}
|
|
4469
|
-
if (forced) {
|
|
4470
|
-
// See: https://github.com/whatwg/html/issues/4472
|
|
4471
|
-
kind = 'forced';
|
|
4472
|
-
}
|
|
4473
|
-
const trackElement =
|
|
4474
|
-
/** @type {!HTMLTrackElement} */(document.createElement('track'));
|
|
4475
|
-
trackElement.src = this.cmcdManager_.appendTextTrackData(uri);
|
|
4476
|
-
trackElement.label = label || '';
|
|
4477
|
-
trackElement.kind = kind;
|
|
4478
|
-
trackElement.srclang = language;
|
|
4479
|
-
// Because we're pulling in the text track file via Javascript, the
|
|
4480
|
-
// same-origin policy applies. If you'd like to have a player served
|
|
4481
|
-
// from one domain, but the text track served from another, you'll
|
|
4482
|
-
// need to enable CORS in order to do so. In addition to enabling CORS
|
|
4483
|
-
// on the server serving the text tracks, you will need to add the
|
|
4484
|
-
// crossorigin attribute to the video element itself.
|
|
4485
|
-
if (!this.video_.getAttribute('crossorigin')) {
|
|
4486
|
-
this.video_.setAttribute('crossorigin', 'anonymous');
|
|
4487
|
-
}
|
|
4488
|
-
this.video_.appendChild(trackElement);
|
|
4489
|
-
const textTracks = this.getTextTracks();
|
|
4490
|
-
const srcTrack = textTracks.find((t) => {
|
|
4491
|
-
return t.language == language &&
|
|
4492
|
-
t.label == (label || '') &&
|
|
4493
|
-
t.kind == kind;
|
|
4494
|
-
});
|
|
4495
|
-
if (srcTrack) {
|
|
4496
|
-
this.onTracksChanged_();
|
|
4497
|
-
return srcTrack;
|
|
4498
|
-
}
|
|
4499
|
-
// This should not happen, but there are browser implementations that may
|
|
4500
|
-
// not support the Track element.
|
|
4501
|
-
shaka.log.error('Cannot add this text when loaded with src=');
|
|
4502
|
-
throw new shaka.util.Error(
|
|
4503
|
-
shaka.util.Error.Severity.RECOVERABLE,
|
|
4504
|
-
shaka.util.Error.Category.TEXT,
|
|
4505
|
-
shaka.util.Error.Code.CANNOT_ADD_EXTERNAL_TEXT_TO_SRC_EQUALS);
|
|
4506
|
-
}
|
|
4507
|
-
|
|
4508
|
-
const ContentType = shaka.util.ManifestParserUtils.ContentType;
|
|
4509
|
-
|
|
4510
|
-
const duration = this.manifest_.presentationTimeline.getDuration();
|
|
4511
|
-
if (duration == Infinity) {
|
|
4512
|
-
throw new shaka.util.Error(
|
|
4513
|
-
shaka.util.Error.Severity.RECOVERABLE,
|
|
4514
|
-
shaka.util.Error.Category.MANIFEST,
|
|
4515
|
-
shaka.util.Error.Code.CANNOT_ADD_EXTERNAL_TEXT_TO_LIVE_STREAM);
|
|
4516
|
-
}
|
|
4517
|
-
|
|
4518
|
-
/** @type {shaka.extern.Stream} */
|
|
4519
|
-
const stream = {
|
|
4520
|
-
id: this.nextExternalStreamId_++,
|
|
4521
|
-
originalId: null,
|
|
4522
|
-
createSegmentIndex: () => Promise.resolve(),
|
|
4523
|
-
segmentIndex: shaka.media.SegmentIndex.forSingleSegment(
|
|
4524
|
-
/* startTime= */ 0,
|
|
4525
|
-
/* duration= */ duration,
|
|
4526
|
-
/* uris= */ [uri]),
|
|
4527
|
-
mimeType: mimeType || '',
|
|
4528
|
-
codecs: codec || '',
|
|
4529
|
-
kind: kind,
|
|
4530
|
-
encrypted: false,
|
|
4531
|
-
drmInfos: [],
|
|
4532
|
-
keyIds: new Set(),
|
|
4533
|
-
language: language,
|
|
4534
|
-
label: label || null,
|
|
4535
|
-
type: ContentType.TEXT,
|
|
4536
|
-
primary: false,
|
|
4537
|
-
trickModeVideo: null,
|
|
4538
|
-
emsgSchemeIdUris: null,
|
|
4539
|
-
roles: [],
|
|
4540
|
-
forced: !!forced,
|
|
4541
|
-
channelsCount: null,
|
|
4542
|
-
audioSamplingRate: null,
|
|
4543
|
-
spatialAudio: false,
|
|
4544
|
-
closedCaptions: null,
|
|
4545
|
-
};
|
|
4546
|
-
|
|
4547
|
-
const fullMimeType = shaka.util.MimeUtils.getFullType(
|
|
4548
|
-
stream.mimeType, stream.codecs);
|
|
4549
|
-
const supported = shaka.text.TextEngine.isTypeSupported(fullMimeType);
|
|
4550
|
-
if (!supported) {
|
|
4551
|
-
throw new shaka.util.Error(
|
|
4552
|
-
shaka.util.Error.Severity.CRITICAL,
|
|
4553
|
-
shaka.util.Error.Category.TEXT,
|
|
4554
|
-
shaka.util.Error.Code.MISSING_TEXT_PLUGIN,
|
|
4555
|
-
mimeType);
|
|
4556
|
-
}
|
|
4557
|
-
|
|
4558
|
-
this.manifest_.textStreams.push(stream);
|
|
4559
|
-
this.onTracksChanged_();
|
|
4560
|
-
return shaka.util.StreamUtils.textStreamToTrack(stream);
|
|
4561
|
-
}
|
|
4562
|
-
|
|
4563
4412
|
/**
|
|
4564
4413
|
* Adds the given text track to the loaded manifest. <code>load()</code> must
|
|
4565
4414
|
* resolve before calling. The presentation must have a duration.
|
|
@@ -4721,25 +4570,41 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
4721
4570
|
if (!mimeType) {
|
|
4722
4571
|
mimeType = await this.getTextMimetype_(uri);
|
|
4723
4572
|
}
|
|
4573
|
+
|
|
4724
4574
|
let adCuePoints = [];
|
|
4725
4575
|
if (this.adManager_) {
|
|
4726
4576
|
try {
|
|
4727
4577
|
adCuePoints = this.adManager_.getServerSideCuePoints();
|
|
4728
4578
|
} catch (error) {}
|
|
4729
4579
|
}
|
|
4730
|
-
|
|
4731
|
-
|
|
4580
|
+
|
|
4581
|
+
/** @type {!HTMLTrackElement} */
|
|
4582
|
+
const trackElement = await this.addSrcTrackElement_(
|
|
4583
|
+
uri, language, /* kind= */ 'chapters', mimeType, /* label= */ '',
|
|
4584
|
+
adCuePoints);
|
|
4585
|
+
|
|
4732
4586
|
const chaptersTracks = this.getChaptersTracks();
|
|
4733
4587
|
const chaptersTrack = chaptersTracks.find((t) => {
|
|
4734
4588
|
return t.language == language;
|
|
4735
4589
|
});
|
|
4590
|
+
|
|
4736
4591
|
if (chaptersTrack) {
|
|
4737
|
-
|
|
4738
|
-
|
|
4739
|
-
|
|
4740
|
-
|
|
4592
|
+
await new Promise((resolve, reject) => {
|
|
4593
|
+
// The chapter data isn't available until the 'load' event fires, and
|
|
4594
|
+
// that won't happen until the chapters track is activated by the
|
|
4595
|
+
// activateChaptersTrack_ method.
|
|
4596
|
+
this.loadEventManager_.listenOnce(trackElement, 'load', resolve);
|
|
4597
|
+
this.loadEventManager_.listenOnce(trackElement, 'error', (event) => {
|
|
4598
|
+
reject(new shaka.util.Error(
|
|
4599
|
+
shaka.util.Error.Severity.RECOVERABLE,
|
|
4600
|
+
shaka.util.Error.Category.TEXT,
|
|
4601
|
+
shaka.util.Error.Code.CHAPTERS_TRACK_FAILED));
|
|
4602
|
+
});
|
|
4603
|
+
});
|
|
4604
|
+
|
|
4741
4605
|
return chaptersTrack;
|
|
4742
4606
|
}
|
|
4607
|
+
|
|
4743
4608
|
// This should not happen, but there are browser implementations that may
|
|
4744
4609
|
// not support the Track element.
|
|
4745
4610
|
shaka.log.error('Cannot add this text when loaded with src=');
|
|
@@ -4793,6 +4658,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
4793
4658
|
* @param {string} mimeType
|
|
4794
4659
|
* @param {string} label
|
|
4795
4660
|
* @param {!Array.<!shaka.extern.AdCuePoint>} adCuePoints
|
|
4661
|
+
* @return {!Promise.<!HTMLTrackElement>}
|
|
4796
4662
|
* @private
|
|
4797
4663
|
*/
|
|
4798
4664
|
async addSrcTrackElement_(uri, language, kind, mimeType, label,
|
|
@@ -4808,12 +4674,14 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
4808
4674
|
uri = shaka.media.MediaSourceEngine.createObjectURL(blob);
|
|
4809
4675
|
mimeType = 'text/vtt';
|
|
4810
4676
|
}
|
|
4677
|
+
|
|
4811
4678
|
const trackElement =
|
|
4812
4679
|
/** @type {!HTMLTrackElement} */(document.createElement('track'));
|
|
4813
4680
|
trackElement.src = this.cmcdManager_.appendTextTrackData(uri);
|
|
4814
4681
|
trackElement.label = label;
|
|
4815
4682
|
trackElement.kind = kind;
|
|
4816
4683
|
trackElement.srclang = language;
|
|
4684
|
+
|
|
4817
4685
|
// Because we're pulling in the text track file via Javascript, the
|
|
4818
4686
|
// same-origin policy applies. If you'd like to have a player served
|
|
4819
4687
|
// from one domain, but the text track served from another, you'll
|
|
@@ -4823,7 +4691,9 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
4823
4691
|
if (!this.video_.getAttribute('crossorigin')) {
|
|
4824
4692
|
this.video_.setAttribute('crossorigin', 'anonymous');
|
|
4825
4693
|
}
|
|
4694
|
+
|
|
4826
4695
|
this.video_.appendChild(trackElement);
|
|
4696
|
+
return trackElement;
|
|
4827
4697
|
}
|
|
4828
4698
|
|
|
4829
4699
|
/**
|
|
@@ -4864,6 +4734,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
4864
4734
|
periodStart: 0,
|
|
4865
4735
|
segmentStart: 0,
|
|
4866
4736
|
segmentEnd: this.video_.duration,
|
|
4737
|
+
vttOffset: 0,
|
|
4867
4738
|
};
|
|
4868
4739
|
const data = shaka.util.BufferUtils.toUint8(buffer);
|
|
4869
4740
|
const cues = obj.parseMedia(data, time);
|
|
@@ -5193,7 +5064,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
5193
5064
|
}
|
|
5194
5065
|
|
|
5195
5066
|
await stream.createSegmentIndex();
|
|
5196
|
-
const
|
|
5067
|
+
const iter = stream.segmentIndex.getIteratorForTime(time);
|
|
5068
|
+
const ref = iter ? iter.next().value : null;
|
|
5197
5069
|
if (!ref) {
|
|
5198
5070
|
return null;
|
|
5199
5071
|
}
|
|
@@ -5862,7 +5734,10 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
5862
5734
|
} // if (keyIds.size)
|
|
5863
5735
|
|
|
5864
5736
|
if (tracksChanged) {
|
|
5865
|
-
this.updateAbrManagerVariants_();
|
|
5737
|
+
const variantsUpdated = this.updateAbrManagerVariants_();
|
|
5738
|
+
if (!variantsUpdated) {
|
|
5739
|
+
return;
|
|
5740
|
+
}
|
|
5866
5741
|
}
|
|
5867
5742
|
|
|
5868
5743
|
const currentVariant = this.streamingEngine_.getCurrentVariant();
|
|
@@ -6516,7 +6391,6 @@ shaka.Player.EventName = {
|
|
|
6516
6391
|
Emsg: 'emsg',
|
|
6517
6392
|
Error: 'error',
|
|
6518
6393
|
ExpirationUpdated: 'expirationupdated',
|
|
6519
|
-
LargeGap: 'largegap',
|
|
6520
6394
|
Loaded: 'loaded',
|
|
6521
6395
|
Loading: 'loading',
|
|
6522
6396
|
ManifestParsed: 'manifestparsed',
|
|
@@ -6576,7 +6450,7 @@ shaka.Player.TYPICAL_BUFFERING_THRESHOLD_ = 0.5;
|
|
|
6576
6450
|
* @define {string} A version number taken from git at compile time.
|
|
6577
6451
|
* @export
|
|
6578
6452
|
*/
|
|
6579
|
-
shaka.Player.version = '
|
|
6453
|
+
shaka.Player.version = 'v4.0.1-uncompiled';
|
|
6580
6454
|
|
|
6581
6455
|
// Initialize the deprecation system using the version string we just set
|
|
6582
6456
|
// on the player.
|