shaka-player 3.2.2 → 3.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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/.github/workflows/build_and_test.yaml +73 -0
- package/.github/workflows/release.yaml +53 -0
- package/AUTHORS +6 -5
- package/CHANGELOG.md +314 -1
- package/CONTRIBUTORS +4 -2
- package/build/checkversion.py +1 -1
- package/build/conformance.textproto +183 -169
- package/build/test.py +6 -0
- 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 +21 -14
- package/dist/locales.js +31 -29
- 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 +232 -18
- package/dist/shaka-player.compiled.debug.d.ts +232 -18
- package/dist/shaka-player.compiled.debug.externs.js +293 -17
- package/dist/shaka-player.compiled.debug.js +481 -422
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +293 -17
- package/dist/shaka-player.compiled.js +846 -817
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.d.ts +250 -30
- package/dist/shaka-player.ui.debug.d.ts +250 -30
- package/dist/shaka-player.ui.debug.externs.js +322 -28
- package/dist/shaka-player.ui.debug.js +630 -553
- package/dist/shaka-player.ui.debug.map +4 -4
- package/dist/shaka-player.ui.externs.js +322 -28
- package/dist/shaka-player.ui.js +1048 -1006
- 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/cmcd.js +186 -0
- 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 +138 -5
- package/externs/shaka/text.js +24 -0
- package/externs/webcrypto.js +18 -0
- package/karma.conf.js +19 -15
- 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/ad_manager.js +1 -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_proxy.js +3 -0
- package/lib/cast/cast_receiver.js +3 -0
- package/lib/cast/cast_utils.js +1 -0
- package/lib/dash/dash_parser.js +79 -33
- 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 +116 -23
- package/lib/hls/manifest_text_parser.js +1 -0
- package/lib/media/quality_observer.js +274 -0
- package/lib/media/region_observer.js +39 -33
- package/lib/media/region_timeline.js +17 -19
- package/lib/media/segment_index.js +8 -1
- package/lib/media/segment_reference.js +37 -4
- package/lib/media/streaming_engine.js +47 -6
- 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 +85 -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 +401 -293
- package/lib/offline/stored_content_utils.js +2 -0
- package/lib/player.js +254 -27
- package/lib/polyfill/media_capabilities.js +30 -15
- package/lib/polyfill/random_uuid.js +52 -0
- package/lib/text/cue.js +18 -0
- package/lib/text/ttml_text_parser.js +109 -60
- package/lib/text/ui_text_displayer.js +19 -13
- package/lib/util/cmcd_manager.js +672 -0
- package/lib/util/error.js +6 -0
- package/lib/util/fake_event_target.js +21 -1
- 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/lib/util/stream_utils.js +86 -10
- package/lib/util/xml_utils.js +19 -0
- package/package.json +3 -6
- 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 +144 -1
- package/test/dash/dash_parser_manifest_unit.js +37 -2
- 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 +76 -0
- package/test/media/drm_engine_unit.js +3 -3
- package/test/media/quality_observer_unit.js +142 -0
- package/test/media/region_observer_unit.js +40 -5
- package/test/media/region_timeline_unit.js +40 -22
- package/test/media/segment_reference_unit.js +16 -1
- package/test/media/streaming_engine_integration.js +4 -2
- package/test/media/streaming_engine_unit.js +147 -0
- package/test/net/http_plugin_unit.js +20 -15
- package/test/offline/storage_integration.js +108 -4
- package/test/player_integration.js +140 -8
- package/test/player_src_equals_integration.js +41 -8
- package/test/player_unit.js +19 -9
- package/test/test/assets/chapters.vtt +2 -2
- package/test/test/assets/chapters2.vtt +10 -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/test/util/ttml_utils.js +81 -0
- package/test/test/util/util.js +10 -7
- package/test/text/mp4_ttml_parser_unit.js +11 -18
- package/test/text/ttml_text_parser_unit.js +544 -228
- package/test/ui/text_displayer_layout_unit.js +8 -7
- package/test/ui/ui_unit.js +250 -0
- package/test/util/cmcd_manager_unit.js +291 -0
- package/test/util/stream_utils_unit.js +36 -30
- package/third_party/closure-uri/uri.js +21 -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 +44 -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/localization.js +12 -36
- 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 +12 -4
- package/ui/ui.js +30 -0
- package/ui/volume_bar.js +1 -1
- package/externs/media_capabilities.js +0 -16
|
@@ -0,0 +1,672 @@
|
|
|
1
|
+
/*! @license
|
|
2
|
+
* Shaka Player
|
|
3
|
+
* Copyright 2016 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
goog.provide('shaka.util.CmcdManager');
|
|
8
|
+
|
|
9
|
+
goog.require('goog.Uri');
|
|
10
|
+
goog.require('shaka.log');
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @summary
|
|
15
|
+
* A CmcdManager maintains CMCD state as well as a collection of utility
|
|
16
|
+
* functions.
|
|
17
|
+
*/
|
|
18
|
+
shaka.util.CmcdManager = class {
|
|
19
|
+
/**
|
|
20
|
+
* @param {shaka.util.CmcdManager.PlayerInterface} playerInterface
|
|
21
|
+
* @param {shaka.extern.CmcdConfiguration} config
|
|
22
|
+
*/
|
|
23
|
+
constructor(playerInterface, config) {
|
|
24
|
+
/** @private {shaka.util.CmcdManager.PlayerInterface} */
|
|
25
|
+
this.playerInterface_ = playerInterface;
|
|
26
|
+
|
|
27
|
+
/** @private {?shaka.extern.CmcdConfiguration} */
|
|
28
|
+
this.config_ = config;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Session ID
|
|
32
|
+
*
|
|
33
|
+
* @private {string}
|
|
34
|
+
*/
|
|
35
|
+
this.sid_ = '';
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Streaming format
|
|
39
|
+
*
|
|
40
|
+
* @private {(shaka.util.CmcdManager.StreamingFormat|undefined)}
|
|
41
|
+
*/
|
|
42
|
+
this.sf_ = undefined;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* @private {boolean}
|
|
46
|
+
*/
|
|
47
|
+
this.playbackStarted_ = false;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* @private {boolean}
|
|
51
|
+
*/
|
|
52
|
+
this.buffering_ = true;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* @private {boolean}
|
|
56
|
+
*/
|
|
57
|
+
this.starved_ = false;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Set the buffering state
|
|
62
|
+
*
|
|
63
|
+
* @param {boolean} buffering
|
|
64
|
+
*/
|
|
65
|
+
setBuffering(buffering) {
|
|
66
|
+
if (!buffering && !this.playbackStarted_) {
|
|
67
|
+
this.playbackStarted_ = true;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (this.playbackStarted_ && buffering) {
|
|
71
|
+
this.starved_ = true;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
this.buffering_ = buffering;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Apply CMCD data to a manifest request.
|
|
79
|
+
*
|
|
80
|
+
* @param {!shaka.extern.Request} request
|
|
81
|
+
* The request to apply CMCD data to
|
|
82
|
+
* @param {shaka.util.CmcdManager.ManifestInfo} manifestInfo
|
|
83
|
+
* The manifest format
|
|
84
|
+
*/
|
|
85
|
+
applyManifestData(request, manifestInfo) {
|
|
86
|
+
try {
|
|
87
|
+
if (!this.config_.enabled) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
this.sf_ = manifestInfo.format;
|
|
92
|
+
|
|
93
|
+
this.apply_(request, {
|
|
94
|
+
ot: shaka.util.CmcdManager.ObjectType.MANIFEST,
|
|
95
|
+
su: !this.playbackStarted_,
|
|
96
|
+
});
|
|
97
|
+
} catch (error) {
|
|
98
|
+
shaka.log.warnOnce('CMCD_MANIFEST_ERROR',
|
|
99
|
+
'Could not generate manifest CMCD data.', error);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Apply CMCD data to a segment request
|
|
105
|
+
*
|
|
106
|
+
* @param {!shaka.extern.Request} request
|
|
107
|
+
* @param {shaka.util.CmcdManager.SegmentInfo} segmentInfo
|
|
108
|
+
*/
|
|
109
|
+
applySegmentData(request, segmentInfo) {
|
|
110
|
+
try {
|
|
111
|
+
if (!this.config_.enabled) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const data = {
|
|
116
|
+
d: segmentInfo.duration * 1000,
|
|
117
|
+
st: this.getStreamType_(),
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
data.ot = this.getObjectType_(segmentInfo);
|
|
121
|
+
|
|
122
|
+
const ObjectType = shaka.util.CmcdManager.ObjectType;
|
|
123
|
+
const isMedia = data.ot === ObjectType.VIDEO ||
|
|
124
|
+
data.ot === ObjectType.AUDIO ||
|
|
125
|
+
data.ot === ObjectType.MUXED ||
|
|
126
|
+
data.ot === ObjectType.TIMED_TEXT;
|
|
127
|
+
|
|
128
|
+
if (isMedia) {
|
|
129
|
+
data.bl = this.getBufferLength_(segmentInfo.type);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (segmentInfo.bandwidth) {
|
|
133
|
+
data.br = segmentInfo.bandwidth / 1000;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (isMedia && data.ot !== ObjectType.TIMED_TEXT) {
|
|
137
|
+
data.tb = this.getTopBandwidth_(data.ot) / 1000;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
this.apply_(request, data);
|
|
141
|
+
} catch (error) {
|
|
142
|
+
shaka.log.warnOnce('CMCD_SEGMENT_ERROR',
|
|
143
|
+
'Could not generate segment CMCD data.', error);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Apply CMCD data to a text request
|
|
149
|
+
*
|
|
150
|
+
* @param {!shaka.extern.Request} request
|
|
151
|
+
*/
|
|
152
|
+
applyTextData(request) {
|
|
153
|
+
try {
|
|
154
|
+
if (!this.config_.enabled) {
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
this.apply_(request, {
|
|
159
|
+
ot: shaka.util.CmcdManager.ObjectType.CAPTION,
|
|
160
|
+
su: true,
|
|
161
|
+
});
|
|
162
|
+
} catch (error) {
|
|
163
|
+
shaka.log.warnOnce('CMCD_TEXT_ERROR',
|
|
164
|
+
'Could not generate text CMCD data.', error);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Apply CMCD data to streams loaded via src=.
|
|
170
|
+
*
|
|
171
|
+
* @param {string} uri
|
|
172
|
+
* @param {string} mimeType
|
|
173
|
+
* @return {string}
|
|
174
|
+
*/
|
|
175
|
+
appendSrcData(uri, mimeType) {
|
|
176
|
+
try {
|
|
177
|
+
if (!this.config_.enabled) {
|
|
178
|
+
return uri;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const data = this.createData_();
|
|
182
|
+
data.ot = this.getObjectTypeFromMimeType_(mimeType);
|
|
183
|
+
data.su = true;
|
|
184
|
+
|
|
185
|
+
const query = shaka.util.CmcdManager.toQuery(data);
|
|
186
|
+
|
|
187
|
+
return shaka.util.CmcdManager.appendQueryToUri(uri, query);
|
|
188
|
+
} catch (error) {
|
|
189
|
+
shaka.log.warnOnce('CMCD_SRC_ERROR',
|
|
190
|
+
'Could not generate src CMCD data.', error);
|
|
191
|
+
return uri;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Apply CMCD data to side car text track uri.
|
|
197
|
+
*
|
|
198
|
+
* @param {string} uri
|
|
199
|
+
* @return {string}
|
|
200
|
+
*/
|
|
201
|
+
appendTextTrackData(uri) {
|
|
202
|
+
try {
|
|
203
|
+
if (!this.config_.enabled) {
|
|
204
|
+
return uri;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const data = this.createData_();
|
|
208
|
+
data.ot = shaka.util.CmcdManager.ObjectType.CAPTION;
|
|
209
|
+
data.su = true;
|
|
210
|
+
|
|
211
|
+
const query = shaka.util.CmcdManager.toQuery(data);
|
|
212
|
+
|
|
213
|
+
return shaka.util.CmcdManager.appendQueryToUri(uri, query);
|
|
214
|
+
} catch (error) {
|
|
215
|
+
shaka.log.warnOnce('CMCD_TEXT_TRACK_ERROR',
|
|
216
|
+
'Could not generate text track CMCD data.', error);
|
|
217
|
+
return uri;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Create baseline CMCD data
|
|
223
|
+
*
|
|
224
|
+
* @return {CmcdData}
|
|
225
|
+
* @private
|
|
226
|
+
*/
|
|
227
|
+
createData_() {
|
|
228
|
+
if (!this.sid_) {
|
|
229
|
+
this.sid_ = this.config_.sessionId || window.crypto.randomUUID();
|
|
230
|
+
}
|
|
231
|
+
return {
|
|
232
|
+
v: shaka.util.CmcdManager.Version,
|
|
233
|
+
sf: this.sf_,
|
|
234
|
+
sid: this.sid_,
|
|
235
|
+
cid: this.config_.contentId,
|
|
236
|
+
mtp: this.playerInterface_.getBandwidthEstimate() / 1000,
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Apply CMCD data to a request.
|
|
242
|
+
*
|
|
243
|
+
* @param {!shaka.extern.Request} request The request to apply CMCD data to
|
|
244
|
+
* @param {!CmcdData} data The data object
|
|
245
|
+
* @param {boolean} useHeaders Send data via request headers
|
|
246
|
+
* @private
|
|
247
|
+
*/
|
|
248
|
+
apply_(request, data = {}, useHeaders = this.config_.useHeaders) {
|
|
249
|
+
if (!this.config_.enabled) {
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// apply baseline data
|
|
254
|
+
Object.assign(data, this.createData_());
|
|
255
|
+
|
|
256
|
+
data.pr = this.playerInterface_.getPlaybackRate();
|
|
257
|
+
|
|
258
|
+
const isVideo = data.ot === shaka.util.CmcdManager.ObjectType.VIDEO ||
|
|
259
|
+
data.ot === shaka.util.CmcdManager.ObjectType.MUXED;
|
|
260
|
+
|
|
261
|
+
if (this.starved_ && isVideo) {
|
|
262
|
+
data.bs = true;
|
|
263
|
+
data.su = true;
|
|
264
|
+
this.starved_ = false;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
if (data.su == null) {
|
|
268
|
+
data.su = this.buffering_;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// TODO: Implement rtp, nrr, nor, dl
|
|
272
|
+
|
|
273
|
+
if (useHeaders) {
|
|
274
|
+
const headers = shaka.util.CmcdManager.toHeaders(data);
|
|
275
|
+
if (!Object.keys(headers).length) {
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
Object.assign(request.headers, headers);
|
|
280
|
+
} else {
|
|
281
|
+
const query = shaka.util.CmcdManager.toQuery(data);
|
|
282
|
+
if (!query) {
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
request.uris = request.uris.map((uri) => {
|
|
287
|
+
return shaka.util.CmcdManager.appendQueryToUri(uri, query);
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* The CMCD object type.
|
|
294
|
+
*
|
|
295
|
+
* @param {shaka.util.CmcdManager.SegmentInfo} segmentInfo
|
|
296
|
+
* @private
|
|
297
|
+
*/
|
|
298
|
+
getObjectType_(segmentInfo) {
|
|
299
|
+
const type = segmentInfo.type;
|
|
300
|
+
|
|
301
|
+
if (segmentInfo.init) {
|
|
302
|
+
return shaka.util.CmcdManager.ObjectType.INIT;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
if (type == 'video') {
|
|
306
|
+
if (segmentInfo.codecs.includes(',')) {
|
|
307
|
+
return shaka.util.CmcdManager.ObjectType.MUXED;
|
|
308
|
+
}
|
|
309
|
+
return shaka.util.CmcdManager.ObjectType.VIDEO;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
if (type == 'audio') {
|
|
313
|
+
return shaka.util.CmcdManager.ObjectType.AUDIO;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
if (type == 'text') {
|
|
317
|
+
if (segmentInfo.mimeType === 'application/mp4') {
|
|
318
|
+
return shaka.util.CmcdManager.ObjectType.TIMED_TEXT;
|
|
319
|
+
}
|
|
320
|
+
return shaka.util.CmcdManager.ObjectType.CAPTION;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
return undefined;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* The CMCD object type from mimeType.
|
|
328
|
+
*
|
|
329
|
+
* @param {!string} mimeType
|
|
330
|
+
* @return {(shaka.util.CmcdManager.ObjectType|undefined)}
|
|
331
|
+
* @private
|
|
332
|
+
*/
|
|
333
|
+
getObjectTypeFromMimeType_(mimeType) {
|
|
334
|
+
switch (mimeType) {
|
|
335
|
+
case 'video/webm':
|
|
336
|
+
case 'video/mp4':
|
|
337
|
+
return shaka.util.CmcdManager.ObjectType.MUXED;
|
|
338
|
+
|
|
339
|
+
case 'application/x-mpegurl':
|
|
340
|
+
return shaka.util.CmcdManager.ObjectType.MANIFEST;
|
|
341
|
+
|
|
342
|
+
default:
|
|
343
|
+
return undefined;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* Get the buffer length for a media type in milliseconds
|
|
349
|
+
*
|
|
350
|
+
* @param {string} type
|
|
351
|
+
* @return {number}
|
|
352
|
+
* @private
|
|
353
|
+
*/
|
|
354
|
+
getBufferLength_(type) {
|
|
355
|
+
const ranges = this.playerInterface_.getBufferedInfo()[type];
|
|
356
|
+
|
|
357
|
+
if (!ranges.length) {
|
|
358
|
+
return NaN;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
const start = this.playerInterface_.getCurrentTime();
|
|
362
|
+
const range = ranges.find((r) => r.start <= start && r.end >= start);
|
|
363
|
+
|
|
364
|
+
if (!range) {
|
|
365
|
+
return NaN;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
return (range.end - start) * 1000;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
/**
|
|
372
|
+
* Get the stream type
|
|
373
|
+
*
|
|
374
|
+
* @return {shaka.util.CmcdManager.StreamType}
|
|
375
|
+
* @private
|
|
376
|
+
*/
|
|
377
|
+
getStreamType_() {
|
|
378
|
+
const isLive = this.playerInterface_.isLive();
|
|
379
|
+
if (isLive) {
|
|
380
|
+
return shaka.util.CmcdManager.StreamType.LIVE;
|
|
381
|
+
} else {
|
|
382
|
+
return shaka.util.CmcdManager.StreamType.VOD;
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* Get the highest bandwidth for a given type.
|
|
388
|
+
*
|
|
389
|
+
* @param {string} type
|
|
390
|
+
* @return {number}
|
|
391
|
+
* @private
|
|
392
|
+
*/
|
|
393
|
+
getTopBandwidth_(type) {
|
|
394
|
+
const variants = this.playerInterface_.getVariantTracks();
|
|
395
|
+
if (!variants.length) {
|
|
396
|
+
return NaN;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
let top = variants[0];
|
|
400
|
+
|
|
401
|
+
for (const variant of variants) {
|
|
402
|
+
if (variant.type === 'variant' && variant.bandwidth > top.bandwidth) {
|
|
403
|
+
top = variant;
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
const ObjectType = shaka.util.CmcdManager.ObjectType;
|
|
408
|
+
|
|
409
|
+
switch (type) {
|
|
410
|
+
case ObjectType.VIDEO:
|
|
411
|
+
return top.videoBandwidth || NaN;
|
|
412
|
+
|
|
413
|
+
case ObjectType.AUDIO:
|
|
414
|
+
return top.audioBandwidth || NaN;
|
|
415
|
+
|
|
416
|
+
default:
|
|
417
|
+
return top.bandwidth;
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
/**
|
|
422
|
+
* Serialize a CMCD data object according to the rules defined in the
|
|
423
|
+
* section 3.2 of
|
|
424
|
+
* [CTA-5004](https://cdn.cta.tech/cta/media/media/resources/standards/pdfs/cta-5004-final.pdf).
|
|
425
|
+
*
|
|
426
|
+
* @param {CmcdData} data The CMCD data object
|
|
427
|
+
* @return {string}
|
|
428
|
+
*/
|
|
429
|
+
static serialize(data) {
|
|
430
|
+
const results = [];
|
|
431
|
+
const isValid = (value) =>
|
|
432
|
+
!Number.isNaN(value) && value != null && value !== '' && value !== false;
|
|
433
|
+
const toRounded = (value) => Math.round(value);
|
|
434
|
+
const toHundred = (value) => toRounded(value / 100) * 100;
|
|
435
|
+
const toUrlSafe = (value) => encodeURIComponent(value);
|
|
436
|
+
const formatters = {
|
|
437
|
+
br: toRounded,
|
|
438
|
+
d: toRounded,
|
|
439
|
+
bl: toHundred,
|
|
440
|
+
dl: toHundred,
|
|
441
|
+
mtp: toHundred,
|
|
442
|
+
nor: toUrlSafe,
|
|
443
|
+
rtp: toHundred,
|
|
444
|
+
tb: toRounded,
|
|
445
|
+
};
|
|
446
|
+
|
|
447
|
+
const keys = Object.keys(data || {}).sort();
|
|
448
|
+
|
|
449
|
+
for (const key of keys) {
|
|
450
|
+
let value = data[key];
|
|
451
|
+
|
|
452
|
+
// ignore invalid values
|
|
453
|
+
if (!isValid(value)) {
|
|
454
|
+
continue;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
// Version should only be reported if not equal to 1.
|
|
458
|
+
if (key === 'v' && value === 1) {
|
|
459
|
+
continue;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
// Playback rate should only be sent if not equal to 1.
|
|
463
|
+
if (key == 'pr' && value === 1) {
|
|
464
|
+
continue;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
// Certain values require special formatting
|
|
468
|
+
const formatter = formatters[key];
|
|
469
|
+
if (formatter) {
|
|
470
|
+
value = formatter(value);
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
// Serialize the key/value pair
|
|
474
|
+
const type = typeof value;
|
|
475
|
+
let result;
|
|
476
|
+
|
|
477
|
+
if (type === 'string' && key !== 'ot' && key !== 'sf' && key !== 'st') {
|
|
478
|
+
result = `${key}=${JSON.stringify(value)}`;
|
|
479
|
+
} else if (type === 'boolean') {
|
|
480
|
+
result = key;
|
|
481
|
+
} else if (type === 'symbol') {
|
|
482
|
+
result = `${key}=${value.description}`;
|
|
483
|
+
} else {
|
|
484
|
+
result = `${key}=${value}`;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
results.push(result);
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
return results.join(',');
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
/**
|
|
494
|
+
* Convert a CMCD data object to request headers according to the rules
|
|
495
|
+
* defined in the section 2.1 and 3.2 of
|
|
496
|
+
* [CTA-5004](https://cdn.cta.tech/cta/media/media/resources/standards/pdfs/cta-5004-final.pdf).
|
|
497
|
+
*
|
|
498
|
+
* @param {CmcdData} data The CMCD data object
|
|
499
|
+
* @return {!Object}
|
|
500
|
+
*/
|
|
501
|
+
static toHeaders(data) {
|
|
502
|
+
const keys = Object.keys(data);
|
|
503
|
+
const headers = {};
|
|
504
|
+
const headerNames = ['Object', 'Request', 'Session', 'Status'];
|
|
505
|
+
const headerGroups = [{}, {}, {}, {}];
|
|
506
|
+
const headerMap = {
|
|
507
|
+
br: 0, d: 0, ot: 0, tb: 0,
|
|
508
|
+
bl: 1, dl: 1, mtp: 1, nor: 1, nrr: 1, su: 1,
|
|
509
|
+
cid: 2, pr: 2, sf: 2, sid: 2, st: 2, v: 2,
|
|
510
|
+
bs: 3, rtp: 3,
|
|
511
|
+
};
|
|
512
|
+
|
|
513
|
+
for (const key of keys) {
|
|
514
|
+
// Unmapped fields are mapped to the Request header
|
|
515
|
+
const index = (headerMap[key] != null) ? headerMap[key] : 1;
|
|
516
|
+
headerGroups[index][key] = data[key];
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
for (let i = 0; i < headerGroups.length; i++) {
|
|
520
|
+
const value = shaka.util.CmcdManager.serialize(headerGroups[i]);
|
|
521
|
+
if (value) {
|
|
522
|
+
headers[`CMCD-${headerNames[i]}`] = value;
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
return headers;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
/**
|
|
530
|
+
* Convert a CMCD data object to query args according to the rules
|
|
531
|
+
* defined in the section 2.2 and 3.2 of
|
|
532
|
+
* [CTA-5004](https://cdn.cta.tech/cta/media/media/resources/standards/pdfs/cta-5004-final.pdf).
|
|
533
|
+
*
|
|
534
|
+
* @param {CmcdData} data The CMCD data object
|
|
535
|
+
* @return {string}
|
|
536
|
+
*/
|
|
537
|
+
static toQuery(data) {
|
|
538
|
+
return shaka.util.CmcdManager.serialize(data);
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
/**
|
|
542
|
+
* Append query args to a uri.
|
|
543
|
+
*
|
|
544
|
+
* @param {string} uri
|
|
545
|
+
* @param {string} query
|
|
546
|
+
* @return {string}
|
|
547
|
+
*/
|
|
548
|
+
static appendQueryToUri(uri, query) {
|
|
549
|
+
if (!query) {
|
|
550
|
+
return uri;
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
if (uri.includes('offline:')) {
|
|
554
|
+
return uri;
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
const url = new goog.Uri(uri);
|
|
558
|
+
url.getQueryData().set('CMCD', query);
|
|
559
|
+
return url.toString();
|
|
560
|
+
}
|
|
561
|
+
};
|
|
562
|
+
|
|
563
|
+
|
|
564
|
+
/**
|
|
565
|
+
* @typedef {{
|
|
566
|
+
* getBandwidthEstimate: function():number,
|
|
567
|
+
* getBufferedInfo: function():shaka.extern.BufferedInfo,
|
|
568
|
+
* getCurrentTime: function():number,
|
|
569
|
+
* getVariantTracks: function():Array.<shaka.extern.Track>,
|
|
570
|
+
* getPlaybackRate: function():number,
|
|
571
|
+
* isLive: function():boolean
|
|
572
|
+
* }}
|
|
573
|
+
*
|
|
574
|
+
* @property {function():number} getBandwidthEstimate
|
|
575
|
+
* Get the estimated bandwidth in bits per second.
|
|
576
|
+
* @property {function():shaka.extern.BufferedInfo} getBufferedInfo
|
|
577
|
+
* Get information about what the player has buffered.
|
|
578
|
+
* @property {function():number} getCurrentTime
|
|
579
|
+
* Get the current time
|
|
580
|
+
* @property {function():Array.<shaka.extern.Track>} getVariantTracks
|
|
581
|
+
* Get the variant tracks
|
|
582
|
+
* @property {function():number} getPlaybackRate
|
|
583
|
+
* Get the playback rate
|
|
584
|
+
* @property {function():boolean} isLive
|
|
585
|
+
* Get if the player is playing live content.
|
|
586
|
+
*/
|
|
587
|
+
shaka.util.CmcdManager.PlayerInterface;
|
|
588
|
+
|
|
589
|
+
|
|
590
|
+
/**
|
|
591
|
+
* @typedef {{
|
|
592
|
+
* type: string,
|
|
593
|
+
* init: boolean,
|
|
594
|
+
* duration: number,
|
|
595
|
+
* mimeType: string,
|
|
596
|
+
* codecs: string,
|
|
597
|
+
* bandwidth: (number|undefined)
|
|
598
|
+
* }}
|
|
599
|
+
*
|
|
600
|
+
* @property {string} type
|
|
601
|
+
* The media type
|
|
602
|
+
* @property {boolean} init
|
|
603
|
+
* Flag indicating whether the segment is an init segment
|
|
604
|
+
* @property {number} duration
|
|
605
|
+
* The duration of the segment in seconds
|
|
606
|
+
* @property {string} mimeType
|
|
607
|
+
* The segment's mime type
|
|
608
|
+
* @property {string} codecs
|
|
609
|
+
* The segment's codecs
|
|
610
|
+
* @property {(number|undefined)} bandwidth
|
|
611
|
+
* The segment's variation bandwidth
|
|
612
|
+
*
|
|
613
|
+
* @export
|
|
614
|
+
*/
|
|
615
|
+
shaka.util.CmcdManager.SegmentInfo;
|
|
616
|
+
|
|
617
|
+
|
|
618
|
+
/**
|
|
619
|
+
* @typedef {{
|
|
620
|
+
* format: shaka.util.CmcdManager.StreamingFormat
|
|
621
|
+
* }}
|
|
622
|
+
*
|
|
623
|
+
* @property {shaka.util.CmcdManager.StreamingFormat} format
|
|
624
|
+
* The manifest's stream format
|
|
625
|
+
*
|
|
626
|
+
* @export
|
|
627
|
+
*/
|
|
628
|
+
shaka.util.CmcdManager.ManifestInfo;
|
|
629
|
+
|
|
630
|
+
|
|
631
|
+
/**
|
|
632
|
+
* @enum {string}
|
|
633
|
+
*/
|
|
634
|
+
shaka.util.CmcdManager.ObjectType = {
|
|
635
|
+
MANIFEST: 'm',
|
|
636
|
+
AUDIO: 'a',
|
|
637
|
+
VIDEO: 'v',
|
|
638
|
+
MUXED: 'av',
|
|
639
|
+
INIT: 'i',
|
|
640
|
+
CAPTION: 'c',
|
|
641
|
+
TIMED_TEXT: 'tt',
|
|
642
|
+
KEY: 'k',
|
|
643
|
+
OTHER: 'o',
|
|
644
|
+
};
|
|
645
|
+
|
|
646
|
+
|
|
647
|
+
/**
|
|
648
|
+
* @enum {string}
|
|
649
|
+
*/
|
|
650
|
+
shaka.util.CmcdManager.StreamType = {
|
|
651
|
+
VOD: 'v',
|
|
652
|
+
LIVE: 'l',
|
|
653
|
+
};
|
|
654
|
+
|
|
655
|
+
|
|
656
|
+
/**
|
|
657
|
+
* @enum {string}
|
|
658
|
+
* @export
|
|
659
|
+
*/
|
|
660
|
+
shaka.util.CmcdManager.StreamingFormat = {
|
|
661
|
+
DASH: 'd',
|
|
662
|
+
HLS: 'h',
|
|
663
|
+
SMOOTH: 's',
|
|
664
|
+
OTHER: 'o',
|
|
665
|
+
};
|
|
666
|
+
|
|
667
|
+
|
|
668
|
+
/**
|
|
669
|
+
* The CMCD spec version
|
|
670
|
+
* @const {number}
|
|
671
|
+
*/
|
|
672
|
+
shaka.util.CmcdManager.Version = 1;
|
package/lib/util/error.js
CHANGED
|
@@ -986,6 +986,12 @@ shaka.util.Error.Code = {
|
|
|
986
986
|
*/
|
|
987
987
|
'DOWNLOAD_SIZE_CALLBACK_ERROR': 9015,
|
|
988
988
|
|
|
989
|
+
/**
|
|
990
|
+
* The storage cell does not allow new operations that significantly change
|
|
991
|
+
* existing data.
|
|
992
|
+
*/
|
|
993
|
+
'MODIFY_OPERATION_NOT_SUPPORTED': 9016,
|
|
994
|
+
|
|
989
995
|
/**
|
|
990
996
|
* CS IMA SDK, required for ad insertion, has not been included on the page.
|
|
991
997
|
*/
|