shaka-player 4.0.0 → 4.0.1
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/config.yml +1 -0
- package/.github/workflows/release-please.yaml +6 -11
- package/CHANGELOG.md +15 -0
- package/build/misspellings.txt +1 -0
- package/dist/controls.css +1 -1
- package/dist/locales.js +32 -32
- package/dist/shaka-player.compiled.d.ts +2 -1
- package/dist/shaka-player.compiled.debug.d.ts +2 -1
- package/dist/shaka-player.compiled.debug.externs.js +1 -0
- package/dist/shaka-player.compiled.debug.js +170 -165
- package/dist/shaka-player.compiled.debug.map +3 -3
- package/dist/shaka-player.compiled.externs.js +1 -0
- package/dist/shaka-player.compiled.js +783 -779
- package/dist/shaka-player.compiled.map +3 -3
- package/dist/shaka-player.ui.d.ts +2 -1
- package/dist/shaka-player.ui.debug.d.ts +2 -1
- package/dist/shaka-player.ui.debug.externs.js +1 -0
- package/dist/shaka-player.ui.debug.js +182 -177
- package/dist/shaka-player.ui.debug.map +3 -3
- package/dist/shaka-player.ui.externs.js +1 -0
- package/dist/shaka-player.ui.js +924 -920
- package/dist/shaka-player.ui.map +3 -3
- package/docs/tutorials/upgrade.md +4 -2
- package/externs/shaka/player.js +11 -0
- package/karma.conf.js +4 -0
- package/lib/dash/dash_parser.js +2 -2
- package/lib/hls/hls_parser.js +20 -11
- package/lib/media/drm_engine.js +16 -0
- package/lib/media/media_source_engine.js +91 -37
- package/lib/media/streaming_engine.js +1 -2
- package/lib/offline/indexeddb/storage_mechanism.js +4 -2
- package/lib/player.js +165 -107
- package/lib/text/vtt_text_parser.js +7 -7
- package/lib/util/config_utils.js +25 -0
- package/lib/util/error.js +7 -0
- package/lib/util/manifest_parser_utils.js +1 -1
- package/lib/util/mime_utils.js +48 -1
- package/lib/util/periods.js +5 -4
- package/lib/util/player_configuration.js +14 -14
- package/lib/util/stream_utils.js +4 -2
- package/package.json +4 -1
- package/test/hls/hls_live_unit.js +22 -0
- package/test/hls/manifest_text_parser_unit.js +19 -0
- package/test/offline/indexeddb_storage_unit.js +1 -1
- package/test/offline/storage_compatibility_unit.js +1 -1
- package/test/player_external.js +7 -1
- package/test/player_integration.js +6 -10
- package/test/player_src_equals_integration.js +81 -83
- package/test/player_unit.js +98 -1
- package/test/test/boot.js +9 -0
- package/test/test/externs/filters.js +4 -0
- package/test/test/util/simple_fakes.js +31 -2
- package/test/text/vtt_text_parser_unit.js +64 -5
- package/test/util/mime_utils_unit.js +54 -0
- package/test/util/periods_unit.js +79 -0
- package/ui/resolution_selection.js +1 -1
- package/docs/tutorials/gsoc-ideas-list.md +0 -3
|
@@ -42,10 +42,12 @@ application:
|
|
|
42
42
|
`manifest.defaultPresentationDelay` (deprecated in v3.0.0)
|
|
43
43
|
- Configuration of factories should be plain factory functions, not
|
|
44
44
|
constructors; these will not be invoked with `new` (deprecated in v3.1.0)
|
|
45
|
-
- `drm.initDataTransform`
|
|
46
|
-
minimum supported version of iOS is now 13)
|
|
45
|
+
- `drm.initDataTransform` now defaults to a no-op
|
|
47
46
|
- `streaming.smallGapLimit` and `streaming.jumpLargeGaps` have been removed;
|
|
48
47
|
all gaps will now be jumped
|
|
48
|
+
- `manifest.hls.useFullSegmentsForStartTime` has been removed; this setting
|
|
49
|
+
is no longer necessary, as we no longer fetch segments for start times in
|
|
50
|
+
the HLS parser
|
|
49
51
|
|
|
50
52
|
- Player API changes:
|
|
51
53
|
- `shaka.Player.prototype.addTextTrack()` has been replaced by
|
package/externs/shaka/player.js
CHANGED
|
@@ -618,6 +618,9 @@ shaka.extern.AdvancedDrmConfiguration;
|
|
|
618
618
|
* clearKeys: !Object.<string, string>,
|
|
619
619
|
* delayLicenseRequestUntilPlayed: boolean,
|
|
620
620
|
* advanced: Object.<string, shaka.extern.AdvancedDrmConfiguration>,
|
|
621
|
+
* initDataTransform:
|
|
622
|
+
* ((function(!Uint8Array, string, ?shaka.extern.DrmInfo):!Uint8Array)|
|
|
623
|
+
* undefined),
|
|
621
624
|
* logLicenseExchange: boolean,
|
|
622
625
|
* updateExpirationTime: number,
|
|
623
626
|
* preferredKeySystems: !Array.<string>
|
|
@@ -641,6 +644,14 @@ shaka.extern.AdvancedDrmConfiguration;
|
|
|
641
644
|
* <i>Optional.</i> <br>
|
|
642
645
|
* A dictionary which maps key system IDs to advanced DRM configuration for
|
|
643
646
|
* those key systems.
|
|
647
|
+
* @property
|
|
648
|
+
* {((function(!Uint8Array, string, ?shaka.extern.DrmInfo):!Uint8Array)|
|
|
649
|
+
* undefined)}
|
|
650
|
+
* initDataTransform
|
|
651
|
+
* <i>Optional.</i><br>
|
|
652
|
+
* If given, this function is called with the init data from the
|
|
653
|
+
* manifest/media and should return the (possibly transformed) init data to
|
|
654
|
+
* pass to the browser.
|
|
644
655
|
* @property {boolean} logLicenseExchange
|
|
645
656
|
* <i>Optional.</i><br>
|
|
646
657
|
* If set to <code>true</code>, prints logs containing the license exchange.
|
package/karma.conf.js
CHANGED
|
@@ -363,6 +363,8 @@ module.exports = (config) => {
|
|
|
363
363
|
// If testing custom assets, we don't serve other unit or integration tests.
|
|
364
364
|
// External asset tests are the basis for custom asset testing, so this file
|
|
365
365
|
// is automatically included.
|
|
366
|
+
clientArgs.testFiles.push('demo/common/asset.js');
|
|
367
|
+
clientArgs.testFiles.push('demo/common/assets.js');
|
|
366
368
|
clientArgs.testFiles.push('test/player_external.js');
|
|
367
369
|
} else {
|
|
368
370
|
// In a normal test run, we serve unit tests.
|
|
@@ -374,6 +376,8 @@ module.exports = (config) => {
|
|
|
374
376
|
}
|
|
375
377
|
if (settings.external) {
|
|
376
378
|
// If --external is present, we serve external asset tests.
|
|
379
|
+
clientArgs.testFiles.push('demo/common/asset.js');
|
|
380
|
+
clientArgs.testFiles.push('demo/common/assets.js');
|
|
377
381
|
clientArgs.testFiles.push('test/**/*_external.js');
|
|
378
382
|
}
|
|
379
383
|
}
|
package/lib/dash/dash_parser.js
CHANGED
|
@@ -765,8 +765,8 @@ shaka.dash.DashParser = class {
|
|
|
765
765
|
// currently support that. Just choose one.
|
|
766
766
|
// TODO: https://github.com/shaka-project/shaka-player/issues/1528
|
|
767
767
|
stream.trickModeVideo = trickModeSet.streams.find((trickStream) =>
|
|
768
|
-
shaka.util.MimeUtils.
|
|
769
|
-
shaka.util.MimeUtils.
|
|
768
|
+
shaka.util.MimeUtils.getNormalizedCodec(stream.codecs) ==
|
|
769
|
+
shaka.util.MimeUtils.getNormalizedCodec(trickStream.codecs));
|
|
770
770
|
}
|
|
771
771
|
}
|
|
772
772
|
}
|
package/lib/hls/hls_parser.js
CHANGED
|
@@ -1825,7 +1825,7 @@ shaka.hls.HlsParser = class {
|
|
|
1825
1825
|
* @param {!Map.<string, string>} variables
|
|
1826
1826
|
* @param {string} absoluteMediaPlaylistUri
|
|
1827
1827
|
* @param {string} type
|
|
1828
|
-
* @return {
|
|
1828
|
+
* @return {shaka.media.SegmentReference}
|
|
1829
1829
|
* @private
|
|
1830
1830
|
*/
|
|
1831
1831
|
createSegmentReference_(
|
|
@@ -1870,9 +1870,23 @@ shaka.hls.HlsParser = class {
|
|
|
1870
1870
|
status = shaka.media.SegmentReference.Status.MISSING;
|
|
1871
1871
|
}
|
|
1872
1872
|
|
|
1873
|
+
if (!extinfTag) {
|
|
1874
|
+
if (hlsSegment.partialSegments.length == 0) {
|
|
1875
|
+
// EXTINF tag must be available if the segment has no partial segments.
|
|
1876
|
+
throw new shaka.util.Error(
|
|
1877
|
+
shaka.util.Error.Severity.CRITICAL,
|
|
1878
|
+
shaka.util.Error.Category.MANIFEST,
|
|
1879
|
+
shaka.util.Error.Code.HLS_REQUIRED_TAG_MISSING, 'EXTINF');
|
|
1880
|
+
} else if (!this.lowLatencyMode_) {
|
|
1881
|
+
// Without EXTINF and without low-latency mode, partial segments get
|
|
1882
|
+
// ignored.
|
|
1883
|
+
return null;
|
|
1884
|
+
}
|
|
1885
|
+
}
|
|
1886
|
+
|
|
1873
1887
|
// Create SegmentReferences for the partial segments.
|
|
1874
1888
|
const partialSegmentRefs = [];
|
|
1875
|
-
if (this.lowLatencyMode_
|
|
1889
|
+
if (this.lowLatencyMode_) {
|
|
1876
1890
|
for (let i = 0; i < hlsSegment.partialSegments.length; i++) {
|
|
1877
1891
|
const item = hlsSegment.partialSegments[i];
|
|
1878
1892
|
const pPreviousReference = i == 0 ?
|
|
@@ -1913,14 +1927,6 @@ shaka.hls.HlsParser = class {
|
|
|
1913
1927
|
/* appendWindowEnd= */ Infinity);
|
|
1914
1928
|
partialSegmentRefs.push(partial);
|
|
1915
1929
|
} // for-loop of hlsSegment.partialSegments
|
|
1916
|
-
} else {
|
|
1917
|
-
// EXTINF tag must be available if the segment has no partial segments.
|
|
1918
|
-
if (!extinfTag) {
|
|
1919
|
-
throw new shaka.util.Error(
|
|
1920
|
-
shaka.util.Error.Severity.CRITICAL,
|
|
1921
|
-
shaka.util.Error.Category.MANIFEST,
|
|
1922
|
-
shaka.util.Error.Code.HLS_REQUIRED_TAG_MISSING, 'EXTINF');
|
|
1923
|
-
}
|
|
1924
1930
|
}
|
|
1925
1931
|
|
|
1926
1932
|
// If the segment has EXTINF tag, set the segment's end time, start byte
|
|
@@ -1939,6 +1945,7 @@ shaka.hls.HlsParser = class {
|
|
|
1939
1945
|
} else {
|
|
1940
1946
|
endTime = partialSegmentRefs[partialSegmentRefs.length - 1].endTime;
|
|
1941
1947
|
}
|
|
1948
|
+
|
|
1942
1949
|
// If the segment has EXT-X-BYTERANGE tag, set the start byte and end byte
|
|
1943
1950
|
// base on the byterange information. If segment has no EXT-X-BYTERANGE tag
|
|
1944
1951
|
// and has partial segments, set the start byte and end byte base on the
|
|
@@ -2107,7 +2114,9 @@ shaka.hls.HlsParser = class {
|
|
|
2107
2114
|
playlist.absoluteUri,
|
|
2108
2115
|
type);
|
|
2109
2116
|
|
|
2110
|
-
|
|
2117
|
+
if (reference) {
|
|
2118
|
+
references.push(reference);
|
|
2119
|
+
}
|
|
2111
2120
|
}
|
|
2112
2121
|
|
|
2113
2122
|
// If some segments have sync times, but not all, extrapolate the sync
|
package/lib/media/drm_engine.js
CHANGED
|
@@ -1253,6 +1253,22 @@ shaka.media.DrmEngine = class {
|
|
|
1253
1253
|
};
|
|
1254
1254
|
this.activeSessions_.set(session, metadata);
|
|
1255
1255
|
|
|
1256
|
+
try {
|
|
1257
|
+
initData = this.config_.initDataTransform(
|
|
1258
|
+
initData, initDataType, this.currentDrmInfo_);
|
|
1259
|
+
} catch (error) {
|
|
1260
|
+
let shakaError = error;
|
|
1261
|
+
if (!(error instanceof shaka.util.Error)) {
|
|
1262
|
+
shakaError = new shaka.util.Error(
|
|
1263
|
+
shaka.util.Error.Severity.CRITICAL,
|
|
1264
|
+
shaka.util.Error.Category.DRM,
|
|
1265
|
+
shaka.util.Error.Code.INIT_DATA_TRANSFORM_ERROR,
|
|
1266
|
+
error);
|
|
1267
|
+
}
|
|
1268
|
+
this.onError_(shakaError);
|
|
1269
|
+
return;
|
|
1270
|
+
}
|
|
1271
|
+
|
|
1256
1272
|
if (this.config_.logLicenseExchange) {
|
|
1257
1273
|
const str = shaka.util.Uint8ArrayUtils.toBase64(initData);
|
|
1258
1274
|
shaka.log.info('EME init data: type=', initDataType, 'data=', str);
|
|
@@ -106,6 +106,12 @@ shaka.media.MediaSourceEngine = class {
|
|
|
106
106
|
|
|
107
107
|
/** @private {string} */
|
|
108
108
|
this.url_ = '';
|
|
109
|
+
|
|
110
|
+
/** @private {boolean} */
|
|
111
|
+
this.sequenceMode_ = false;
|
|
112
|
+
|
|
113
|
+
/** @private {!shaka.util.PublicPromise.<number>} */
|
|
114
|
+
this.textSequenceModeOffset_ = new shaka.util.PublicPromise();
|
|
109
115
|
}
|
|
110
116
|
|
|
111
117
|
/**
|
|
@@ -331,6 +337,8 @@ shaka.media.MediaSourceEngine = class {
|
|
|
331
337
|
|
|
332
338
|
await this.mediaSourceOpen_;
|
|
333
339
|
|
|
340
|
+
this.sequenceMode_ = sequenceMode;
|
|
341
|
+
|
|
334
342
|
for (const contentType of streamsByType.keys()) {
|
|
335
343
|
const stream = streamsByType.get(contentType);
|
|
336
344
|
goog.asserts.assert(
|
|
@@ -348,11 +356,9 @@ shaka.media.MediaSourceEngine = class {
|
|
|
348
356
|
mimeType =
|
|
349
357
|
shaka.media.Transmuxer.convertTsCodecs(contentType, mimeType);
|
|
350
358
|
}
|
|
359
|
+
|
|
351
360
|
const sourceBuffer = this.mediaSource_.addSourceBuffer(mimeType);
|
|
352
|
-
|
|
353
|
-
sourceBuffer.mode =
|
|
354
|
-
shaka.media.MediaSourceEngine.SourceBufferMode_.SEQUENCE;
|
|
355
|
-
}
|
|
361
|
+
|
|
356
362
|
this.eventManager_.listen(
|
|
357
363
|
sourceBuffer, 'error',
|
|
358
364
|
() => this.onError_(contentType));
|
|
@@ -515,35 +521,29 @@ shaka.media.MediaSourceEngine = class {
|
|
|
515
521
|
* @param {?boolean} hasClosedCaptions True if the buffer contains CEA closed
|
|
516
522
|
* captions
|
|
517
523
|
* @param {boolean=} seeked True if we just seeked
|
|
518
|
-
* @param {boolean=} sequenceMode True if sequence mode
|
|
519
524
|
* @return {!Promise}
|
|
520
525
|
*/
|
|
521
|
-
async appendBuffer(
|
|
522
|
-
|
|
526
|
+
async appendBuffer(
|
|
527
|
+
contentType, data, startTime, endTime, hasClosedCaptions, seeked) {
|
|
523
528
|
const ContentType = shaka.util.ManifestParserUtils.ContentType;
|
|
524
529
|
|
|
525
|
-
if (
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
if (seeked) {
|
|
531
|
-
const timestampOffset = /** @type {number} */ (startTime);
|
|
532
|
-
this.enqueueOperation_(
|
|
533
|
-
contentType,
|
|
534
|
-
() => this.setTimestampOffset_(contentType, timestampOffset));
|
|
530
|
+
if (contentType == ContentType.TEXT) {
|
|
531
|
+
if (this.sequenceMode_) {
|
|
532
|
+
// This won't be known until the first video segment is appended.
|
|
533
|
+
const offset = await this.textSequenceModeOffset_;
|
|
534
|
+
this.textEngine_.setTimestampOffset(offset);
|
|
535
535
|
}
|
|
536
|
+
await this.textEngine_.appendBuffer(data, startTime, endTime);
|
|
537
|
+
return;
|
|
536
538
|
}
|
|
537
539
|
|
|
538
|
-
if (contentType
|
|
539
|
-
await this.textEngine_.appendBuffer(data, startTime, endTime);
|
|
540
|
-
} else if (this.transmuxers_[contentType]) {
|
|
540
|
+
if (this.transmuxers_[contentType]) {
|
|
541
541
|
const transmuxedData =
|
|
542
542
|
await this.transmuxers_[contentType].transmux(data);
|
|
543
543
|
// For HLS CEA-608/708 CLOSED-CAPTIONS, text data is embedded in
|
|
544
544
|
// the video stream, so textEngine may not have been initialized.
|
|
545
545
|
if (!this.textEngine_) {
|
|
546
|
-
this.reinitText('text/vtt',
|
|
546
|
+
this.reinitText('text/vtt', this.sequenceMode_);
|
|
547
547
|
}
|
|
548
548
|
|
|
549
549
|
if (transmuxedData.metadata) {
|
|
@@ -562,15 +562,10 @@ shaka.media.MediaSourceEngine = class {
|
|
|
562
562
|
closedCaptions, startTime, endTime, videoOffset);
|
|
563
563
|
}
|
|
564
564
|
|
|
565
|
-
|
|
566
|
-
transmuxedSegment = this.workAroundBrokenPlatforms_(
|
|
567
|
-
transmuxedSegment, startTime, contentType);
|
|
568
|
-
|
|
569
|
-
await this.enqueueOperation_(
|
|
570
|
-
contentType, () => this.append_(contentType, transmuxedSegment));
|
|
565
|
+
data = transmuxedData.data;
|
|
571
566
|
} else if (hasClosedCaptions) {
|
|
572
567
|
if (!this.textEngine_) {
|
|
573
|
-
this.reinitText('text/vtt',
|
|
568
|
+
this.reinitText('text/vtt', this.sequenceMode_);
|
|
574
569
|
}
|
|
575
570
|
// If it is the init segment for closed captions, initialize the closed
|
|
576
571
|
// caption parser.
|
|
@@ -585,19 +580,78 @@ shaka.media.MediaSourceEngine = class {
|
|
|
585
580
|
closedCaptions, startTime, endTime, videoOffset);
|
|
586
581
|
}
|
|
587
582
|
}
|
|
583
|
+
}
|
|
588
584
|
|
|
589
|
-
|
|
585
|
+
data = this.workAroundBrokenPlatforms_(data, startTime, contentType);
|
|
586
|
+
|
|
587
|
+
const sourceBuffer = this.sourceBuffers_[contentType];
|
|
588
|
+
const SEQUENCE = shaka.media.MediaSourceEngine.SourceBufferMode_.SEQUENCE;
|
|
589
|
+
|
|
590
|
+
if (this.sequenceMode_ && sourceBuffer.mode != SEQUENCE &&
|
|
591
|
+
startTime != null) {
|
|
592
|
+
// This is the first media segment to be appended to a SourceBuffer in
|
|
593
|
+
// sequence mode. We set the mode late so that we can trick MediaSource
|
|
594
|
+
// into extracting a timestamp for us to align text segments in sequence
|
|
595
|
+
// mode.
|
|
596
|
+
|
|
597
|
+
// Timestamps can only be reliably extracted from video, not audio.
|
|
598
|
+
// Packed audio formats do not have internal timestamps at all.
|
|
599
|
+
// Prefer video for this when available.
|
|
600
|
+
const isBestSourceBufferForTimestamps =
|
|
601
|
+
contentType == ContentType.VIDEO ||
|
|
602
|
+
!(ContentType.VIDEO in this.sourceBuffers_);
|
|
603
|
+
if (isBestSourceBufferForTimestamps) {
|
|
604
|
+
// Append the segment in segments mode first, with offset of 0 and an
|
|
605
|
+
// open append window.
|
|
606
|
+
const originalRange =
|
|
607
|
+
[sourceBuffer.appendWindowStart, sourceBuffer.appendWindowEnd];
|
|
608
|
+
sourceBuffer.appendWindowStart = 0;
|
|
609
|
+
sourceBuffer.appendWindowEnd = Infinity;
|
|
610
|
+
|
|
611
|
+
const originalOffset = sourceBuffer.timestampOffset;
|
|
612
|
+
sourceBuffer.timestampOffset = 0;
|
|
613
|
+
|
|
614
|
+
await this.enqueueOperation_(
|
|
615
|
+
contentType, () => this.append_(contentType, data));
|
|
616
|
+
|
|
617
|
+
// Reset the offset and append window.
|
|
618
|
+
sourceBuffer.timestampOffset = originalOffset;
|
|
619
|
+
sourceBuffer.appendWindowStart = originalRange[0];
|
|
620
|
+
sourceBuffer.appendWindowEnd = originalRange[1];
|
|
621
|
+
|
|
622
|
+
// Now get the timestamp of the segment and compute the offset for text
|
|
623
|
+
// segments.
|
|
624
|
+
const mediaStartTime = shaka.media.TimeRangesUtils.bufferStart(
|
|
625
|
+
this.getBuffered_(contentType));
|
|
626
|
+
const textOffset = (startTime || 0) - (mediaStartTime || 0);
|
|
627
|
+
this.textSequenceModeOffset_.resolve(textOffset);
|
|
628
|
+
|
|
629
|
+
// Finally, clear the buffer.
|
|
630
|
+
await this.enqueueOperation_(
|
|
631
|
+
contentType,
|
|
632
|
+
() => this.remove_(contentType, 0, this.mediaSource_.duration));
|
|
633
|
+
}
|
|
590
634
|
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
} else {
|
|
595
|
-
data = this.workAroundBrokenPlatforms_(data, startTime, contentType);
|
|
635
|
+
// Now switch to sequence mode and fall through to our normal operations.
|
|
636
|
+
sourceBuffer.mode = SEQUENCE;
|
|
637
|
+
}
|
|
596
638
|
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
639
|
+
if (startTime != null && this.sequenceMode_ &&
|
|
640
|
+
contentType != ContentType.TEXT) {
|
|
641
|
+
// In sequence mode, for non-text streams, if we just cleared the buffer
|
|
642
|
+
// and are performing an unbuffered seek, we need to set a new
|
|
643
|
+
// timestampOffset on the sourceBuffer.
|
|
644
|
+
if (seeked) {
|
|
645
|
+
const timestampOffset = /** @type {number} */ (startTime);
|
|
646
|
+
this.enqueueOperation_(
|
|
647
|
+
contentType,
|
|
648
|
+
() => this.setTimestampOffset_(contentType, timestampOffset));
|
|
649
|
+
}
|
|
600
650
|
}
|
|
651
|
+
|
|
652
|
+
await this.enqueueOperation_(
|
|
653
|
+
contentType,
|
|
654
|
+
() => this.append_(contentType, data));
|
|
601
655
|
}
|
|
602
656
|
|
|
603
657
|
/**
|
|
@@ -1605,8 +1605,7 @@ shaka.media.StreamingEngine = class {
|
|
|
1605
1605
|
reference.syncTime == null ? reference.startTime : reference.syncTime,
|
|
1606
1606
|
reference.endTime,
|
|
1607
1607
|
hasClosedCaptions,
|
|
1608
|
-
seeked
|
|
1609
|
-
this.manifest_.sequenceMode);
|
|
1608
|
+
seeked);
|
|
1610
1609
|
this.destroyer_.ensureNotDestroyed();
|
|
1611
1610
|
shaka.log.v2(logPrefix, 'appended media segment');
|
|
1612
1611
|
}
|
|
@@ -368,8 +368,10 @@ shaka.offline.indexeddb.StorageMechanism.SESSION_ID_STORE = 'session-ids';
|
|
|
368
368
|
shaka.offline.StorageMuxer.register(
|
|
369
369
|
'idb',
|
|
370
370
|
() => {
|
|
371
|
-
// Offline storage is not supported on the Chromecast
|
|
372
|
-
|
|
371
|
+
// Offline storage is not supported on the Chromecast or Xbox One
|
|
372
|
+
// platforms.
|
|
373
|
+
if (shaka.util.Platform.isChromecast() ||
|
|
374
|
+
shaka.util.Platform.isXboxOne()) {
|
|
373
375
|
return null;
|
|
374
376
|
}
|
|
375
377
|
// Offline storage requires the IndexedDB API.
|