shaka-player 3.3.17 → 3.3.19
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 +4 -4
- package/.github/workflows/demo-version-index.yaml +6 -0
- package/.github/workflows/selenium-lab-tests.yaml +78 -17
- package/.github/workflows/update-screenshots.yaml +142 -0
- package/AUTHORS +2 -1
- package/CHANGELOG.md +44 -0
- package/CONTRIBUTORS +4 -1
- package/demo/common/asset.js +15 -0
- package/demo/common/assets.js +4 -2
- package/demo/common/message_ids.js +1 -0
- package/demo/custom.js +19 -0
- package/demo/locales/en.json +1 -0
- package/demo/locales/source.json +4 -0
- package/demo/main.js +14 -0
- package/dist/controls.css +1 -1
- package/dist/demo.compiled.debug.js +146 -144
- package/dist/demo.compiled.debug.map +3 -3
- package/dist/demo.compiled.js +146 -144
- package/dist/demo.compiled.map +3 -3
- package/dist/deps.js +1 -1
- package/dist/locales.js +31 -31
- package/dist/receiver.compiled.debug.js +15 -15
- package/dist/receiver.compiled.debug.map +2 -2
- package/dist/receiver.compiled.js +15 -15
- package/dist/receiver.compiled.map +2 -2
- package/dist/shaka-player.compiled.d.ts +13 -2
- package/dist/shaka-player.compiled.debug.d.ts +13 -2
- package/dist/shaka-player.compiled.debug.js +160 -158
- package/dist/shaka-player.compiled.debug.map +3 -3
- package/dist/shaka-player.compiled.js +338 -335
- package/dist/shaka-player.compiled.map +3 -3
- package/dist/shaka-player.ui.d.ts +13 -2
- package/dist/shaka-player.ui.debug.d.ts +13 -2
- package/dist/shaka-player.ui.debug.js +224 -222
- package/dist/shaka-player.ui.debug.map +3 -3
- package/dist/shaka-player.ui.js +501 -498
- package/dist/shaka-player.ui.map +3 -3
- package/docs/tutorials/errors.md +94 -0
- package/docs/tutorials/fairplay.md +2 -2
- package/docs/tutorials/index.json +2 -0
- package/docs/tutorials/widevine-service-certs.md +45 -0
- package/externs/ima.js +9 -0
- package/externs/shaka/net.js +1 -0
- package/externs/shaka/player.js +13 -7
- package/lib/ads/client_side_ad_manager.js +11 -5
- package/lib/dash/dash_parser.js +49 -48
- package/lib/hls/hls_parser.js +2 -0
- package/lib/media/media_source_engine.js +9 -4
- package/lib/media/streaming_engine.js +8 -3
- package/lib/media/transmuxer.js +13 -7
- package/lib/media/video_wrapper.js +3 -3
- package/lib/net/http_fetch_plugin.js +79 -57
- package/lib/net/networking_engine.js +1 -0
- package/lib/offline/indexeddb/storage_mechanism.js +1 -1
- package/lib/player.js +19 -2
- package/lib/polyfill/media_capabilities.js +15 -8
- package/lib/polyfill/mediasource.js +7 -2
- package/lib/text/mp4_vtt_parser.js +4 -0
- package/lib/text/text_engine.js +1 -0
- package/lib/text/ui_text_displayer.js +1 -0
- package/lib/text/vtt_text_parser.js +4 -5
- package/lib/util/manifest_parser_utils.js +1 -2
- package/lib/util/mime_utils.js +12 -1
- package/lib/util/periods.js +5 -5
- package/lib/util/stream_utils.js +28 -16
- package/maintained-branches.md +3 -4
- package/package.json +1 -1
- package/test/media/content_workarounds_unit.js +43 -0
- package/test/media/drm_engine_integration.js +4 -17
- package/test/media/streaming_engine_unit.js +6 -1
- package/test/net/networking_engine_unit.js +6 -1
- package/test/player_integration.js +39 -0
- package/test/player_unit.js +54 -0
- package/test/polyfill/media_capabilities_unit.js +20 -23
- package/test/test/assets/text-clip-alt.vtt +63 -0
- package/test/test/util/fake_drm_engine.js +3 -0
- package/test/test/util/simple_fakes.js +3 -0
- package/test/test/util/test_scheme.js +9 -14
- package/test/text/mp4_vtt_parser_unit.js +8 -0
- package/test/text/vtt_text_parser_unit.js +26 -2
- package/test/text/web_vtt_layout_integration.js +0 -3
- package/test/util/mime_utils_unit.js +10 -0
|
@@ -120,65 +120,77 @@ shaka.net.HttpFetchPlugin = class {
|
|
|
120
120
|
// not the body yet.
|
|
121
121
|
headersReceived(shaka.net.HttpFetchPlugin.headersToGenericObject_(
|
|
122
122
|
response.headers));
|
|
123
|
-
|
|
124
|
-
//
|
|
125
|
-
//
|
|
126
|
-
//
|
|
127
|
-
//
|
|
128
|
-
//
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
123
|
+
|
|
124
|
+
// In new versions of Chromium, HEAD requests now have a response body
|
|
125
|
+
// that is null.
|
|
126
|
+
// So just don't try to download the body at all, if it's a HEAD request,
|
|
127
|
+
// to avoid null reference errors.
|
|
128
|
+
// See: https://crbug.com/1297060
|
|
129
|
+
if (init.method != 'HEAD') {
|
|
130
|
+
goog.asserts.assert(response.body,
|
|
131
|
+
'non-HEAD responses should have a body');
|
|
132
|
+
|
|
133
|
+
// Getting the reader in this way allows us to observe the process of
|
|
134
|
+
// downloading the body, instead of just waiting for an opaque promise
|
|
135
|
+
// to resolve.
|
|
136
|
+
// We first clone the response because calling getReader locks the body
|
|
137
|
+
// stream; if we didn't clone it here, we would be unable to get the
|
|
138
|
+
// response's arrayBuffer later.
|
|
139
|
+
const reader = response.clone().body.getReader();
|
|
140
|
+
|
|
141
|
+
const contentLengthRaw = response.headers.get('Content-Length');
|
|
142
|
+
const contentLength =
|
|
143
|
+
contentLengthRaw ? parseInt(contentLengthRaw, 10) : 0;
|
|
144
|
+
|
|
145
|
+
const start = (controller) => {
|
|
146
|
+
const push = async () => {
|
|
147
|
+
let readObj;
|
|
148
|
+
try {
|
|
149
|
+
readObj = await reader.read();
|
|
150
|
+
} catch (e) {
|
|
151
|
+
// If we abort the request, we'll get an error here. Just ignore
|
|
152
|
+
// it since real errors will be reported when we read the buffer
|
|
153
|
+
// below.
|
|
154
|
+
shaka.log.v1('error reading from stream', e.message);
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (!readObj.done) {
|
|
159
|
+
loaded += readObj.value.byteLength;
|
|
160
|
+
if (streamDataCallback) {
|
|
161
|
+
await streamDataCallback(readObj.value);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const currentTime = Date.now();
|
|
166
|
+
// If the time between last time and this time we got progress event
|
|
167
|
+
// is long enough, or if a whole segment is downloaded, call
|
|
168
|
+
// progressUpdated().
|
|
169
|
+
if (currentTime - lastTime > 100 || readObj.done) {
|
|
170
|
+
progressUpdated(currentTime - lastTime, loaded - lastLoaded,
|
|
171
|
+
contentLength - loaded);
|
|
172
|
+
lastLoaded = loaded;
|
|
173
|
+
lastTime = currentTime;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (readObj.done) {
|
|
177
|
+
goog.asserts.assert(!readObj.value,
|
|
178
|
+
'readObj should be unset when "done" is true.');
|
|
179
|
+
controller.close();
|
|
180
|
+
} else {
|
|
181
|
+
controller.enqueue(readObj.value);
|
|
182
|
+
push();
|
|
151
183
|
}
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
const currentTime = Date.now();
|
|
155
|
-
// If the time between last time and this time we got progress event
|
|
156
|
-
// is long enough, or if a whole segment is downloaded, call
|
|
157
|
-
// progressUpdated().
|
|
158
|
-
if (currentTime - lastTime > 100 || readObj.done) {
|
|
159
|
-
progressUpdated(currentTime - lastTime, loaded - lastLoaded,
|
|
160
|
-
contentLength - loaded);
|
|
161
|
-
lastLoaded = loaded;
|
|
162
|
-
lastTime = currentTime;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
if (readObj.done) {
|
|
166
|
-
goog.asserts.assert(!readObj.value,
|
|
167
|
-
'readObj should be unset when "done" is true.');
|
|
168
|
-
controller.close();
|
|
169
|
-
} else {
|
|
170
|
-
controller.enqueue(readObj.value);
|
|
171
|
-
push();
|
|
172
|
-
}
|
|
184
|
+
};
|
|
185
|
+
push();
|
|
173
186
|
};
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
arrayBuffer = await response.arrayBuffer();
|
|
187
|
+
// Create a ReadableStream to use the reader. We don't need to use the
|
|
188
|
+
// actual stream for anything, though, as we are using the response's
|
|
189
|
+
// arrayBuffer method to get the body, so we don't store the
|
|
190
|
+
// ReadableStream.
|
|
191
|
+
new ReadableStream({start}); // eslint-disable-line no-new
|
|
192
|
+
arrayBuffer = await response.arrayBuffer();
|
|
193
|
+
}
|
|
182
194
|
} catch (error) {
|
|
183
195
|
if (abortStatus.canceled) {
|
|
184
196
|
throw new shaka.util.Error(
|
|
@@ -243,6 +255,16 @@ shaka.net.HttpFetchPlugin = class {
|
|
|
243
255
|
} else {
|
|
244
256
|
return false;
|
|
245
257
|
}
|
|
258
|
+
// Old fetch implementations hasn't body and ReadableStream implementation
|
|
259
|
+
// See: https://github.com/shaka-project/shaka-player/issues/5088
|
|
260
|
+
if (window.Response) {
|
|
261
|
+
const response = new Response('');
|
|
262
|
+
if (!response.body) {
|
|
263
|
+
return false;
|
|
264
|
+
}
|
|
265
|
+
} else {
|
|
266
|
+
return false;
|
|
267
|
+
}
|
|
246
268
|
return !!(window.fetch && window.AbortController);
|
|
247
269
|
}
|
|
248
270
|
};
|
|
@@ -309,6 +309,7 @@ shaka.net.NetworkingEngine = class extends shaka.util.FakeEventTarget {
|
|
|
309
309
|
if (!responseAndGotProgress.gotProgress &&
|
|
310
310
|
this.onProgressUpdated_ &&
|
|
311
311
|
!response.fromCache &&
|
|
312
|
+
request.method != 'HEAD' &&
|
|
312
313
|
type == shaka.net.NetworkingEngine.RequestType.SEGMENT) {
|
|
313
314
|
this.onProgressUpdated_(response.timeMs, response.data.byteLength);
|
|
314
315
|
}
|
|
@@ -67,7 +67,7 @@ shaka.offline.indexeddb.StorageMechanism = class {
|
|
|
67
67
|
shaka.util.Error.Category.STORAGE,
|
|
68
68
|
shaka.util.Error.Code.INDEXED_DB_INIT_TIMED_OUT));
|
|
69
69
|
});
|
|
70
|
-
timeOutTimer.tickAfter(
|
|
70
|
+
timeOutTimer.tickAfter(5);
|
|
71
71
|
|
|
72
72
|
const open = window.indexedDB.open(name, version);
|
|
73
73
|
open.onsuccess = (event) => {
|
package/lib/player.js
CHANGED
|
@@ -1225,6 +1225,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
1225
1225
|
*/
|
|
1226
1226
|
shouldUseSrcEquals_(payload) {
|
|
1227
1227
|
const Platform = shaka.util.Platform;
|
|
1228
|
+
const MimeUtils = shaka.util.MimeUtils;
|
|
1228
1229
|
|
|
1229
1230
|
// If we are using a platform that does not support media source, we will
|
|
1230
1231
|
// fall back to src= to handle all playback.
|
|
@@ -1279,7 +1280,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
1279
1280
|
// version there.
|
|
1280
1281
|
|
|
1281
1282
|
// Native HLS can be preferred on any platform via this flag:
|
|
1282
|
-
if (
|
|
1283
|
+
if (MimeUtils.isHlsType(mimeType) &&
|
|
1284
|
+
this.config_.streaming.preferNativeHls) {
|
|
1283
1285
|
return true;
|
|
1284
1286
|
}
|
|
1285
1287
|
|
|
@@ -2408,6 +2410,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
2408
2410
|
// goes wrong.
|
|
2409
2411
|
new shaka.util.Timer(resolve).tickAfter(1);
|
|
2410
2412
|
});
|
|
2413
|
+
} else if (textTracks.length > 0) {
|
|
2414
|
+
this.isTextVisible_ = true;
|
|
2411
2415
|
}
|
|
2412
2416
|
|
|
2413
2417
|
// If we have moved on to another piece of content while waiting for
|
|
@@ -4060,6 +4064,19 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
4060
4064
|
firstVariantWithLabel.language, '', 0, label);
|
|
4061
4065
|
|
|
4062
4066
|
this.chooseVariantAndSwitch_();
|
|
4067
|
+
} else if (this.video_ && this.video_.audioTracks) {
|
|
4068
|
+
const audioTracks = Array.from(this.video_.audioTracks);
|
|
4069
|
+
|
|
4070
|
+
let trackMatch = null;
|
|
4071
|
+
|
|
4072
|
+
for (const audioTrack of audioTracks) {
|
|
4073
|
+
if (audioTrack.label == label) {
|
|
4074
|
+
trackMatch = audioTrack;
|
|
4075
|
+
}
|
|
4076
|
+
}
|
|
4077
|
+
if (trackMatch) {
|
|
4078
|
+
this.switchHtml5Track_(trackMatch);
|
|
4079
|
+
}
|
|
4063
4080
|
}
|
|
4064
4081
|
}
|
|
4065
4082
|
|
|
@@ -6663,7 +6680,7 @@ shaka.Player.TYPICAL_BUFFERING_THRESHOLD_ = 0.5;
|
|
|
6663
6680
|
* @define {string} A version number taken from git at compile time.
|
|
6664
6681
|
* @export
|
|
6665
6682
|
*/
|
|
6666
|
-
shaka.Player.version = 'v3.3.
|
|
6683
|
+
shaka.Player.version = 'v3.3.19-uncompiled';
|
|
6667
6684
|
|
|
6668
6685
|
// Initialize the deprecation system using the version string we just set
|
|
6669
6686
|
// on the player.
|
|
@@ -8,7 +8,6 @@ goog.provide('shaka.polyfill.MediaCapabilities');
|
|
|
8
8
|
|
|
9
9
|
goog.require('shaka.log');
|
|
10
10
|
goog.require('shaka.polyfill');
|
|
11
|
-
goog.require('shaka.util.Error');
|
|
12
11
|
goog.require('shaka.util.Platform');
|
|
13
12
|
|
|
14
13
|
|
|
@@ -102,6 +101,19 @@ shaka.polyfill.MediaCapabilities = class {
|
|
|
102
101
|
if (shaka.util.Platform.isChromecast()) {
|
|
103
102
|
isSupported =
|
|
104
103
|
shaka.polyfill.MediaCapabilities.canCastDisplayType_(videoConfig);
|
|
104
|
+
} else if (shaka.util.Platform.isTizen()) {
|
|
105
|
+
let extendedType = videoConfig.contentType;
|
|
106
|
+
if (videoConfig.width && videoConfig.height) {
|
|
107
|
+
extendedType += `; width=${videoConfig.width}`;
|
|
108
|
+
extendedType += `; height=${videoConfig.height}`;
|
|
109
|
+
}
|
|
110
|
+
if (videoConfig.framerate) {
|
|
111
|
+
extendedType += `; framerate=${videoConfig.framerate}`;
|
|
112
|
+
}
|
|
113
|
+
if (videoConfig.bitrate) {
|
|
114
|
+
extendedType += `; bitrate=${videoConfig.bitrate}`;
|
|
115
|
+
}
|
|
116
|
+
isSupported = MediaSource.isTypeSupported(extendedType);
|
|
105
117
|
} else {
|
|
106
118
|
isSupported = MediaSource.isTypeSupported(videoConfig.contentType);
|
|
107
119
|
}
|
|
@@ -212,13 +224,8 @@ shaka.polyfill.MediaCapabilities = class {
|
|
|
212
224
|
* @private
|
|
213
225
|
*/
|
|
214
226
|
static canCastDisplayType_(videoConfig) {
|
|
215
|
-
if (!(window.cast
|
|
216
|
-
|
|
217
|
-
throw new shaka.util.Error(
|
|
218
|
-
shaka.util.Error.Severity.CRITICAL,
|
|
219
|
-
shaka.util.Error.Category.CAST,
|
|
220
|
-
shaka.util.Error.Code.CAST_API_UNAVAILABLE);
|
|
221
|
-
} else if (!(cast.__platform__ && cast.__platform__.canDisplayType)) {
|
|
227
|
+
if (!(window.cast &&
|
|
228
|
+
cast.__platform__ && cast.__platform__.canDisplayType)) {
|
|
222
229
|
shaka.log.warning('Expected cast APIs to be available! Falling back to ' +
|
|
223
230
|
'MediaSource.isTypeSupported() for type support.');
|
|
224
231
|
return MediaSource.isTypeSupported(videoConfig.contentType);
|
|
@@ -58,14 +58,19 @@ shaka.polyfill.MediaSource = class {
|
|
|
58
58
|
// Offsetting the end of the removal range seems to help.
|
|
59
59
|
// Bug filed: https://bugs.webkit.org/show_bug.cgi?id=177884
|
|
60
60
|
shaka.polyfill.MediaSource.patchRemovalRange_();
|
|
61
|
-
} else {
|
|
62
|
-
shaka.log.info('Patching Safari 13 MSE bugs.');
|
|
61
|
+
} else if (safariVersion <= 15) {
|
|
62
|
+
shaka.log.info('Patching Safari 13 & 14 & 15 MSE bugs.');
|
|
63
63
|
// Safari 13 does not correctly implement abort() on SourceBuffer.
|
|
64
64
|
// Calling abort() before appending a segment causes that segment to be
|
|
65
65
|
// incomplete in the buffer.
|
|
66
66
|
// Bug filed: https://bugs.webkit.org/show_bug.cgi?id=165342
|
|
67
67
|
shaka.polyfill.MediaSource.stubAbort_();
|
|
68
68
|
}
|
|
69
|
+
} else if (shaka.util.Platform.isEdge()) {
|
|
70
|
+
shaka.log.info('Rejecting TS container.');
|
|
71
|
+
// TS content is broken on Edge in general.
|
|
72
|
+
// See https://github.com/shaka-project/shaka-player/issues/4955
|
|
73
|
+
shaka.polyfill.MediaSource.rejectTsContent_();
|
|
69
74
|
} else if (shaka.util.Platform.isTizen2() ||
|
|
70
75
|
shaka.util.Platform.isTizen3() ||
|
|
71
76
|
shaka.util.Platform.isTizen4()) {
|
package/lib/text/text_engine.js
CHANGED
|
@@ -134,6 +134,7 @@ shaka.text.TextEngine = class {
|
|
|
134
134
|
// into TextEngine and TextDisplayer.
|
|
135
135
|
if (mimeType == shaka.util.MimeUtils.CEA608_CLOSED_CAPTION_MIMETYPE ||
|
|
136
136
|
mimeType == shaka.util.MimeUtils.CEA708_CLOSED_CAPTION_MIMETYPE) {
|
|
137
|
+
this.parser_ = null;
|
|
137
138
|
return;
|
|
138
139
|
}
|
|
139
140
|
|
|
@@ -480,6 +480,7 @@ shaka.text.UITextDisplayer = class {
|
|
|
480
480
|
wrapper = shaka.util.Dom.createHTMLElement('span');
|
|
481
481
|
wrapper.classList.add('shaka-text-wrapper');
|
|
482
482
|
wrapper.style.backgroundColor = cue.backgroundColor;
|
|
483
|
+
wrapper.style.lineHeight = 'normal';
|
|
483
484
|
cueElement.appendChild(wrapper);
|
|
484
485
|
}
|
|
485
486
|
|
|
@@ -369,8 +369,7 @@ shaka.text.VttTextParser = class {
|
|
|
369
369
|
end += timeOffset;
|
|
370
370
|
|
|
371
371
|
// Get the payload.
|
|
372
|
-
const payload =
|
|
373
|
-
text.slice(1).join('\n').trim());
|
|
372
|
+
const payload = text.slice(1).join('\n').trim();
|
|
374
373
|
|
|
375
374
|
let cue = null;
|
|
376
375
|
if (styles.has('global')) {
|
|
@@ -427,7 +426,7 @@ shaka.text.VttTextParser = class {
|
|
|
427
426
|
const childNode = childNodes[0];
|
|
428
427
|
if (childNode.nodeType == Node.TEXT_NODE ||
|
|
429
428
|
childNode.nodeType == Node.CDATA_SECTION_NODE) {
|
|
430
|
-
rootCue.payload = payload;
|
|
429
|
+
rootCue.payload = VttTextParser.htmlUnescape_(payload);
|
|
431
430
|
return;
|
|
432
431
|
}
|
|
433
432
|
}
|
|
@@ -438,7 +437,7 @@ shaka.text.VttTextParser = class {
|
|
|
438
437
|
rootCue.nestedCues = cues;
|
|
439
438
|
} else {
|
|
440
439
|
shaka.log.warning('The cue\'s markup could not be parsed: ', payload);
|
|
441
|
-
rootCue.payload = payload;
|
|
440
|
+
rootCue.payload = VttTextParser.htmlUnescape_(payload);
|
|
442
441
|
}
|
|
443
442
|
}
|
|
444
443
|
|
|
@@ -682,7 +681,7 @@ shaka.text.VttTextParser = class {
|
|
|
682
681
|
}
|
|
683
682
|
if (text.length > 0) {
|
|
684
683
|
const textCue = nestedCue.clone();
|
|
685
|
-
textCue.payload = text;
|
|
684
|
+
textCue.payload = VttTextParser.htmlUnescape_(text);
|
|
686
685
|
cues.push(textCue);
|
|
687
686
|
}
|
|
688
687
|
isFirst = false;
|
|
@@ -185,8 +185,7 @@ shaka.util.ManifestParserUtils.AUDIO_CODEC_REGEXPS_ = [
|
|
|
185
185
|
/^mp4a/,
|
|
186
186
|
/^[ae]c-3$/,
|
|
187
187
|
/^ac-4$/,
|
|
188
|
-
/^dts[
|
|
189
|
-
/^[du]dts$/, // DTS Surround Sound
|
|
188
|
+
/^dts[cex]$/, // DTS Digital Surround (dtsc), DTS Express (dtse), DTS:X (dtsx)
|
|
190
189
|
];
|
|
191
190
|
|
|
192
191
|
|
package/lib/util/mime_utils.js
CHANGED
|
@@ -50,7 +50,7 @@ shaka.util.MimeUtils = class {
|
|
|
50
50
|
return shaka.media.Transmuxer.convertTsCodecs(
|
|
51
51
|
contentType, fullMimeType);
|
|
52
52
|
}
|
|
53
|
-
} else if (contentType == ContentType.AUDIO) {
|
|
53
|
+
} else if (mimeType != 'video/mp2t' && contentType == ContentType.AUDIO) {
|
|
54
54
|
// video/mp2t is the correct mime type for TS audio, so only replace the
|
|
55
55
|
// word "video" with "audio" for non-TS audio content.
|
|
56
56
|
return fullMimeType.replace('video', 'audio');
|
|
@@ -194,6 +194,17 @@ shaka.util.MimeUtils = class {
|
|
|
194
194
|
return value;
|
|
195
195
|
}
|
|
196
196
|
|
|
197
|
+
/**
|
|
198
|
+
* Checks if the given MIME type is HLS MIME type.
|
|
199
|
+
*
|
|
200
|
+
* @param {string} mimeType
|
|
201
|
+
* @return {boolean}
|
|
202
|
+
*/
|
|
203
|
+
static isHlsType(mimeType) {
|
|
204
|
+
return mimeType === 'application/x-mpegurl' ||
|
|
205
|
+
mimeType === 'application/vnd.apple.mpegurl';
|
|
206
|
+
}
|
|
207
|
+
|
|
197
208
|
/**
|
|
198
209
|
* Get the base and profile of a codec string. Where [0] will be the codec
|
|
199
210
|
* base and [1] will be the profile.
|
package/lib/util/periods.js
CHANGED
|
@@ -671,11 +671,11 @@ shaka.util.PeriodCombiner = class {
|
|
|
671
671
|
// Also checks if the segmentIndex is still valid after the async
|
|
672
672
|
// operations, to make sure we stop if the active stream has changed.
|
|
673
673
|
if (outputStream.segmentIndex instanceof shaka.media.MetaSegmentIndex) {
|
|
674
|
-
for (let i =
|
|
674
|
+
for (let i = firstNewPeriodIndex; i < streams.length; i++) {
|
|
675
675
|
const match = streams[i];
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
676
|
+
goog.asserts.assert(match.segmentIndex,
|
|
677
|
+
'stream should have a segmentIndex.');
|
|
678
|
+
if (match.segmentIndex) {
|
|
679
679
|
outputStream.segmentIndex.appendSegmentIndex(match.segmentIndex);
|
|
680
680
|
}
|
|
681
681
|
}
|
|
@@ -728,7 +728,7 @@ shaka.util.PeriodCombiner = class {
|
|
|
728
728
|
// in advance. concat() will add them to the output's MetaSegmentIndex.
|
|
729
729
|
}
|
|
730
730
|
|
|
731
|
-
if (!outputStream.matchedStreams) {
|
|
731
|
+
if (!outputStream.matchedStreams || !outputStream.matchedStreams.length) {
|
|
732
732
|
// This is not a stream we can build output from, but it may become part
|
|
733
733
|
// of another output based on another period's stream.
|
|
734
734
|
return null;
|
package/lib/util/stream_utils.js
CHANGED
|
@@ -703,26 +703,38 @@ shaka.util.StreamUtils = class {
|
|
|
703
703
|
}
|
|
704
704
|
|
|
705
705
|
if (audio) {
|
|
706
|
-
|
|
706
|
+
// See: https://github.com/shaka-project/shaka-player/issues/4659
|
|
707
|
+
if (info.audioRobustness != '') {
|
|
708
|
+
if (!keySystemConfig.audio) {
|
|
709
|
+
// KeySystemTrackConfiguration
|
|
710
|
+
keySystemConfig.audio = {
|
|
711
|
+
robustness: info.audioRobustness,
|
|
712
|
+
};
|
|
713
|
+
} else {
|
|
714
|
+
keySystemConfig.audio.robustness =
|
|
715
|
+
keySystemConfig.audio.robustness || info.audioRobustness;
|
|
716
|
+
}
|
|
717
|
+
} else if (!keySystemConfig.audio) {
|
|
707
718
|
// KeySystemTrackConfiguration
|
|
708
|
-
keySystemConfig.audio = {
|
|
709
|
-
robustness: info.audioRobustness,
|
|
710
|
-
};
|
|
711
|
-
} else {
|
|
712
|
-
keySystemConfig.audio.robustness =
|
|
713
|
-
keySystemConfig.audio.robustness || info.audioRobustness;
|
|
719
|
+
keySystemConfig.audio = {};
|
|
714
720
|
}
|
|
715
721
|
}
|
|
716
722
|
|
|
717
723
|
if (video) {
|
|
718
|
-
|
|
724
|
+
// See: https://github.com/shaka-project/shaka-player/issues/4659
|
|
725
|
+
if (info.videoRobustness != '') {
|
|
726
|
+
if (!keySystemConfig.video) {
|
|
727
|
+
// KeySystemTrackConfiguration
|
|
728
|
+
keySystemConfig.video = {
|
|
729
|
+
robustness: info.videoRobustness,
|
|
730
|
+
};
|
|
731
|
+
} else {
|
|
732
|
+
keySystemConfig.video.robustness =
|
|
733
|
+
keySystemConfig.video.robustness || info.videoRobustness;
|
|
734
|
+
}
|
|
735
|
+
} else if (!keySystemConfig.video) {
|
|
719
736
|
// KeySystemTrackConfiguration
|
|
720
|
-
keySystemConfig.video = {
|
|
721
|
-
robustness: info.videoRobustness,
|
|
722
|
-
};
|
|
723
|
-
} else {
|
|
724
|
-
keySystemConfig.video.robustness =
|
|
725
|
-
keySystemConfig.video.robustness || info.videoRobustness;
|
|
737
|
+
keySystemConfig.video = {};
|
|
726
738
|
}
|
|
727
739
|
}
|
|
728
740
|
}
|
|
@@ -809,7 +821,7 @@ shaka.util.StreamUtils = class {
|
|
|
809
821
|
const video = variant.video;
|
|
810
822
|
if (audio && currentVariant && currentVariant.audio) {
|
|
811
823
|
if (!StreamUtils.areStreamsCompatible_(audio, currentVariant.audio)) {
|
|
812
|
-
shaka.log.debug('
|
|
824
|
+
shaka.log.debug('Dropping variant - not compatible with active audio',
|
|
813
825
|
'active audio',
|
|
814
826
|
StreamUtils.getStreamSummaryString_(currentVariant.audio),
|
|
815
827
|
'variant.audio',
|
|
@@ -820,7 +832,7 @@ shaka.util.StreamUtils = class {
|
|
|
820
832
|
|
|
821
833
|
if (video && currentVariant && currentVariant.video) {
|
|
822
834
|
if (!StreamUtils.areStreamsCompatible_(video, currentVariant.video)) {
|
|
823
|
-
shaka.log.debug('
|
|
835
|
+
shaka.log.debug('Dropping variant - not compatible with active video',
|
|
824
836
|
'active video',
|
|
825
837
|
StreamUtils.getStreamSummaryString_(currentVariant.video),
|
|
826
838
|
'variant.video',
|
package/maintained-branches.md
CHANGED
|
@@ -2,10 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
We are currently maintaining the following branches of Shaka Player:
|
|
4
4
|
|
|
5
|
-
- v4.
|
|
6
|
-
- v4.
|
|
7
|
-
-
|
|
8
|
-
- v3.2 (in use by the Cast Application Framework)
|
|
5
|
+
- v4.3 (latest, also in use by the Cast Application Framework)
|
|
6
|
+
- v4.2 (previous)
|
|
7
|
+
- No active LTS branches at this time
|
|
9
8
|
|
|
10
9
|
Other branches are no longer receiving bug fixes, and we recommend you upgrade
|
|
11
10
|
to a maintained branch. For details on upgrading, please see our
|
package/package.json
CHANGED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/*! @license
|
|
2
|
+
* Shaka Player
|
|
3
|
+
* Copyright 2016 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
describe('ContentWorkarounds', () => {
|
|
8
|
+
const encryptionBoxes = {
|
|
9
|
+
'encv': ['hev1', 'hvc1', 'avc1', 'avc3'],
|
|
10
|
+
'enca': ['ac-3', 'ec-3', 'mp4a'],
|
|
11
|
+
};
|
|
12
|
+
for (const encryptionBox of Object.keys(encryptionBoxes)) {
|
|
13
|
+
for (const box of encryptionBoxes[encryptionBox]) {
|
|
14
|
+
it(`adds ${encryptionBox} box for ${box}`, () => {
|
|
15
|
+
const boxType = [];
|
|
16
|
+
for (const char of box) {
|
|
17
|
+
boxType.push(char.charCodeAt(0));
|
|
18
|
+
}
|
|
19
|
+
const unencrypted = new Uint8Array([
|
|
20
|
+
0x00, 0x00, 0x00, 0x20, // size
|
|
21
|
+
0x73, 0x74, 0x73, 0x64, // stsd
|
|
22
|
+
0x01, // version
|
|
23
|
+
0x12, 0x34, 0x56, // flags
|
|
24
|
+
0x00, 0x00, 0x00, 0x01, // count
|
|
25
|
+
0x00, 0x00, 0x00, 0x10, // size
|
|
26
|
+
...boxType, // box type
|
|
27
|
+
0x01, // version
|
|
28
|
+
0x12, 0x34, 0x56, // flags
|
|
29
|
+
0x00, 0x11, 0x22, 0x33, // payload
|
|
30
|
+
]);
|
|
31
|
+
|
|
32
|
+
const faked =
|
|
33
|
+
shaka.media.ContentWorkarounds.fakeEncryption(unencrypted);
|
|
34
|
+
const spy = jasmine.createSpy('boxCallback');
|
|
35
|
+
new shaka.util.Mp4Parser()
|
|
36
|
+
.fullBox('stsd', shaka.util.Mp4Parser.sampleDescription)
|
|
37
|
+
.box(encryptionBox, /** @type {!Function} */ (spy))
|
|
38
|
+
.parse(faked);
|
|
39
|
+
expect(spy).toHaveBeenCalled();
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
});
|
|
@@ -74,19 +74,6 @@ describe('DrmEngine', () => {
|
|
|
74
74
|
onEventSpy = jasmine.createSpy('onEvent');
|
|
75
75
|
|
|
76
76
|
networkingEngine = new shaka.net.NetworkingEngine();
|
|
77
|
-
networkingEngine.registerRequestFilter((type, request) => {
|
|
78
|
-
if (type != shaka.net.NetworkingEngine.RequestType.LICENSE) {
|
|
79
|
-
return;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
request.headers['X-AxDRM-Message'] = [
|
|
83
|
-
'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ2ZXJzaW9uIjoxLCJjb21fa2V5X2lk',
|
|
84
|
-
'IjoiNjllNTQwODgtZTllMC00NTMwLThjMWEtMWViNmRjZDBkMTRlIiwibWVzc2FnZSI6e',
|
|
85
|
-
'yJ0eXBlIjoiZW50aXRsZW1lbnRfbWVzc2FnZSIsImtleXMiOlt7ImlkIjoiNmU1YTFkMj',
|
|
86
|
-
'YtMjc1Ny00N2Q3LTgwNDYtZWFhNWQxZDM0YjVhIn1dfX0.yF7PflOPv9qHnu3ZWJNZ12j',
|
|
87
|
-
'gkqTabmwXbDWk_47tLNE',
|
|
88
|
-
].join('');
|
|
89
|
-
});
|
|
90
77
|
|
|
91
78
|
const playerInterface = {
|
|
92
79
|
netEngine: networkingEngine,
|
|
@@ -99,22 +86,22 @@ describe('DrmEngine', () => {
|
|
|
99
86
|
drmEngine = new shaka.media.DrmEngine(playerInterface);
|
|
100
87
|
const config = shaka.util.PlayerConfiguration.createDefault().drm;
|
|
101
88
|
config.servers['com.widevine.alpha'] =
|
|
102
|
-
'https://
|
|
89
|
+
'https://cwip-shaka-proxy.appspot.com/specific_key?blodJidXR9eARuql0dNLWg=GX8m9XLIZNIzizrl0RTqnA';
|
|
103
90
|
config.servers['com.microsoft.playready'] =
|
|
104
|
-
'https://
|
|
91
|
+
'https://test.playready.microsoft.com/service/rightsmanager.asmx?cfg=(kid:6e5a1d26-2757-47d7-8046-eaa5d1d34b5a,contentkey:GX8m9XLIZNIzizrl0RTqnA==,sl:150)';
|
|
105
92
|
drmEngine.configure(config);
|
|
106
93
|
|
|
107
94
|
manifest = shaka.test.ManifestGenerator.generate((manifest) => {
|
|
108
95
|
manifest.addVariant(0, (variant) => {
|
|
109
96
|
variant.addVideo(1, (stream) => {
|
|
110
97
|
stream.encrypted = true;
|
|
111
|
-
stream.addDrmInfo('com.widevine.alpha');
|
|
112
98
|
stream.addDrmInfo('com.microsoft.playready');
|
|
99
|
+
stream.addDrmInfo('com.widevine.alpha');
|
|
113
100
|
});
|
|
114
101
|
variant.addAudio(2, (stream) => {
|
|
115
102
|
stream.encrypted = true;
|
|
116
|
-
stream.addDrmInfo('com.widevine.alpha');
|
|
117
103
|
stream.addDrmInfo('com.microsoft.playready');
|
|
104
|
+
stream.addDrmInfo('com.widevine.alpha');
|
|
118
105
|
});
|
|
119
106
|
});
|
|
120
107
|
});
|
|
@@ -3277,7 +3277,12 @@ describe('StreamingEngine', () => {
|
|
|
3277
3277
|
netEngine.request.and.callFake((requestType, request) => {
|
|
3278
3278
|
const buffer = new ArrayBuffer(0);
|
|
3279
3279
|
/** @type {shaka.extern.Response} */
|
|
3280
|
-
const response = {
|
|
3280
|
+
const response = {
|
|
3281
|
+
uri: request.uris[0],
|
|
3282
|
+
originalUri: request.uris[0],
|
|
3283
|
+
data: buffer,
|
|
3284
|
+
headers: {},
|
|
3285
|
+
};
|
|
3281
3286
|
return shaka.util.AbortableOperation.completed(response);
|
|
3282
3287
|
});
|
|
3283
3288
|
|
|
@@ -1226,6 +1226,11 @@ describe('NetworkingEngine', /** @suppress {accessControls} */ () => {
|
|
|
1226
1226
|
|
|
1227
1227
|
/** @return {shaka.extern.Response} */
|
|
1228
1228
|
function createResponse() {
|
|
1229
|
-
return {
|
|
1229
|
+
return {
|
|
1230
|
+
uri: '',
|
|
1231
|
+
originalUri: '',
|
|
1232
|
+
data: new ArrayBuffer(5),
|
|
1233
|
+
headers: {},
|
|
1234
|
+
};
|
|
1230
1235
|
}
|
|
1231
1236
|
}); // describe('NetworkingEngine')
|