shaka-player 3.2.2 → 3.3.0
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/ISSUE_TEMPLATE/bug_report.md +1 -1
- package/.github/ISSUE_TEMPLATE/feature_request.md +1 -1
- package/.github/ISSUE_TEMPLATE/question.md +1 -1
- package/AUTHORS +6 -5
- package/CHANGELOG.md +247 -0
- package/CONTRIBUTORS +4 -2
- package/build/types/core +3 -0
- package/build/types/offline +1 -0
- package/build/types/polyfill +1 -0
- package/build/types/ui +2 -0
- package/demo/common/assets.js +18 -0
- package/demo/common/message_ids.js +13 -1
- package/demo/config.js +31 -1
- package/demo/index.html +1 -1
- package/demo/locales/en.json +12 -0
- package/demo/locales/source.json +48 -0
- package/dist/controls.css +26 -2
- package/dist/controls.css.map +1 -1
- package/dist/demo.compiled.debug.js +19 -16
- package/dist/demo.compiled.debug.map +3 -3
- package/dist/demo.compiled.js +19 -16
- package/dist/demo.compiled.map +3 -3
- package/dist/deps.js +18 -11
- package/dist/locales.js +28 -26
- package/dist/receiver.compiled.debug.js +11 -9
- package/dist/receiver.compiled.debug.map +3 -3
- package/dist/receiver.compiled.js +11 -9
- package/dist/receiver.compiled.map +3 -3
- package/dist/shaka-player.compiled.d.ts +205 -15
- package/dist/shaka-player.compiled.debug.d.ts +205 -15
- package/dist/shaka-player.compiled.debug.externs.js +256 -6
- package/dist/shaka-player.compiled.debug.js +406 -354
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +256 -6
- package/dist/shaka-player.compiled.js +826 -800
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.d.ts +221 -16
- package/dist/shaka-player.ui.debug.d.ts +221 -16
- package/dist/shaka-player.ui.debug.externs.js +283 -6
- package/dist/shaka-player.ui.debug.js +547 -476
- package/dist/shaka-player.ui.debug.map +4 -4
- package/dist/shaka-player.ui.externs.js +283 -6
- package/dist/shaka-player.ui.js +1019 -980
- package/dist/shaka-player.ui.map +4 -4
- package/docs/design/bg-fetch-after.gv +29 -0
- package/docs/design/bg-fetch-after.gv.png +0 -0
- package/docs/design/bg-fetch-before.gv +18 -0
- package/docs/design/bg-fetch-before.gv.png +0 -0
- package/docs/design/bg-fetch.md +134 -0
- package/docs/tutorials/blob-url.md +15 -0
- package/docs/tutorials/index.json +1 -0
- package/docs/tutorials/ui-customization.md +66 -0
- package/docs/tutorials/ui.md +5 -5
- package/externs/ima.js +3 -0
- package/externs/shaka/ads.js +5 -0
- package/externs/shaka/manifest.js +12 -1
- package/externs/shaka/manifest_parser.js +10 -1
- package/externs/shaka/net.js +20 -4
- package/externs/shaka/offline.js +31 -2
- package/externs/shaka/player.js +130 -5
- package/externs/shaka/text.js +14 -0
- package/externs/webcrypto.js +18 -0
- package/lib/abr/ewma.js +14 -0
- package/lib/abr/ewma_bandwidth_estimator.js +16 -2
- package/lib/abr/simple_abr_manager.js +6 -0
- package/lib/ads/client_side_ad.js +8 -0
- package/lib/ads/client_side_ad_manager.js +8 -4
- package/lib/ads/server_side_ad.js +7 -0
- package/lib/cast/cast_utils.js +1 -0
- package/lib/dash/dash_parser.js +48 -14
- package/lib/dash/segment_base.js +25 -1
- package/lib/dash/segment_list.js +18 -9
- package/lib/dash/segment_template.js +23 -10
- package/lib/hls/hls_parser.js +86 -23
- package/lib/media/quality_observer.js +291 -0
- package/lib/media/segment_index.js +6 -0
- package/lib/media/segment_reference.js +18 -3
- package/lib/media/streaming_engine.js +42 -4
- package/lib/net/http_fetch_plugin.js +31 -11
- package/lib/net/http_plugin_utils.js +1 -0
- package/lib/net/http_xhr_plugin.js +40 -14
- package/lib/net/networking_engine.js +81 -18
- package/lib/offline/download_info.js +68 -0
- package/lib/offline/download_manager.js +13 -5
- package/lib/offline/indexeddb/base_storage_cell.js +35 -0
- package/lib/offline/indexeddb/storage_mechanism.js +1 -1
- package/lib/offline/indexeddb/v5_storage_cell.js +5 -0
- package/lib/offline/storage.js +393 -284
- package/lib/offline/stored_content_utils.js +2 -0
- package/lib/player.js +206 -7
- package/lib/polyfill/random_uuid.js +52 -0
- package/lib/text/cue.js +12 -0
- package/lib/text/ttml_text_parser.js +25 -2
- package/lib/text/ui_text_displayer.js +2 -2
- package/lib/util/cmcd_manager.js +826 -0
- package/lib/util/error.js +6 -0
- package/lib/util/language_utils.js +12 -0
- package/lib/util/mutex.js +52 -0
- package/lib/util/periods.js +98 -64
- package/lib/util/player_configuration.js +18 -0
- package/package.json +1 -1
- package/shaka-player.uncompiled.js +3 -0
- package/test/dash/dash_parser_content_protection_unit.js +2 -0
- package/test/dash/dash_parser_live_unit.js +101 -1
- package/test/dash/dash_parser_manifest_unit.js +35 -1
- package/test/dash/dash_parser_segment_base_unit.js +2 -0
- package/test/dash/dash_parser_segment_list_unit.js +2 -1
- package/test/dash/dash_parser_segment_template_unit.js +2 -1
- package/test/hls/hls_live_unit.js +2 -0
- package/test/hls/hls_parser_unit.js +2 -0
- package/test/media/quality_observer_unit.js +139 -0
- package/test/media/segment_reference_unit.js +16 -1
- package/test/media/streaming_engine_integration.js +2 -1
- package/test/media/streaming_engine_unit.js +2 -0
- package/test/net/http_plugin_unit.js +20 -15
- package/test/offline/storage_integration.js +108 -4
- package/test/player_integration.js +99 -0
- package/test/test/util/dash_parser_util.js +4 -0
- package/test/test/util/fake_ad.js +7 -0
- package/test/test/util/fake_drm_engine.js +9 -2
- package/test/test/util/manifest_generator.js +3 -2
- package/test/test/util/test_scheme.js +14 -1
- package/test/text/ttml_text_parser_unit.js +47 -0
- package/test/ui/ui_unit.js +250 -0
- package/test/util/cmcd_manager_unit.js +277 -0
- package/ui/airplay_button.js +1 -0
- package/ui/audio_language_selection.js +7 -0
- package/ui/cast_button.js +1 -0
- package/ui/context_menu.js +109 -0
- package/ui/controls.js +41 -7
- package/ui/controls.less +1 -0
- package/ui/enums.js +4 -0
- package/ui/externs/ui.js +28 -1
- package/ui/fast_forward_button.js +14 -5
- package/ui/fullscreen_button.js +1 -0
- package/ui/less/buttons.less +0 -4
- package/ui/less/containers.less +74 -0
- package/ui/less/overflow_menu.less +0 -10
- package/ui/less/tooltip.less +97 -0
- package/ui/locales/en.json +1 -0
- package/ui/locales/source.json +4 -0
- package/ui/loop_button.js +5 -0
- package/ui/mute_button.js +2 -1
- package/ui/overflow_menu.js +5 -25
- package/ui/pip_button.js +5 -0
- package/ui/play_button.js +2 -2
- package/ui/playback_rate_selection.js +8 -9
- package/ui/resolution_selection.js +7 -0
- package/ui/rewind_button.js +15 -6
- package/ui/seek_bar.js +4 -2
- package/ui/settings_menu.js +36 -4
- package/ui/small_play_button.js +1 -0
- package/ui/statistics_button.js +253 -0
- package/ui/text_selection.js +11 -4
- package/ui/ui.js +30 -0
- package/ui/volume_bar.js +1 -1
|
@@ -47,6 +47,7 @@ shaka.offline.StoredContentUtils = class {
|
|
|
47
47
|
expiration: Infinity,
|
|
48
48
|
tracks: tracks,
|
|
49
49
|
appMetadata: metadata,
|
|
50
|
+
isIncomplete: false,
|
|
50
51
|
};
|
|
51
52
|
|
|
52
53
|
return content;
|
|
@@ -87,6 +88,7 @@ shaka.offline.StoredContentUtils = class {
|
|
|
87
88
|
expiration: manifestDB.expiration,
|
|
88
89
|
tracks: tracks,
|
|
89
90
|
appMetadata: metadata,
|
|
91
|
+
isIncomplete: (manifestDB.isIncomplete || false),
|
|
90
92
|
};
|
|
91
93
|
|
|
92
94
|
return content;
|
package/lib/player.js
CHANGED
|
@@ -22,6 +22,7 @@ goog.require('shaka.media.PlayRateController');
|
|
|
22
22
|
goog.require('shaka.media.Playhead');
|
|
23
23
|
goog.require('shaka.media.PlayheadObserverManager');
|
|
24
24
|
goog.require('shaka.media.PreferenceBasedCriteria');
|
|
25
|
+
goog.require('shaka.media.QualityObserver');
|
|
25
26
|
goog.require('shaka.media.RegionObserver');
|
|
26
27
|
goog.require('shaka.media.RegionTimeline');
|
|
27
28
|
goog.require('shaka.media.SegmentIndex');
|
|
@@ -36,6 +37,7 @@ goog.require('shaka.text.UITextDisplayer');
|
|
|
36
37
|
goog.require('shaka.text.WebVttGenerator');
|
|
37
38
|
goog.require('shaka.util.AbortableOperation');
|
|
38
39
|
goog.require('shaka.util.BufferUtils');
|
|
40
|
+
goog.require('shaka.util.CmcdManager');
|
|
39
41
|
goog.require('shaka.util.ConfigUtils');
|
|
40
42
|
goog.require('shaka.util.Error');
|
|
41
43
|
goog.require('shaka.util.EventManager');
|
|
@@ -106,6 +108,32 @@ goog.requireType('shaka.routing.Payload');
|
|
|
106
108
|
*/
|
|
107
109
|
|
|
108
110
|
|
|
111
|
+
/**
|
|
112
|
+
* @event shaka.Player.DownloadFailed
|
|
113
|
+
* @description Fired when a download has failed, for any reason.
|
|
114
|
+
* 'downloadfailed'
|
|
115
|
+
* @property {!shaka.extern.Request} request
|
|
116
|
+
* @property {?shaka.util.Error} error
|
|
117
|
+
* @param {number} httpResponseCode
|
|
118
|
+
* @param {boolean} aborted
|
|
119
|
+
* @exportDoc
|
|
120
|
+
*/
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* @event shaka.Player.DownloadHeadersReceived
|
|
125
|
+
* @description Fired when the networking engine has received the headers for
|
|
126
|
+
* a download, but before the body has been downloaded.
|
|
127
|
+
* If the HTTP plugin being used does not track this information, this event
|
|
128
|
+
* will default to being fired when the body is received, instead.
|
|
129
|
+
* @property {!Object.<string, string>} headers
|
|
130
|
+
* @property {!shaka.extern.Request} request
|
|
131
|
+
* @property {!shaka.net.NetworkingEngine.RequestType} type
|
|
132
|
+
* 'downloadheadersreceived'
|
|
133
|
+
* @exportDoc
|
|
134
|
+
*/
|
|
135
|
+
|
|
136
|
+
|
|
109
137
|
/**
|
|
110
138
|
* @event shaka.Player.DrmSessionUpdateEvent
|
|
111
139
|
* @description Fired when the CDM has accepted the license response.
|
|
@@ -147,6 +175,21 @@ goog.requireType('shaka.routing.Payload');
|
|
|
147
175
|
* @exportDoc
|
|
148
176
|
*/
|
|
149
177
|
|
|
178
|
+
/**
|
|
179
|
+
* @event shaka.Player.MediaQualityChangedEvent
|
|
180
|
+
* @description Fired when the media quality changes at the playhead.
|
|
181
|
+
* That may be caused by an adaptation change or a DASH period transition.
|
|
182
|
+
* Separate events are emitted for audio and video contentTypes.
|
|
183
|
+
* This is supported for only DASH streams at this time.
|
|
184
|
+
* @property {string} type
|
|
185
|
+
* 'mediaqualitychanged'
|
|
186
|
+
* @property {shaka.extern.MediaQualityInfo} mediaQuality
|
|
187
|
+
* Information about media quality at the playhead position.
|
|
188
|
+
* @property {number} position
|
|
189
|
+
* The playhead position.
|
|
190
|
+
* @exportDoc
|
|
191
|
+
*/
|
|
192
|
+
|
|
150
193
|
|
|
151
194
|
/**
|
|
152
195
|
* @event shaka.Player.BufferingEvent
|
|
@@ -441,6 +484,12 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
441
484
|
/** @private {shaka.media.RegionTimeline} */
|
|
442
485
|
this.regionTimeline_ = null;
|
|
443
486
|
|
|
487
|
+
/** @private {shaka.util.CmcdManager} */
|
|
488
|
+
this.cmcdManager_ = null;
|
|
489
|
+
|
|
490
|
+
/** @private {shaka.media.QualityObserver} */
|
|
491
|
+
this.qualityObserver_ = null;
|
|
492
|
+
|
|
444
493
|
/** @private {shaka.media.StreamingEngine} */
|
|
445
494
|
this.streamingEngine_ = null;
|
|
446
495
|
|
|
@@ -507,6 +556,15 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
507
556
|
/** @private {!Array.<function():(!Promise|undefined)>} */
|
|
508
557
|
this.cleanupOnUnload_ = [];
|
|
509
558
|
|
|
559
|
+
/**
|
|
560
|
+
* This playback start position will be used when
|
|
561
|
+
* <code>updateStartTime()</code> has been called to provide an updated
|
|
562
|
+
* start position during the media loading process.
|
|
563
|
+
*
|
|
564
|
+
* @private {?number}
|
|
565
|
+
*/
|
|
566
|
+
this.updatedStartTime_ = null;
|
|
567
|
+
|
|
510
568
|
if (dependencyInjector) {
|
|
511
569
|
dependencyInjector(this);
|
|
512
570
|
}
|
|
@@ -723,6 +781,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
723
781
|
this.config_ = null;
|
|
724
782
|
this.stats_ = null;
|
|
725
783
|
this.videoContainer_ = null;
|
|
784
|
+
this.cmcdManager_ = null;
|
|
726
785
|
|
|
727
786
|
if (this.networkingEngine_) {
|
|
728
787
|
await this.networkingEngine_.destroy();
|
|
@@ -1020,6 +1079,19 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
1020
1079
|
return this.wrapWalkerListenersWithPromise_(events);
|
|
1021
1080
|
}
|
|
1022
1081
|
|
|
1082
|
+
/**
|
|
1083
|
+
* Provides a way to update the stream start position during the media loading
|
|
1084
|
+
* process. Can for example be called from the <code>manifestparsed</code>
|
|
1085
|
+
* event handler to update the start position based on information in the
|
|
1086
|
+
* manifest.
|
|
1087
|
+
*
|
|
1088
|
+
* @param {number} startTime
|
|
1089
|
+
* @export
|
|
1090
|
+
*/
|
|
1091
|
+
updateStartTime(startTime) {
|
|
1092
|
+
this.updatedStartTime_ = startTime;
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1023
1095
|
/**
|
|
1024
1096
|
* Tell the player to load the content at <code>assetUri</code> and start
|
|
1025
1097
|
* playback at <code>startTime</code>. Before calling <code>load</code>,
|
|
@@ -1040,6 +1112,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
1040
1112
|
* @export
|
|
1041
1113
|
*/
|
|
1042
1114
|
load(assetUri, startTime, mimeType) {
|
|
1115
|
+
this.updatedStartTime_ = null;
|
|
1116
|
+
|
|
1043
1117
|
// Do not allow the player to be used after |destroy| is called.
|
|
1044
1118
|
if (this.loadMode_ == shaka.Player.LoadMode.DESTROYED) {
|
|
1045
1119
|
return Promise.reject(this.createAbortLoadError_());
|
|
@@ -1093,6 +1167,9 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
1093
1167
|
// before we allow calls to |updateStateHistory|.
|
|
1094
1168
|
this.stats_ = new shaka.util.Stats();
|
|
1095
1169
|
|
|
1170
|
+
// Create the CMCD manager so client data can be attached to all requests
|
|
1171
|
+
this.cmcdManager_ = this.createCmcd_();
|
|
1172
|
+
|
|
1096
1173
|
// Load's request is a little different, so we can't use our normal
|
|
1097
1174
|
// listeners-to-promise method. It is the only request where we may skip the
|
|
1098
1175
|
// request, so we need to set the on skip callback to reject with a specific
|
|
@@ -1594,6 +1671,9 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
1594
1671
|
goog.asserts.assert(
|
|
1595
1672
|
this.networkingEngine_,
|
|
1596
1673
|
'Need networking engine to parse manifest.');
|
|
1674
|
+
goog.asserts.assert(
|
|
1675
|
+
this.cmcdManager_,
|
|
1676
|
+
'Need CMCD manager to populate manifest request data.');
|
|
1597
1677
|
goog.asserts.assert(
|
|
1598
1678
|
this.config_,
|
|
1599
1679
|
'Need player config to parse manifest.');
|
|
@@ -1617,9 +1697,23 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
1617
1697
|
this.adManager_.onDashTimedMetadata(region);
|
|
1618
1698
|
}
|
|
1619
1699
|
});
|
|
1700
|
+
this.qualityObserver_ = null;
|
|
1701
|
+
if (this.config_.streaming.observeQualityChanges) {
|
|
1702
|
+
this.qualityObserver_ = new shaka.media.QualityObserver(
|
|
1703
|
+
() => this.getBufferedInfo());
|
|
1704
|
+
this.qualityObserver_.setListeners((mediaQualityInfo, position) => {
|
|
1705
|
+
this.onMediaQualityChange_(mediaQualityInfo, position);
|
|
1706
|
+
});
|
|
1707
|
+
}
|
|
1620
1708
|
|
|
1621
1709
|
const playerInterface = {
|
|
1622
1710
|
networkingEngine: networkingEngine,
|
|
1711
|
+
modifyManifestRequest: (request, manifestInfo) => {
|
|
1712
|
+
this.cmcdManager_.applyManifestData(request, manifestInfo);
|
|
1713
|
+
},
|
|
1714
|
+
modifySegmentRequest: (request, segmentInfo) => {
|
|
1715
|
+
this.cmcdManager_.applySegmentData(request, segmentInfo);
|
|
1716
|
+
},
|
|
1623
1717
|
filter: (manifest) => this.filterManifest_(manifest),
|
|
1624
1718
|
makeTextStreamsForClosedCaptions: (manifest) => {
|
|
1625
1719
|
return this.makeTextStreamsForClosedCaptions_(manifest);
|
|
@@ -1780,6 +1874,13 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
1780
1874
|
// something we are now depending on.
|
|
1781
1875
|
has.startTime = wants.startTime;
|
|
1782
1876
|
|
|
1877
|
+
// If updateStartTime() has been called since load() was invoked use the
|
|
1878
|
+
// requested startTime
|
|
1879
|
+
if (this.updatedStartTime_ != null) {
|
|
1880
|
+
has.startTime = this.updatedStartTime_;
|
|
1881
|
+
this.updatedStartTime_ = null;
|
|
1882
|
+
}
|
|
1883
|
+
|
|
1783
1884
|
// Store a reference to values in |has| after asserting so that closure will
|
|
1784
1885
|
// know that they will still be non-null between calls to await.
|
|
1785
1886
|
const mediaElement = has.mediaElement;
|
|
@@ -2177,9 +2278,13 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
2177
2278
|
this.video_.textTracks, 'change', () => this.onTracksChanged_());
|
|
2178
2279
|
}
|
|
2179
2280
|
|
|
2281
|
+
const extension = shaka.media.ManifestParser.getExtension(has.uri);
|
|
2282
|
+
const mimeType =
|
|
2283
|
+
shaka.Player.SRC_EQUAL_EXTENSIONS_TO_MIME_TYPES_[extension];
|
|
2284
|
+
|
|
2180
2285
|
// By setting |src| we are done "loading" with src=. We don't need to set
|
|
2181
2286
|
// the current time because |playhead| will do that for us.
|
|
2182
|
-
has.mediaElement.src = has.uri;
|
|
2287
|
+
has.mediaElement.src = this.cmcdManager_.appendSrcData(has.uri, mimeType);
|
|
2183
2288
|
|
|
2184
2289
|
// Tizen 3 / WebOS won't load anything unless you call load() explicitly,
|
|
2185
2290
|
// no matter the value of the preload attribute. This is harmful on some
|
|
@@ -2509,8 +2614,30 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
2509
2614
|
this.abrManager_.segmentDownloaded(deltaTimeMs, bytesDownloaded);
|
|
2510
2615
|
}
|
|
2511
2616
|
};
|
|
2617
|
+
/** @type {shaka.net.NetworkingEngine.OnHeadersReceived} */
|
|
2618
|
+
const onHeadersReceived_ = (headers, request, requestType) => {
|
|
2619
|
+
// Release a 'downloadheadersreceived' event.
|
|
2620
|
+
const name = shaka.Player.EventName.DownloadHeadersReceived;
|
|
2621
|
+
const data = new Map()
|
|
2622
|
+
.set('headers', headers)
|
|
2623
|
+
.set('request', request)
|
|
2624
|
+
.set('requestType', requestType);
|
|
2625
|
+
this.dispatchEvent(this.makeEvent_(name, data));
|
|
2626
|
+
};
|
|
2627
|
+
/** @type {shaka.net.NetworkingEngine.OnDownloadFailed} */
|
|
2628
|
+
const onDownloadFailed_ = (request, error, httpResponseCode, aborted) => {
|
|
2629
|
+
// Release a 'downloadfailed' event.
|
|
2630
|
+
const name = shaka.Player.EventName.DownloadFailed;
|
|
2631
|
+
const data = new Map()
|
|
2632
|
+
.set('request', request)
|
|
2633
|
+
.set('error', error)
|
|
2634
|
+
.set('httpResponseCode', httpResponseCode)
|
|
2635
|
+
.set('aborted', aborted);
|
|
2636
|
+
this.dispatchEvent(this.makeEvent_(name, data));
|
|
2637
|
+
};
|
|
2512
2638
|
|
|
2513
|
-
return new shaka.net.NetworkingEngine(
|
|
2639
|
+
return new shaka.net.NetworkingEngine(
|
|
2640
|
+
onProgressUpdated_, onHeadersReceived_, onDownloadFailed_);
|
|
2514
2641
|
}
|
|
2515
2642
|
|
|
2516
2643
|
/**
|
|
@@ -2566,7 +2693,9 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
2566
2693
|
// Now that we have all our observers, create a manager for them.
|
|
2567
2694
|
const manager = new shaka.media.PlayheadObserverManager(this.video_);
|
|
2568
2695
|
manager.manage(regionObserver);
|
|
2569
|
-
|
|
2696
|
+
if (this.qualityObserver_) {
|
|
2697
|
+
manager.manage(this.qualityObserver_);
|
|
2698
|
+
}
|
|
2570
2699
|
return manager;
|
|
2571
2700
|
}
|
|
2572
2701
|
|
|
@@ -2682,6 +2811,27 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
2682
2811
|
mediaElement, closedCaptionsParser, textDisplayer, onMetadata);
|
|
2683
2812
|
}
|
|
2684
2813
|
|
|
2814
|
+
/**
|
|
2815
|
+
* Create a new CMCD manager.
|
|
2816
|
+
*
|
|
2817
|
+
* @private
|
|
2818
|
+
*/
|
|
2819
|
+
createCmcd_() {
|
|
2820
|
+
const abr = this.abrManager_;
|
|
2821
|
+
|
|
2822
|
+
/** @type {shaka.util.CmcdManager.PlayerInterface} */
|
|
2823
|
+
const playerInterface = {
|
|
2824
|
+
getBandwidthEstimate: () => abr ? abr.getBandwidthEstimate() : NaN,
|
|
2825
|
+
getBufferedInfo: () => this.getBufferedInfo(),
|
|
2826
|
+
getCurrentTime: () => this.video_ ? this.video_.currentTime : 0,
|
|
2827
|
+
getManifest: () => this.manifest_,
|
|
2828
|
+
getPlaybackRate: () => this.getPlaybackRate(),
|
|
2829
|
+
isLive: () => this.isLive(),
|
|
2830
|
+
};
|
|
2831
|
+
|
|
2832
|
+
return new shaka.util.CmcdManager(playerInterface, this.config_.cmcd);
|
|
2833
|
+
}
|
|
2834
|
+
|
|
2685
2835
|
/**
|
|
2686
2836
|
* Creates a new instance of StreamingEngine. This can be replaced by tests
|
|
2687
2837
|
* to create fake instances instead.
|
|
@@ -2691,19 +2841,28 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
2691
2841
|
createStreamingEngine() {
|
|
2692
2842
|
goog.asserts.assert(
|
|
2693
2843
|
this.playhead_ && this.abrManager_ && this.mediaSourceEngine_ &&
|
|
2694
|
-
this.manifest_,
|
|
2844
|
+
this.cmcdManager_ && this.manifest_,
|
|
2695
2845
|
'Must not be destroyed');
|
|
2696
2846
|
|
|
2697
2847
|
/** @type {shaka.media.StreamingEngine.PlayerInterface} */
|
|
2698
2848
|
const playerInterface = {
|
|
2699
2849
|
getPresentationTime: () => this.playhead_.getTime(),
|
|
2700
2850
|
getBandwidthEstimate: () => this.abrManager_.getBandwidthEstimate(),
|
|
2851
|
+
modifySegmentRequest: (request, segmentInfo) => {
|
|
2852
|
+
this.cmcdManager_.applySegmentData(request, segmentInfo);
|
|
2853
|
+
},
|
|
2701
2854
|
mediaSourceEngine: this.mediaSourceEngine_,
|
|
2702
2855
|
netEngine: this.networkingEngine_,
|
|
2703
2856
|
onError: (error) => this.onError_(error),
|
|
2704
2857
|
onEvent: (event) => this.dispatchEvent(event),
|
|
2705
2858
|
onManifestUpdate: () => this.onManifestUpdate_(),
|
|
2706
2859
|
onSegmentAppended: () => this.onSegmentAppended_(),
|
|
2860
|
+
onInitSegmentAppended: (position, initSegment) => {
|
|
2861
|
+
const mediaQuality = initSegment.getMediaQuality();
|
|
2862
|
+
if (mediaQuality && this.qualityObserver_) {
|
|
2863
|
+
this.qualityObserver_.addMediaQualityChange(mediaQuality, position);
|
|
2864
|
+
}
|
|
2865
|
+
},
|
|
2707
2866
|
};
|
|
2708
2867
|
|
|
2709
2868
|
return new shaka.media.StreamingEngine(this.manifest_, playerInterface);
|
|
@@ -4267,7 +4426,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
4267
4426
|
}
|
|
4268
4427
|
const trackElement =
|
|
4269
4428
|
/** @type {!HTMLTrackElement} */(document.createElement('track'));
|
|
4270
|
-
trackElement.src = uri;
|
|
4429
|
+
trackElement.src = this.cmcdManager_.appendTextTrackData(uri);
|
|
4271
4430
|
trackElement.label = label || '';
|
|
4272
4431
|
trackElement.kind = kind;
|
|
4273
4432
|
trackElement.srclang = language;
|
|
@@ -4605,7 +4764,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
4605
4764
|
}
|
|
4606
4765
|
const trackElement =
|
|
4607
4766
|
/** @type {!HTMLTrackElement} */(document.createElement('track'));
|
|
4608
|
-
trackElement.src = uri;
|
|
4767
|
+
trackElement.src = this.cmcdManager_.appendTextTrackData(uri);
|
|
4609
4768
|
trackElement.label = label;
|
|
4610
4769
|
trackElement.kind = kind;
|
|
4611
4770
|
trackElement.srclang = language;
|
|
@@ -4634,6 +4793,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
4634
4793
|
const request = shaka.net.NetworkingEngine.makeRequest([uri], retryParams);
|
|
4635
4794
|
request.method = 'GET';
|
|
4636
4795
|
|
|
4796
|
+
this.cmcdManager_.applyTextData(request);
|
|
4797
|
+
|
|
4637
4798
|
const response = await netEngine.request(type, request).promise;
|
|
4638
4799
|
|
|
4639
4800
|
return response.data;
|
|
@@ -5031,6 +5192,9 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
5031
5192
|
|
|
5032
5193
|
if (loaded) {
|
|
5033
5194
|
this.playRateController_.setBuffering(isBuffering);
|
|
5195
|
+
if (this.cmcdManager_) {
|
|
5196
|
+
this.cmcdManager_.setBuffering(isBuffering);
|
|
5197
|
+
}
|
|
5034
5198
|
this.updateStateHistory_();
|
|
5035
5199
|
}
|
|
5036
5200
|
|
|
@@ -5505,6 +5669,38 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
5505
5669
|
this.dispatchEvent(this.makeEvent_(eventName, data));
|
|
5506
5670
|
}
|
|
5507
5671
|
|
|
5672
|
+
/**
|
|
5673
|
+
* When notified of a media quality change we need to emit a
|
|
5674
|
+
* MediaQualityChange event to the app.
|
|
5675
|
+
*
|
|
5676
|
+
* @param {shaka.extern.MediaQualityInfo} mediaQuality
|
|
5677
|
+
* @param {number} position
|
|
5678
|
+
*
|
|
5679
|
+
* @private
|
|
5680
|
+
*/
|
|
5681
|
+
onMediaQualityChange_(mediaQuality, position) {
|
|
5682
|
+
// Always make a copy to avoid exposing our internal data to the app.
|
|
5683
|
+
const clone = {
|
|
5684
|
+
bandwidth: mediaQuality.bandwidth,
|
|
5685
|
+
audioSamplingRate: mediaQuality.audioSamplingRate,
|
|
5686
|
+
codecs: mediaQuality.codecs,
|
|
5687
|
+
contentType: mediaQuality.contentType,
|
|
5688
|
+
frameRate: mediaQuality.frameRate,
|
|
5689
|
+
height: mediaQuality.height,
|
|
5690
|
+
mimeType: mediaQuality.mimeType,
|
|
5691
|
+
channelsCount: mediaQuality.channelsCount,
|
|
5692
|
+
pixelAspectRatio: mediaQuality.pixelAspectRatio,
|
|
5693
|
+
width: mediaQuality.width,
|
|
5694
|
+
};
|
|
5695
|
+
|
|
5696
|
+
const data = new Map()
|
|
5697
|
+
.set('mediaQuality', clone)
|
|
5698
|
+
.set('position', position);
|
|
5699
|
+
|
|
5700
|
+
this.dispatchEvent(this.makeEvent_(
|
|
5701
|
+
shaka.Player.EventName.MediaQualityChanged, data));
|
|
5702
|
+
}
|
|
5703
|
+
|
|
5508
5704
|
/**
|
|
5509
5705
|
* Turn the media element's error object into a Shaka Player error object.
|
|
5510
5706
|
*
|
|
@@ -6268,6 +6464,8 @@ shaka.Player.EventName = {
|
|
|
6268
6464
|
AbrStatusChanged: 'abrstatuschanged',
|
|
6269
6465
|
Adaptation: 'adaptation',
|
|
6270
6466
|
Buffering: 'buffering',
|
|
6467
|
+
DownloadFailed: 'downloadfailed',
|
|
6468
|
+
DownloadHeadersReceived: 'downloadheadersreceived',
|
|
6271
6469
|
DrmSessionUpdate: 'drmsessionupdate',
|
|
6272
6470
|
Emsg: 'emsg',
|
|
6273
6471
|
Error: 'error',
|
|
@@ -6276,6 +6474,7 @@ shaka.Player.EventName = {
|
|
|
6276
6474
|
Loaded: 'loaded',
|
|
6277
6475
|
Loading: 'loading',
|
|
6278
6476
|
ManifestParsed: 'manifestparsed',
|
|
6477
|
+
MediaQualityChanged: 'mediaqualitychanged',
|
|
6279
6478
|
Metadata: 'metadata',
|
|
6280
6479
|
OnStateChange: 'onstatechange',
|
|
6281
6480
|
OnStateIdle: 'onstateidle',
|
|
@@ -6331,7 +6530,7 @@ shaka.Player.TYPICAL_BUFFERING_THRESHOLD_ = 0.5;
|
|
|
6331
6530
|
* @define {string} A version number taken from git at compile time.
|
|
6332
6531
|
* @export
|
|
6333
6532
|
*/
|
|
6334
|
-
shaka.Player.version = 'v3.
|
|
6533
|
+
shaka.Player.version = 'v3.3.0-uncompiled';
|
|
6335
6534
|
|
|
6336
6535
|
// Initialize the deprecation system using the version string we just set
|
|
6337
6536
|
// on the player.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/*! @license
|
|
2
|
+
* Shaka Player
|
|
3
|
+
* Copyright 2016 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
goog.provide('shaka.polyfill.RandomUUID');
|
|
7
|
+
|
|
8
|
+
goog.require('shaka.log');
|
|
9
|
+
goog.require('shaka.polyfill');
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @summary A polyfill to provide window.crypto.randomUUID in all browsers.
|
|
13
|
+
* @export
|
|
14
|
+
*/
|
|
15
|
+
shaka.polyfill.RandomUUID = class {
|
|
16
|
+
/**
|
|
17
|
+
* Install the polyfill if needed.
|
|
18
|
+
* @export
|
|
19
|
+
*/
|
|
20
|
+
static install() {
|
|
21
|
+
shaka.log.debug('randomUUID.install');
|
|
22
|
+
|
|
23
|
+
if (!window.crypto) {
|
|
24
|
+
// See: https://caniuse.com/cryptography
|
|
25
|
+
shaka.log.debug(
|
|
26
|
+
'window.crypto must be available to install randomUUID polyfill.');
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if ('randomUUID' in window.crypto) {
|
|
31
|
+
shaka.log.debug(
|
|
32
|
+
'RandomUUID: Native window.crypto.randomUUID() support found.');
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
window.crypto.randomUUID = shaka.polyfill.RandomUUID.randomUUID_;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* @return {string}
|
|
41
|
+
* @private
|
|
42
|
+
*/
|
|
43
|
+
static randomUUID_() {
|
|
44
|
+
const url = URL.createObjectURL(new Blob());
|
|
45
|
+
const uuid = url.toString();
|
|
46
|
+
URL.revokeObjectURL(url);
|
|
47
|
+
return uuid.substr(uuid.lastIndexOf('/') + 1);
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
shaka.polyfill.register(shaka.polyfill.RandomUUID.install);
|
package/lib/text/cue.js
CHANGED
|
@@ -144,6 +144,18 @@ shaka.text.Cue = class {
|
|
|
144
144
|
*/
|
|
145
145
|
this.border = '';
|
|
146
146
|
|
|
147
|
+
/**
|
|
148
|
+
* @override
|
|
149
|
+
* @exportInterface
|
|
150
|
+
*/
|
|
151
|
+
this.textStrokeColor = '';
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* @override
|
|
155
|
+
* @exportInterface
|
|
156
|
+
*/
|
|
157
|
+
this.textStrokeWidth = '';
|
|
158
|
+
|
|
147
159
|
/**
|
|
148
160
|
* @override
|
|
149
161
|
* @exportInterface
|
|
@@ -531,7 +531,6 @@ shaka.text.TtmlTextParser = class {
|
|
|
531
531
|
|
|
532
532
|
const color = TtmlTextParser.getStyleAttribute_(
|
|
533
533
|
cueElement, region, styles, 'color', shouldInheritRegionStyles);
|
|
534
|
-
|
|
535
534
|
if (color) {
|
|
536
535
|
cue.color = color;
|
|
537
536
|
}
|
|
@@ -584,7 +583,6 @@ shaka.text.TtmlTextParser = class {
|
|
|
584
583
|
|
|
585
584
|
const fontSize = TtmlTextParser.getStyleAttribute_(
|
|
586
585
|
cueElement, region, styles, 'fontSize', shouldInheritRegionStyles);
|
|
587
|
-
|
|
588
586
|
if (fontSize) {
|
|
589
587
|
const isValidFontSizeUnit =
|
|
590
588
|
fontSize.match(TtmlTextParser.unitValues_) ||
|
|
@@ -622,6 +620,31 @@ shaka.text.TtmlTextParser = class {
|
|
|
622
620
|
}
|
|
623
621
|
}
|
|
624
622
|
|
|
623
|
+
const textOutline = TtmlTextParser.getStyleAttribute_(
|
|
624
|
+
cueElement, region, styles, 'textOutline', shouldInheritRegionStyles);
|
|
625
|
+
if (textOutline) {
|
|
626
|
+
// tts:textOutline isn't natively supported by browsers, but it can be
|
|
627
|
+
// mostly replicated using the non-standard -webkit-text-stroke-width and
|
|
628
|
+
// -webkit-text-stroke-color properties.
|
|
629
|
+
const split = textOutline.split(' ');
|
|
630
|
+
if (split[0].match(TtmlTextParser.unitValues_)) {
|
|
631
|
+
// There is no defined color, so default to the text color.
|
|
632
|
+
cue.textStrokeColor = cue.color;
|
|
633
|
+
} else {
|
|
634
|
+
cue.textStrokeColor = split[0];
|
|
635
|
+
split.shift();
|
|
636
|
+
}
|
|
637
|
+
if (split[0] && split[0].match(TtmlTextParser.unitValues_)) {
|
|
638
|
+
cue.textStrokeWidth = split[0];
|
|
639
|
+
} else {
|
|
640
|
+
// If there is no width, or the width is not a number, don't draw a
|
|
641
|
+
// border.
|
|
642
|
+
cue.textStrokeColor = '';
|
|
643
|
+
}
|
|
644
|
+
// There is an optional blur radius also, but we have no way of
|
|
645
|
+
// replicating that, so ignore it.
|
|
646
|
+
}
|
|
647
|
+
|
|
625
648
|
const letterSpacing = TtmlTextParser.getStyleAttribute_(
|
|
626
649
|
cueElement, region, styles, 'letterSpacing', shouldInheritRegionStyles);
|
|
627
650
|
if (letterSpacing && letterSpacing.match(TtmlTextParser.unitValues_)) {
|
|
@@ -403,8 +403,8 @@ shaka.text.UITextDisplayer = class {
|
|
|
403
403
|
return nonBreakingSpace.repeat(match.length);
|
|
404
404
|
});
|
|
405
405
|
|
|
406
|
-
style.
|
|
407
|
-
style.
|
|
406
|
+
style.webkitTextStrokeColor = cue.textStrokeColor;
|
|
407
|
+
style.webkitTextStrokeWidth = cue.textStrokeWidth;
|
|
408
408
|
style.color = cue.color;
|
|
409
409
|
style.direction = cue.direction;
|
|
410
410
|
style.opacity = cue.opacity;
|