shaka-player 3.2.0 → 3.2.4
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/workflows/build_and_test.yaml +73 -0
- package/.github/workflows/release.yaml +53 -0
- package/AUTHORS +3 -0
- package/CHANGELOG.md +182 -1
- package/CONTRIBUTORS +3 -0
- package/README.md +4 -4
- package/build/checkversion.py +1 -1
- package/build/generateExterns.js +1 -1
- package/build/misspellings.txt +1 -0
- package/build/shakaBuildHelpers.py +6 -5
- package/build/subprocessWindowsPatch.py +103 -0
- package/build/test.py +6 -0
- package/demo/common/assets.js +1 -1
- package/demo/index.html +1 -1
- package/dist/controls.css +2 -2
- package/dist/controls.css.map +1 -1
- package/dist/demo.compiled.debug.js +1 -1
- package/dist/demo.compiled.js +1 -1
- package/dist/deps.js +8 -8
- package/dist/locales.js +37 -37
- package/dist/receiver.compiled.debug.js +1 -1
- package/dist/receiver.compiled.js +1 -1
- package/dist/shaka-player.compiled.d.ts +195 -5
- package/dist/shaka-player.compiled.debug.d.ts +195 -5
- package/dist/shaka-player.compiled.debug.externs.js +226 -14
- package/dist/shaka-player.compiled.debug.js +424 -399
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +226 -14
- package/dist/shaka-player.compiled.js +826 -812
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.d.ts +197 -16
- package/dist/shaka-player.ui.debug.d.ts +197 -16
- package/dist/shaka-player.ui.debug.externs.js +230 -27
- package/dist/shaka-player.ui.debug.js +466 -442
- package/dist/shaka-player.ui.debug.map +4 -4
- package/dist/shaka-player.ui.externs.js +230 -27
- package/dist/shaka-player.ui.js +946 -932
- package/dist/shaka-player.ui.map +4 -4
- package/docs/tutorials/fairplay.md +1 -1
- package/docs/tutorials/faq.md +14 -0
- package/docs/tutorials/ui.md +5 -5
- package/externs/ima.js +4 -0
- package/externs/shaka/ads.js +25 -0
- package/externs/shaka/player.js +8 -0
- package/externs/shaka/text.js +10 -0
- package/karma.conf.js +20 -15
- package/lib/ads/ad_manager.js +46 -26
- package/lib/ads/client_side_ad_manager.js +82 -88
- package/lib/ads/server_side_ad_manager.js +45 -13
- package/lib/cast/cast_proxy.js +6 -2
- package/lib/cast/cast_receiver.js +5 -1
- package/lib/cast/cast_sender.js +2 -2
- package/lib/cea/sei_processor.js +24 -17
- package/lib/dash/dash_parser.js +131 -24
- package/lib/dash/segment_list.js +1 -1
- package/lib/dash/segment_template.js +1 -1
- package/lib/hls/hls_parser.js +74 -17
- package/lib/hls/manifest_text_parser.js +1 -0
- package/lib/media/closed_caption_parser.js +3 -1
- package/lib/media/content_workarounds.js +12 -0
- package/lib/media/drm_engine.js +20 -1
- package/lib/media/gap_jumping_controller.js +8 -4
- package/lib/media/media_source_engine.js +1 -2
- package/lib/media/playhead.js +1 -1
- package/lib/media/region_observer.js +39 -33
- package/lib/media/region_timeline.js +17 -19
- package/lib/media/segment_index.js +2 -1
- package/lib/media/segment_reference.js +19 -1
- package/lib/media/streaming_engine.js +8 -4
- package/lib/net/networking_engine.js +6 -1
- package/lib/offline/download_manager.js +1 -2
- package/lib/offline/storage.js +8 -9
- package/lib/player.js +129 -59
- package/lib/polyfill/aria.js +12 -2
- package/lib/polyfill/encryption_scheme.js +2 -0
- package/lib/polyfill/fullscreen.js +2 -0
- package/lib/polyfill/mathround.js +2 -0
- package/lib/polyfill/media_capabilities.js +73 -21
- package/lib/polyfill/mediasource.js +8 -0
- package/lib/polyfill/orientation.js +3 -1
- package/lib/polyfill/patchedmediakeys_apple.js +6 -4
- package/lib/polyfill/patchedmediakeys_ms.js +6 -4
- package/lib/polyfill/patchedmediakeys_nop.js +2 -0
- package/lib/polyfill/patchedmediakeys_webkit.js +6 -4
- package/lib/polyfill/pip_webkit.js +2 -0
- package/lib/polyfill/storage_estimate.js +2 -0
- package/lib/polyfill/video_play_promise.js +2 -0
- package/lib/polyfill/videoplaybackquality.js +2 -0
- package/lib/polyfill/vttcue.js +2 -0
- package/lib/text/cue.js +6 -0
- package/lib/text/mp4_ttml_parser.js +3 -0
- package/lib/text/text_engine.js +14 -2
- package/lib/text/ttml_text_parser.js +135 -87
- package/lib/text/ui_text_displayer.js +213 -80
- package/lib/text/vtt_text_parser.js +4 -2
- package/lib/text/web_vtt_generator.js +21 -12
- package/lib/util/fake_event.js +53 -7
- package/lib/util/fake_event_target.js +21 -1
- package/lib/util/mp4_box_parsers.js +1 -1
- package/lib/util/periods.js +4 -1
- package/lib/util/platform.js +13 -1
- package/lib/util/stream_utils.js +105 -13
- package/lib/util/xml_utils.js +50 -12
- package/package.json +3 -6
- package/roadmap.md +24 -22
- package/test/cast/cast_proxy_unit.js +12 -6
- package/test/cast/cast_receiver_integration.js +1 -1
- package/test/cast/cast_utils_unit.js +1 -1
- package/test/cea/mp4_cea_parser_unit.js +26 -0
- package/test/dash/dash_parser_live_unit.js +43 -0
- package/test/dash/dash_parser_manifest_unit.js +222 -3
- package/test/hls/hls_parser_unit.js +79 -1
- package/test/media/closed_caption_parser_unit.js +20 -0
- package/test/media/drm_engine_integration.js +86 -2
- package/test/media/drm_engine_unit.js +57 -0
- package/test/media/playhead_unit.js +27 -1
- package/test/media/region_observer_unit.js +40 -5
- package/test/media/region_timeline_unit.js +40 -22
- package/test/media/streaming_engine_integration.js +2 -1
- package/test/media/streaming_engine_unit.js +145 -0
- package/test/player_integration.js +79 -8
- package/test/player_src_equals_integration.js +41 -8
- package/test/player_unit.js +14 -4
- package/test/test/assets/3675/chunk-stream0-00001.m4s +0 -0
- package/test/test/assets/3675/chunk-stream0-00002.m4s +0 -0
- package/test/test/assets/3675/chunk-stream0-00003.m4s +0 -0
- package/test/test/assets/3675/chunk-stream0-00004.m4s +0 -0
- package/test/test/assets/3675/chunk-stream0-00005.m4s +0 -0
- package/test/test/assets/3675/chunk-stream0-00006.m4s +0 -0
- package/test/test/assets/3675/chunk-stream0-00007.m4s +0 -0
- package/test/test/assets/3675/dash_0.mpd +30 -0
- package/test/test/assets/3675/dash_1.mpd +30 -0
- package/test/test/assets/3675/dash_2.mpd +30 -0
- package/test/test/assets/3675/dash_3.mpd +30 -0
- package/test/test/assets/3675/dash_4.mpd +30 -0
- package/test/test/assets/3675/dash_5.mpd +26 -0
- package/test/test/assets/3675/init-stream0.m4s +0 -0
- package/test/test/assets/chapters.vtt +2 -2
- package/test/test/assets/chapters2.vtt +10 -0
- package/test/test/assets/empty_caption_video_init.mp4 +0 -0
- package/test/test/assets/empty_caption_video_segment.mp4 +0 -0
- package/test/test/util/fake_ad_manager.js +11 -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 +542 -220
- package/test/text/ui_text_displayer_unit.js +93 -20
- package/test/text/vtt_text_parser_unit.js +17 -1
- package/test/text/web_vtt_generator_unit.js +58 -3
- package/test/ui/localization_unit.js +15 -14
- package/test/ui/text_displayer_layout_unit.js +21 -8
- package/test/util/mp4_box_parsers_unit.js +28 -0
- package/test/util/stream_utils_unit.js +60 -3
- package/ui/cast_button.js +2 -3
- package/ui/controls.js +11 -6
- package/ui/less/buttons.less +0 -4
- package/ui/less/containers.less +6 -7
- package/ui/locales/ru.json +6 -6
- package/ui/localization.js +40 -87
- package/ui/pip_button.js +2 -3
- package/ui/seek_bar.js +1 -2
- package/ui/text_selection.js +1 -0
|
@@ -13,10 +13,12 @@ goog.provide('shaka.ads.ClientSideAdManager');
|
|
|
13
13
|
|
|
14
14
|
goog.require('goog.asserts');
|
|
15
15
|
goog.require('shaka.ads.ClientSideAd');
|
|
16
|
+
goog.require('shaka.util.IReleasable');
|
|
16
17
|
|
|
17
18
|
|
|
18
19
|
/**
|
|
19
20
|
* A class responsible for client-side ad interactions.
|
|
21
|
+
* @implements {shaka.util.IReleasable}
|
|
20
22
|
*/
|
|
21
23
|
shaka.ads.ClientSideAdManager = class {
|
|
22
24
|
/**
|
|
@@ -32,6 +34,9 @@ shaka.ads.ClientSideAdManager = class {
|
|
|
32
34
|
/** @private {HTMLMediaElement} */
|
|
33
35
|
this.video_ = video;
|
|
34
36
|
|
|
37
|
+
/** @private {ResizeObserver} */
|
|
38
|
+
this.resizeObserver_ = null;
|
|
39
|
+
|
|
35
40
|
/** @private {number} */
|
|
36
41
|
this.requestAdsStartTime_ = NaN;
|
|
37
42
|
|
|
@@ -106,6 +111,21 @@ shaka.ads.ClientSideAdManager = class {
|
|
|
106
111
|
}
|
|
107
112
|
}
|
|
108
113
|
|
|
114
|
+
/** @override */
|
|
115
|
+
release() {
|
|
116
|
+
this.stop();
|
|
117
|
+
if (this.resizeObserver_) {
|
|
118
|
+
this.resizeObserver_.disconnect();
|
|
119
|
+
}
|
|
120
|
+
if (this.eventManager_) {
|
|
121
|
+
this.eventManager_.release();
|
|
122
|
+
}
|
|
123
|
+
if (this.imaAdsManager_) {
|
|
124
|
+
this.imaAdsManager_.destroy();
|
|
125
|
+
}
|
|
126
|
+
this.adsLoader_.destroy();
|
|
127
|
+
}
|
|
128
|
+
|
|
109
129
|
/**
|
|
110
130
|
* @param {!google.ima.AdErrorEvent} e
|
|
111
131
|
* @private
|
|
@@ -118,7 +138,7 @@ shaka.ads.ClientSideAdManager = class {
|
|
|
118
138
|
// Remove ad breaks from the timeline
|
|
119
139
|
this.onEvent_(
|
|
120
140
|
new shaka.util.FakeEvent(shaka.ads.AdManager.CUEPOINTS_CHANGED,
|
|
121
|
-
|
|
141
|
+
(new Map()).set('cuepoints', [])));
|
|
122
142
|
}
|
|
123
143
|
|
|
124
144
|
|
|
@@ -131,30 +151,31 @@ shaka.ads.ClientSideAdManager = class {
|
|
|
131
151
|
|
|
132
152
|
const now = Date.now() / 1000;
|
|
133
153
|
const loadTime = now - this.requestAdsStartTime_;
|
|
134
|
-
this.onEvent_(
|
|
135
|
-
new
|
|
136
|
-
{'loadTime': loadTime}));
|
|
154
|
+
this.onEvent_(new shaka.util.FakeEvent(shaka.ads.AdManager.ADS_LOADED,
|
|
155
|
+
(new Map()).set('loadTime', loadTime)));
|
|
137
156
|
|
|
138
157
|
this.imaAdsManager_ = e.getAdsManager(this.video_);
|
|
139
158
|
|
|
140
159
|
this.onEvent_(new shaka.util.FakeEvent(
|
|
141
160
|
shaka.ads.AdManager.IMA_AD_MANAGER_LOADED,
|
|
142
|
-
|
|
143
|
-
'imaAdManager': this.imaAdsManager_,
|
|
144
|
-
}));
|
|
161
|
+
(new Map()).set('imaAdManager', this.imaAdsManager_)));
|
|
145
162
|
|
|
146
163
|
const cuePointStarts = this.imaAdsManager_.getCuePoints();
|
|
147
164
|
if (cuePointStarts.length) {
|
|
148
|
-
/** @type {!Array.<!shaka.
|
|
165
|
+
/** @type {!Array.<!shaka.extern.AdCuePoint>} */
|
|
149
166
|
const cuePoints = [];
|
|
150
167
|
for (const start of cuePointStarts) {
|
|
151
|
-
|
|
168
|
+
/** @type {shaka.extern.AdCuePoint} */
|
|
169
|
+
const shakaCuePoint = {
|
|
170
|
+
start: start,
|
|
171
|
+
end: null,
|
|
172
|
+
};
|
|
152
173
|
cuePoints.push(shakaCuePoint);
|
|
153
174
|
}
|
|
154
175
|
|
|
155
|
-
this.onEvent_(
|
|
156
|
-
|
|
157
|
-
|
|
176
|
+
this.onEvent_(new shaka.util.FakeEvent(
|
|
177
|
+
shaka.ads.AdManager.CUEPOINTS_CHANGED,
|
|
178
|
+
(new Map()).set('cuepoints', cuePoints)));
|
|
158
179
|
}
|
|
159
180
|
|
|
160
181
|
this.addImaEventListeners_();
|
|
@@ -176,6 +197,16 @@ shaka.ads.ClientSideAdManager = class {
|
|
|
176
197
|
this.video_.offsetHeight, viewMode);
|
|
177
198
|
});
|
|
178
199
|
|
|
200
|
+
if ('ResizeObserver' in window) {
|
|
201
|
+
this.resizeObserver_ = new ResizeObserver(() => {
|
|
202
|
+
const viewMode = document.fullscreenElement ?
|
|
203
|
+
google.ima.ViewMode.FULLSCREEN : google.ima.ViewMode.NORMAL;
|
|
204
|
+
this.imaAdsManager_.resize(this.video_.offsetWidth,
|
|
205
|
+
this.video_.offsetHeight, viewMode);
|
|
206
|
+
});
|
|
207
|
+
this.resizeObserver_.observe(this.video_);
|
|
208
|
+
}
|
|
209
|
+
|
|
179
210
|
// Single video and overlay ads will start at this time
|
|
180
211
|
// TODO (ismena): Need a better inderstanding of what this does.
|
|
181
212
|
// The docs say it's called to 'start playing the ads,' but I haven't
|
|
@@ -194,6 +225,15 @@ shaka.ads.ClientSideAdManager = class {
|
|
|
194
225
|
* @private
|
|
195
226
|
*/
|
|
196
227
|
addImaEventListeners_() {
|
|
228
|
+
/**
|
|
229
|
+
* @param {!Event} e
|
|
230
|
+
* @param {string} type
|
|
231
|
+
*/
|
|
232
|
+
const convertEventAndSend = (e, type) => {
|
|
233
|
+
const data = (new Map()).set('originalEvent', e);
|
|
234
|
+
this.onEvent_(new shaka.util.FakeEvent(type, data));
|
|
235
|
+
};
|
|
236
|
+
|
|
197
237
|
this.eventManager_.listen(this.imaAdsManager_,
|
|
198
238
|
google.ima.AdErrorEvent.Type.AD_ERROR, (error) => {
|
|
199
239
|
this.onAdError_(/** @type {!google.ima.AdErrorEvent} */ (error));
|
|
@@ -211,30 +251,22 @@ shaka.ads.ClientSideAdManager = class {
|
|
|
211
251
|
|
|
212
252
|
this.eventManager_.listen(this.imaAdsManager_,
|
|
213
253
|
google.ima.AdEvent.Type.FIRST_QUARTILE, (e) => {
|
|
214
|
-
|
|
215
|
-
new shaka.util.FakeEvent(shaka.ads.AdManager.AD_FIRST_QUARTILE,
|
|
216
|
-
{'originalEvent': e}));
|
|
254
|
+
convertEventAndSend(e, shaka.ads.AdManager.AD_FIRST_QUARTILE);
|
|
217
255
|
});
|
|
218
256
|
|
|
219
257
|
this.eventManager_.listen(this.imaAdsManager_,
|
|
220
258
|
google.ima.AdEvent.Type.MIDPOINT, (e) => {
|
|
221
|
-
|
|
222
|
-
new shaka.util.FakeEvent(shaka.ads.AdManager.AD_MIDPOINT,
|
|
223
|
-
{'originalEvent': e}));
|
|
259
|
+
convertEventAndSend(e, shaka.ads.AdManager.AD_MIDPOINT);
|
|
224
260
|
});
|
|
225
261
|
|
|
226
262
|
this.eventManager_.listen(this.imaAdsManager_,
|
|
227
263
|
google.ima.AdEvent.Type.THIRD_QUARTILE, (e) => {
|
|
228
|
-
|
|
229
|
-
new shaka.util.FakeEvent(shaka.ads.AdManager.AD_THIRD_QUARTILE,
|
|
230
|
-
{'originalEvent': e}));
|
|
264
|
+
convertEventAndSend(e, shaka.ads.AdManager.AD_THIRD_QUARTILE);
|
|
231
265
|
});
|
|
232
266
|
|
|
233
267
|
this.eventManager_.listen(this.imaAdsManager_,
|
|
234
268
|
google.ima.AdEvent.Type.COMPLETE, (e) => {
|
|
235
|
-
|
|
236
|
-
new shaka.util.FakeEvent(shaka.ads.AdManager.AD_COMPLETE,
|
|
237
|
-
{'originalEvent': e}));
|
|
269
|
+
convertEventAndSend(e, shaka.ads.AdManager.AD_COMPLETE);
|
|
238
270
|
});
|
|
239
271
|
|
|
240
272
|
this.eventManager_.listen(this.imaAdsManager_,
|
|
@@ -249,140 +281,102 @@ shaka.ads.ClientSideAdManager = class {
|
|
|
249
281
|
|
|
250
282
|
this.eventManager_.listen(this.imaAdsManager_,
|
|
251
283
|
google.ima.AdEvent.Type.SKIPPED, (e) => {
|
|
252
|
-
|
|
253
|
-
new shaka.util.FakeEvent(shaka.ads.AdManager.AD_SKIPPED,
|
|
254
|
-
{'originalEvent': e}));
|
|
284
|
+
convertEventAndSend(e, shaka.ads.AdManager.AD_SKIPPED);
|
|
255
285
|
});
|
|
256
286
|
|
|
257
287
|
this.eventManager_.listen(this.imaAdsManager_,
|
|
258
288
|
google.ima.AdEvent.Type.VOLUME_CHANGED, (e) => {
|
|
259
|
-
|
|
260
|
-
new shaka.util.FakeEvent(shaka.ads.AdManager.AD_VOLUME_CHANGED,
|
|
261
|
-
{'originalEvent': e}));
|
|
289
|
+
convertEventAndSend(e, shaka.ads.AdManager.AD_VOLUME_CHANGED);
|
|
262
290
|
});
|
|
263
291
|
|
|
264
292
|
this.eventManager_.listen(this.imaAdsManager_,
|
|
265
293
|
google.ima.AdEvent.Type.VOLUME_MUTED, (e) => {
|
|
266
|
-
|
|
267
|
-
new shaka.util.FakeEvent(shaka.ads.AdManager.AD_MUTED,
|
|
268
|
-
{'originalEvent': e}));
|
|
294
|
+
convertEventAndSend(e, shaka.ads.AdManager.AD_MUTED);
|
|
269
295
|
});
|
|
270
296
|
|
|
271
297
|
this.eventManager_.listen(this.imaAdsManager_,
|
|
272
298
|
google.ima.AdEvent.Type.PAUSED, (e) => {
|
|
273
299
|
goog.asserts.assert(this.ad_ != null, 'Ad should not be null!');
|
|
274
300
|
this.ad_.setPaused(true);
|
|
275
|
-
|
|
276
|
-
new shaka.util.FakeEvent(shaka.ads.AdManager.AD_PAUSED,
|
|
277
|
-
{'originalEvent': e}));
|
|
301
|
+
convertEventAndSend(e, shaka.ads.AdManager.AD_PAUSED);
|
|
278
302
|
});
|
|
279
303
|
|
|
280
304
|
this.eventManager_.listen(this.imaAdsManager_,
|
|
281
305
|
google.ima.AdEvent.Type.RESUMED, (e) => {
|
|
282
306
|
goog.asserts.assert(this.ad_ != null, 'Ad should not be null!');
|
|
283
307
|
this.ad_.setPaused(false);
|
|
284
|
-
|
|
285
|
-
new shaka.util.FakeEvent(shaka.ads.AdManager.AD_RESUMED,
|
|
286
|
-
{'originalEvent': e}));
|
|
308
|
+
convertEventAndSend(e, shaka.ads.AdManager.AD_RESUMED);
|
|
287
309
|
});
|
|
288
310
|
|
|
289
311
|
this.eventManager_.listen(this.imaAdsManager_,
|
|
290
312
|
google.ima.AdEvent.Type.SKIPPABLE_STATE_CHANGED, (e) => {
|
|
291
313
|
goog.asserts.assert(this.ad_ != null, 'Ad should not be null!');
|
|
292
|
-
|
|
293
|
-
shaka.ads.AdManager.AD_SKIP_STATE_CHANGED,
|
|
294
|
-
{'originalEvent': e}));
|
|
314
|
+
convertEventAndSend(e, shaka.ads.AdManager.AD_SKIP_STATE_CHANGED);
|
|
295
315
|
});
|
|
296
316
|
|
|
297
317
|
this.eventManager_.listen(this.imaAdsManager_,
|
|
298
318
|
google.ima.AdEvent.Type.CLICK, (e) => {
|
|
299
|
-
|
|
300
|
-
shaka.ads.AdManager.AD_CLICKED,
|
|
301
|
-
{'originalEvent': e}));
|
|
319
|
+
convertEventAndSend(e, shaka.ads.AdManager.AD_CLICKED);
|
|
302
320
|
});
|
|
303
321
|
|
|
304
322
|
this.eventManager_.listen(this.imaAdsManager_,
|
|
305
323
|
google.ima.AdEvent.Type.AD_PROGRESS, (e) => {
|
|
306
|
-
|
|
307
|
-
shaka.ads.AdManager.AD_PROGRESS,
|
|
308
|
-
{'originalEvent': e}));
|
|
324
|
+
convertEventAndSend(e, shaka.ads.AdManager.AD_PROGRESS);
|
|
309
325
|
});
|
|
310
326
|
|
|
311
327
|
this.eventManager_.listen(this.imaAdsManager_,
|
|
312
328
|
google.ima.AdEvent.Type.AD_BUFFERING, (e) => {
|
|
313
|
-
|
|
314
|
-
shaka.ads.AdManager.AD_BUFFERING,
|
|
315
|
-
{'originalEvent': e}));
|
|
329
|
+
convertEventAndSend(e, shaka.ads.AdManager.AD_BUFFERING);
|
|
316
330
|
});
|
|
317
331
|
|
|
318
332
|
this.eventManager_.listen(this.imaAdsManager_,
|
|
319
333
|
google.ima.AdEvent.Type.IMPRESSION, (e) => {
|
|
320
|
-
|
|
321
|
-
shaka.ads.AdManager.AD_IMPRESSION,
|
|
322
|
-
{'originalEvent': e}));
|
|
334
|
+
convertEventAndSend(e, shaka.ads.AdManager.AD_IMPRESSION);
|
|
323
335
|
});
|
|
324
336
|
|
|
325
337
|
this.eventManager_.listen(this.imaAdsManager_,
|
|
326
338
|
google.ima.AdEvent.Type.DURATION_CHANGE, (e) => {
|
|
327
|
-
|
|
328
|
-
shaka.ads.AdManager.AD_DURATION_CHANGED,
|
|
329
|
-
{'originalEvent': e}));
|
|
339
|
+
convertEventAndSend(e, shaka.ads.AdManager.AD_DURATION_CHANGED);
|
|
330
340
|
});
|
|
331
341
|
|
|
332
342
|
this.eventManager_.listen(this.imaAdsManager_,
|
|
333
343
|
google.ima.AdEvent.Type.USER_CLOSE, (e) => {
|
|
334
|
-
|
|
335
|
-
shaka.ads.AdManager.AD_CLOSED,
|
|
336
|
-
{'originalEvent': e}));
|
|
344
|
+
convertEventAndSend(e, shaka.ads.AdManager.AD_CLOSED);
|
|
337
345
|
});
|
|
338
346
|
|
|
339
347
|
this.eventManager_.listen(this.imaAdsManager_,
|
|
340
348
|
google.ima.AdEvent.Type.LOADED, (e) => {
|
|
341
|
-
|
|
342
|
-
shaka.ads.AdManager.AD_LOADED,
|
|
343
|
-
{'originalEvent': e}));
|
|
349
|
+
convertEventAndSend(e, shaka.ads.AdManager.AD_LOADED);
|
|
344
350
|
});
|
|
345
351
|
|
|
346
352
|
this.eventManager_.listen(this.imaAdsManager_,
|
|
347
353
|
google.ima.AdEvent.Type.ALL_ADS_COMPLETED, (e) => {
|
|
348
|
-
|
|
349
|
-
shaka.ads.AdManager.ALL_ADS_COMPLETED,
|
|
350
|
-
{'originalEvent': e}));
|
|
354
|
+
convertEventAndSend(e, shaka.ads.AdManager.ALL_ADS_COMPLETED);
|
|
351
355
|
});
|
|
352
356
|
|
|
353
357
|
this.eventManager_.listen(this.imaAdsManager_,
|
|
354
358
|
google.ima.AdEvent.Type.LINEAR_CHANGED, (e) => {
|
|
355
|
-
|
|
356
|
-
shaka.ads.AdManager.AD_LINEAR_CHANGED,
|
|
357
|
-
{'originalEvent': e}));
|
|
359
|
+
convertEventAndSend(e, shaka.ads.AdManager.AD_LINEAR_CHANGED);
|
|
358
360
|
});
|
|
359
361
|
|
|
360
362
|
this.eventManager_.listen(this.imaAdsManager_,
|
|
361
363
|
google.ima.AdEvent.Type.AD_METADATA, (e) => {
|
|
362
|
-
|
|
363
|
-
shaka.ads.AdManager.AD_METADATA,
|
|
364
|
-
{'originalEvent': e}));
|
|
364
|
+
convertEventAndSend(e, shaka.ads.AdManager.AD_METADATA);
|
|
365
365
|
});
|
|
366
366
|
|
|
367
367
|
this.eventManager_.listen(this.imaAdsManager_,
|
|
368
368
|
google.ima.AdEvent.Type.LOG, (e) => {
|
|
369
|
-
|
|
370
|
-
shaka.ads.AdManager.AD_RECOVERABLE_ERROR,
|
|
371
|
-
{'originalEvent': e}));
|
|
369
|
+
convertEventAndSend(e, shaka.ads.AdManager.AD_RECOVERABLE_ERROR);
|
|
372
370
|
});
|
|
373
371
|
|
|
374
372
|
this.eventManager_.listen(this.imaAdsManager_,
|
|
375
373
|
google.ima.AdEvent.Type.AD_BREAK_READY, (e) => {
|
|
376
|
-
|
|
377
|
-
shaka.ads.AdManager.AD_BREAK_READY,
|
|
378
|
-
{'originalEvent': e}));
|
|
374
|
+
convertEventAndSend(e, shaka.ads.AdManager.AD_BREAK_READY);
|
|
379
375
|
});
|
|
380
376
|
|
|
381
377
|
this.eventManager_.listen(this.imaAdsManager_,
|
|
382
378
|
google.ima.AdEvent.Type.INTERACTION, (e) => {
|
|
383
|
-
|
|
384
|
-
shaka.ads.AdManager.AD_INTERACTION,
|
|
385
|
-
{'originalEvent': e}));
|
|
379
|
+
convertEventAndSend(e, shaka.ads.AdManager.AD_INTERACTION);
|
|
386
380
|
});
|
|
387
381
|
}
|
|
388
382
|
|
|
@@ -396,12 +390,12 @@ shaka.ads.ClientSideAdManager = class {
|
|
|
396
390
|
|
|
397
391
|
const imaAd = e.getAd();
|
|
398
392
|
this.ad_ = new shaka.ads.ClientSideAd(imaAd, this.imaAdsManager_);
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
393
|
+
const data = new Map()
|
|
394
|
+
.set('ad', this.ad_)
|
|
395
|
+
.set('sdkAdObject', imaAd)
|
|
396
|
+
.set('originalEvent', e);
|
|
397
|
+
this.onEvent_(new shaka.util.FakeEvent(
|
|
398
|
+
shaka.ads.AdManager.AD_STARTED, data));
|
|
405
399
|
this.adContainer_.setAttribute('ad-active', 'true');
|
|
406
400
|
this.video_.pause();
|
|
407
401
|
}
|
|
@@ -412,7 +406,7 @@ shaka.ads.ClientSideAdManager = class {
|
|
|
412
406
|
*/
|
|
413
407
|
onAdComplete_(e) {
|
|
414
408
|
this.onEvent_(new shaka.util.FakeEvent(shaka.ads.AdManager.AD_STOPPED,
|
|
415
|
-
|
|
409
|
+
(new Map()).set('originalEvent', e)));
|
|
416
410
|
this.adContainer_.removeAttribute('ad-active');
|
|
417
411
|
this.video_.play();
|
|
418
412
|
}
|
|
@@ -14,10 +14,12 @@ goog.provide('shaka.ads.ServerSideAdManager');
|
|
|
14
14
|
goog.require('goog.asserts');
|
|
15
15
|
goog.require('shaka.ads.ServerSideAd');
|
|
16
16
|
goog.require('shaka.log');
|
|
17
|
+
goog.require('shaka.util.IReleasable');
|
|
17
18
|
|
|
18
19
|
|
|
19
20
|
/**
|
|
20
21
|
* A class responsible for server-side ad interactions.
|
|
22
|
+
* @implements {shaka.util.IReleasable}
|
|
21
23
|
*/
|
|
22
24
|
shaka.ads.ServerSideAdManager = class {
|
|
23
25
|
/**
|
|
@@ -62,6 +64,9 @@ shaka.ads.ServerSideAdManager = class {
|
|
|
62
64
|
/** @private {string} */
|
|
63
65
|
this.backupUrl_ = '';
|
|
64
66
|
|
|
67
|
+
/** @private {!Array.<!shaka.extern.AdCuePoint>} */
|
|
68
|
+
this.currentCuePoints_ = [];
|
|
69
|
+
|
|
65
70
|
/** @private {shaka.util.EventManager} */
|
|
66
71
|
this.eventManager_ = new shaka.util.EventManager();
|
|
67
72
|
|
|
@@ -75,9 +80,7 @@ shaka.ads.ServerSideAdManager = class {
|
|
|
75
80
|
|
|
76
81
|
this.onEvent_(new shaka.util.FakeEvent(
|
|
77
82
|
shaka.ads.AdManager.IMA_STREAM_MANAGER_LOADED,
|
|
78
|
-
|
|
79
|
-
'imaStreamManager': this.streamManager_,
|
|
80
|
-
}));
|
|
83
|
+
(new Map()).set('imaStreamManager', this.streamManager_)));
|
|
81
84
|
|
|
82
85
|
// Events
|
|
83
86
|
this.eventManager_.listen(this.streamManager_,
|
|
@@ -201,9 +204,26 @@ shaka.ads.ServerSideAdManager = class {
|
|
|
201
204
|
* Resets the stream manager and removes any continuous polling.
|
|
202
205
|
*/
|
|
203
206
|
stop() {
|
|
204
|
-
|
|
207
|
+
// TODO:
|
|
208
|
+
// For SS DAI streams, if a different asset gets unloaded as
|
|
209
|
+
// part of the process
|
|
210
|
+
// of loading a DAI asset, stream manager state gets reset and we
|
|
211
|
+
// don't get any ad events.
|
|
212
|
+
// We need to figure out if it makes sense to stop the SS
|
|
213
|
+
// manager on unload, and, if it does, find
|
|
214
|
+
// a way to do it safely.
|
|
215
|
+
// this.streamManager_.reset();
|
|
205
216
|
this.backupUrl_ = '';
|
|
206
217
|
this.snapForwardTime_ = null;
|
|
218
|
+
this.currentCuePoints_ = [];
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/** @override */
|
|
222
|
+
release() {
|
|
223
|
+
this.stop();
|
|
224
|
+
if (this.eventManager_) {
|
|
225
|
+
this.eventManager_.release();
|
|
226
|
+
}
|
|
207
227
|
}
|
|
208
228
|
|
|
209
229
|
/**
|
|
@@ -233,6 +253,13 @@ shaka.ads.ServerSideAdManager = class {
|
|
|
233
253
|
}
|
|
234
254
|
}
|
|
235
255
|
|
|
256
|
+
/**
|
|
257
|
+
* @return {!Array.<!shaka.extern.AdCuePoint>}
|
|
258
|
+
*/
|
|
259
|
+
getCuePoints() {
|
|
260
|
+
return this.currentCuePoints_;
|
|
261
|
+
}
|
|
262
|
+
|
|
236
263
|
/**
|
|
237
264
|
* If a seek jumped over the ad break, return to the start of the
|
|
238
265
|
* ad break, then complete the seek after the ad played through.
|
|
@@ -280,7 +307,7 @@ shaka.ads.ServerSideAdManager = class {
|
|
|
280
307
|
}
|
|
281
308
|
|
|
282
309
|
this.onEvent_(new shaka.util.FakeEvent(shaka.ads.AdManager.AD_STARTED,
|
|
283
|
-
|
|
310
|
+
(new Map()).set('ad', this.ad_)));
|
|
284
311
|
this.adContainer_.setAttribute('ad-active', 'true');
|
|
285
312
|
}
|
|
286
313
|
|
|
@@ -306,9 +333,8 @@ shaka.ads.ServerSideAdManager = class {
|
|
|
306
333
|
onLoaded_(e) {
|
|
307
334
|
const now = Date.now() / 1000;
|
|
308
335
|
const loadTime = now - this.streamRequestStartTime_;
|
|
309
|
-
this.onEvent_(
|
|
310
|
-
new
|
|
311
|
-
{'loadTime': loadTime}));
|
|
336
|
+
this.onEvent_(new shaka.util.FakeEvent(shaka.ads.AdManager.ADS_LOADED,
|
|
337
|
+
(new Map()).set('loadTime', loadTime)));
|
|
312
338
|
|
|
313
339
|
const streamData = e.getStreamData();
|
|
314
340
|
const url = streamData.url;
|
|
@@ -361,15 +387,21 @@ shaka.ads.ServerSideAdManager = class {
|
|
|
361
387
|
onCuePointsChanged_(e) {
|
|
362
388
|
const streamData = e.getStreamData();
|
|
363
389
|
|
|
364
|
-
/** @type {!Array.<!shaka.
|
|
390
|
+
/** @type {!Array.<!shaka.extern.AdCuePoint>} */
|
|
365
391
|
const cuePoints = [];
|
|
366
392
|
for (const point of streamData.cuepoints) {
|
|
367
|
-
|
|
393
|
+
/** @type {shaka.extern.AdCuePoint} */
|
|
394
|
+
const shakaCuePoint = {
|
|
395
|
+
start: point.start,
|
|
396
|
+
end: point.end,
|
|
397
|
+
};
|
|
368
398
|
cuePoints.push(shakaCuePoint);
|
|
369
399
|
}
|
|
370
400
|
|
|
371
|
-
this.
|
|
372
|
-
|
|
373
|
-
|
|
401
|
+
this.currentCuePoints_ = cuePoints;
|
|
402
|
+
|
|
403
|
+
this.onEvent_(new shaka.util.FakeEvent(
|
|
404
|
+
shaka.ads.AdManager.CUEPOINTS_CHANGED,
|
|
405
|
+
(new Map()).set('cuepoints', cuePoints)));
|
|
374
406
|
}
|
|
375
407
|
};
|
package/lib/cast/cast_proxy.js
CHANGED
|
@@ -120,6 +120,9 @@ shaka.cast.CastProxy = class extends shaka.util.FakeEventTarget {
|
|
|
120
120
|
this.videoProxy_ = null;
|
|
121
121
|
this.playerProxy_ = null;
|
|
122
122
|
|
|
123
|
+
// FakeEventTarget implements IReleasable
|
|
124
|
+
super.release();
|
|
125
|
+
|
|
123
126
|
return Promise.all(waitFor);
|
|
124
127
|
}
|
|
125
128
|
|
|
@@ -525,7 +528,8 @@ shaka.cast.CastProxy = class extends shaka.util.FakeEventTarget {
|
|
|
525
528
|
goog.asserts.assert(error instanceof shaka.util.Error,
|
|
526
529
|
'Wrong error type!');
|
|
527
530
|
const eventType = shaka.Player.EventName.Error;
|
|
528
|
-
const
|
|
531
|
+
const data = (new Map()).set('detail', error);
|
|
532
|
+
const event = new shaka.util.FakeEvent(eventType, data);
|
|
529
533
|
this.localPlayer_.dispatchEvent(event);
|
|
530
534
|
});
|
|
531
535
|
}
|
|
@@ -598,7 +602,7 @@ shaka.cast.CastProxy = class extends shaka.util.FakeEventTarget {
|
|
|
598
602
|
|
|
599
603
|
// Convert this real Event into a FakeEvent for dispatch from our
|
|
600
604
|
// FakeEventListener.
|
|
601
|
-
const fakeEvent =
|
|
605
|
+
const fakeEvent = shaka.util.FakeEvent.fromRealEvent(event);
|
|
602
606
|
this.videoEventTarget_.dispatchEvent(fakeEvent);
|
|
603
607
|
}
|
|
604
608
|
|
|
@@ -238,6 +238,9 @@ shaka.cast.CastReceiver = class extends shaka.util.FakeEventTarget {
|
|
|
238
238
|
this.shakaBus_ = null;
|
|
239
239
|
this.genericBus_ = null;
|
|
240
240
|
|
|
241
|
+
// FakeEventTarget implements IReleasable
|
|
242
|
+
super.release();
|
|
243
|
+
|
|
241
244
|
await Promise.all(waitFor);
|
|
242
245
|
|
|
243
246
|
const manager = cast.receiver.CastReceiverManager.getInstance();
|
|
@@ -407,7 +410,8 @@ shaka.cast.CastReceiver = class extends shaka.util.FakeEventTarget {
|
|
|
407
410
|
goog.asserts.assert(error instanceof shaka.util.Error,
|
|
408
411
|
'Wrong error type!');
|
|
409
412
|
const eventType = shaka.Player.EventName.Error;
|
|
410
|
-
const
|
|
413
|
+
const data = (new Map()).set('detail', error);
|
|
414
|
+
const event = new shaka.util.FakeEvent(eventType, data);
|
|
411
415
|
// Only dispatch the event if the player still exists.
|
|
412
416
|
if (this.player_) {
|
|
413
417
|
this.player_.dispatchEvent(event);
|
package/lib/cast/cast_sender.js
CHANGED
|
@@ -647,7 +647,7 @@ shaka.cast.CastSender = class {
|
|
|
647
647
|
case 'event': {
|
|
648
648
|
const targetName = message['targetName'];
|
|
649
649
|
const event = message['event'];
|
|
650
|
-
const fakeEvent =
|
|
650
|
+
const fakeEvent = shaka.util.FakeEvent.fromRealEvent(event);
|
|
651
651
|
this.onRemoteEvent_(targetName, fakeEvent);
|
|
652
652
|
break;
|
|
653
653
|
}
|
|
@@ -725,7 +725,7 @@ shaka.cast.CastSender = class {
|
|
|
725
725
|
|
|
726
726
|
// Dispatch it through the Player proxy
|
|
727
727
|
const fakeEvent = new shaka.util.FakeEvent(
|
|
728
|
-
'error',
|
|
728
|
+
'error', (new Map()).set('detail', shakaError));
|
|
729
729
|
this.onRemoteEvent_('player', fakeEvent);
|
|
730
730
|
|
|
731
731
|
// Force this session to disconnect and transfer playback to the local
|
package/lib/cea/sei_processor.js
CHANGED
|
@@ -17,31 +17,31 @@ shaka.cea.SeiProcessor = class {
|
|
|
17
17
|
* @return {!Iterable.<!Uint8Array>}
|
|
18
18
|
*/
|
|
19
19
|
* process(naluData) {
|
|
20
|
-
const
|
|
20
|
+
const naluClone = this.removeEmu(naluData);
|
|
21
21
|
|
|
22
22
|
// The following is an implementation of section 7.3.2.3.1
|
|
23
23
|
// in Rec. ITU-T H.264 (06/2019), the H.264 spec.
|
|
24
24
|
let offset = 0;
|
|
25
25
|
|
|
26
|
-
while (offset
|
|
26
|
+
while (offset < naluClone.length) {
|
|
27
27
|
let payloadType = 0; // SEI payload type as defined by H.264 spec
|
|
28
|
-
while (
|
|
28
|
+
while (naluClone[offset] == 0xFF) {
|
|
29
29
|
payloadType += 255;
|
|
30
30
|
offset++;
|
|
31
31
|
}
|
|
32
|
-
payloadType +=
|
|
32
|
+
payloadType += naluClone[offset++];
|
|
33
33
|
|
|
34
34
|
let payloadSize = 0; // SEI payload size as defined by H.264 spec
|
|
35
|
-
while (
|
|
35
|
+
while (naluClone[offset] == 0xFF) {
|
|
36
36
|
payloadSize += 255;
|
|
37
37
|
offset++;
|
|
38
38
|
}
|
|
39
|
-
payloadSize +=
|
|
39
|
+
payloadSize += naluClone[offset++];
|
|
40
40
|
|
|
41
41
|
// Payload type 4 is user_data_registered_itu_t_t35, as per the H.264
|
|
42
42
|
// spec. This payload type contains caption data.
|
|
43
43
|
if (payloadType == 0x04) {
|
|
44
|
-
yield
|
|
44
|
+
yield naluClone.subarray(offset, offset + payloadSize);
|
|
45
45
|
}
|
|
46
46
|
offset += payloadSize;
|
|
47
47
|
}
|
|
@@ -50,28 +50,35 @@ shaka.cea.SeiProcessor = class {
|
|
|
50
50
|
|
|
51
51
|
/**
|
|
52
52
|
* Removes H.264 emulation prevention bytes from the byte array.
|
|
53
|
+
*
|
|
54
|
+
* Note: Remove bytes by shifting will cause Chromium (VDA) to complain
|
|
55
|
+
* about conformance. Recreating a new array solves it.
|
|
56
|
+
*
|
|
53
57
|
* @param {!Uint8Array} naluData NALU from which EMUs should be removed.
|
|
54
|
-
* @return {
|
|
55
|
-
* @private
|
|
58
|
+
* @return {!Uint8Array} The NALU with the emulation prevention byte removed.
|
|
56
59
|
*/
|
|
57
|
-
|
|
60
|
+
removeEmu(naluData) {
|
|
61
|
+
let naluClone = naluData;
|
|
58
62
|
let zeroCount = 0;
|
|
59
63
|
let src = 0;
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
64
|
+
while (src < naluClone.length) {
|
|
65
|
+
if (zeroCount == 2 && naluClone[src] == 0x03) {
|
|
66
|
+
// 0x00, 0x00, 0x03 pattern detected
|
|
63
67
|
zeroCount = 0;
|
|
68
|
+
|
|
69
|
+
// Splice the array and recreate a new one, instead of shifting bytes
|
|
70
|
+
const newArr = [...naluClone];
|
|
71
|
+
newArr.splice(src, 1);
|
|
72
|
+
naluClone = new Uint8Array(newArr);
|
|
64
73
|
} else {
|
|
65
|
-
if (
|
|
74
|
+
if (naluClone[src] == 0x00) {
|
|
66
75
|
zeroCount++;
|
|
67
76
|
} else {
|
|
68
77
|
zeroCount = 0;
|
|
69
78
|
}
|
|
70
|
-
naluData[dst] = naluData[src];
|
|
71
|
-
dst++;
|
|
72
79
|
}
|
|
73
80
|
src++;
|
|
74
81
|
}
|
|
75
|
-
return
|
|
82
|
+
return naluClone;
|
|
76
83
|
}
|
|
77
84
|
};
|