eyevinn-channel-engine 3.0.5 → 3.0.6

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.
@@ -136,7 +136,7 @@ class SessionLive {
136
136
  if (!this.masterManifestUri) {
137
137
  await timer(3000);
138
138
  continue;
139
- }
139
+ }
140
140
  if (this.playheadState === PlayheadState.STOPPED) {
141
141
  debug(`[${this.sessionId}]: Playhead has Stopped, clearing local session and store.`);
142
142
  this.waitForPlayhead = false;
@@ -208,7 +208,7 @@ class SessionLive {
208
208
  while (!this.masterManifestUri && attempts > 0) {
209
209
  attempts--;
210
210
  try {
211
- debug(`[${this.instanceId}][${this.sessionId}]: Going to fetch Live Master Manifest!`)
211
+ debug(`[${this.instanceId}][${this.sessionId}]: Going to fetch Live Master Manifest!`);
212
212
  // Load & Parse all Media Manifest URIs from Master
213
213
  await this._loadMasterManifest(masterManifestUri);
214
214
  this.masterManifestUri = masterManifestUri;
@@ -390,7 +390,7 @@ class SessionLive {
390
390
  // Generate manifest to give to client
391
391
  async getCurrentMediaManifestAsync(bw) {
392
392
  if (!this.sessionLiveState) {
393
- throw new Error('SessionLive not ready');
393
+ throw new Error("SessionLive not ready");
394
394
  }
395
395
  if (bw === null) {
396
396
  debug(`[${this.sessionId}]: No bandwidth provided`);
@@ -488,7 +488,11 @@ class SessionLive {
488
488
  const size = this.liveSegsForFollowers[liveBws[0]].length;
489
489
 
490
490
  let newSegCount = 0;
491
- this.liveSegsForFollowers[liveBws[0]].map((seg) => {if (seg.uri) { newSegCount++ }});
491
+ this.liveSegsForFollowers[liveBws[0]].map((seg) => {
492
+ if (seg.uri) {
493
+ newSegCount++;
494
+ }
495
+ });
492
496
 
493
497
  debug(`[${this.sessionId}]: FOLLOWER: liveSegsForFollowers Bws=${Object.keys(this.liveSegsForFollowers)}_newSegCount=${newSegCount} `);
494
498
  // Remove transitional segs & add live source segs collected from store
@@ -509,7 +513,7 @@ class SessionLive {
509
513
  // Push to bottom, new live source segment on all variants
510
514
  for (let segIdx = 0; segIdx < size; segIdx++) {
511
515
  let incrementDiscSeqCount = false;
512
- liveBws.forEach((bw)=>{
516
+ liveBws.forEach((bw) => {
513
517
  let liveSegFromLeader = this.liveSegsForFollowers[bw][segIdx];
514
518
  if (!this.liveSegQueue[bw]) {
515
519
  this.liveSegQueue[bw] = [];
@@ -517,7 +521,11 @@ class SessionLive {
517
521
  this.liveSegQueue[bw].push(liveSegFromLeader);
518
522
 
519
523
  let segCount = 0;
520
- this.liveSegQueue[bw].map((seg) => {if (seg.uri) { segCount++ }});
524
+ this.liveSegQueue[bw].map((seg) => {
525
+ if (seg.uri) {
526
+ segCount++;
527
+ }
528
+ });
521
529
  if (segCount > this.targetNumSeg) {
522
530
  let seg = this.liveSegQueue[bw].shift();
523
531
  if (seg && seg.discontinuity) {
@@ -651,7 +659,7 @@ class SessionLive {
651
659
  }
652
660
 
653
661
  // Handle if any promise got rejected
654
- if (manifestList.some(result => result.status === "rejected")) {
662
+ if (manifestList.some((result) => result.status === "rejected")) {
655
663
  debug(`[${this.sessionId}]: ALERT! Promises I: Failed, Rejection Found! Trying again...`);
656
664
  continue;
657
665
  }
@@ -663,16 +671,21 @@ class SessionLive {
663
671
  return item.value.mediaSeq;
664
672
  });
665
673
 
666
-
667
674
  // Handle if mediaSeqCounts are NOT synced up!
668
675
  if (!allMediaSeqCounts.every((val, i, arr) => val === arr[0])) {
669
-
670
676
  debug(`[${this.sessionId}]: Live Mseq counts=[${allMediaSeqCounts}]`);
671
677
  // Decrement fetch counter
672
678
  FETCH_ATTEMPTS--;
679
+ // Calculate retry delay time. Default=1500
680
+ let retryDelayMs = 1500;
681
+ if (Object.keys(this.liveSegQueue).length > 0) {
682
+ const firstBw = Object.keys(this.liveSegQueue)[0];
683
+ const lastIdx = this.liveSegQueue[firstBw].length - 1;
684
+ retryDelayMs = this.liveSegQueue[firstBw][lastIdx].duration * 1000 * 0.25;
685
+ }
673
686
  // Wait a little before trying again
674
- debug(`[${this.sessionId}]: ALERT! Live Source Data NOT in sync! Will try again after 1500ms`);
675
- await timer(1500);
687
+ debug(`[${this.sessionId}]: ALERT! Live Source Data NOT in sync! Will try again after ${retryDelayMs}ms`);
688
+ await timer(retryDelayMs);
676
689
  this.timerCompensation = false;
677
690
  continue;
678
691
  }
@@ -681,7 +694,7 @@ class SessionLive {
681
694
  let leadersFirstSeqCounts = await this.sessionLiveState.get("firstCounts");
682
695
  let tries = 20;
683
696
 
684
- while (!leadersFirstSeqCounts.liveSourceMseqCount && tries > 0 || (leadersFirstSeqCounts.liveSourceMseqCount === 0)) {
697
+ while ((!leadersFirstSeqCounts.liveSourceMseqCount && tries > 0) || leadersFirstSeqCounts.liveSourceMseqCount === 0) {
685
698
  debug(`[${this.sessionId}]: NEW FOLLOWER: Waiting for LEADER to add 'firstCounts' in store! Will look again after 1000ms (tries left=${tries})`);
686
699
  await timer(1000);
687
700
  leadersFirstSeqCounts = await this.sessionLiveState.get("firstCounts");
@@ -727,7 +740,7 @@ class SessionLive {
727
740
  this.pushAmount = 1; // Follower from start
728
741
  } else {
729
742
  // RESPAWNED NODES
730
- this.pushAmount = (allMediaSeqCounts[0] - leadersFirstSeqCounts.liveSourceMseqCount) + 1;
743
+ this.pushAmount = allMediaSeqCounts[0] - leadersFirstSeqCounts.liveSourceMseqCount + 1;
731
744
 
732
745
  const transitSegs = await this.sessionLiveState.get("transitSegs");
733
746
  //debug(`[${this.sessionId}]: NEW FOLLOWER: I tried to get 'transitSegs'. This is what I found ${JSON.stringify(transitSegs)}`);
@@ -760,7 +773,7 @@ class SessionLive {
760
773
  }
761
774
 
762
775
  if (FETCH_ATTEMPTS === 0) {
763
- debug(`[${this.sessionId}]: Fetching from Live-Source did not work! Returning to Playhead Loop...`)
776
+ debug(`[${this.sessionId}]: Fetching from Live-Source did not work! Returning to Playhead Loop...`);
764
777
  return;
765
778
  }
766
779
 
@@ -781,8 +794,7 @@ class SessionLive {
781
794
  this.firstTime = false;
782
795
  debug(`[${this.sessionId}]: Got all needed segments from live-source (read from store).\nWe are now able to build Live Manifest: [${this.mediaSeqCount}]`);
783
796
  return;
784
- }
785
- else if (leadersCurrentMseqRaw < this.lastRequestedMediaSeqRaw) {
797
+ } else if (leadersCurrentMseqRaw < this.lastRequestedMediaSeqRaw) {
786
798
  // WE ARE A RESPAWN-NODE, and we are ahead of leader.
787
799
  this.blockGenerateManifest = true;
788
800
  }
@@ -798,7 +810,7 @@ class SessionLive {
798
810
  }
799
811
  // Segment Pushing
800
812
  debug(`[${this.sessionId}]: Executing Promises II: Segment Pushing`);
801
- let results = await allSettled(pushPromises);//await Promise.all(pushPromises);
813
+ let results = await allSettled(pushPromises); //await Promise.all(pushPromises);
802
814
  const removedDiscSeqList = results.map((item) => {
803
815
  if (item.status === "rejected") {
804
816
  return -1;
@@ -951,7 +963,9 @@ class SessionLive {
951
963
  // this.targetNumSeg = m3u.items.PlaylistItem.length;
952
964
  // }
953
965
 
954
- this.lastRequestedMediaSeqRaw = m3u.get("mediaSequence");
966
+ if (this.pushAmount >= 0) {
967
+ this.lastRequestedMediaSeqRaw = m3u.get("mediaSequence");
968
+ }
955
969
  this.targetDuration = m3u.get("targetDuration");
956
970
  let amountRemovedDiscSeqs = 0;
957
971
  let startIdx = m3u.items.PlaylistItem.length - this.pushAmount;
@@ -962,8 +976,8 @@ class SessionLive {
962
976
  }
963
977
  let resolveObj = {
964
978
  removedDiscSeqs: amountRemovedDiscSeqs,
965
- bw: liveTargetBandwidth
966
- }
979
+ bw: liveTargetBandwidth,
980
+ };
967
981
  resolve(resolveObj);
968
982
  } catch (exc) {
969
983
  console.error("ERROR: " + exc);
@@ -998,7 +1012,7 @@ class SessionLive {
998
1012
  }
999
1013
  cueData["out"] = true;
1000
1014
  cueData["duration"] = attributes["cueout"];
1001
- }
1015
+ }
1002
1016
  if ("cuecont" in attributes) {
1003
1017
  if (!cueData) {
1004
1018
  cueData = {};
@@ -1046,10 +1060,14 @@ class SessionLive {
1046
1060
  this.liveSegQueue[liveTargetBandwidth].push(seg);
1047
1061
  this.liveSegsForFollowers[liveTargetBandwidth].push(seg);
1048
1062
  let segCount = 0;
1049
- this.liveSegQueue[liveTargetBandwidth].map((seg) => {if (seg.uri) { segCount++ }});
1063
+ this.liveSegQueue[liveTargetBandwidth].map((seg) => {
1064
+ if (seg.uri) {
1065
+ segCount++;
1066
+ }
1067
+ });
1050
1068
  debug(`[${this.sessionId}]: size of queue=${segCount}_targetNumseg=${this.targetNumSeg}`);
1051
1069
  if (segCount > this.targetNumSeg) {
1052
- debug(`[${this.sessionId}]: liveTargetBandwidth=${liveTargetBandwidth}_seg=${JSON.stringify(seg,null,2)}`);
1070
+ debug(`[${this.sessionId}]: liveTargetBandwidth=${liveTargetBandwidth}_seg=${JSON.stringify(seg, null, 2)}`);
1053
1071
  seg = this.liveSegQueue[liveTargetBandwidth].shift();
1054
1072
  if (seg) {
1055
1073
  if (seg.discontinuity) {
@@ -1079,8 +1097,7 @@ class SessionLive {
1079
1097
  }
1080
1098
  const liveTargetBandwidth = this._findNearestBw(bw, Object.keys(this.mediaManifestURIs));
1081
1099
  const vodTargetBandwidth = this._findNearestBw(bw, Object.keys(this.vodSegments));
1082
- debug(`[${this.sessionId}]: Client requesting manifest for bw=(${bw}). Nearest LiveBw=(${liveTargetBandwidth})`)
1083
-
1100
+ debug(`[${this.sessionId}]: Client requesting manifest for bw=(${bw}). Nearest LiveBw=(${liveTargetBandwidth})`);
1084
1101
 
1085
1102
  if (this.blockGenerateManifest) {
1086
1103
  debug(`[${this.sessionId}]: FOLLOWER: Cannot Generate Manifest! Waiting to sync-up with Leader...`);
@@ -1154,7 +1171,7 @@ class SessionLive {
1154
1171
  m3u8 += "#EXT-X-DISCONTINUITY\n";
1155
1172
  }
1156
1173
  if (seg.cue) {
1157
- if(seg.cue.out) {
1174
+ if (seg.cue.out) {
1158
1175
  if (seg.cue.scteData) {
1159
1176
  m3u8 += "#EXT-OATCLS-SCTE35:" + seg.cue.scteData + "\n";
1160
1177
  }
@@ -1166,8 +1183,7 @@ class SessionLive {
1166
1183
  if (seg.cue.cont) {
1167
1184
  if (seg.cue.scteData) {
1168
1185
  m3u8 += "#EXT-X-CUE-OUT-CONT:ElapsedTime=" + seg.cue.cont + ",Duration=" + seg.cue.duration + ",SCTE35=" + seg.cue.scteData + "\n";
1169
- }
1170
- else {
1186
+ } else {
1171
1187
  m3u8 += "#EXT-X-CUE-OUT-CONT:" + seg.cue.cont + "/" + seg.cue.duration + "\n";
1172
1188
  }
1173
1189
  }
@@ -1176,14 +1192,16 @@ class SessionLive {
1176
1192
  m3u8 += `#EXT-X-PROGRAM-DATE-TIME:${seg.datetime}\n`;
1177
1193
  }
1178
1194
  if (seg.daterange) {
1179
- const dateRangeAttributes = Object.keys(seg.daterange).map(key => daterangeAttribute(key, seg.daterange[key])).join(',');
1180
- if (!seg.datetime && seg.daterange['start-date']) {
1181
- m3u8 += "#EXT-X-PROGRAM-DATE-TIME:" + seg.daterange['start-date'] + "\n";
1195
+ const dateRangeAttributes = Object.keys(seg.daterange)
1196
+ .map((key) => daterangeAttribute(key, seg.daterange[key]))
1197
+ .join(",");
1198
+ if (!seg.datetime && seg.daterange["start-date"]) {
1199
+ m3u8 += "#EXT-X-PROGRAM-DATE-TIME:" + seg.daterange["start-date"] + "\n";
1182
1200
  }
1183
1201
  m3u8 += "#EXT-X-DATERANGE:" + dateRangeAttributes + "\n";
1184
1202
  }
1185
1203
  // Mimick logic used in hls-vodtolive
1186
- if (seg.cue && seg.cue.in){
1204
+ if (seg.cue && seg.cue.in) {
1187
1205
  m3u8 += "#EXT-X-CUE-IN" + "\n";
1188
1206
  }
1189
1207
  if (seg.uri) {
@@ -1234,13 +1252,13 @@ class SessionLive {
1234
1252
  const profiles = this.sessionLiveProfile;
1235
1253
  const toKeep = new Set();
1236
1254
  let newItem = {};
1237
- profiles.forEach(profile => {
1255
+ profiles.forEach((profile) => {
1238
1256
  let bwToKeep = this._findNearestBw(profile.bw, Object.keys(this.mediaManifestURIs));
1239
1257
  toKeep.add(bwToKeep);
1240
1258
  });
1241
1259
  toKeep.forEach((bw) => {
1242
1260
  newItem[bw] = this.mediaManifestURIs[bw];
1243
- })
1261
+ });
1244
1262
  this.mediaManifestURIs = newItem;
1245
1263
  }
1246
1264
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eyevinn-channel-engine",
3
- "version": "3.0.5",
3
+ "version": "3.0.6",
4
4
  "description": "OTT TV Channel Engine",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/server-livemix.js CHANGED
@@ -155,7 +155,7 @@ class StreamSwitchManager {
155
155
  type: StreamType.LIVE,
156
156
  start_time: startOffset,
157
157
  end_time: endTime,
158
- uri: "https://cph-p2p-msl.akamaized.net/hls/live/2000341/test/master.m3u8",
158
+ uri: "https://d2fz24s2fts31b.cloudfront.net/out/v1/2e5b17b7dd0548c7b844eb1b311b6434/manifest.m3u8",
159
159
  },
160
160
  {
161
161
  eventId: this.generateID(),