shaka-player 3.3.12 → 3.3.14
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/AUTHORS +1 -0
- package/CHANGELOG.md +33 -0
- package/CONTRIBUTORS +1 -0
- package/dist/deps.js +3 -3
- package/dist/locales.js +31 -31
- package/dist/shaka-player.compiled.d.ts +1 -1
- package/dist/shaka-player.compiled.debug.d.ts +1 -1
- package/dist/shaka-player.compiled.debug.externs.js +2 -1
- package/dist/shaka-player.compiled.debug.js +135 -126
- package/dist/shaka-player.compiled.debug.map +3 -3
- package/dist/shaka-player.compiled.externs.js +2 -1
- package/dist/shaka-player.compiled.js +744 -739
- package/dist/shaka-player.compiled.map +3 -3
- package/dist/shaka-player.ui.d.ts +1 -1
- package/dist/shaka-player.ui.debug.d.ts +1 -1
- package/dist/shaka-player.ui.debug.externs.js +2 -1
- package/dist/shaka-player.ui.debug.js +228 -219
- package/dist/shaka-player.ui.debug.map +3 -3
- package/dist/shaka-player.ui.externs.js +2 -1
- package/dist/shaka-player.ui.js +849 -845
- package/dist/shaka-player.ui.map +3 -3
- package/docs/tutorials/welcome.md +2 -2
- package/externs/shaka/player.js +2 -1
- package/lib/cast/cast_proxy.js +2 -1
- package/lib/cast/cast_receiver.js +19 -5
- package/lib/cast/cast_sender.js +2 -1
- package/lib/cast/cast_utils.js +16 -6
- package/lib/cea/cea708_window.js +2 -2
- package/lib/dash/segment_template.js +1 -1
- package/lib/hls/hls_parser.js +17 -3
- package/lib/media/content_workarounds.js +12 -0
- package/lib/media/playhead.js +23 -1
- package/lib/media/streaming_engine.js +3 -12
- package/lib/player.js +24 -11
- package/lib/polyfill/media_capabilities.js +59 -9
- package/lib/text/ttml_text_parser.js +32 -7
- package/lib/text/ui_text_displayer.js +22 -5
- package/lib/util/manifest_parser_utils.js +4 -0
- package/lib/util/platform.js +21 -2
- package/lib/util/stream_utils.js +30 -10
- package/package.json +1 -1
- package/test/cast/cast_receiver_integration.js +97 -16
- package/test/cast/cast_receiver_unit.js +17 -12
- package/test/cast/cast_utils_unit.js +1 -0
- package/test/dash/dash_parser_manifest_unit.js +1 -0
- package/test/hls/hls_parser_unit.js +1 -0
- package/test/media/playhead_unit.js +41 -0
- package/test/media/streaming_engine_integration.js +13 -0
- package/test/media/streaming_engine_unit.js +23 -8
- package/test/player_unit.js +87 -0
- package/test/polyfill/media_capabilities_unit.js +261 -0
- package/test/test/util/simple_fakes.js +3 -0
- package/test/text/mp4_ttml_parser_unit.js +4 -4
- package/test/text/ttml_text_parser_unit.js +119 -86
- package/test/text/ui_text_displayer_unit.js +76 -0
- package/test/ui/text_displayer_layout_unit.js +14 -0
- package/test/util/stream_utils_unit.js +18 -0
- package/test/util/xml_utils_unit.js +6 -1
- package/ui/controls.js +5 -2
- package/ui/settings_menu.js +11 -2
|
@@ -168,6 +168,7 @@ shaka.util.ManifestParserUtils.VIDEO_CODEC_REGEXPS_ = [
|
|
|
168
168
|
/^hvc/,
|
|
169
169
|
/^vp0?[89]/,
|
|
170
170
|
/^av01/,
|
|
171
|
+
/^dvhe/,
|
|
171
172
|
];
|
|
172
173
|
|
|
173
174
|
|
|
@@ -183,6 +184,9 @@ shaka.util.ManifestParserUtils.AUDIO_CODEC_REGEXPS_ = [
|
|
|
183
184
|
/^flac$/,
|
|
184
185
|
/^mp4a/,
|
|
185
186
|
/^[ae]c-3$/,
|
|
187
|
+
/^ac-4$/,
|
|
188
|
+
/^dts[cx]$/, // DTS Surround Sound
|
|
189
|
+
/^[du]dts$/, // DTS Surround Sound
|
|
186
190
|
];
|
|
187
191
|
|
|
188
192
|
|
package/lib/util/platform.js
CHANGED
|
@@ -184,7 +184,7 @@ shaka.util.Platform = class {
|
|
|
184
184
|
* @return {?number} A major version number or null if not Chromium-based.
|
|
185
185
|
*/
|
|
186
186
|
static chromeVersion() {
|
|
187
|
-
if (!shaka.util.Platform.
|
|
187
|
+
if (!shaka.util.Platform.isChrome()) {
|
|
188
188
|
return null;
|
|
189
189
|
}
|
|
190
190
|
|
|
@@ -223,7 +223,9 @@ shaka.util.Platform = class {
|
|
|
223
223
|
return !!navigator.vendor && navigator.vendor.includes('Apple') &&
|
|
224
224
|
!shaka.util.Platform.isTizen() &&
|
|
225
225
|
!shaka.util.Platform.isEOS() &&
|
|
226
|
-
!shaka.util.Platform.
|
|
226
|
+
!shaka.util.Platform.isVirginMedia() &&
|
|
227
|
+
!shaka.util.Platform.isPS4() &&
|
|
228
|
+
!shaka.util.Platform.isAmazonFireTV();
|
|
227
229
|
}
|
|
228
230
|
|
|
229
231
|
/**
|
|
@@ -246,6 +248,23 @@ shaka.util.Platform = class {
|
|
|
246
248
|
return shaka.util.Platform.userAgentContains_('PlayStation 4');
|
|
247
249
|
}
|
|
248
250
|
|
|
251
|
+
/**
|
|
252
|
+
* Check if the current platform is Virgin Media device.
|
|
253
|
+
*/
|
|
254
|
+
static isVirginMedia() {
|
|
255
|
+
return shaka.util.Platform.userAgentContains_('VirginMedia');
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Check if the current platform is Amazon Fire TV.
|
|
260
|
+
* https://developer.amazon.com/docs/fire-tv/identify-amazon-fire-tv-devices.html
|
|
261
|
+
*
|
|
262
|
+
* @return {boolean}
|
|
263
|
+
*/
|
|
264
|
+
static isAmazonFireTV() {
|
|
265
|
+
return shaka.util.Platform.userAgentContains_('AFT');
|
|
266
|
+
}
|
|
267
|
+
|
|
249
268
|
/**
|
|
250
269
|
* Returns a major version number for Safari, or Safari-based iOS browsers.
|
|
251
270
|
*
|
package/lib/util/stream_utils.js
CHANGED
|
@@ -431,15 +431,20 @@ shaka.util.StreamUtils = class {
|
|
|
431
431
|
const video = variant.video;
|
|
432
432
|
const ContentType = shaka.util.ManifestParserUtils.ContentType;
|
|
433
433
|
if (video) {
|
|
434
|
-
let videoCodecs =
|
|
434
|
+
let videoCodecs =
|
|
435
|
+
shaka.util.StreamUtils.getCorrectVideoCodecs_(video.codecs);
|
|
435
436
|
// For multiplexed streams. Here we must check the audio of the
|
|
436
437
|
// stream to see if it is compatible.
|
|
437
438
|
if (video.codecs.includes(',')) {
|
|
438
439
|
const allCodecs = video.codecs.split(',');
|
|
439
440
|
videoCodecs = shaka.util.ManifestParserUtils.guessCodecs(
|
|
440
441
|
ContentType.VIDEO, allCodecs);
|
|
441
|
-
|
|
442
|
+
videoCodecs =
|
|
443
|
+
shaka.util.StreamUtils.getCorrectVideoCodecs_(videoCodecs);
|
|
444
|
+
let audioCodecs = shaka.util.ManifestParserUtils.guessCodecs(
|
|
442
445
|
ContentType.AUDIO, allCodecs);
|
|
446
|
+
audioCodecs =
|
|
447
|
+
shaka.util.StreamUtils.getCorrectAudioCodecs_(audioCodecs);
|
|
443
448
|
const audioFullType = shaka.util.MimeUtils.getFullOrConvertedType(
|
|
444
449
|
video.mimeType, audioCodecs, ContentType.AUDIO);
|
|
445
450
|
if (!MediaSource.isTypeSupported(audioFullType)) {
|
|
@@ -559,7 +564,8 @@ shaka.util.StreamUtils = class {
|
|
|
559
564
|
const allCodecs = video.codecs.split(',');
|
|
560
565
|
videoCodecs = shaka.util.ManifestParserUtils.guessCodecs(
|
|
561
566
|
ContentType.VIDEO, allCodecs);
|
|
562
|
-
videoCodecs =
|
|
567
|
+
videoCodecs =
|
|
568
|
+
shaka.util.StreamUtils.getCorrectVideoCodecs_(videoCodecs);
|
|
563
569
|
const audioCodecs = shaka.util.ManifestParserUtils.guessCodecs(
|
|
564
570
|
ContentType.AUDIO, allCodecs);
|
|
565
571
|
|
|
@@ -573,7 +579,7 @@ shaka.util.StreamUtils = class {
|
|
|
573
579
|
spatialRendering: false,
|
|
574
580
|
};
|
|
575
581
|
}
|
|
576
|
-
videoCodecs = shaka.util.StreamUtils.
|
|
582
|
+
videoCodecs = shaka.util.StreamUtils.getCorrectVideoCodecs_(videoCodecs);
|
|
577
583
|
const fullType = shaka.util.MimeUtils.getFullOrConvertedType(
|
|
578
584
|
video.mimeType, videoCodecs, ContentType.VIDEO);
|
|
579
585
|
// VideoConfiguration
|
|
@@ -742,15 +748,29 @@ shaka.util.StreamUtils = class {
|
|
|
742
748
|
|
|
743
749
|
|
|
744
750
|
/**
|
|
745
|
-
*
|
|
746
|
-
*
|
|
747
|
-
* mediaCapabilities enabled.
|
|
748
|
-
*
|
|
751
|
+
* Generates the correct video codec for MediaDecodingConfiguration and
|
|
752
|
+
* for MediaSource.isTypeSupported.
|
|
749
753
|
* @param {string} codec
|
|
750
754
|
* @return {string}
|
|
755
|
+
* @private
|
|
751
756
|
*/
|
|
752
|
-
static
|
|
753
|
-
if (codec
|
|
757
|
+
static getCorrectVideoCodecs_(codec) {
|
|
758
|
+
if (codec.includes('avc1')) {
|
|
759
|
+
// Convert avc1 codec string from RFC-4281 to RFC-6381 for
|
|
760
|
+
// MediaSource.isTypeSupported
|
|
761
|
+
// Example, convert avc1.66.30 to avc1.42001e (0x42 == 66 and 0x1e == 30)
|
|
762
|
+
const avcdata = codec.split('.');
|
|
763
|
+
if (avcdata.length == 3) {
|
|
764
|
+
let result = avcdata.shift() + '.';
|
|
765
|
+
result += parseInt(avcdata.shift(), 10).toString(16);
|
|
766
|
+
result +=
|
|
767
|
+
('000' + parseInt(avcdata.shift(), 10).toString(16)).slice(-4);
|
|
768
|
+
return result;
|
|
769
|
+
}
|
|
770
|
+
} else if (codec == 'vp9') {
|
|
771
|
+
// MediaCapabilities supports 'vp09...' codecs, but not 'vp9'. Translate
|
|
772
|
+
// vp9 codec strings into 'vp09...', to allow such content to play with
|
|
773
|
+
// mediaCapabilities enabled.
|
|
754
774
|
// This means profile 0, level 4.1, 8-bit color. This supports 1080p @
|
|
755
775
|
// 60Hz. See https://en.wikipedia.org/wiki/VP9#Levels
|
|
756
776
|
//
|
package/package.json
CHANGED
|
@@ -34,6 +34,8 @@ filterDescribe('CastReceiver', castReceiverIntegrationSupport, () => {
|
|
|
34
34
|
|
|
35
35
|
/** @type {shaka.util.PublicPromise} */
|
|
36
36
|
let messageWaitPromise;
|
|
37
|
+
/** @type {Array.<string>} */
|
|
38
|
+
let pendingMessages = null;
|
|
37
39
|
|
|
38
40
|
/** @type {!Array.<function()>} */
|
|
39
41
|
let toRestore;
|
|
@@ -91,6 +93,9 @@ filterDescribe('CastReceiver', castReceiverIntegrationSupport, () => {
|
|
|
91
93
|
toRestore = [];
|
|
92
94
|
pendingWaitWrapperCalls = 0;
|
|
93
95
|
|
|
96
|
+
messageWaitPromise = null;
|
|
97
|
+
pendingMessages = null;
|
|
98
|
+
|
|
94
99
|
fakeInitState = {
|
|
95
100
|
player: {
|
|
96
101
|
configure: {},
|
|
@@ -118,6 +123,12 @@ filterDescribe('CastReceiver', castReceiverIntegrationSupport, () => {
|
|
|
118
123
|
player = null;
|
|
119
124
|
video = null;
|
|
120
125
|
receiver = null;
|
|
126
|
+
|
|
127
|
+
if (messageWaitPromise) {
|
|
128
|
+
messageWaitPromise.resolve([]);
|
|
129
|
+
}
|
|
130
|
+
messageWaitPromise = null;
|
|
131
|
+
pendingMessages = null;
|
|
121
132
|
});
|
|
122
133
|
|
|
123
134
|
afterAll(() => {
|
|
@@ -128,6 +139,66 @@ filterDescribe('CastReceiver', castReceiverIntegrationSupport, () => {
|
|
|
128
139
|
}
|
|
129
140
|
});
|
|
130
141
|
|
|
142
|
+
describe('without drm', () => {
|
|
143
|
+
it('sends reasonably-sized updates', async () => {
|
|
144
|
+
// Use an unencrypted asset.
|
|
145
|
+
fakeInitState.manifest = 'test:sintel';
|
|
146
|
+
|
|
147
|
+
const p = waitForLoadedData();
|
|
148
|
+
|
|
149
|
+
// Start the process of loading by sending a fake init message.
|
|
150
|
+
fakeConnectedSenders(1);
|
|
151
|
+
fakeIncomingMessage({
|
|
152
|
+
type: 'init',
|
|
153
|
+
initState: fakeInitState,
|
|
154
|
+
appData: {},
|
|
155
|
+
}, mockShakaMessageBus);
|
|
156
|
+
|
|
157
|
+
await p;
|
|
158
|
+
// Wait for an update message.
|
|
159
|
+
const messages = await waitForUpdateMessages();
|
|
160
|
+
for (const message of messages) {
|
|
161
|
+
// Check that the update message is of a reasonable size. From previous
|
|
162
|
+
// testing we found that the socket would silently reject data that got
|
|
163
|
+
// too big. 6KB is safely below the limit.
|
|
164
|
+
expect(message.length).toBeLessThan(6000);
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
it('has reasonable average message size', async () => {
|
|
169
|
+
// Use an unencrypted asset.
|
|
170
|
+
fakeInitState.manifest = 'test:sintel';
|
|
171
|
+
|
|
172
|
+
const p = waitForLoadedData();
|
|
173
|
+
|
|
174
|
+
// Start the process of loading by sending a fake init message.
|
|
175
|
+
fakeConnectedSenders(1);
|
|
176
|
+
fakeIncomingMessage({
|
|
177
|
+
type: 'init',
|
|
178
|
+
initState: fakeInitState,
|
|
179
|
+
appData: {},
|
|
180
|
+
}, mockShakaMessageBus);
|
|
181
|
+
|
|
182
|
+
await p;
|
|
183
|
+
|
|
184
|
+
// Collect messages over 50 update cycles, and average their length.
|
|
185
|
+
// Not all properties are passed along on every update message, so
|
|
186
|
+
// the average length is expected to be lower than the length of the first
|
|
187
|
+
// update message.
|
|
188
|
+
let totalLength = 0;
|
|
189
|
+
let totalMessages = 0;
|
|
190
|
+
for (let i = 0; i < 50; i++) {
|
|
191
|
+
// eslint-disable-next-line no-await-in-loop
|
|
192
|
+
const messages = await waitForUpdateMessages();
|
|
193
|
+
for (const message of messages) {
|
|
194
|
+
totalLength += message.length;
|
|
195
|
+
totalMessages += 1;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
expect(totalLength / totalMessages).toBeLessThan(2000);
|
|
199
|
+
});
|
|
200
|
+
});
|
|
201
|
+
|
|
131
202
|
filterDescribe('with drm', () => support['com.widevine.alpha'], () => {
|
|
132
203
|
drmIt('sends reasonably-sized updates', async () => {
|
|
133
204
|
// Use an encrypted asset, to make sure DRM info doesn't balloon the size.
|
|
@@ -150,11 +221,13 @@ filterDescribe('CastReceiver', castReceiverIntegrationSupport, () => {
|
|
|
150
221
|
|
|
151
222
|
await p;
|
|
152
223
|
// Wait for an update message.
|
|
153
|
-
const
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
224
|
+
const messages = await waitForUpdateMessages();
|
|
225
|
+
for (const message of messages) {
|
|
226
|
+
// Check that the update message is of a reasonable size. From previous
|
|
227
|
+
// testing we found that the socket would silently reject data that got
|
|
228
|
+
// too big. 6KB is safely below the limit.
|
|
229
|
+
expect(message.length).toBeLessThan(6000);
|
|
230
|
+
}
|
|
158
231
|
});
|
|
159
232
|
|
|
160
233
|
drmIt('has reasonable average message size', async () => {
|
|
@@ -177,17 +250,22 @@ filterDescribe('CastReceiver', castReceiverIntegrationSupport, () => {
|
|
|
177
250
|
}, mockShakaMessageBus);
|
|
178
251
|
|
|
179
252
|
await p;
|
|
180
|
-
|
|
253
|
+
|
|
254
|
+
// Collect messages over 50 update cycles, and average their length.
|
|
181
255
|
// Not all properties are passed along on every update message, so
|
|
182
256
|
// the average length is expected to be lower than the length of the first
|
|
183
257
|
// update message.
|
|
184
258
|
let totalLength = 0;
|
|
259
|
+
let totalMessages = 0;
|
|
185
260
|
for (let i = 0; i < 50; i++) {
|
|
186
261
|
// eslint-disable-next-line no-await-in-loop
|
|
187
|
-
const
|
|
188
|
-
|
|
262
|
+
const messages = await waitForUpdateMessages();
|
|
263
|
+
for (const message of messages) {
|
|
264
|
+
totalLength += message.length;
|
|
265
|
+
totalMessages += 1;
|
|
266
|
+
}
|
|
189
267
|
}
|
|
190
|
-
expect(totalLength /
|
|
268
|
+
expect(totalLength / totalMessages).toBeLessThan(2000);
|
|
191
269
|
});
|
|
192
270
|
});
|
|
193
271
|
|
|
@@ -227,12 +305,12 @@ filterDescribe('CastReceiver', castReceiverIntegrationSupport, () => {
|
|
|
227
305
|
expect(pendingWaitWrapperCalls).toBe(0);
|
|
228
306
|
|
|
229
307
|
// Wait for a final update message before proceeding.
|
|
230
|
-
await
|
|
308
|
+
await waitForUpdateMessages();
|
|
231
309
|
});
|
|
232
310
|
|
|
233
311
|
/**
|
|
234
312
|
* Creates a wrapper around a method on a given prototype, which makes it
|
|
235
|
-
* wait on
|
|
313
|
+
* wait on waitForUpdateMessages before returning, and registers that wrapper
|
|
236
314
|
* to be uninstalled afterwards.
|
|
237
315
|
* The replaced method is expected to be a method that returns a promise.
|
|
238
316
|
* @param {!Object} prototype
|
|
@@ -249,7 +327,7 @@ filterDescribe('CastReceiver', castReceiverIntegrationSupport, () => {
|
|
|
249
327
|
'Waiting for update message before calling ' +
|
|
250
328
|
name + '.' + methodName + '...');
|
|
251
329
|
const originalArguments = Array.from(arguments);
|
|
252
|
-
await
|
|
330
|
+
await waitForUpdateMessages();
|
|
253
331
|
// eslint-disable-next-line no-restricted-syntax
|
|
254
332
|
return original.apply(this, originalArguments);
|
|
255
333
|
};
|
|
@@ -265,7 +343,8 @@ filterDescribe('CastReceiver', castReceiverIntegrationSupport, () => {
|
|
|
265
343
|
});
|
|
266
344
|
}
|
|
267
345
|
|
|
268
|
-
function
|
|
346
|
+
function waitForUpdateMessages() {
|
|
347
|
+
pendingMessages = [];
|
|
269
348
|
messageWaitPromise = new shaka.util.PublicPromise();
|
|
270
349
|
return messageWaitPromise;
|
|
271
350
|
}
|
|
@@ -316,10 +395,12 @@ filterDescribe('CastReceiver', castReceiverIntegrationSupport, () => {
|
|
|
316
395
|
bus.messages.push(CastUtils.deserialize(message));
|
|
317
396
|
// Check to see if it's an update message.
|
|
318
397
|
const parsed = CastUtils.deserialize(message);
|
|
319
|
-
if (parsed.type == 'update' &&
|
|
398
|
+
if (parsed.type == 'update' && pendingMessages) {
|
|
320
399
|
shaka.log.debug('Received update message. Proceeding...');
|
|
321
|
-
|
|
322
|
-
|
|
400
|
+
// The code waiting on this Promise will get an array of all of the
|
|
401
|
+
// messages processed within this tick.
|
|
402
|
+
pendingMessages.push(message);
|
|
403
|
+
messageWaitPromise.resolve(pendingMessages);
|
|
323
404
|
}
|
|
324
405
|
});
|
|
325
406
|
const channel = {
|
|
@@ -245,18 +245,20 @@ filterDescribe('CastReceiver', castReceiverSupport, () => {
|
|
|
245
245
|
const fakeEvent = {type: 'timeupdate'};
|
|
246
246
|
mockVideo.on['timeupdate'](fakeEvent);
|
|
247
247
|
|
|
248
|
-
// There are now "update" and "event" messages, in that
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
248
|
+
// There are now some number of "update" and "event" messages, in that
|
|
249
|
+
// order.
|
|
250
|
+
expect(mockShakaMessageBus.messages).toContain({
|
|
251
|
+
type: 'update',
|
|
252
|
+
update: jasmine.any(Object),
|
|
253
|
+
});
|
|
254
|
+
expect(mockShakaMessageBus.messages).toContain({
|
|
255
|
+
type: 'event',
|
|
256
|
+
targetName: 'video',
|
|
257
|
+
event: jasmine.objectContaining(fakeEvent),
|
|
258
|
+
});
|
|
259
|
+
const eventIndex = mockShakaMessageBus.messages.findIndex(
|
|
260
|
+
(message) => message.type == 'event');
|
|
261
|
+
expect(eventIndex).toBe(mockShakaMessageBus.messages.length - 1);
|
|
260
262
|
});
|
|
261
263
|
});
|
|
262
264
|
|
|
@@ -1105,6 +1107,9 @@ filterDescribe('CastReceiver', castReceiverSupport, () => {
|
|
|
1105
1107
|
for (const name in CastUtils.PlayerGetterMethods) {
|
|
1106
1108
|
player[name] = jasmine.createSpy(name);
|
|
1107
1109
|
}
|
|
1110
|
+
for (const name in CastUtils.LargePlayerGetterMethods) {
|
|
1111
|
+
player[name] = jasmine.createSpy(name);
|
|
1112
|
+
}
|
|
1108
1113
|
for (const name in CastUtils.PlayerGetterMethodsThatRequireLive) {
|
|
1109
1114
|
player[name] = jasmine.createSpy(name);
|
|
1110
1115
|
}
|
|
@@ -34,6 +34,7 @@ describe('CastUtils', () => {
|
|
|
34
34
|
const castMembers = CastUtils.PlayerVoidMethods
|
|
35
35
|
.concat(CastUtils.PlayerPromiseMethods)
|
|
36
36
|
.concat(Object.keys(CastUtils.PlayerGetterMethods))
|
|
37
|
+
.concat(Object.keys(CastUtils.LargePlayerGetterMethods))
|
|
37
38
|
.concat(Object.keys(CastUtils.PlayerGetterMethodsThatRequireLive));
|
|
38
39
|
// eslint-disable-next-line no-restricted-syntax
|
|
39
40
|
const allPlayerMembers = Object.getOwnPropertyNames(shaka.Player.prototype);
|
|
@@ -2105,6 +2105,7 @@ describe('DashParser Manifest', () => {
|
|
|
2105
2105
|
/** @type {shaka.extern.Manifest} */
|
|
2106
2106
|
const manifest = await parser.start('dummy://foo', playerInterface);
|
|
2107
2107
|
expect(manifest.imageStreams.length).toBe(1);
|
|
2108
|
+
expect(manifest.presentationTimeline.getMaxSegmentDuration()).toBe(1);
|
|
2108
2109
|
const imageStream = manifest.imageStreams[0];
|
|
2109
2110
|
expect(imageStream.width).toBe(1024);
|
|
2110
2111
|
expect(imageStream.height).toBe(1152);
|
|
@@ -171,6 +171,8 @@ describe('Playhead', () => {
|
|
|
171
171
|
Util.spyFunc(onSeek),
|
|
172
172
|
Util.spyFunc(onEvent));
|
|
173
173
|
|
|
174
|
+
playhead.ready();
|
|
175
|
+
|
|
174
176
|
expect(video.currentTime).toBe(5);
|
|
175
177
|
expect(playhead.getTime()).toBe(5);
|
|
176
178
|
|
|
@@ -192,6 +194,8 @@ describe('Playhead', () => {
|
|
|
192
194
|
Util.spyFunc(onSeek),
|
|
193
195
|
Util.spyFunc(onEvent));
|
|
194
196
|
|
|
197
|
+
playhead.ready();
|
|
198
|
+
|
|
195
199
|
expect(video.addEventListener).toHaveBeenCalledWith(
|
|
196
200
|
'loadedmetadata', jasmine.any(Function), jasmine.anything());
|
|
197
201
|
expect(video.addEventListener).not.toHaveBeenCalledWith(
|
|
@@ -233,6 +237,8 @@ describe('Playhead', () => {
|
|
|
233
237
|
Util.spyFunc(onSeek),
|
|
234
238
|
Util.spyFunc(onEvent));
|
|
235
239
|
|
|
240
|
+
playhead.ready();
|
|
241
|
+
|
|
236
242
|
video.on['seeking']();
|
|
237
243
|
expect(playhead.getTime()).toBe(5);
|
|
238
244
|
expect(video.currentTime).toBe(5);
|
|
@@ -266,6 +272,8 @@ describe('Playhead', () => {
|
|
|
266
272
|
video, manifest, config, /* startTime= */ 60, Util.spyFunc(onSeek),
|
|
267
273
|
Util.spyFunc(onEvent));
|
|
268
274
|
|
|
275
|
+
playhead.ready();
|
|
276
|
+
|
|
269
277
|
expect(playhead.getTime()).toBe(59); // duration - durationBackoff
|
|
270
278
|
expect(video.currentTime).toBe(59); // duration - durationBackoff
|
|
271
279
|
});
|
|
@@ -296,6 +304,8 @@ describe('Playhead', () => {
|
|
|
296
304
|
video, manifest, config, /* startTime= */ -40, Util.spyFunc(onSeek),
|
|
297
305
|
Util.spyFunc(onEvent));
|
|
298
306
|
|
|
307
|
+
playhead.ready();
|
|
308
|
+
|
|
299
309
|
expect(playhead.getTime()).toBe(30);
|
|
300
310
|
});
|
|
301
311
|
|
|
@@ -308,6 +318,8 @@ describe('Playhead', () => {
|
|
|
308
318
|
Util.spyFunc(onSeek),
|
|
309
319
|
Util.spyFunc(onEvent));
|
|
310
320
|
|
|
321
|
+
playhead.ready();
|
|
322
|
+
|
|
311
323
|
expect(video.addEventListener).toHaveBeenCalledWith(
|
|
312
324
|
'loadedmetadata', jasmine.any(Function), jasmine.anything());
|
|
313
325
|
|
|
@@ -341,6 +353,8 @@ describe('Playhead', () => {
|
|
|
341
353
|
Util.spyFunc(onSeek),
|
|
342
354
|
Util.spyFunc(onEvent));
|
|
343
355
|
|
|
356
|
+
playhead.ready();
|
|
357
|
+
|
|
344
358
|
expect(video.addEventListener).toHaveBeenCalledWith(
|
|
345
359
|
'loadedmetadata', jasmine.any(Function), jasmine.anything());
|
|
346
360
|
|
|
@@ -374,6 +388,8 @@ describe('Playhead', () => {
|
|
|
374
388
|
Util.spyFunc(onSeek),
|
|
375
389
|
Util.spyFunc(onEvent));
|
|
376
390
|
|
|
391
|
+
playhead.ready();
|
|
392
|
+
|
|
377
393
|
// This has to periodically increment the mock date to allow the onSeeking_
|
|
378
394
|
// handler to seek, if appropriate.
|
|
379
395
|
|
|
@@ -646,6 +662,8 @@ describe('Playhead', () => {
|
|
|
646
662
|
expect(currentTime).toBe(1000);
|
|
647
663
|
seekCount = 0;
|
|
648
664
|
|
|
665
|
+
playhead.ready();
|
|
666
|
+
|
|
649
667
|
// The availability window slips ahead.
|
|
650
668
|
timeline.getSeekRangeStart.and.returnValue(1030);
|
|
651
669
|
timeline.getSeekRangeEnd.and.returnValue(1030);
|
|
@@ -690,6 +708,8 @@ describe('Playhead', () => {
|
|
|
690
708
|
Util.spyFunc(onSeek),
|
|
691
709
|
Util.spyFunc(onEvent));
|
|
692
710
|
|
|
711
|
+
playhead.ready();
|
|
712
|
+
|
|
693
713
|
video.on['seeking']();
|
|
694
714
|
expect(video.currentTime).toBe(5);
|
|
695
715
|
expect(playhead.getTime()).toBe(5);
|
|
@@ -722,6 +742,8 @@ describe('Playhead', () => {
|
|
|
722
742
|
Util.spyFunc(onSeek),
|
|
723
743
|
Util.spyFunc(onEvent));
|
|
724
744
|
|
|
745
|
+
playhead.ready();
|
|
746
|
+
|
|
725
747
|
video.on['seeking']();
|
|
726
748
|
expect(video.currentTime).toBe(5);
|
|
727
749
|
expect(playhead.getTime()).toBe(5);
|
|
@@ -759,6 +781,9 @@ describe('Playhead', () => {
|
|
|
759
781
|
|
|
760
782
|
video.currentTime = 0;
|
|
761
783
|
video.seeking = true;
|
|
784
|
+
|
|
785
|
+
playhead.ready();
|
|
786
|
+
|
|
762
787
|
// "video.seeking" stays true until the buffered range intersects with
|
|
763
788
|
// "video.currentTime". Playhead should correct anyway.
|
|
764
789
|
video.on['seeking']();
|
|
@@ -803,6 +828,8 @@ describe('Playhead', () => {
|
|
|
803
828
|
Util.spyFunc(onSeek),
|
|
804
829
|
Util.spyFunc(onEvent));
|
|
805
830
|
|
|
831
|
+
playhead.ready();
|
|
832
|
+
|
|
806
833
|
/**
|
|
807
834
|
* Prevent retries on the initial start time seek. This will ensure that
|
|
808
835
|
* only one call is made for the initial seek, and that any additional calls
|
|
@@ -955,6 +982,8 @@ describe('Playhead', () => {
|
|
|
955
982
|
Util.spyFunc(onSeek),
|
|
956
983
|
Util.spyFunc(onEvent));
|
|
957
984
|
|
|
985
|
+
playhead.ready();
|
|
986
|
+
|
|
958
987
|
jasmine.clock().tick(500);
|
|
959
988
|
for (let time = data.start; time < data.waitingAt; time++) {
|
|
960
989
|
// We don't want to run tick() for 1 second because it will trigger
|
|
@@ -1208,6 +1237,8 @@ describe('Playhead', () => {
|
|
|
1208
1237
|
Util.spyFunc(onSeek),
|
|
1209
1238
|
Util.spyFunc(onEvent));
|
|
1210
1239
|
|
|
1240
|
+
playhead.ready();
|
|
1241
|
+
|
|
1211
1242
|
jasmine.clock().tick(500);
|
|
1212
1243
|
expect(onEvent).not.toHaveBeenCalled();
|
|
1213
1244
|
|
|
@@ -1257,6 +1288,8 @@ describe('Playhead', () => {
|
|
|
1257
1288
|
Util.spyFunc(onSeek),
|
|
1258
1289
|
Util.spyFunc(onEvent));
|
|
1259
1290
|
|
|
1291
|
+
playhead.ready();
|
|
1292
|
+
|
|
1260
1293
|
playhead.notifyOfBufferingChange();
|
|
1261
1294
|
jasmine.clock().tick(500);
|
|
1262
1295
|
|
|
@@ -1280,6 +1313,8 @@ describe('Playhead', () => {
|
|
|
1280
1313
|
Util.spyFunc(onSeek),
|
|
1281
1314
|
Util.spyFunc(onEvent));
|
|
1282
1315
|
|
|
1316
|
+
playhead.ready();
|
|
1317
|
+
|
|
1283
1318
|
playhead.notifyOfBufferingChange();
|
|
1284
1319
|
jasmine.clock().tick(500);
|
|
1285
1320
|
|
|
@@ -1305,6 +1340,8 @@ describe('Playhead', () => {
|
|
|
1305
1340
|
Util.spyFunc(onSeek),
|
|
1306
1341
|
Util.spyFunc(onEvent));
|
|
1307
1342
|
|
|
1343
|
+
playhead.ready();
|
|
1344
|
+
|
|
1308
1345
|
playhead.notifyOfBufferingChange();
|
|
1309
1346
|
jasmine.clock().tick(500);
|
|
1310
1347
|
|
|
@@ -1330,6 +1367,8 @@ describe('Playhead', () => {
|
|
|
1330
1367
|
Util.spyFunc(onSeek),
|
|
1331
1368
|
Util.spyFunc(onEvent));
|
|
1332
1369
|
|
|
1370
|
+
playhead.ready();
|
|
1371
|
+
|
|
1333
1372
|
playhead.notifyOfBufferingChange();
|
|
1334
1373
|
jasmine.clock().tick(500);
|
|
1335
1374
|
|
|
@@ -1362,6 +1401,8 @@ describe('Playhead', () => {
|
|
|
1362
1401
|
Util.spyFunc(onSeek),
|
|
1363
1402
|
Util.spyFunc(onEvent));
|
|
1364
1403
|
|
|
1404
|
+
playhead.ready();
|
|
1405
|
+
|
|
1365
1406
|
jasmine.clock().tick(500);
|
|
1366
1407
|
expect(onEvent).not.toHaveBeenCalled();
|
|
1367
1408
|
|
|
@@ -154,6 +154,19 @@ describe('StreamingEngine', () => {
|
|
|
154
154
|
/* presentationDuration= */ Infinity);
|
|
155
155
|
setupPlayhead();
|
|
156
156
|
|
|
157
|
+
// Retry on failure for live streams.
|
|
158
|
+
config.failureCallback = () => streamingEngine.retry(0.1);
|
|
159
|
+
|
|
160
|
+
// Ignore 404 errors in live stream tests.
|
|
161
|
+
onError.and.callFake((error) => {
|
|
162
|
+
if (error.code == shaka.util.Error.Code.BAD_HTTP_STATUS &&
|
|
163
|
+
error.data[1] == 404) {
|
|
164
|
+
// 404 error
|
|
165
|
+
} else {
|
|
166
|
+
fail(error);
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
|
|
157
170
|
createStreamingEngine();
|
|
158
171
|
}
|
|
159
172
|
|