shaka-player 4.11.20 → 4.11.21

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.
@@ -1374,7 +1374,8 @@ shaka.extern.MssManifestConfiguration;
1374
1374
  * @property {number} defaultPresentationDelay
1375
1375
  * For DASH, it's a default <code>presentationDelay</code> value if
1376
1376
  * <code>suggestedPresentationDelay</code> is missing in the MPEG DASH
1377
- * manifest. The default value is <code>1.5 * minBufferTime</code> if not
1377
+ * manifest. The default value is the lower of <code>1.5 *
1378
+ * minBufferTime</code> and <code>segmentAvailabilityDuration</code> if not
1378
1379
  * configured or set as 0.
1379
1380
  * For HLS, the default value is 3 segments duration if not configured or
1380
1381
  * set as 0.
@@ -169,24 +169,16 @@ shaka.cea.Cea708Service = class {
169
169
  const firstByte = dtvccPacket.readByte().value;
170
170
  const secondByte = dtvccPacket.readByte().value;
171
171
 
172
- const isTextBlock = (b) => {
173
- return (b >= 0x20 && b <= 0x7f) || (b >= 0xa0 && b <= 0xff);
172
+ const toHexString = (byteArray) => {
173
+ return byteArray.map((byte) => {
174
+ return ('0' + (byte & 0xFF).toString(16)).slice(-2);
175
+ }).join('');
174
176
  };
175
-
176
- if (isTextBlock(firstByte) && isTextBlock(secondByte)) {
177
- const toHexString = (byteArray) => {
178
- return byteArray.map((byte) => {
179
- return ('0' + (byte & 0xFF).toString(16)).slice(-2);
180
- }).join('');
181
- };
182
- const unicode = toHexString([firstByte, secondByte]);
183
- // Takes a unicode hex string and creates a single character.
184
- const char = String.fromCharCode(parseInt(unicode, 16));
185
- this.currentWindow_.setCharacter(char);
186
- return null;
187
- } else {
188
- dtvccPacket.rewind(2);
189
- }
177
+ const unicode = toHexString([firstByte, secondByte]);
178
+ // Takes a unicode hex string and creates a single character.
179
+ const char = String.fromCharCode(parseInt(unicode, 16));
180
+ this.currentWindow_.setCharacter(char);
181
+ return null;
190
182
  }
191
183
 
192
184
  const window = this.currentWindow_;
@@ -709,18 +709,28 @@ shaka.dash.DashParser = class {
709
709
  // feasible choices for the value. Nothing older than
710
710
  // timeShiftBufferDepth is still available, and anything less than
711
711
  // minBufferTime will cause buffering issues.
712
- //
713
- // We have decided that our default will be the configured value, or
714
- // 1.5 * minBufferTime if not configured. This is fairly conservative.
715
- // Content providers should provide a suggestedPresentationDelay whenever
716
- // possible to optimize the live streaming experience.
717
- const defaultPresentationDelay =
718
- this.config_.defaultPresentationDelay || minBufferTime * 1.5;
719
- const presentationDelay = suggestedPresentationDelay != null ?
720
- suggestedPresentationDelay : defaultPresentationDelay;
712
+ let delay = 0;
713
+ if (suggestedPresentationDelay != null) {
714
+ // 1. If a suggestedPresentationDelay is provided by the manifest, that
715
+ // will be used preferentially.
716
+ // This is given a minimum bound of segmentAvailabilityDuration.
717
+ // Content providers should provide a suggestedPresentationDelay
718
+ // whenever possible to optimize the live streaming experience.
719
+ delay = Math.min(
720
+ suggestedPresentationDelay,
721
+ segmentAvailabilityDuration || Infinity);
722
+ } else if (this.config_.defaultPresentationDelay > 0) {
723
+ // 2. If the developer provides a value for
724
+ // "manifest.defaultPresentationDelay", that is used as a fallback.
725
+ delay = this.config_.defaultPresentationDelay;
726
+ } else {
727
+ // 3. Otherwise, we default to the lower of segmentAvailabilityDuration
728
+ // and 1.5 * minBufferTime. This is fairly conservative.
729
+ delay = Math.min(
730
+ minBufferTime * 1.5, segmentAvailabilityDuration || Infinity);
731
+ }
721
732
  presentationTimeline = new shaka.media.PresentationTimeline(
722
- presentationStartTime, presentationDelay,
723
- this.config_.dash.autoCorrectDrift);
733
+ presentationStartTime, delay, this.config_.dash.autoCorrectDrift);
724
734
  }
725
735
 
726
736
  presentationTimeline.setStatic(mpdType == 'static');
@@ -131,24 +131,6 @@ shaka.dash.SegmentTemplate = class {
131
131
 
132
132
  shaka.log.debug(`New manifest ${periodStart} - ${periodEnd}`);
133
133
 
134
- /* When to fit segments. All refactors should honor/update this table:
135
- *
136
- * | dynamic | infinite | last | should | notes |
137
- * | | period | period | fit | |
138
- * | ------- | -------- | ------ | ------ | ------------------------- |
139
- * | F | F | X | T | typical VOD |
140
- * | F | T | X | X | impossible: infinite VOD |
141
- * | T | F | F | T | typical live, old period |
142
- * | T | F | T | F | typical IPR |
143
- * | T | T | F | X | impossible: old, infinite |
144
- * | T | T | T | F | typical live, new period |
145
- */
146
-
147
- // We never fit the final period of dynamic content, which could be
148
- // infinite live (with no limit to fit to) or IPR (which would expand the
149
- // most recent segment to the end of the presentation).
150
- const shouldFit = !(context.dynamic && context.periodInfo.isLastPeriod);
151
-
152
134
  if (!segmentIndex) {
153
135
  shaka.log.debug(`Creating TSI with end ${periodEnd}`);
154
136
  segmentIndex = new TimelineSegmentIndex(
@@ -160,14 +142,13 @@ shaka.dash.SegmentTemplate = class {
160
142
  periodStart,
161
143
  periodEnd,
162
144
  initSegmentReference,
163
- shouldFit,
164
145
  aesKey,
165
146
  context.representation.segmentSequenceCadence,
166
147
  );
167
148
  } else {
168
149
  const tsi = /** @type {!TimelineSegmentIndex} */(segmentIndex);
169
150
  tsi.appendTemplateInfo(
170
- info, periodStart, periodEnd, shouldFit, initSegmentReference);
151
+ info, periodStart, periodEnd, initSegmentReference);
171
152
 
172
153
  const availabilityStart =
173
154
  context.presentationTimeline.getSegmentAvailabilityStart();
@@ -177,7 +158,9 @@ shaka.dash.SegmentTemplate = class {
177
158
  if (info.timeline &&
178
159
  context.adaptationSet.contentType !== 'image' &&
179
160
  context.adaptationSet.contentType !== 'text') {
180
- const timeline = info.timeline;
161
+ const tsi = /** @type {!TimelineSegmentIndex} */(segmentIndex);
162
+ // getTimeline is the info.timeline but fitted to the period.
163
+ const timeline = tsi.getTimeline();
181
164
  context.presentationTimeline.notifyTimeRange(
182
165
  timeline,
183
166
  periodStart);
@@ -195,7 +178,7 @@ shaka.dash.SegmentTemplate = class {
195
178
  if (segmentIndex instanceof shaka.dash.TimelineSegmentIndex &&
196
179
  segmentIndex.isEmpty()) {
197
180
  segmentIndex.appendTemplateInfo(info, periodStart,
198
- periodEnd, shouldFit, initSegmentReference);
181
+ periodEnd, initSegmentReference);
199
182
  }
200
183
  return Promise.resolve(segmentIndex);
201
184
  },
@@ -744,40 +727,45 @@ shaka.dash.TimelineSegmentIndex = class extends shaka.media.SegmentIndex {
744
727
  * @param {number} periodStart
745
728
  * @param {number} periodEnd
746
729
  * @param {shaka.media.InitSegmentReference} initSegmentReference
747
- * @param {boolean} shouldFit
748
730
  * @param {shaka.extern.aesKey|undefined} aesKey
749
731
  * @param {number} segmentSequenceCadence
750
732
  */
751
733
  constructor(templateInfo, representationId, bandwidth, getBaseUris,
752
- urlParams, periodStart, periodEnd, initSegmentReference, shouldFit,
734
+ urlParams, periodStart, periodEnd, initSegmentReference,
753
735
  aesKey, segmentSequenceCadence) {
754
736
  super([]);
755
737
 
756
738
  /** @private {?shaka.dash.SegmentTemplate.SegmentTemplateInfo} */
757
739
  this.templateInfo_ = templateInfo;
740
+
758
741
  /** @private {?string} */
759
742
  this.representationId_ = representationId;
743
+
760
744
  /** @private {number} */
761
745
  this.bandwidth_ = bandwidth;
746
+
762
747
  /** @private {function():Array.<string>} */
763
748
  this.getBaseUris_ = getBaseUris;
749
+
764
750
  /** @private {function():string} */
765
751
  this.urlParams_ = urlParams;
752
+
766
753
  /** @private {number} */
767
754
  this.periodStart_ = periodStart;
755
+
768
756
  /** @private {number} */
769
757
  this.periodEnd_ = periodEnd;
758
+
770
759
  /** @private {shaka.media.InitSegmentReference} */
771
760
  this.initSegmentReference_ = initSegmentReference;
761
+
772
762
  /** @private {shaka.extern.aesKey|undefined} */
773
763
  this.aesKey_ = aesKey;
764
+
774
765
  /** @private {number} */
775
766
  this.segmentSequenceCadence_ = segmentSequenceCadence;
776
767
 
777
-
778
- if (shouldFit) {
779
- this.fitTimeline();
780
- }
768
+ this.fitTimeline();
781
769
  }
782
770
 
783
771
  /**
@@ -845,11 +833,9 @@ shaka.dash.TimelineSegmentIndex = class extends shaka.media.SegmentIndex {
845
833
  * @param {shaka.dash.SegmentTemplate.SegmentTemplateInfo} info
846
834
  * @param {number} periodStart
847
835
  * @param {number} periodEnd
848
- * @param {boolean} shouldFit
849
836
  * @param {shaka.media.InitSegmentReference} initSegmentReference
850
837
  */
851
- appendTemplateInfo(info, periodStart, periodEnd, shouldFit,
852
- initSegmentReference) {
838
+ appendTemplateInfo(info, periodStart, periodEnd, initSegmentReference) {
853
839
  this.updateInitSegmentReference(initSegmentReference);
854
840
  if (!this.templateInfo_) {
855
841
  this.templateInfo_ = info;
@@ -883,9 +869,7 @@ shaka.dash.TimelineSegmentIndex = class extends shaka.media.SegmentIndex {
883
869
  }
884
870
  }
885
871
 
886
- if (shouldFit) {
887
- this.fitTimeline();
888
- }
872
+ this.fitTimeline();
889
873
  }
890
874
 
891
875
  /**
@@ -930,14 +914,19 @@ shaka.dash.TimelineSegmentIndex = class extends shaka.media.SegmentIndex {
930
914
  return;
931
915
  }
932
916
  const timeline = this.templateInfo_.timeline;
933
- while (timeline.length) {
934
- const lastTimePeriod = timeline[timeline.length - 1];
935
- if (lastTimePeriod.start >= this.periodEnd_) {
936
- timeline.pop();
917
+ goog.asserts.assert(timeline, 'Timeline should be non-null!');
918
+ const newTimeline = [];
919
+ for (const range of timeline) {
920
+ if (range.start >= this.periodEnd_) {
921
+ // Starts after end of period.
922
+ } else if (range.end <= 0) {
923
+ // Ends before start of period.
937
924
  } else {
938
- break;
925
+ // Usable.
926
+ newTimeline.push(range);
939
927
  }
940
928
  }
929
+ this.templateInfo_.timeline = newTimeline;
941
930
 
942
931
  this.evict(this.periodStart_);
943
932
 
@@ -947,6 +936,19 @@ shaka.dash.TimelineSegmentIndex = class extends shaka.media.SegmentIndex {
947
936
  // find/get() methods whenever possible.
948
937
  }
949
938
 
939
+ /**
940
+ * Get the current timeline
941
+ * @return {!Array<shaka.media.PresentationTimeline.TimeRange>}
942
+ */
943
+ getTimeline() {
944
+ if (!this.templateInfo_) {
945
+ return [];
946
+ }
947
+ const timeline = this.templateInfo_.timeline;
948
+ goog.asserts.assert(timeline, 'Timeline should be non-null!');
949
+ return timeline;
950
+ }
951
+
950
952
  /**
951
953
  * @override
952
954
  */
@@ -53,6 +53,9 @@ shaka.media.GapJumpingController = class {
53
53
  /** @private {shaka.util.EventManager} */
54
54
  this.eventManager_ = new shaka.util.EventManager();
55
55
 
56
+ /** @private {boolean} */
57
+ this.started_ = false;
58
+
56
59
  /** @private {boolean} */
57
60
  this.seekingEventReceived_ = false;
58
61
 
@@ -90,7 +93,7 @@ shaka.media.GapJumpingController = class {
90
93
  */
91
94
  this.gapJumpTimer_ = new shaka.util.Timer(() => {
92
95
  this.onPollGapJump_();
93
- }).tickEvery(this.config_.gapJumpTimerTime);
96
+ });
94
97
  }
95
98
 
96
99
 
@@ -134,16 +137,22 @@ shaka.media.GapJumpingController = class {
134
137
  * @param {number} startTime
135
138
  */
136
139
  onStarted(startTime) {
140
+ this.started_ = true;
137
141
  if (this.video_.seeking && !this.seekingEventReceived_) {
138
142
  this.seekingEventReceived_ = true;
139
143
  this.startTime_ = startTime;
140
144
  }
145
+ if (this.gapJumpTimer_) {
146
+ this.gapJumpTimer_.tickEvery(this.config_.gapJumpTimerTime);
147
+ }
148
+ this.onPollGapJump_();
141
149
  }
142
150
 
143
151
  /** Called when a seek has started. */
144
152
  onSeeking() {
145
153
  this.seekingEventReceived_ = true;
146
154
  this.hadSegmentAppended_ = false;
155
+ this.onPollGapJump_();
147
156
  }
148
157
 
149
158
 
@@ -167,6 +176,10 @@ shaka.media.GapJumpingController = class {
167
176
  if (this.video_.readyState == 0) {
168
177
  return;
169
178
  }
179
+ // Don't gap jump before playback started
180
+ if (!this.started_) {
181
+ return;
182
+ }
170
183
  // Do not gap jump if seeking has begun, but the seeking event has not
171
184
  // yet fired for this particular seek.
172
185
  if (this.video_.seeking) {
@@ -1301,20 +1301,24 @@ shaka.media.MediaSourceEngine = class {
1301
1301
  null));
1302
1302
  }
1303
1303
  }
1304
- operations.push(this.enqueueOperation_(
1305
- contentType,
1306
- () => this.setAppendWindow_(
1307
- contentType, appendWindowStart, appendWindowEnd),
1308
- null));
1309
- if (this.needSplitMuxedContent_) {
1304
+ if (appendWindowStart != 0 || appendWindowEnd != Infinity) {
1310
1305
  operations.push(this.enqueueOperation_(
1311
- ContentType.AUDIO,
1306
+ contentType,
1312
1307
  () => this.setAppendWindow_(
1313
- ContentType.AUDIO, appendWindowStart, appendWindowEnd),
1308
+ contentType, appendWindowStart, appendWindowEnd),
1314
1309
  null));
1310
+ if (this.needSplitMuxedContent_) {
1311
+ operations.push(this.enqueueOperation_(
1312
+ ContentType.AUDIO,
1313
+ () => this.setAppendWindow_(
1314
+ ContentType.AUDIO, appendWindowStart, appendWindowEnd),
1315
+ null));
1316
+ }
1315
1317
  }
1316
1318
 
1317
- await Promise.all(operations);
1319
+ if (operations.length) {
1320
+ await Promise.all(operations);
1321
+ }
1318
1322
  }
1319
1323
 
1320
1324
  /**
package/lib/player.js CHANGED
@@ -8153,7 +8153,7 @@ shaka.Player.TYPICAL_BUFFERING_THRESHOLD_ = 0.5;
8153
8153
  * @export
8154
8154
  */
8155
8155
  // eslint-disable-next-line no-useless-concat, max-len
8156
- shaka.Player.version = 'v4.11.20' + '-uncompiled'; // x-release-please-version
8156
+ shaka.Player.version = 'v4.11.21' + '-uncompiled'; // x-release-please-version
8157
8157
 
8158
8158
  // Initialize the deprecation system using the version string we just set
8159
8159
  // 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.11.20",
4
+ "version": "4.11.21",
5
5
  "homepage": "https://github.com/shaka-project/shaka-player",
6
6
  "author": "Google",
7
7
  "maintainers": [