shaka-player 3.2.12 → 3.2.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/.github/workflows/build-and-test.yaml +42 -22
- package/.github/workflows/compute-incremental-coverage.py +14 -3
- package/.github/workflows/custom-actions/set-commit-status/action.yaml +1 -5
- package/.github/workflows/deflake.yaml +28 -0
- package/.github/workflows/demo-version-index.yaml +9 -1
- package/.github/workflows/nightly-demo.yaml +1 -1
- package/.github/workflows/release-please.yaml +4 -4
- package/.github/workflows/report-incremental-coverage.yaml +1 -1
- package/.github/workflows/selenium-lab-tests.yaml +21 -10
- package/AUTHORS +3 -0
- package/CHANGELOG.md +25 -0
- package/CONTRIBUTORS +2 -0
- package/dist/deps.js +3 -3
- package/dist/locales.js +28 -28
- package/dist/shaka-player.compiled.d.ts +1 -0
- package/dist/shaka-player.compiled.debug.d.ts +1 -0
- package/dist/shaka-player.compiled.debug.externs.js +1 -0
- package/dist/shaka-player.compiled.debug.js +181 -179
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +1 -0
- package/dist/shaka-player.compiled.js +664 -663
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.d.ts +1 -0
- package/dist/shaka-player.ui.debug.d.ts +1 -0
- package/dist/shaka-player.ui.debug.externs.js +1 -0
- package/dist/shaka-player.ui.debug.js +222 -220
- package/dist/shaka-player.ui.debug.map +4 -4
- package/dist/shaka-player.ui.externs.js +1 -0
- package/dist/shaka-player.ui.js +819 -818
- package/dist/shaka-player.ui.map +4 -4
- package/docs/jsdoc-template/publish.js +33 -0
- package/docs/jsdoc-template/tmpl/container.tmpl +4 -1
- package/docs/jsdoc.conf.json +1 -0
- package/docs/tutorials/welcome.md +2 -2
- package/lib/ads/client_side_ad_manager.js +5 -2
- package/lib/cast/cast_sender.js +39 -14
- package/lib/cea/cea608_memory.js +4 -0
- package/lib/media/drm_engine.js +4 -2
- package/lib/media/streaming_engine.js +41 -4
- package/lib/offline/indexeddb/storage_mechanism.js +24 -0
- package/lib/player.js +1 -1
- package/lib/polyfill/media_capabilities.js +1 -0
- package/lib/text/ttml_text_parser.js +69 -87
- package/lib/util/error.js +7 -0
- package/lib/util/periods.js +9 -9
- package/lib/util/platform.js +34 -0
- package/lib/util/stream_utils.js +2 -1
- package/lib/util/xml_utils.js +45 -6
- package/package.json +1 -1
- package/test/cea/cea608_memory_unit.js +88 -0
- package/test/media/streaming_engine_integration.js +8 -7
- package/test/offline/offline_integration.js +3 -3
- package/test/offline/storage_integration.js +30 -0
- package/test/test/util/ttml_utils.js +0 -2
- package/test/text/ttml_text_parser_unit.js +46 -0
- package/test/ui/text_displayer_layout_unit.js +17 -2
- package/test/util/periods_unit.js +149 -11
- package/test/util/xml_utils_unit.js +64 -0
|
@@ -440,6 +440,7 @@ function buildNav(members) {
|
|
|
440
440
|
[members.externals, 'Externals', seen, linktoExternal],
|
|
441
441
|
[members.namespaces, 'Namespaces', seen, linkto],
|
|
442
442
|
[members.classes, 'Classes', seen, linkto],
|
|
443
|
+
[members.enums, 'Enums', seen, linkto],
|
|
443
444
|
[members.interfaces, 'Interfaces', seen, linkto],
|
|
444
445
|
[members.events, 'Events', seen, linkto],
|
|
445
446
|
[members.mixins, 'Mixins', seen, linkto],
|
|
@@ -484,6 +485,7 @@ function fixUpType(type) {
|
|
|
484
485
|
exports.publish = (taffyData, opts, tutorials) => {
|
|
485
486
|
let classes;
|
|
486
487
|
let conf;
|
|
488
|
+
let enums;
|
|
487
489
|
let externals;
|
|
488
490
|
let files;
|
|
489
491
|
let fromDir;
|
|
@@ -733,6 +735,31 @@ exports.publish = (taffyData, opts, tutorials) => {
|
|
|
733
735
|
});
|
|
734
736
|
|
|
735
737
|
members = helper.getMembers(data);
|
|
738
|
+
members.enums = [];
|
|
739
|
+
|
|
740
|
+
data().each(doclet => {
|
|
741
|
+
if (doclet.isEnum) {
|
|
742
|
+
const hasParent = !!docletMap[doclet.memberof];
|
|
743
|
+
|
|
744
|
+
// Enums without parents (not attached to a class, but directly to a
|
|
745
|
+
// namespace) aren't recognized by jsdoc by default and need to be
|
|
746
|
+
// massaged into the docs separately.
|
|
747
|
+
if (!hasParent) {
|
|
748
|
+
// Temporarily call this a "class", so that we can fix the URL.
|
|
749
|
+
doclet.kind = 'class';
|
|
750
|
+
// Regenerate the URL, so that this enum gets its own page
|
|
751
|
+
// instead of a URL that links to an ID within a non-existent
|
|
752
|
+
// parent page.
|
|
753
|
+
delete helper.longnameToUrl[doclet.longname];
|
|
754
|
+
helper.createLink(doclet);
|
|
755
|
+
// Mark this as an enum (custom type), so that it doesn't get
|
|
756
|
+
// slotted with the classes.
|
|
757
|
+
doclet.kind = 'enum';
|
|
758
|
+
members.enums.push(doclet);
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
});
|
|
762
|
+
|
|
736
763
|
members.tutorials = tutorials.children;
|
|
737
764
|
if (conf.default.sortTutorialsByConfigOrder) {
|
|
738
765
|
members.tutorials.sort((a, b) => {
|
|
@@ -778,6 +805,7 @@ exports.publish = (taffyData, opts, tutorials) => {
|
|
|
778
805
|
|
|
779
806
|
// set up the lists that we'll use to generate pages
|
|
780
807
|
classes = taffy(members.classes);
|
|
808
|
+
enums = taffy(members.enums);
|
|
781
809
|
modules = taffy(members.modules);
|
|
782
810
|
namespaces = taffy(members.namespaces);
|
|
783
811
|
mixins = taffy(members.mixins);
|
|
@@ -786,6 +814,7 @@ exports.publish = (taffyData, opts, tutorials) => {
|
|
|
786
814
|
|
|
787
815
|
Object.keys(helper.longnameToUrl).forEach(longname => {
|
|
788
816
|
const myClasses = helper.find(classes, {longname: longname});
|
|
817
|
+
const myEnums = helper.find(enums, {longname: longname});
|
|
789
818
|
const myExternals = helper.find(externals, {longname: longname});
|
|
790
819
|
const myInterfaces = helper.find(interfaces, {longname: longname});
|
|
791
820
|
const myMixins = helper.find(mixins, {longname: longname});
|
|
@@ -800,6 +829,10 @@ exports.publish = (taffyData, opts, tutorials) => {
|
|
|
800
829
|
generate(`Class: ${myClasses[0].longname}`, myClasses, helper.longnameToUrl[longname]);
|
|
801
830
|
}
|
|
802
831
|
|
|
832
|
+
if (myEnums.length) {
|
|
833
|
+
generate(`Enum: ${myEnums[0].longname}`, myEnums, helper.longnameToUrl[longname]);
|
|
834
|
+
}
|
|
835
|
+
|
|
803
836
|
if (myNamespaces.length) {
|
|
804
837
|
generate(`Namespace: ${myNamespaces[0].longname}`, myNamespaces, helper.longnameToUrl[longname]);
|
|
805
838
|
}
|
|
@@ -144,7 +144,10 @@
|
|
|
144
144
|
return m.longname && m.longname.indexOf('module:') !== 0;
|
|
145
145
|
});
|
|
146
146
|
}
|
|
147
|
-
|
|
147
|
+
|
|
148
|
+
// Skip enums, since they already have their values listed under
|
|
149
|
+
// "Properties".
|
|
150
|
+
if (members && members.length && members.forEach && doc.kind != 'enum') {
|
|
148
151
|
?>
|
|
149
152
|
<h3 class="subsection-title">Members</h3>
|
|
150
153
|
|
package/docs/jsdoc.conf.json
CHANGED
|
@@ -66,8 +66,8 @@ python build/all.py
|
|
|
66
66
|
|
|
67
67
|
Alternatively you can use a docker container:
|
|
68
68
|
```sh
|
|
69
|
-
|
|
70
|
-
docker
|
|
69
|
+
docker build -t shaka-player-build build/docker
|
|
70
|
+
docker run -v $(pwd):/usr/src --user $(id -u):$(id -g) shaka-player-build
|
|
71
71
|
```
|
|
72
72
|
|
|
73
73
|
The output is:
|
|
@@ -15,7 +15,6 @@ goog.require('goog.asserts');
|
|
|
15
15
|
goog.require('shaka.ads.ClientSideAd');
|
|
16
16
|
goog.require('shaka.util.IReleasable');
|
|
17
17
|
|
|
18
|
-
|
|
19
18
|
/**
|
|
20
19
|
* A class responsible for client-side ad interactions.
|
|
21
20
|
* @implements {shaka.util.IReleasable}
|
|
@@ -211,7 +210,11 @@ shaka.ads.ClientSideAdManager = class {
|
|
|
211
210
|
// TODO (ismena): Need a better inderstanding of what this does.
|
|
212
211
|
// The docs say it's called to 'start playing the ads,' but I haven't
|
|
213
212
|
// seen the ads actually play until requestAds() is called.
|
|
214
|
-
|
|
213
|
+
// Note: We listen for a play event to avoid autoplay issues that might
|
|
214
|
+
// crash IMA.
|
|
215
|
+
this.video_.addEventListener('play', () => {
|
|
216
|
+
this.imaAdsManager_.start();
|
|
217
|
+
}, {once: true});
|
|
215
218
|
} catch (adError) {
|
|
216
219
|
// If there was a problem with the VAST response,
|
|
217
220
|
// we we won't be getting an ad. Hide ad UI if we showed it already
|
package/lib/cast/cast_sender.js
CHANGED
|
@@ -186,21 +186,14 @@ shaka.cast.CastSender = class {
|
|
|
186
186
|
// If the API becomes available before this instance dies, init will be
|
|
187
187
|
// called again.
|
|
188
188
|
|
|
189
|
-
//
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
// be overwritten.
|
|
196
|
-
if (!window.__onGCastApiAvailable) {
|
|
197
|
-
window.__onGCastApiAvailable = shaka.cast.CastSender.onSdkLoaded_;
|
|
198
|
-
}
|
|
199
|
-
if (window.__onGCastApiAvailable != shaka.cast.CastSender.onSdkLoaded_) {
|
|
200
|
-
shaka.log.alwaysWarn('A global Cast SDK hook is already installed! ' +
|
|
201
|
-
'Shaka Player will be unable to receive a notification when the ' +
|
|
202
|
-
'Cast SDK is ready.');
|
|
189
|
+
// Check if our callback is already installed.
|
|
190
|
+
if (window.__onGCastApiAvailable !== CastSender.onGCastApiAvailable_) {
|
|
191
|
+
// Save pre-existing __onGCastApiAvailable in order to restore later.
|
|
192
|
+
CastSender.__onGCastApiAvailable_ =
|
|
193
|
+
window.__onGCastApiAvailable || null;
|
|
194
|
+
window.__onGCastApiAvailable = CastSender.onGCastApiAvailable_;
|
|
203
195
|
}
|
|
196
|
+
|
|
204
197
|
return;
|
|
205
198
|
}
|
|
206
199
|
|
|
@@ -747,6 +740,9 @@ shaka.cast.CastSender.hasReceivers_ = false;
|
|
|
747
740
|
/** @private {chrome.cast.Session} */
|
|
748
741
|
shaka.cast.CastSender.session_ = null;
|
|
749
742
|
|
|
743
|
+
/** @private {?function(boolean)} */
|
|
744
|
+
shaka.cast.CastSender.__onGCastApiAvailable_ = null;
|
|
745
|
+
|
|
750
746
|
/**
|
|
751
747
|
* A set of all living CastSender instances. The constructor and destroy
|
|
752
748
|
* methods will add and remove instances from this set.
|
|
@@ -774,3 +770,32 @@ shaka.cast.CastSender.onSdkLoaded_ = (loaded) => {
|
|
|
774
770
|
}
|
|
775
771
|
}
|
|
776
772
|
};
|
|
773
|
+
|
|
774
|
+
/**
|
|
775
|
+
* @param {boolean} available
|
|
776
|
+
* @private
|
|
777
|
+
*/
|
|
778
|
+
shaka.cast.CastSender.onGCastApiAvailable_ = (available) => {
|
|
779
|
+
// Restore callback from saved.
|
|
780
|
+
if (shaka.cast.CastSender.__onGCastApiAvailable_) {
|
|
781
|
+
window.__onGCastApiAvailable =
|
|
782
|
+
shaka.cast.CastSender.__onGCastApiAvailable_;
|
|
783
|
+
} else {
|
|
784
|
+
delete window.__onGCastApiAvailable;
|
|
785
|
+
}
|
|
786
|
+
shaka.cast.CastSender.__onGCastApiAvailable_ = null;
|
|
787
|
+
|
|
788
|
+
// A note about this value: In our testing environment, we load both
|
|
789
|
+
// uncompiled and compiled code. This global callback in uncompiled mode
|
|
790
|
+
// can be overwritten by the same in compiled mode. The two versions will
|
|
791
|
+
// each have their own instances_ map. Therefore the callback must have a
|
|
792
|
+
// name, as opposed to being anonymous. This way, the CastSender tests
|
|
793
|
+
// can invoke the named static method instead of using a global that could
|
|
794
|
+
// be overwritten.
|
|
795
|
+
shaka.cast.CastSender.onSdkLoaded_(available);
|
|
796
|
+
|
|
797
|
+
// call restored callback (if any)
|
|
798
|
+
if (typeof window.__onGCastApiAvailable === 'function') {
|
|
799
|
+
window.__onGCastApiAvailable(available);
|
|
800
|
+
}
|
|
801
|
+
};
|
package/lib/cea/cea608_memory.js
CHANGED
|
@@ -184,6 +184,10 @@ shaka.cea.Cea608Memory = class {
|
|
|
184
184
|
* @param {number} count Count of rows to move.
|
|
185
185
|
*/
|
|
186
186
|
moveRows(dst, src, count) {
|
|
187
|
+
if (src < 0 || dst < 0) {
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
|
|
187
191
|
if (dst >= src) {
|
|
188
192
|
for (let i = count-1; i >= 0; i--) {
|
|
189
193
|
this.rows_[dst + i] = this.rows_[src + i].map((e) => e);
|
package/lib/media/drm_engine.js
CHANGED
|
@@ -27,6 +27,7 @@ goog.require('shaka.util.StreamUtils');
|
|
|
27
27
|
goog.require('shaka.util.StringUtils');
|
|
28
28
|
goog.require('shaka.util.Timer');
|
|
29
29
|
goog.require('shaka.util.Uint8ArrayUtils');
|
|
30
|
+
goog.require('shaka.util.XmlUtils');
|
|
30
31
|
|
|
31
32
|
|
|
32
33
|
/** @implements {shaka.util.IDestroyable} */
|
|
@@ -1439,7 +1440,8 @@ shaka.media.DrmEngine = class {
|
|
|
1439
1440
|
return;
|
|
1440
1441
|
}
|
|
1441
1442
|
shaka.log.debug('Unwrapping PlayReady request.');
|
|
1442
|
-
const dom =
|
|
1443
|
+
const dom = shaka.util.XmlUtils.parseXmlString(xml, 'PlayReadyKeyMessage');
|
|
1444
|
+
goog.asserts.assert(dom, 'Failed to parse PlayReady XML!');
|
|
1443
1445
|
|
|
1444
1446
|
// Set request headers.
|
|
1445
1447
|
const headers = dom.getElementsByTagName('HttpHeader');
|
|
@@ -1523,7 +1525,7 @@ shaka.media.DrmEngine = class {
|
|
|
1523
1525
|
hasExpiredKeys = true;
|
|
1524
1526
|
}
|
|
1525
1527
|
|
|
1526
|
-
const keyIdHex = shaka.util.Uint8ArrayUtils.toHex(keyId);
|
|
1528
|
+
const keyIdHex = shaka.util.Uint8ArrayUtils.toHex(keyId).slice(0, 32);
|
|
1527
1529
|
|
|
1528
1530
|
this.keyStatusByKeyId_.set(keyIdHex, status);
|
|
1529
1531
|
});
|
|
@@ -980,7 +980,11 @@ shaka.media.StreamingEngine = class {
|
|
|
980
980
|
const timeUntilEnd =
|
|
981
981
|
this.manifest_.presentationTimeline.getDuration() - timeNeeded;
|
|
982
982
|
const oneMicrosecond = 1e-6;
|
|
983
|
-
|
|
983
|
+
|
|
984
|
+
const bufferEnd =
|
|
985
|
+
this.playerInterface_.mediaSourceEngine.bufferEnd(mediaState.type);
|
|
986
|
+
|
|
987
|
+
if (timeUntilEnd < oneMicrosecond && !!bufferEnd) {
|
|
984
988
|
// We shouldn't rebuffer if the playhead is close to the end of the
|
|
985
989
|
// presentation.
|
|
986
990
|
shaka.log.debug(logPrefix, 'buffered to end of presentation');
|
|
@@ -1010,8 +1014,6 @@ shaka.media.StreamingEngine = class {
|
|
|
1010
1014
|
return this.config_.updateIntervalSeconds / 2;
|
|
1011
1015
|
}
|
|
1012
1016
|
|
|
1013
|
-
const bufferEnd =
|
|
1014
|
-
this.playerInterface_.mediaSourceEngine.bufferEnd(mediaState.type);
|
|
1015
1017
|
const reference = this.getSegmentReferenceNeeded_(
|
|
1016
1018
|
mediaState, presentationTime, bufferEnd);
|
|
1017
1019
|
if (!reference) {
|
|
@@ -1207,7 +1209,16 @@ shaka.media.StreamingEngine = class {
|
|
|
1207
1209
|
// Enable MP4 low latency streaming with ReadableStream chunked data.
|
|
1208
1210
|
if (this.config_.lowLatencyMode && isReadableStreamSupported && isMP4) {
|
|
1209
1211
|
let remaining = new Uint8Array(0);
|
|
1212
|
+
let processingResult = false;
|
|
1213
|
+
let callbackCalled = false;
|
|
1210
1214
|
const streamDataCallback = async (data) => {
|
|
1215
|
+
if (processingResult) {
|
|
1216
|
+
// If the fallback result processing was triggered, don't also
|
|
1217
|
+
// append the buffer here. In theory this should never happen,
|
|
1218
|
+
// but it does on some older TVs.
|
|
1219
|
+
return;
|
|
1220
|
+
}
|
|
1221
|
+
callbackCalled = true;
|
|
1211
1222
|
this.destroyer_.ensureNotDestroyed();
|
|
1212
1223
|
if (this.fatalError_) {
|
|
1213
1224
|
return;
|
|
@@ -1238,7 +1249,33 @@ shaka.media.StreamingEngine = class {
|
|
|
1238
1249
|
}
|
|
1239
1250
|
};
|
|
1240
1251
|
|
|
1241
|
-
|
|
1252
|
+
const result =
|
|
1253
|
+
await this.fetch_(mediaState, reference, streamDataCallback);
|
|
1254
|
+
if (!callbackCalled) {
|
|
1255
|
+
// In some environments, we might be forced to use network plugins
|
|
1256
|
+
// that don't support streamDataCallback. In those cases, as a
|
|
1257
|
+
// fallback, append the buffer here.
|
|
1258
|
+
processingResult = true;
|
|
1259
|
+
this.destroyer_.ensureNotDestroyed();
|
|
1260
|
+
if (this.fatalError_) {
|
|
1261
|
+
return;
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1264
|
+
// If the text stream gets switched between fetch_() and append_(),
|
|
1265
|
+
// the new text parser is initialized, but the new init segment is
|
|
1266
|
+
// not fetched yet. That would cause an error in
|
|
1267
|
+
// TextParser.parseMedia().
|
|
1268
|
+
// See http://b/168253400
|
|
1269
|
+
if (mediaState.waitingToClearBuffer) {
|
|
1270
|
+
shaka.log.info(logPrefix, 'waitingToClearBuffer, skip append');
|
|
1271
|
+
mediaState.performingUpdate = false;
|
|
1272
|
+
this.scheduleUpdate_(mediaState, 0);
|
|
1273
|
+
return;
|
|
1274
|
+
}
|
|
1275
|
+
|
|
1276
|
+
await this.append_(
|
|
1277
|
+
mediaState, presentationTime, stream, reference, result);
|
|
1278
|
+
}
|
|
1242
1279
|
} else {
|
|
1243
1280
|
if (this.config_.lowLatencyMode && !isReadableStreamSupported) {
|
|
1244
1281
|
shaka.log.warning('Low latency streaming mode is enabled, but ' +
|
|
@@ -16,6 +16,7 @@ goog.require('shaka.offline.indexeddb.V5StorageCell');
|
|
|
16
16
|
goog.require('shaka.util.Error');
|
|
17
17
|
goog.require('shaka.util.PublicPromise');
|
|
18
18
|
goog.require('shaka.util.Platform');
|
|
19
|
+
goog.require('shaka.util.Timer');
|
|
19
20
|
|
|
20
21
|
|
|
21
22
|
/**
|
|
@@ -55,8 +56,25 @@ shaka.offline.indexeddb.StorageMechanism = class {
|
|
|
55
56
|
const version = shaka.offline.indexeddb.StorageMechanism.VERSION;
|
|
56
57
|
|
|
57
58
|
const p = new shaka.util.PublicPromise();
|
|
59
|
+
|
|
60
|
+
// Add a timeout mechanism, for the (rare?) case where no callbacks are
|
|
61
|
+
// called at all, so that this method doesn't hang forever.
|
|
62
|
+
let timedOut = false;
|
|
63
|
+
const timeOutTimer = new shaka.util.Timer(() => {
|
|
64
|
+
timedOut = true;
|
|
65
|
+
p.reject(new shaka.util.Error(
|
|
66
|
+
shaka.util.Error.Severity.CRITICAL,
|
|
67
|
+
shaka.util.Error.Category.STORAGE,
|
|
68
|
+
shaka.util.Error.Code.INDEXED_DB_INIT_TIMED_OUT));
|
|
69
|
+
});
|
|
70
|
+
timeOutTimer.tickAfter(2);
|
|
71
|
+
|
|
58
72
|
const open = window.indexedDB.open(name, version);
|
|
59
73
|
open.onsuccess = (event) => {
|
|
74
|
+
if (timedOut) {
|
|
75
|
+
// Too late, we have already given up on opening the storage mechanism.
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
60
78
|
const db = open.result;
|
|
61
79
|
this.db_ = db;
|
|
62
80
|
this.v1_ = shaka.offline.indexeddb.StorageMechanism.createV1_(db);
|
|
@@ -68,6 +86,7 @@ shaka.offline.indexeddb.StorageMechanism = class {
|
|
|
68
86
|
this.v5_ = shaka.offline.indexeddb.StorageMechanism.createV5_(db);
|
|
69
87
|
this.sessions_ =
|
|
70
88
|
shaka.offline.indexeddb.StorageMechanism.createEmeSessionCell_(db);
|
|
89
|
+
timeOutTimer.stop();
|
|
71
90
|
p.resolve();
|
|
72
91
|
};
|
|
73
92
|
open.onupgradeneeded = (event) => {
|
|
@@ -75,11 +94,16 @@ shaka.offline.indexeddb.StorageMechanism = class {
|
|
|
75
94
|
this.createStores_(open.result);
|
|
76
95
|
};
|
|
77
96
|
open.onerror = (event) => {
|
|
97
|
+
if (timedOut) {
|
|
98
|
+
// Too late, we have already given up on opening the storage mechanism.
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
78
101
|
p.reject(new shaka.util.Error(
|
|
79
102
|
shaka.util.Error.Severity.CRITICAL,
|
|
80
103
|
shaka.util.Error.Category.STORAGE,
|
|
81
104
|
shaka.util.Error.Code.INDEXED_DB_ERROR,
|
|
82
105
|
open.error));
|
|
106
|
+
timeOutTimer.stop();
|
|
83
107
|
|
|
84
108
|
// Firefox will raise an error on the main thread unless we stop it here.
|
|
85
109
|
event.preventDefault();
|
package/lib/player.js
CHANGED
|
@@ -6431,7 +6431,7 @@ shaka.Player.TYPICAL_BUFFERING_THRESHOLD_ = 0.5;
|
|
|
6431
6431
|
* @define {string} A version number taken from git at compile time.
|
|
6432
6432
|
* @export
|
|
6433
6433
|
*/
|
|
6434
|
-
shaka.Player.version = 'v3.2.
|
|
6434
|
+
shaka.Player.version = 'v3.2.14-uncompiled';
|
|
6435
6435
|
|
|
6436
6436
|
// Initialize the deprecation system using the version string we just set
|
|
6437
6437
|
// on the player.
|
|
@@ -43,6 +43,7 @@ shaka.polyfill.MediaCapabilities = class {
|
|
|
43
43
|
!shaka.util.Platform.isPS5() &&
|
|
44
44
|
!shaka.util.Platform.isWebOS() &&
|
|
45
45
|
!shaka.util.Platform.isTizen() &&
|
|
46
|
+
!shaka.util.Platform.isEOS() &&
|
|
46
47
|
navigator.mediaCapabilities) {
|
|
47
48
|
shaka.log.info(
|
|
48
49
|
'MediaCapabilities: Native mediaCapabilities support found.');
|
|
@@ -41,8 +41,6 @@ shaka.text.TtmlTextParser = class {
|
|
|
41
41
|
const ttsNs = TtmlTextParser.styleNs_;
|
|
42
42
|
const str = shaka.util.StringUtils.fromUTF8(data);
|
|
43
43
|
const cues = [];
|
|
44
|
-
const parser = new DOMParser();
|
|
45
|
-
let xml = null;
|
|
46
44
|
|
|
47
45
|
// dont try to parse empty string as
|
|
48
46
|
// DOMParser will not throw error but return an errored xml
|
|
@@ -50,9 +48,8 @@ shaka.text.TtmlTextParser = class {
|
|
|
50
48
|
return cues;
|
|
51
49
|
}
|
|
52
50
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
} catch (exception) {
|
|
51
|
+
const tt = XmlUtils.parseXmlString(str, 'tt');
|
|
52
|
+
if (!tt) {
|
|
56
53
|
throw new shaka.util.Error(
|
|
57
54
|
shaka.util.Error.Severity.CRITICAL,
|
|
58
55
|
shaka.util.Error.Category.TEXT,
|
|
@@ -60,104 +57,89 @@ shaka.text.TtmlTextParser = class {
|
|
|
60
57
|
'Failed to parse TTML.');
|
|
61
58
|
}
|
|
62
59
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
shaka.util.Error.Severity.CRITICAL,
|
|
68
|
-
shaka.util.Error.Category.TEXT,
|
|
69
|
-
shaka.util.Error.Code.INVALID_XML,
|
|
70
|
-
parserError.textContent);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const tt = xml.getElementsByTagName('tt')[0];
|
|
74
|
-
// TTML should always have tt element.
|
|
75
|
-
if (!tt) {
|
|
76
|
-
throw new shaka.util.Error(
|
|
77
|
-
shaka.util.Error.Severity.CRITICAL,
|
|
78
|
-
shaka.util.Error.Category.TEXT,
|
|
79
|
-
shaka.util.Error.Code.INVALID_XML,
|
|
80
|
-
'TTML does not contain <tt> tag.');
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
const body = tt.getElementsByTagName('body')[0];
|
|
84
|
-
if (!body) {
|
|
85
|
-
return [];
|
|
86
|
-
}
|
|
60
|
+
const body = tt.getElementsByTagName('body')[0];
|
|
61
|
+
if (!body) {
|
|
62
|
+
return [];
|
|
63
|
+
}
|
|
87
64
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
65
|
+
// Get the framerate, subFrameRate and frameRateMultiplier if applicable.
|
|
66
|
+
const frameRate = XmlUtils.getAttributeNSList(tt, ttpNs, 'frameRate');
|
|
67
|
+
const subFrameRate = XmlUtils.getAttributeNSList(
|
|
68
|
+
tt, ttpNs, 'subFrameRate');
|
|
69
|
+
const frameRateMultiplier =
|
|
70
|
+
XmlUtils.getAttributeNSList(tt, ttpNs, 'frameRateMultiplier');
|
|
71
|
+
const tickRate = XmlUtils.getAttributeNSList(tt, ttpNs, 'tickRate');
|
|
95
72
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
73
|
+
const cellResolution = XmlUtils.getAttributeNSList(
|
|
74
|
+
tt, ttpNs, 'cellResolution');
|
|
75
|
+
const spaceStyle = tt.getAttribute('xml:space') || 'default';
|
|
76
|
+
const extent = XmlUtils.getAttributeNSList(tt, ttsNs, 'extent');
|
|
100
77
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
78
|
+
if (spaceStyle != 'default' && spaceStyle != 'preserve') {
|
|
79
|
+
throw new shaka.util.Error(
|
|
80
|
+
shaka.util.Error.Severity.CRITICAL,
|
|
81
|
+
shaka.util.Error.Category.TEXT,
|
|
82
|
+
shaka.util.Error.Code.INVALID_XML,
|
|
83
|
+
'Invalid xml:space value: ' + spaceStyle);
|
|
84
|
+
}
|
|
85
|
+
const whitespaceTrim = spaceStyle == 'default';
|
|
109
86
|
|
|
110
|
-
|
|
111
|
-
|
|
87
|
+
const rateInfo = new TtmlTextParser.RateInfo_(
|
|
88
|
+
frameRate, subFrameRate, frameRateMultiplier, tickRate);
|
|
112
89
|
|
|
113
|
-
|
|
114
|
-
|
|
90
|
+
const cellResolutionInfo =
|
|
91
|
+
TtmlTextParser.getCellResolution_(cellResolution);
|
|
115
92
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
93
|
+
const metadata = tt.getElementsByTagName('metadata')[0];
|
|
94
|
+
const metadataElements = metadata ? XmlUtils.getChildren(metadata) : [];
|
|
95
|
+
const styles = Array.from(tt.getElementsByTagName('style'));
|
|
96
|
+
const regionElements = Array.from(tt.getElementsByTagName('region'));
|
|
120
97
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
}
|
|
98
|
+
const cueRegions = [];
|
|
99
|
+
for (const region of regionElements) {
|
|
100
|
+
const cueRegion =
|
|
101
|
+
TtmlTextParser.parseCueRegion_(region, styles, extent);
|
|
102
|
+
if (cueRegion) {
|
|
103
|
+
cueRegions.push(cueRegion);
|
|
128
104
|
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// A <body> element should only contain <div> elements, not <p> or <span>
|
|
108
|
+
// elements. We used to allow this, but it is non-compliant, and the
|
|
109
|
+
// loose nature of our previous parser made it difficult to implement TTML
|
|
110
|
+
// nesting more fully.
|
|
111
|
+
if (XmlUtils.findChildren(body, 'p').length) {
|
|
112
|
+
throw new shaka.util.Error(
|
|
113
|
+
shaka.util.Error.Severity.CRITICAL,
|
|
114
|
+
shaka.util.Error.Category.TEXT,
|
|
115
|
+
shaka.util.Error.Code.INVALID_TEXT_CUE,
|
|
116
|
+
'<p> can only be inside <div> in TTML');
|
|
117
|
+
}
|
|
129
118
|
|
|
130
|
-
|
|
131
|
-
//
|
|
132
|
-
|
|
133
|
-
// nesting more fully.
|
|
134
|
-
if (XmlUtils.findChildren(body, 'p').length) {
|
|
119
|
+
for (const div of XmlUtils.findChildren(body, 'div')) {
|
|
120
|
+
// A <div> element should only contain <p>, not <span>.
|
|
121
|
+
if (XmlUtils.findChildren(div, 'span').length) {
|
|
135
122
|
throw new shaka.util.Error(
|
|
136
123
|
shaka.util.Error.Severity.CRITICAL,
|
|
137
124
|
shaka.util.Error.Category.TEXT,
|
|
138
125
|
shaka.util.Error.Code.INVALID_TEXT_CUE,
|
|
139
|
-
'<
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
for (const div of XmlUtils.findChildren(body, 'div')) {
|
|
143
|
-
// A <div> element should only contain <p>, not <span>.
|
|
144
|
-
if (XmlUtils.findChildren(div, 'span').length) {
|
|
145
|
-
throw new shaka.util.Error(
|
|
146
|
-
shaka.util.Error.Severity.CRITICAL,
|
|
147
|
-
shaka.util.Error.Category.TEXT,
|
|
148
|
-
shaka.util.Error.Code.INVALID_TEXT_CUE,
|
|
149
|
-
'<span> can only be inside <p> in TTML');
|
|
150
|
-
}
|
|
126
|
+
'<span> can only be inside <p> in TTML');
|
|
151
127
|
}
|
|
128
|
+
}
|
|
152
129
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
130
|
+
const cue = TtmlTextParser.parseCue_(
|
|
131
|
+
body, time.periodStart, rateInfo, metadataElements, styles,
|
|
132
|
+
regionElements, cueRegions, whitespaceTrim,
|
|
133
|
+
cellResolutionInfo, /* parentCueElement= */ null,
|
|
134
|
+
/* isContent= */ false);
|
|
135
|
+
if (cue) {
|
|
136
|
+
// According to the TTML spec, backgrounds default to transparent.
|
|
137
|
+
// So default the background of the top-level element to transparent.
|
|
138
|
+
// Nested elements may override that background color already.
|
|
139
|
+
if (!cue.backgroundColor) {
|
|
140
|
+
cue.backgroundColor = 'transparent';
|
|
160
141
|
}
|
|
142
|
+
cues.push(cue);
|
|
161
143
|
}
|
|
162
144
|
|
|
163
145
|
return cues;
|
package/lib/util/error.js
CHANGED
|
@@ -993,6 +993,13 @@ shaka.util.Error.Code = {
|
|
|
993
993
|
*/
|
|
994
994
|
'DOWNLOAD_SIZE_CALLBACK_ERROR': 9015,
|
|
995
995
|
|
|
996
|
+
/**
|
|
997
|
+
* When attempting to open an indexedDB instance, nothing happened for long
|
|
998
|
+
* enough for us to time out. This keeps the storage mechanism from hanging
|
|
999
|
+
* indefinitely, if neither the success nor error callbacks are called.
|
|
1000
|
+
*/
|
|
1001
|
+
'INDEXED_DB_INIT_TIMED_OUT': 9017,
|
|
1002
|
+
|
|
996
1003
|
/**
|
|
997
1004
|
* CS IMA SDK, required for ad insertion, has not been included on the page.
|
|
998
1005
|
*/
|
package/lib/util/periods.js
CHANGED
|
@@ -1146,15 +1146,6 @@ shaka.util.PeriodCombiner = class {
|
|
|
1146
1146
|
return false;
|
|
1147
1147
|
}
|
|
1148
1148
|
|
|
1149
|
-
// If the language doesn't match, but the candidate is the "primary"
|
|
1150
|
-
// language, then that should be preferred as a fallback.
|
|
1151
|
-
if (!best.primary && candidate.primary) {
|
|
1152
|
-
return true;
|
|
1153
|
-
}
|
|
1154
|
-
if (best.primary && !candidate.primary) {
|
|
1155
|
-
return false;
|
|
1156
|
-
}
|
|
1157
|
-
|
|
1158
1149
|
// If language-based differences haven't decided this, look at roles. If
|
|
1159
1150
|
// the candidate has more roles in common with the output, upgrade to the
|
|
1160
1151
|
// candidate.
|
|
@@ -1188,6 +1179,15 @@ shaka.util.PeriodCombiner = class {
|
|
|
1188
1179
|
return false;
|
|
1189
1180
|
}
|
|
1190
1181
|
|
|
1182
|
+
// If the language doesn't match, but the candidate is the "primary"
|
|
1183
|
+
// language, then that should be preferred as a fallback.
|
|
1184
|
+
if (!best.primary && candidate.primary) {
|
|
1185
|
+
return true;
|
|
1186
|
+
}
|
|
1187
|
+
if (best.primary && !candidate.primary) {
|
|
1188
|
+
return false;
|
|
1189
|
+
}
|
|
1190
|
+
|
|
1191
1191
|
// If language-based and role-based features are equivalent, take the audio
|
|
1192
1192
|
// with the closes channel count to the output.
|
|
1193
1193
|
const channelsBetterOrWorse =
|