shaka-player 4.6.0 → 4.6.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.
@@ -285,7 +285,8 @@ shaka.dash.DashParser = class {
285
285
 
286
286
  // For redirections add the response uri to the first entry in the
287
287
  // Manifest Uris array.
288
- if (response.uri && !this.manifestUris_.includes(response.uri)) {
288
+ if (response.uri && response.uri != response.originalUri &&
289
+ !this.manifestUris_.includes(response.uri)) {
289
290
  this.manifestUris_.unshift(response.uri);
290
291
  }
291
292
 
@@ -373,19 +374,16 @@ shaka.dash.DashParser = class {
373
374
 
374
375
  const contentSteering = XmlUtils.findChild(mpd, 'ContentSteering');
375
376
  if (contentSteering && this.playerInterface_) {
376
- const hasPrevContentSteeringManager = !!this.contentSteeringManager_;
377
+ const defaultPathwayId =
378
+ contentSteering.getAttribute('defaultServiceLocation');
377
379
  if (!this.contentSteeringManager_) {
378
380
  this.contentSteeringManager_ =
379
381
  new shaka.util.ContentSteeringManager(this.playerInterface_);
380
- }
381
- this.contentSteeringManager_.configure(this.config_);
382
- this.contentSteeringManager_.setBaseUris(manifestBaseUris);
383
- this.contentSteeringManager_.setManifestType(
384
- shaka.media.ManifestParser.DASH);
385
- const defaultPathwayId =
386
- contentSteering.getAttribute('defaultServiceLocation');
387
- this.contentSteeringManager_.setDefaultPathwayId(defaultPathwayId);
388
- if (!hasPrevContentSteeringManager) {
382
+ this.contentSteeringManager_.configure(this.config_);
383
+ this.contentSteeringManager_.setManifestType(
384
+ shaka.media.ManifestParser.DASH);
385
+ this.contentSteeringManager_.setBaseUris(manifestBaseUris);
386
+ this.contentSteeringManager_.setDefaultPathwayId(defaultPathwayId);
389
387
  const uri = XmlUtils.getContents(contentSteering);
390
388
  if (uri) {
391
389
  const queryBeforeStart =
@@ -398,6 +396,9 @@ shaka.dash.DashParser = class {
398
396
  this.contentSteeringManager_.requestInfo(uri);
399
397
  }
400
398
  }
399
+ } else {
400
+ this.contentSteeringManager_.setBaseUris(manifestBaseUris);
401
+ this.contentSteeringManager_.setDefaultPathwayId(defaultPathwayId);
401
402
  }
402
403
  }
403
404
 
@@ -141,7 +141,8 @@ shaka.dash.SegmentTemplate = class {
141
141
  );
142
142
  } else {
143
143
  const tsi = /** @type {!TimelineSegmentIndex} */(segmentIndex);
144
- tsi.appendTemplateInfo(info, periodStart, periodEnd, shouldFit);
144
+ tsi.appendTemplateInfo(
145
+ info, periodStart, periodEnd, shouldFit, initSegmentReference);
145
146
 
146
147
  const availabilityStart =
147
148
  context.presentationTimeline.getSegmentAvailabilityStart();
@@ -167,7 +168,7 @@ shaka.dash.SegmentTemplate = class {
167
168
  if (segmentIndex instanceof shaka.dash.TimelineSegmentIndex &&
168
169
  segmentIndex.isEmpty()) {
169
170
  segmentIndex.appendTemplateInfo(info, periodStart,
170
- periodEnd, shouldFit);
171
+ periodEnd, shouldFit, initSegmentReference);
171
172
  }
172
173
  return Promise.resolve(segmentIndex);
173
174
  },
@@ -684,8 +685,11 @@ shaka.dash.TimelineSegmentIndex = class extends shaka.media.SegmentIndex {
684
685
  * @param {number} periodStart
685
686
  * @param {number} periodEnd
686
687
  * @param {boolean} shouldFit
688
+ * @param {shaka.media.InitSegmentReference} initSegmentReference
687
689
  */
688
- appendTemplateInfo(info, periodStart, periodEnd, shouldFit) {
690
+ appendTemplateInfo(info, periodStart, periodEnd, shouldFit,
691
+ initSegmentReference) {
692
+ this.initSegmentReference_ = initSegmentReference;
689
693
  if (!this.templateInfo_) {
690
694
  this.templateInfo_ = info;
691
695
  this.periodStart_ = periodStart;
@@ -693,6 +697,8 @@ shaka.dash.TimelineSegmentIndex = class extends shaka.media.SegmentIndex {
693
697
  } else {
694
698
  const currentTimeline = this.templateInfo_.timeline;
695
699
 
700
+ this.templateInfo_.mediaTemplate = info.mediaTemplate;
701
+
696
702
  // Append timeline
697
703
  const lastCurrentEntry = currentTimeline[currentTimeline.length - 1];
698
704
  const newEntries = info.timeline.filter((entry) => {
@@ -1672,9 +1672,15 @@ shaka.hls.HlsParser = class {
1672
1672
  // the value NONE. If the value is a quoted-string, it MUST match the
1673
1673
  // value of the GROUP-ID attribute of an EXT-X-MEDIA tag elsewhere in the
1674
1674
  // Playlist whose TYPE attribute is CLOSED-CAPTIONS.
1675
- if (type == ContentType.VIDEO && closedCaptionsAttr &&
1676
- closedCaptionsAttr != 'NONE') {
1677
- return this.groupIdToClosedCaptionsMap_.get(closedCaptionsAttr);
1675
+ if (type == ContentType.VIDEO) {
1676
+ if (closedCaptionsAttr && closedCaptionsAttr != 'NONE') {
1677
+ return this.groupIdToClosedCaptionsMap_.get(closedCaptionsAttr);
1678
+ } else if (!closedCaptionsAttr &&
1679
+ this.groupIdToClosedCaptionsMap_.size) {
1680
+ for (const key of this.groupIdToClosedCaptionsMap_.keys()) {
1681
+ return this.groupIdToClosedCaptionsMap_.get(key);
1682
+ }
1683
+ }
1678
1684
  }
1679
1685
  return null;
1680
1686
  }
@@ -1351,6 +1351,7 @@ shaka.media.StreamingEngine = class {
1351
1351
  let remaining = new Uint8Array(0);
1352
1352
  let processingResult = false;
1353
1353
  let callbackCalled = false;
1354
+ let streamDataCallbackError;
1354
1355
  const streamDataCallback = async (data) => {
1355
1356
  if (processingResult) {
1356
1357
  // If the fallback result processing was triggered, don't also
@@ -1363,40 +1364,47 @@ shaka.media.StreamingEngine = class {
1363
1364
  if (this.fatalError_) {
1364
1365
  return;
1365
1366
  }
1366
- // Append the data with complete boxes.
1367
- // Every time streamDataCallback gets called, append the new data to
1368
- // the remaining data.
1369
- // Find the last fully completed Mdat box, and slice the data into two
1370
- // parts: the first part with completed Mdat boxes, and the second
1371
- // part with an incomplete box.
1372
- // Append the first part, and save the second part as remaining data,
1373
- // and handle it with the next streamDataCallback call.
1374
- remaining = this.concatArray_(remaining, data);
1375
- let sawMDAT = false;
1376
- let offset = 0;
1377
- new shaka.util.Mp4Parser()
1378
- .box('mdat', (box) => {
1379
- offset = box.size + box.start;
1380
- sawMDAT = true;
1381
- })
1382
- .parse(remaining, /* partialOkay= */ false,
1367
+ try {
1368
+ // Append the data with complete boxes.
1369
+ // Every time streamDataCallback gets called, append the new data
1370
+ // to the remaining data.
1371
+ // Find the last fully completed Mdat box, and slice the data into
1372
+ // two parts: the first part with completed Mdat boxes, and the
1373
+ // second part with an incomplete box.
1374
+ // Append the first part, and save the second part as remaining
1375
+ // data, and handle it with the next streamDataCallback call.
1376
+ remaining = this.concatArray_(remaining, data);
1377
+ let sawMDAT = false;
1378
+ let offset = 0;
1379
+ new shaka.util.Mp4Parser()
1380
+ .box('mdat', (box) => {
1381
+ offset = box.size + box.start;
1382
+ sawMDAT = true;
1383
+ })
1384
+ .parse(remaining, /* partialOkay= */ false,
1385
+ /* isChunkedData= */ true);
1386
+ if (sawMDAT) {
1387
+ const dataToAppend = remaining.subarray(0, offset);
1388
+ remaining = remaining.subarray(offset);
1389
+ await this.append_(
1390
+ mediaState, presentationTime, stream, reference, dataToAppend,
1383
1391
  /* isChunkedData= */ true);
1384
- if (sawMDAT) {
1385
- const dataToAppend = remaining.subarray(0, offset);
1386
- remaining = remaining.subarray(offset);
1387
- await this.append_(
1388
- mediaState, presentationTime, stream, reference, dataToAppend,
1389
- /* isChunkedData= */ true);
1390
-
1391
- if (mediaState.segmentPrefetch && mediaState.segmentIterator) {
1392
- mediaState.segmentPrefetch.prefetchSegments(
1393
- reference, /* skipFirst= */ true);
1392
+
1393
+ if (mediaState.segmentPrefetch && mediaState.segmentIterator) {
1394
+ mediaState.segmentPrefetch.prefetchSegments(
1395
+ reference, /* skipFirst= */ true);
1396
+ }
1394
1397
  }
1398
+ } catch (error) {
1399
+ streamDataCallbackError = error;
1395
1400
  }
1396
1401
  };
1397
1402
 
1398
1403
  const result =
1399
1404
  await this.fetch_(mediaState, reference, streamDataCallback);
1405
+ if (streamDataCallbackError) {
1406
+ throw streamDataCallbackError;
1407
+ }
1400
1408
  if (!callbackCalled) {
1401
1409
  // In some environments, we might be forced to use network plugins
1402
1410
  // that don't support streamDataCallback. In those cases, as a
package/lib/player.js CHANGED
@@ -4595,9 +4595,13 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
4595
4595
  }
4596
4596
  await this.addSrcTrackElement_(uri, language, kind, mimeType, label || '',
4597
4597
  adCuePoints);
4598
+
4599
+ const LanguageUtils = shaka.util.LanguageUtils;
4600
+ const languageNormalized = LanguageUtils.normalize(language);
4601
+
4598
4602
  const textTracks = this.getTextTracks();
4599
4603
  const srcTrack = textTracks.find((t) => {
4600
- return t.language == language &&
4604
+ return LanguageUtils.normalize(t.language) == languageNormalized &&
4601
4605
  t.label == (label || '') &&
4602
4606
  t.kind == kind;
4603
4607
  });
@@ -6777,7 +6781,7 @@ shaka.Player.TYPICAL_BUFFERING_THRESHOLD_ = 0.5;
6777
6781
  * @export
6778
6782
  */
6779
6783
  // eslint-disable-next-line no-useless-concat
6780
- shaka.Player.version = 'v4.6.0' + '-uncompiled'; // x-release-please-version
6784
+ shaka.Player.version = 'v4.6.1' + '-uncompiled'; // x-release-please-version
6781
6785
 
6782
6786
  // Initialize the deprecation system using the version string we just set
6783
6787
  // on the player.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "shaka-player",
3
3
  "description": "DASH/EME video player library",
4
- "version": "4.6.0",
4
+ "version": "4.6.1",
5
5
  "homepage": "https://github.com/shaka-project/shaka-player",
6
6
  "author": "Google",
7
7
  "maintainers": [
@@ -750,6 +750,46 @@ describe('HlsParser', () => {
750
750
  await testHlsParser(master, media, manifest);
751
751
  });
752
752
 
753
+ it('parses audio+video variant with global closed captions', async () => {
754
+ const master = [
755
+ '#EXTM3U\n',
756
+ '#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="aud1",LANGUAGE="eng",CHANNELS="2",',
757
+ 'URI="audio"\n',
758
+ '#EXT-X-MEDIA:TYPE=CLOSED-CAPTIONS,GROUP-ID="cap1",LANGUAGE="eng",',
759
+ 'INSTREAM-ID="CC1"\n',
760
+ '#EXT-X-STREAM-INF:BANDWIDTH=200,CODECS="avc1,mp4a",',
761
+ 'RESOLUTION=960x540,FRAME-RATE=60,AUDIO="aud1"\n',
762
+ 'video\n',
763
+ ].join('');
764
+
765
+ const media = [
766
+ '#EXTM3U\n',
767
+ '#EXT-X-PLAYLIST-TYPE:VOD\n',
768
+ '#EXT-X-MAP:URI="init.mp4",BYTERANGE="616@0"\n',
769
+ '#EXTINF:5,\n',
770
+ '#EXT-X-BYTERANGE:121090@616\n',
771
+ 'main.mp4',
772
+ ].join('');
773
+
774
+ const closedCaptions = new Map([['CC1', 'en']]);
775
+ const manifest = shaka.test.ManifestGenerator.generate((manifest) => {
776
+ manifest.anyTimeline();
777
+ manifest.addPartialVariant((variant) => {
778
+ variant.addPartialStream(ContentType.VIDEO, (stream) => {
779
+ stream.closedCaptions = closedCaptions;
780
+ stream.mime('video/mp4', 'avc1');
781
+ });
782
+ variant.addPartialStream(ContentType.AUDIO, (stream) => {
783
+ stream.mime('audio/mp4', 'mp4a');
784
+ });
785
+ });
786
+ manifest.sequenceMode = sequenceMode;
787
+ manifest.type = shaka.media.ManifestParser.HLS;
788
+ });
789
+
790
+ await testHlsParser(master, media, manifest);
791
+ });
792
+
753
793
  it('parses audio+video variant with no closed captions', async () => {
754
794
  const master = [
755
795
  '#EXTM3U\n',