eyevinn-channel-engine 3.2.7 → 3.3.0

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/README.md CHANGED
@@ -108,6 +108,7 @@ Available options when constructing the Channel Engine object are:
108
108
  - `maxTickInterval`: The maximum interval for playhead tick interval. Default is 10000 ms.
109
109
  - `cloudWatchMetrics`: Output CloudWatch JSON metrics on console log. Default is false.
110
110
  - `useDemuxedAudio`: Enable playing VODs with multiple audio tracks. Default is false.
111
+ - `alwaysNewSegments`: Force all new HLS media sequences to always contain at least 1 new segment. Default is false.
111
112
 
112
113
  ## High Availability
113
114
 
package/engine/server.js CHANGED
@@ -33,9 +33,13 @@ class ChannelEngine {
33
33
  this.adXchangeUri = options.adXchangeUri;
34
34
  }
35
35
  this.useDemuxedAudio = false;
36
- if (options && options.useDemuxedAudio === true) {
36
+ if (options && options.useDemuxedAudio) {
37
37
  this.useDemuxedAudio = true;
38
38
  }
39
+ this.alwaysNewSegments = false;
40
+ if (options && options.alwaysNewSegments) {
41
+ this.alwaysNewSegments = true;
42
+ }
39
43
  if (options && options.defaultSlateUri) {
40
44
  this.defaultSlateUri = options.defaultSlateUri;
41
45
  this.slateRepetitions = options.slateRepetitions || 10;
@@ -228,6 +232,7 @@ class ChannelEngine {
228
232
  sessionId: channel.id,
229
233
  averageSegmentDuration: channel.options && channel.options.averageSegmentDuration ? channel.options.averageSegmentDuration : this.streamerOpts.defaultAverageSegmentDuration,
230
234
  useDemuxedAudio: options.useDemuxedAudio,
235
+ alwaysNewSegments: options.alwaysNewSegments,
231
236
  playheadDiffThreshold: channel.options && channel.options.playheadDiffThreshold ? channel.options.playheadDiffThreshold : this.streamerOpts.defaultPlayheadDiffThreshold,
232
237
  maxTickInterval: channel.options && channel.options.maxTickInterval ? channel.options.maxTickInterval : this.streamerOpts.defaultMaxTickInterval,
233
238
  targetDurationPadding: channel.options && channel.options.targetDurationPadding ? channel.options.targetDurationPadding : this.streamerOpts.targetDurationPadding,
@@ -444,6 +449,7 @@ class ChannelEngine {
444
449
  options.adXchangeUri = this.adXchangeUri;
445
450
  options.averageSegmentDuration = this.streamerOpts.defaultAverageSegmentDuration;
446
451
  options.useDemuxedAudio = this.useDemuxedAudio;
452
+ options.alwaysNewSegments = this.alwaysNewSegments;
447
453
  options.playheadDiffThreshold = this.streamerOpts.defaultPlayheadDiffThreshold;
448
454
  options.maxTickInterval = this.streamerOpts.defaultMaxTickInterval;
449
455
  options.targetDurationPadding = this.streamerOpts.targetDurationPadding;
package/engine/session.js CHANGED
@@ -47,6 +47,10 @@ class Session {
47
47
  video: null,
48
48
  audio: null
49
49
  }
50
+ this.prevMediaSeqOffset = {
51
+ video: null,
52
+ audio: null
53
+ }
50
54
  this.waitingForNextVod = false;
51
55
  this.leaderIsSettingNextVod = false;
52
56
  this.isSwitchingBackToV2L = false;
@@ -58,8 +62,12 @@ class Session {
58
62
  reloadBehind: null,
59
63
  }
60
64
  this.isAllowedToClearVodCache = null;
61
-
65
+ this.alwaysNewSegments = null;
62
66
  if (config) {
67
+ if (config.alwaysNewSegments) {
68
+ this.alwaysNewSegments = config.alwaysNewSegments;
69
+ }
70
+
63
71
  if (config.sessionId) {
64
72
  this._sessionId = config.sessionId;
65
73
  }
@@ -195,7 +203,7 @@ class Session {
195
203
  this.diffCompensation -= DIFF_COMPENSATION;
196
204
  }
197
205
  debug(`[${this._sessionId}]: Requested tickInterval=${tickInterval}s (max=${this.maxTickInterval / 1000}s, diffThreshold=${this.playheadDiffThreshold}msec)`);
198
- if (tickInterval <= 0) {
206
+ if (tickInterval <= 0.5) {
199
207
  tickInterval = 0.5;
200
208
  } else if (tickInterval > (this.maxTickInterval / 1000)) {
201
209
  tickInterval = this.maxTickInterval / 1000;
@@ -376,7 +384,16 @@ class Session {
376
384
  if (currentVod) {
377
385
  try {
378
386
  const mediaSegments = currentVod.getLiveMediaSequenceSegments(playheadState.vodMediaSeqVideo);
379
- debug(`[${this._sessionId}]: Requesting all segments from Media Sequence: ${playheadState.vodMediaSeqVideo}_${currentVod.getLiveMediaSequencesCount()}`);
387
+
388
+ let mediaSequenceValue = 0;
389
+ if (currentVod.sequenceAlwaysContainNewSegments) {
390
+ mediaSequenceValue = currentVod.mediaSequenceValues[playheadState.vodMediaSeqVideo];
391
+ debug(`[${this._sessionId}]: {${mediaSequenceValue}}_{${currentVod.getLastSequenceMediaSequenceValue()}`);
392
+ } else {
393
+ mediaSequenceValue = playheadState.vodMediaSeqVideo;
394
+ }
395
+
396
+ debug(`[${this._sessionId}]: Requesting all segments from Media Sequence: ${playheadState.vodMediaSeqVideo}(${mediaSequenceValue})_${currentVod.getLiveMediaSequencesCount()}`);
380
397
  return mediaSegments;
381
398
  } catch (err) {
382
399
  logerror(this._sessionId, err);
@@ -428,10 +445,18 @@ class Session {
428
445
  const currentVod = await this._sessionState.getCurrentVod();
429
446
  if (currentVod) {
430
447
  try {
448
+ let mediaSequenceValue = 0;
449
+ if (currentVod.sequenceAlwaysContainNewSegments) {
450
+ mediaSequenceValue = currentVod.mediaSequenceValues[playheadState.vodMediaSeqVideo];
451
+ debug(`[${this._sessionId}]: seqIndex=${playheadState.vodMediaSeqVideo}_seqValue=${mediaSequenceValue}`)
452
+ } else {
453
+ mediaSequenceValue = playheadState.vodMediaSeqVideo;
454
+ }
431
455
  const discSeqCount = discSeqOffset + currentVod.discontinuities[playheadState.vodMediaSeqVideo];
432
- debug(`[${this._sessionId}]: MediaSeq: (${(playheadState.mediaSeq + playheadState.vodMediaSeqVideo)}) and DiscSeq: (${discSeqCount}) requested `);
456
+
457
+ debug(`[${this._sessionId}]: MediaSeq: (${playheadState.mediaSeq}+${mediaSequenceValue}=${(playheadState.mediaSeq + mediaSequenceValue)}) and DiscSeq: (${discSeqCount}) requested `);
433
458
  return {
434
- 'mediaSeq': (playheadState.mediaSeq + playheadState.vodMediaSeqVideo),
459
+ 'mediaSeq': (playheadState.mediaSeq + mediaSequenceValue),
435
460
  'discSeq': discSeqCount,
436
461
  'vodMediaSeqVideo': playheadState.vodMediaSeqVideo,
437
462
  };
@@ -464,6 +489,9 @@ class Session {
464
489
  if (this.prevVodMediaSeq.video === null) {
465
490
  this.prevVodMediaSeq.video = playheadState.vodMediaSeqVideo;
466
491
  }
492
+ if (this.prevMediaSeqOffset.video === null) {
493
+ this.prevMediaSeqOffset.video = playheadState.mediaSeq;
494
+ }
467
495
 
468
496
  if (playheadState.vodMediaSeqVideo > sessionState.vodMediaSeqVideo) {
469
497
  debug(`[${this._sessionId}]: Recently Loaded Next Vod. PlayheadState not up-to-date. Return the last generated m3u8`);
@@ -477,8 +505,13 @@ class Session {
477
505
  }
478
506
 
479
507
  // Force reading up from store, but only once if the condition is right
480
- if (playheadState.vodMediaSeqVideo < 2 || playheadState.vodMediaSeqVideo < this.prevVodMediaSeq.video) {
508
+ if (playheadState.vodMediaSeqVideo < 2 || playheadState.mediaSeq !== this.prevMediaSeqOffset.video) {
481
509
  debug(`[${this._sessionId}]: current[${playheadState.vodMediaSeqVideo}]_prev[${this.prevVodMediaSeq.video}]`);
510
+ debug(`[${this._sessionId}]: current-offset[${playheadState.mediaSeq}]_prev-offset[${this.prevMediaSeqOffset.video}]`);
511
+ // If true, then we have not updated the prev-values and not cleared the cache yet.
512
+ if (playheadState.vodMediaSeqVideo < this.prevVodMediaSeq.video || playheadState.mediaSeq !== this.prevMediaSeqOffset.video) {
513
+ this.isAllowedToClearVodCache = true;
514
+ }
482
515
  const isLeader = await this._sessionStateStore.isLeader(this._instanceId);
483
516
  if (!isLeader && this.isAllowedToClearVodCache) {
484
517
  debug(`[${this._sessionId}]: Not a leader and first|second media sequence in a VOD is requested. Invalidate cache to ensure having the correct VOD.`);
@@ -492,10 +525,17 @@ class Session {
492
525
  const currentVod = await this._sessionState.getCurrentVod();
493
526
  if (currentVod) {
494
527
  try {
528
+
529
+ if (currentVod.sequenceAlwaysContainNewSegments) {
530
+ const mediaSequenceValue = currentVod.mediaSequenceValues[playheadState.vodMediaSeqVideo];
531
+ debug(`[${this._sessionId}]: {${mediaSequenceValue}}_{${currentVod.getLastSequenceMediaSequenceValue()}}`);
532
+ }
533
+
495
534
  debug(`[${this._sessionId}]: [${playheadState.vodMediaSeqVideo}]_[${currentVod.getLiveMediaSequencesCount()}]`);
496
535
  const m3u8 = currentVod.getLiveMediaSequences(playheadState.mediaSeq, bw, playheadState.vodMediaSeqVideo, sessionState.discSeq, this.targetDurationPadding, this.forceTargetDuration);
497
536
  debug(`[${this._sessionId}]: [${playheadState.mediaSeq + playheadState.vodMediaSeqVideo}][${sessionState.discSeq}][+${this.targetDurationPadding || 0}] Current media manifest for ${bw} requested`);
498
537
  this.prevVodMediaSeq.video = playheadState.vodMediaSeqVideo;
538
+ this.prevMediaSeqOffset.video = playheadState.mediaSeq;
499
539
  return m3u8;
500
540
  } catch (err) {
501
541
  logerror(this._sessionId, err);
@@ -591,19 +631,25 @@ class Session {
591
631
  playheadState.mediaSeq = await this._playheadState.set("mediaSeq", sessionState.mediaSeq);
592
632
  playheadState.vodMediaSeqVideo = await this._playheadState.set("vodMediaSeqVideo", sessionState.vodMediaSeqVideo);
593
633
  playheadState.vodMediaSeqAudio = await this._playheadState.set("vodMediaSeqAudio", sessionState.vodMediaSeqAudio);
634
+
635
+ if (currentVod.sequenceAlwaysContainNewSegments) {
636
+ const mediaSequenceValue = currentVod.mediaSequenceValues[playheadState.vodMediaSeqVideo];
637
+ debug(`[${this._sessionId}]: Session can now serve mseq={${playheadState.mediaSeq + mediaSequenceValue}}`);
638
+ }
639
+
594
640
  debug(`[${this._sessionId}]: INCREMENT (mseq=${playheadState.mediaSeq + playheadState.vodMediaSeqVideo}) vodMediaSeq=(${playheadState.vodMediaSeqVideo}_${playheadState.vodMediaSeqAudio} of ${currentVod.getLiveMediaSequencesCount()})`);
595
- let m3u8 = currentVod.getLiveMediaSequences(playheadState.mediaSeq, 180000, playheadState.vodMediaSeqVideo, sessionState.discSeq);
596
- await this._playheadState.setLastM3u8(m3u8);
597
641
 
598
642
  // As a FOLLOWER, we might need to read up from shared store...
599
- if (playheadState.vodMediaSeqVideo < 2 || playheadState.vodMediaSeqVideo < this.prevVodMediaSeq.video) {
643
+ if (playheadState.vodMediaSeqVideo < 2 || playheadState.mediaSeq !== this.prevMediaSeqOffset.video) {
600
644
  debug(`[${this._sessionId}]: current[${playheadState.vodMediaSeqVideo}]_prev[${this.prevVodMediaSeq.video}]`);
601
- if (playheadState.vodMediaSeqVideo < this.prevVodMediaSeq.video) {
602
- this.alreadyCleredVodCache = false;
645
+ debug(`[${this._sessionId}]: current-offset[${playheadState.mediaSeq}]_prev-offset[${this.prevMediaSeqOffset.video}]`);
646
+ if (playheadState.vodMediaSeqVideo < this.prevVodMediaSeq.video || playheadState.mediaSeq !== this.prevMediaSeqOffset.video) {
647
+ this.isAllowedToClearVodCache = true;
603
648
  }
604
649
  if (!isLeader && this.isAllowedToClearVodCache) {
605
650
  debug(`[${this._sessionId}]: Not a leader and have just set 'playheadState.vodMediaSeqVideo' to 0|1. Invalidate cache to ensure having the correct VOD.`);
606
651
  await this._sessionState.clearCurrentVodCache();
652
+ currentVod = await this._sessionState.getCurrentVod();
607
653
  this.isAllowedToClearVodCache = false;
608
654
  }
609
655
  } else {
@@ -611,7 +657,10 @@ class Session {
611
657
  }
612
658
  // Update Value for Previous Sequence
613
659
  this.prevVodMediaSeq.video = playheadState.vodMediaSeqVideo;
660
+ this.prevMediaSeqOffset.video = playheadState.mediaSeq;
614
661
 
662
+ let m3u8 = currentVod.getLiveMediaSequences(playheadState.mediaSeq, 180000, playheadState.vodMediaSeqVideo, sessionState.discSeq);
663
+ await this._playheadState.setLastM3u8(m3u8);
615
664
  return m3u8;
616
665
  }
617
666
 
@@ -828,17 +877,21 @@ class Session {
828
877
  const slateVod = await this._loadSlate(currentVod);
829
878
  debug(`[${this._sessionId}]: slate loaded`);
830
879
  const sessionState = await this._sessionState.getValues(["slateCount", "mediaSeq", "discSeq"]);
831
- let length = 0;
880
+ let endValue = 0;
832
881
  let lastDiscontinuity = 0;
833
882
  if (currentVod) {
834
- length = currentVod.getLiveMediaSequencesCount();
883
+ if (currentVod.sequenceAlwaysContainNewSegments) {
884
+ endValue = currentVod.getLastSequenceMediaSequenceValue();
885
+ } else {
886
+ endValue = currentVod.getLiveMediaSequencesCount();
887
+ }
835
888
  lastDiscontinuity = currentVod.getLastDiscontinuity();
836
889
  }
837
890
  await this._sessionState.set("vodMediaSeqVideo", 0);
838
891
  await this._sessionState.set("vodMediaSeqAudio", 0);
839
892
  await this._sessionState.set("state", SessionState.VOD_NEXT_INITIATING);
840
893
  await this._sessionState.setCurrentVod(slateVod);
841
- await this._sessionState.set("mediaSeq", sessionState.mediaSeq + length);
894
+ await this._sessionState.set("mediaSeq", sessionState.mediaSeq + endValue);
842
895
  await this._sessionState.set("discSeq", sessionState.discSeq + lastDiscontinuity);
843
896
  await this._sessionState.set("slateCount", sessionState.slateCount + 1);
844
897
  await this._playheadState.set("playheadRef", Date.now());
@@ -891,7 +944,8 @@ class Session {
891
944
  let loadPromise;
892
945
  if (!vodResponse.type) {
893
946
  debug(`[${this._sessionId}]: got first VOD uri=${vodResponse.uri}:${vodResponse.offset || 0}`);
894
- newVod = new HLSVod(vodResponse.uri, [], null, vodResponse.offset * 1000, m3u8Header(this._instanceId));
947
+ const hlsOpts = { sequenceAlwaysContainNewSegments: this.alwaysNewSegments };
948
+ newVod = new HLSVod(vodResponse.uri, [], null, vodResponse.offset * 1000, m3u8Header(this._instanceId), hlsOpts);
895
949
  if (vodResponse.timedMetadata) {
896
950
  Object.keys(vodResponse.timedMetadata).map(k => {
897
951
  newVod.addMetadata(k, vodResponse.timedMetadata[k]);
@@ -961,6 +1015,9 @@ class Session {
961
1015
  if (this.prevVodMediaSeq.video === null) {
962
1016
  this.prevVodMediaSeq.video = sessionState.vodMediaSeqVideo;
963
1017
  }
1018
+ if (this.prevMediaSeqOffset.video === null) {
1019
+ this.prevMediaSeqOffset.video = sessionState.mediaSeq;
1020
+ }
964
1021
  // Clear Cache if prev count is HIGHER than current...
965
1022
  if (sessionState.vodMediaSeqVideo < this.prevVodMediaSeq.video) {
966
1023
  debug(`[${this._sessionId}]: state=VOD_PLAYING, current[${sessionState.vodMediaSeqVideo}], prev[${this.prevVodMediaSeq.video}], total[${currentVod.getLiveMediaSequencesCount()}]`);
@@ -970,8 +1027,9 @@ class Session {
970
1027
  }
971
1028
  } else {
972
1029
  // Handle edge case where Leader loaded next vod but Follower remained in state=VOD_PLAYING
973
- if (this.prevVodMediaSeq.video !== null & sessionState.vodMediaSeqVideo < this.prevVodMediaSeq.video) {
1030
+ if (this.prevMediaSeqOffset.video !== null & sessionState.mediaSeq !== this.prevMediaSeqOffset.video) {
974
1031
  debug(`[${this._sessionId}]: state=VOD_PLAYING, current[${sessionState.vodMediaSeqVideo}], prev[${this.prevVodMediaSeq.video}], total[${currentVod.getLiveMediaSequencesCount()}]`);
1032
+ debug(`[${this._sessionId}]: mediaSeq offsets -> current[${sessionState.vodMediaSeqVideo}], prev[${this.prevVodMediaSeq.video}]`);
975
1033
  // Allow Follower to clear VodCache...
976
1034
  this.isAllowedToClearVodCache = true;
977
1035
  }
@@ -996,6 +1054,12 @@ class Session {
996
1054
  return;
997
1055
  }
998
1056
  const length = currentVod.getLiveMediaSequencesCount();
1057
+ let endMseqValue;
1058
+ if (currentVod.sequenceAlwaysContainNewSegments) {
1059
+ endMseqValue = currentVod.getLastSequenceMediaSequenceValue();
1060
+ } else {
1061
+ endMseqValue = currentVod.getLiveMediaSequencesCount();
1062
+ }
999
1063
  const lastDiscontinuity = currentVod.getLastDiscontinuity();
1000
1064
  sessionState.state = await this._sessionState.set("state", SessionState.VOD_NEXT_INITIATING);
1001
1065
  let vodPromise = this._getNextVod();
@@ -1013,7 +1077,8 @@ class Session {
1013
1077
  let loadPromise;
1014
1078
  if (!vodResponse.type) {
1015
1079
  debug(`[${this._sessionId}]: got next VOD uri=${vodResponse.uri}:${vodResponse.offset}`);
1016
- newVod = new HLSVod(vodResponse.uri, null, null, vodResponse.offset * 1000, m3u8Header(this._instanceId));
1080
+ const hlsOpts = { sequenceAlwaysContainNewSegments: this.alwaysNewSegments };
1081
+ newVod = new HLSVod(vodResponse.uri, null, null, vodResponse.offset * 1000, m3u8Header(this._instanceId), hlsOpts);
1017
1082
  if (vodResponse.timedMetadata) {
1018
1083
  Object.keys(vodResponse.timedMetadata).map(k => {
1019
1084
  newVod.addMetadata(k, vodResponse.timedMetadata[k]);
@@ -1049,10 +1114,10 @@ class Session {
1049
1114
  debug(`[${this._sessionId}]: ${newVod.getPlayheadPositions()}`);
1050
1115
  currentVod = newVod;
1051
1116
  debug(`[${this._sessionId}]: msequences=${currentVod.getLiveMediaSequencesCount()}`);
1117
+ sessionState.mediaSeq = await this._sessionState.set("mediaSeq", sessionState.mediaSeq + endMseqValue);
1118
+ sessionState.discSeq = await this._sessionState.set("discSeq", sessionState.discSeq + lastDiscontinuity);
1052
1119
  sessionState.vodMediaSeqVideo = await this._sessionState.set("vodMediaSeqVideo", 0);
1053
1120
  sessionState.vodMediaSeqAudio = await this._sessionState.set("vodMediaSeqAudio", 0);
1054
- sessionState.mediaSeq = await this._sessionState.set("mediaSeq", sessionState.mediaSeq + length);
1055
- sessionState.discSeq = await this._sessionState.set("discSeq", sessionState.discSeq + lastDiscontinuity);
1056
1121
  debug(`[${this._sessionId}]: new sequence data set in store [${sessionState.mediaSeq}][${sessionState.discSeq}]`);
1057
1122
  await this._sessionState.remove("nextVod");
1058
1123
  sessionState.currentVod = await this._sessionState.setCurrentVod(currentVod, { ttl: currentVod.getDuration() * 1000 });
@@ -1103,7 +1168,12 @@ class Session {
1103
1168
  sessionState.state = await this._sessionState.set("state", SessionState.VOD_RELOAD_INITIATING);
1104
1169
 
1105
1170
  // 2) Set new 'offset' sequences, to carry on the continuity from session-live
1106
- const mSeq = this.switchDataForSession.mediaSeq;
1171
+ let mSeq = this.switchDataForSession.mediaSeq;
1172
+ let currentVod = await this._sessionState.getCurrentVod();
1173
+ if (currentVod.sequenceAlwaysContainNewSegments) {
1174
+ // (!) will need to compensate if using this setting on HLSVod Object.
1175
+ mSeq -= 1;
1176
+ }
1107
1177
  const dSeq = this.switchDataForSession.discSeq;
1108
1178
  const mSeqOffset = this.switchDataForSession.mediaSeqOffset;
1109
1179
  const reloadBehind = this.switchDataForSession.reloadBehind;
@@ -1122,15 +1192,14 @@ class Session {
1122
1192
  // 3) Set new media segments/currentVod, to carry on the continuity from session-live
1123
1193
  debug(`[${this._sessionId}]: LEADER: making changes to current VOD. I will also update currentVod in store.`);
1124
1194
  const playheadState = await this._playheadState.getValues(["vodMediaSeqVideo"]);
1125
- let currentVod = await this._sessionState.getCurrentVod();
1126
- let currentMseq = playheadState.vodMediaSeqVideo + mSeqOffset;
1127
- if (currentMseq > currentVod.getLiveMediaSequencesCount() - 1) {
1128
- currentMseq = currentVod.getLiveMediaSequencesCount() - 1;
1195
+ let nextMseq = playheadState.vodMediaSeqVideo + 1;
1196
+ if (nextMseq > currentVod.getLiveMediaSequencesCount() - 1) {
1197
+ nextMseq = currentVod.getLiveMediaSequencesCount() - 1;
1129
1198
  }
1130
1199
 
1131
1200
  // TODO: Support reloading with audioSegments as well
1132
1201
 
1133
- await currentVod.reload(currentMseq, segments, null, reloadBehind);
1202
+ await currentVod.reload(nextMseq, segments, null, reloadBehind);
1134
1203
  await this._sessionState.setCurrentVod(currentVod, { ttl: currentVod.getDuration() * 1000 });
1135
1204
  await this._sessionState.set("vodReloaded", 1);
1136
1205
  await this._sessionState.set("vodMediaSeqVideo", 0);
@@ -1210,7 +1279,8 @@ class Session {
1210
1279
 
1211
1280
  slateVod.load()
1212
1281
  .then(() => {
1213
- hlsVod = new HLSVod(this.slateUri, null, null, null, m3u8Header(this._instanceId));
1282
+ const hlsOpts = { sequenceAlwaysContainNewSegments: this.alwaysNewSegments };
1283
+ hlsVod = new HLSVod(this.slateUri, null, null, null, m3u8Header(this._instanceId), hlsOpts);
1214
1284
  const timestamp = Date.now();
1215
1285
  hlsVod.addMetadata('id', `slate-${timestamp}`);
1216
1286
  hlsVod.addMetadata('start-date', new Date(timestamp).toISOString());
@@ -1254,7 +1324,8 @@ class Session {
1254
1324
 
1255
1325
  slateVod.load()
1256
1326
  .then(() => {
1257
- hlsVod = new HLSVod(nexVodUri, null, null, null, m3u8Header(this._instanceId));
1327
+ const hlsOpts = { sequenceAlwaysContainNewSegments: this.alwaysNewSegments };
1328
+ hlsVod = new HLSVod(nexVodUri, null, null, null, m3u8Header(this._instanceId), hlsOpts);
1258
1329
  const timestamp = Date.now();
1259
1330
  hlsVod.addMetadata('id', `slate-${timestamp}`);
1260
1331
  hlsVod.addMetadata('start-date', new Date(timestamp).toISOString());
@@ -542,7 +542,7 @@ class SessionLive {
542
542
  this.blockGenerateManifest = false;
543
543
  }
544
544
 
545
- let attempts = 5;
545
+ let attempts = 10;
546
546
  // CHECK AGAIN CASE 1: Store Empty
547
547
  while (!leadersMediaSeqRaw && attempts > 0) {
548
548
  const segDur = this._getAnyFirstSegmentDurationMs() || DEFAULT_PLAYHEAD_INTERVAL_MS;
@@ -565,7 +565,7 @@ class SessionLive {
565
565
  }
566
566
  }
567
567
 
568
- attempts = 5;
568
+ attempts = 10;
569
569
  // CHECK AGAIN CASE 2: Store Old
570
570
  while (leadersMediaSeqRaw <= this.lastRequestedMediaSeqRaw && attempts > 0) {
571
571
  const segDur = this._getAnyFirstSegmentDurationMs() || DEFAULT_PLAYHEAD_INTERVAL_MS;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eyevinn-channel-engine",
3
- "version": "3.2.7",
3
+ "version": "3.3.0",
4
4
  "description": "OTT TV Channel Engine",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -22,7 +22,7 @@
22
22
  "dependencies": {
23
23
  "@eyevinn/hls-repeat": "^0.1.1",
24
24
  "@eyevinn/hls-truncate": "^0.1.0",
25
- "@eyevinn/hls-vodtolive": "^1.17.1",
25
+ "@eyevinn/hls-vodtolive": "^2.0.0",
26
26
  "@eyevinn/m3u8": "^0.4.1",
27
27
  "abort-controller": "^3.0.0",
28
28
  "debug": "^3.2.7",
package/server.js CHANGED
@@ -100,4 +100,4 @@ const engineOptions = {
100
100
 
101
101
  const engine = new ChannelEngine(refAssetManager, engineOptions);
102
102
  engine.start();
103
- engine.listen(process.env.port || 8000);
103
+ engine.listen(process.env.PORT || 8000);
@@ -413,12 +413,14 @@ describe("The initialize switching", () => {
413
413
  uri: "http://mock.mock.com/180000/seg12.ts",
414
414
  });
415
415
  expect(sessionCurrentSegs["1313000"][size - 1 - 2]).toEqual({
416
- discontinuity: true,
417
- cue: { in: true },
416
+ duration: 7.5,
417
+ timelinePosition: null,
418
+ uri: 'https://maitv-vod.lab.eyevinn.technology/tearsofsteel_4k.mov/600/600-00008.ts',
419
+ cue: null
418
420
  });
419
421
  expect(sessionCurrentSegs["1313000"][size - 1]).toEqual({
420
422
  duration: 7.5,
421
- uri: "https://maitv-vod.lab.eyevinn.technology/tearsofsteel_4k.mov/600/600-00016.ts",
423
+ uri: "https://maitv-vod.lab.eyevinn.technology/tearsofsteel_4k.mov/600/600-00010.ts",
422
424
  timelinePosition: null,
423
425
  cue: null,
424
426
  });
@@ -469,7 +471,7 @@ describe("The initialize switching", () => {
469
471
  const size = sessionCurrentSegs["1313000"].length;
470
472
  expect(sessionCurrentSegs["1313000"][0]).toEqual({
471
473
  duration: 7.5,
472
- uri: "https://maitv-vod.lab.eyevinn.technology/tearsofsteel_4k.mov/600/600-00011.ts",
474
+ uri: "https://maitv-vod.lab.eyevinn.technology/tearsofsteel_4k.mov/600/600-00012.ts",
473
475
  timelinePosition: null,
474
476
  cue: null,
475
477
  });
@@ -745,41 +747,41 @@ describe("The initialize switching", () => {
745
747
  const borderSegment = newVodSegments["1313000"][6];
746
748
 
747
749
  const expectedLastVODSegItem = {
748
- duration: 7.2,
749
- uri: "https://maitv-vod.lab.eyevinn.technology/MORBIUS_Trailer_2020.mp4/1000/1000-00008.ts",
750
- timelinePosition: null,
751
- cue: null,
750
+ discontinuity: true,
751
+ daterange: null
752
752
  }
753
753
  const expectedFirstV2LSegItem = {
754
- duration: 10.846444,
755
- uri: "https://maitv-vod.lab.eyevinn.technology/VINN.mp4/600/600-00000.ts",
754
+ duration: 7.2,
756
755
  timelinePosition: null,
757
756
  cue: null,
757
+ uri: 'https://maitv-vod.lab.eyevinn.technology/VINN.mp4/600/600-00001.ts'
758
758
  }
759
759
  const expectedSecondVODSegItem = {
760
760
  duration: 7.5075,
761
- uri: "https://maitv-vod.lab.eyevinn.technology/BECKY_Trailer_2020.mp4/600/600-00001.ts",
761
+ uri: "https://maitv-vod.lab.eyevinn.technology/BECKY_Trailer_2020.mp4/1000/1000-00001.ts",
762
762
  timelinePosition: null,
763
763
  cue: null,
764
764
  }
765
765
 
766
766
  expect(newVodSegments["1313000"][0]).toEqual(expectedLastVODSegItem);
767
767
  expect(newVodSegments["1313000"][1]).toEqual({
768
- discontinuity: true,
769
- daterange: null,
768
+ duration: 10.846444,
769
+ timelinePosition: null,
770
+ cue: null,
771
+ uri: 'https://maitv-vod.lab.eyevinn.technology/VINN.mp4/600/600-00000.ts'
770
772
  });
771
773
  expect(newVodSegments["1313000"][2]).toEqual(expectedFirstV2LSegItem);
772
- expect(newVodSegments["1313000"][5]).toEqual({
773
- discontinuity: true,
774
- cue: { in: true },
775
- });
774
+ // expect(newVodSegments["1313000"][5]).toEqual({
775
+ // discontinuity: true,
776
+ // cue: { in: true },
777
+ // });
776
778
  expect(borderSegment.daterange["planned-duration"]).toEqual(vodEventDurationMs2 / 1000);
777
779
  expect("start-date" in borderSegment.daterange).toBe(true);
778
780
  expect("id" in borderSegment.daterange).toBe(true);
779
- expect(borderSegment.duration).toEqual(11.3077);
781
+ expect(borderSegment.duration).toEqual(11.3447);
780
782
  expect(borderSegment.timelinePosition).toEqual(null);
781
783
  expect(borderSegment.cue).toEqual(null);
782
- expect(borderSegment.uri).toEqual("https://maitv-vod.lab.eyevinn.technology/BECKY_Trailer_2020.mp4/600/600-00000.ts");
784
+ expect(borderSegment.uri).toEqual("https://maitv-vod.lab.eyevinn.technology/BECKY_Trailer_2020.mp4/1000/1000-00000.ts");
783
785
  expect(newVodSegments["1313000"][7]).toEqual(expectedSecondVODSegItem);
784
786
  });
785
787