eyevinn-channel-engine 3.3.3 → 3.3.4

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/engine/session.js CHANGED
@@ -566,14 +566,16 @@ class Session {
566
566
  if (currentVod) {
567
567
  try {
568
568
 
569
+ let manifestMseq = playheadState.mediaSeq + playheadState.vodMediaSeqVideo;
569
570
  if (currentVod.sequenceAlwaysContainNewSegments) {
570
571
  const mediaSequenceValue = currentVod.mediaSequenceValues[playheadState.vodMediaSeqVideo];
571
572
  debug(`[${this._sessionId}]: {${mediaSequenceValue}}_{${currentVod.getLastSequenceMediaSequenceValue()}}`);
573
+ manifestMseq = playheadState.mediaSeq + mediaSequenceValue;
572
574
  }
573
575
 
574
576
  debug(`[${this._sessionId}]: [${playheadState.vodMediaSeqVideo}]_[${currentVod.getLiveMediaSequencesCount()}]`);
575
577
  const m3u8 = currentVod.getLiveMediaSequences(playheadState.mediaSeq, bw, playheadState.vodMediaSeqVideo, sessionState.discSeq, this.targetDurationPadding, this.forceTargetDuration);
576
- debug(`[${this._sessionId}]: [${playheadState.mediaSeq + playheadState.vodMediaSeqVideo}][${sessionState.discSeq}][+${this.targetDurationPadding || 0}] Current media manifest for ${bw} requested`);
578
+ debug(`[${this._sessionId}]: [${manifestMseq}][${sessionState.discSeq}][+${this.targetDurationPadding || 0}] Current media manifest for ${bw} requested`);
577
579
  this.prevVodMediaSeq.video = playheadState.vodMediaSeqVideo;
578
580
  this.prevMediaSeqOffset.video = playheadState.mediaSeq;
579
581
  return m3u8;
@@ -1234,34 +1236,33 @@ class Session {
1234
1236
  try {
1235
1237
  debug(`[${this._sessionId}]: state=VOD_RELOAD_INIT`);
1236
1238
  if (isLeader) {
1237
-
1238
1239
  const startTS = Date.now();
1239
-
1240
1240
  // 1) To tell Follower that, Leader is working on it!
1241
1241
  sessionState.state = await this._sessionState.set("state", SessionState.VOD_RELOAD_INITIATING);
1242
-
1243
1242
  // 2) Set new 'offset' sequences, to carry on the continuity from session-live
1244
1243
  let mSeq = this.switchDataForSession.mediaSeq;
1245
1244
  let currentVod = await this._sessionState.getCurrentVod();
1246
1245
  if (currentVod.sequenceAlwaysContainNewSegments) {
1247
1246
  // (!) will need to compensate if using this setting on HLSVod Object.
1248
- mSeq -= 1;
1249
- }
1247
+ Object.keys(this.switchDataForSession.transitionSegments).forEach(bw => {
1248
+ let shiftedSeg = this.switchDataForSession.transitionSegments[bw].shift();
1249
+ if (shiftedSeg && shiftedSeg.discontinuity) {
1250
+ shiftedSeg = this.switchDataForSession.transitionSegments[bw].shift();
1251
+ }
1252
+ });
1253
+ }
1250
1254
  const dSeq = this.switchDataForSession.discSeq;
1251
1255
  const mSeqOffset = this.switchDataForSession.mediaSeqOffset;
1252
1256
  const reloadBehind = this.switchDataForSession.reloadBehind;
1253
1257
  const segments = this.switchDataForSession.transitionSegments;
1254
-
1255
1258
  if ([mSeq,dSeq,mSeqOffset,reloadBehind,segments].includes(null)) {
1256
1259
  debug(`[${this._sessionId}]: LEADER: Cannot Reload VOD, missing switch-back data`);
1257
1260
  return;
1258
1261
  }
1259
-
1260
1262
  await this._sessionState.set("mediaSeq", mSeq);
1261
1263
  await this._playheadState.set("mediaSeq", mSeq);
1262
1264
  await this._sessionState.set("discSeq", dSeq);
1263
1265
  debug(`[${this._sessionId}]: Setting current media and discontinuity count -> [${mSeq}]:[${dSeq}]`);
1264
-
1265
1266
  // 3) Set new media segments/currentVod, to carry on the continuity from session-live
1266
1267
  debug(`[${this._sessionId}]: LEADER: making changes to current VOD. I will also update currentVod in store.`);
1267
1268
  const playheadState = await this._playheadState.getValues(["vodMediaSeqVideo"]);
@@ -1270,8 +1271,10 @@ class Session {
1270
1271
  nextMseq = currentVod.getLiveMediaSequencesCount() - 1;
1271
1272
  }
1272
1273
 
1273
- // TODO: Support reloading with audioSegments as well
1274
-
1274
+ // ---------------------------------------------------.
1275
+ // TODO: Support reloading with audioSegments as well |
1276
+ // ---------------------------------------------------'
1277
+
1275
1278
  await currentVod.reload(nextMseq, segments, null, reloadBehind);
1276
1279
  await this._sessionState.setCurrentVod(currentVod, { ttl: currentVod.getDuration() * 1000 });
1277
1280
  await this._sessionState.set("vodReloaded", 1);
@@ -1280,13 +1283,12 @@ class Session {
1280
1283
  await this._playheadState.set("vodMediaSeqVideo", 0);
1281
1284
  await this._playheadState.set("vodMediaSeqAudio", 0);
1282
1285
  await this._playheadState.set("playheadRef", Date.now());
1286
+ // 4) Log to debug and cloudwatch
1283
1287
  debug(`[${this._sessionId}]: LEADER: Set new Reloaded VOD and vodMediaSeq counts in store.`);
1284
- // 4) emit cloudwatch event object
1285
1288
  debug(`[${this._sessionId}]: next VOD Reloaded (${currentVod.getDeltaTimes()})`);
1286
1289
  debug(`[${this._sessionId}]: ${currentVod.getPlayheadPositions()}`);
1287
1290
  debug(`[${this._sessionId}]: msequences=${currentVod.getLiveMediaSequencesCount()}`);
1288
1291
  cloudWatchLog(!this.cloudWatchLogging, "engine-session", { event: "switchback", channel: this._sessionId, reqTimeMs: Date.now() - startTS });
1289
-
1290
1292
  return;
1291
1293
  } else {
1292
1294
  debug(`[${this._sessionId}]: not a leader so will go directly to state VOD_RELOAD_INITIATING`);
@@ -218,6 +218,7 @@ class SessionLive {
218
218
  this.masterManifestUri = masterManifestUri;
219
219
  if (this.sessionLiveProfile) {
220
220
  this._filterLiveProfiles();
221
+ debug(`[${this.sessionId}]: Filtered Live profiles! (${Object.keys(this.mediaManifestURIs).length}) profiles left!`);
221
222
  }
222
223
  } catch (err) {
223
224
  this.masterManifestUri = null;
@@ -253,14 +254,30 @@ class SessionLive {
253
254
  if (segments[bw][0].discontinuity) {
254
255
  segments[bw].shift();
255
256
  }
256
-
257
+ let cueInExists = null;
257
258
  for (let segIdx = 0; segIdx < segments[bw].length; segIdx++) {
258
- this.vodSegments[bw].push(segments[bw][segIdx]);
259
+ const v2lSegment = segments[bw][segIdx];
260
+ if (v2lSegment.cue) {
261
+ if (v2lSegment.cue["in"]) {
262
+ cueInExists = true;
263
+ } else {
264
+ cueInExists = false;
265
+ }
266
+ }
267
+ this.vodSegments[bw].push(v2lSegment);
259
268
  }
260
- if (!segments[bw][segments[bw].length - 1].discontinuity) {
261
- this.vodSegments[bw].push({ discontinuity: true, cue: { in: true } });
269
+
270
+ const endIdx = segments[bw].length - 1;
271
+ if (!segments[bw][endIdx].discontinuity) {
272
+ const finalSegItem = { discontinuity: true };
273
+ if (!cueInExists) {
274
+ finalSegItem["cue"] = { in: true };
275
+ }
276
+ this.vodSegments[bw].push(finalSegItem);
262
277
  } else {
263
- segments[bw][segments[bw].length - 1]["cue"] = { in: true };
278
+ if (!cueInExists) {
279
+ segments[bw][endIdx]["cue"] = { in: true };
280
+ }
264
281
  }
265
282
  }
266
283
  } else {
@@ -601,7 +618,7 @@ class SessionLive {
601
618
  // ---------------------------------
602
619
  let FETCH_ATTEMPTS = 10;
603
620
  this.liveSegsForFollowers = {};
604
-
621
+ let bandwidthsToSkipOnRetry = [];
605
622
  while (FETCH_ATTEMPTS > 0) {
606
623
  if (isLeader) {
607
624
  debug(`[${this.sessionId}]: LEADER: Trying to fetch manifests for all bandwidths\n Attempts left=[${FETCH_ATTEMPTS}]`);
@@ -619,9 +636,15 @@ class SessionLive {
619
636
  let manifestList = [];
620
637
  this.pushAmount = 0;
621
638
  try {
639
+ if (bandwidthsToSkipOnRetry.length > 0) {
640
+ debug(`[${this.sessionId}]: (X) Skipping loadMedia promises for bws ${JSON.stringify(bandwidthsToSkipOnRetry)}`);
641
+ }
622
642
  // Collect Live Source Requesting Promises
623
643
  for (let i = 0; i < Object.keys(this.mediaManifestURIs).length; i++) {
624
644
  let bw = Object.keys(this.mediaManifestURIs)[i];
645
+ if (bandwidthsToSkipOnRetry.includes(bw)) {
646
+ continue;
647
+ }
625
648
  livePromises.push(this._loadMediaManifest(bw));
626
649
  debug(`[${this.sessionId}]: Pushed loadMedia promise for bw=[${bw}]`);
627
650
  }
@@ -642,16 +665,28 @@ class SessionLive {
642
665
  continue;
643
666
  }
644
667
 
645
- const allMediaSeqCounts = manifestList.map((item) => {
646
- if (item.status === "rejected") {
647
- return item.reason.mediaSeq;
668
+ // Store the results locally
669
+ manifestList.forEach((variantItem) => {
670
+ const bw = variantItem.value.bandwidth;
671
+ if (!this.liveSourceM3Us[bw]) {
672
+ this.liveSourceM3Us[bw] = {};
648
673
  }
649
- return item.value.mediaSeq;
674
+ this.liveSourceM3Us[bw] = variantItem.value;
650
675
  });
651
676
 
677
+ const allStoredMediaSeqCounts = Object.keys(this.liveSourceM3Us).map((variant) => this.liveSourceM3Us[variant].mediaSeq);
678
+
652
679
  // Handle if mediaSeqCounts are NOT synced up!
653
- if (!allMediaSeqCounts.every((val, i, arr) => val === arr[0])) {
654
- debug(`[${this.sessionId}]: Live Mseq counts=[${allMediaSeqCounts}]`);
680
+ if (!allStoredMediaSeqCounts.every((val, i, arr) => val === arr[0])) {
681
+ debug(`[${this.sessionId}]: Live Mseq counts=[${allStoredMediaSeqCounts}]`);
682
+ // Figure out what bw's are behind.
683
+ const higestMediaSeqCount = Math.max(...allStoredMediaSeqCounts);
684
+ bandwidthsToSkipOnRetry = Object.keys(this.liveSourceM3Us).filter((bw) => {
685
+ if (this.liveSourceM3Us[bw].mediaSeq === higestMediaSeqCount) {
686
+ return true;
687
+ }
688
+ return false;
689
+ });
655
690
  // Decrement fetch counter
656
691
  FETCH_ATTEMPTS--;
657
692
  // Calculate retry delay time. Default=1000
@@ -672,7 +707,7 @@ class SessionLive {
672
707
  continue;
673
708
  }
674
709
 
675
- currentMseqRaw = allMediaSeqCounts[0];
710
+ currentMseqRaw = allStoredMediaSeqCounts[0];
676
711
 
677
712
  if (!isLeader) {
678
713
  let leadersFirstSeqCounts = await this.sessionLiveState.get("firstCounts");
@@ -733,7 +768,6 @@ class SessionLive {
733
768
  if (currentMseqRaw === leadersFirstSeqCounts.liveSourceMseqCount) {
734
769
  this.pushAmount = 1; // Follower from start
735
770
  } else {
736
-
737
771
  // TODO: To support and account for past discontinuity tags in the Live Source stream,
738
772
  // we will need to get the real 'current' discontinuity-sequence count from Leader somehow.
739
773
 
@@ -1030,8 +1064,8 @@ class SessionLive {
1030
1064
  const resolveObj = {
1031
1065
  M3U: m3u,
1032
1066
  mediaSeq: m3u.get("mediaSequence"),
1067
+ bandwidth: liveTargetBandwidth,
1033
1068
  };
1034
- this.liveSourceM3Us[liveTargetBandwidth] = resolveObj;
1035
1069
  resolve(resolveObj);
1036
1070
  } catch (exc) {
1037
1071
  debug(`[${this.sessionId}]: Error when parsing latest manifest`);
@@ -626,7 +626,7 @@ class StreamSwitcher {
626
626
  } else {
627
627
  const lastSeg = toSegments[bw][toSegments[bw].length - 1];
628
628
  if (lastSeg.uri && !lastSeg.discontinuity) {
629
- toSegments[bw].push({ discontinuity: true });
629
+ toSegments[bw].push({ discontinuity: true, cue: { in: true } });
630
630
  OUTPUT_SEGMENTS[bw] = toSegments[bw].concat(fromSegments[targetBw]);
631
631
  } else {
632
632
  OUTPUT_SEGMENTS[bw] = toSegments[bw].concat(fromSegments[targetBw]);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eyevinn-channel-engine",
3
- "version": "3.3.3",
3
+ "version": "3.3.4",
4
4
  "description": "OTT TV Channel Engine",
5
5
  "main": "index.js",
6
6
  "scripts": {