eyevinn-channel-engine 3.3.3 → 3.3.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.
- package/Dockerfile +1 -1
- package/engine/session.js +15 -13
- package/engine/session_live.js +82 -38
- package/engine/stream_switcher.js +10 -7
- package/package.json +1 -1
package/Dockerfile
CHANGED
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}]: [${
|
|
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
|
-
|
|
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
|
-
//
|
|
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`);
|
package/engine/session_live.js
CHANGED
|
@@ -85,7 +85,7 @@ class SessionLive {
|
|
|
85
85
|
if (resetDelay === null || resetDelay < 0) {
|
|
86
86
|
resetDelay = RESET_DELAY;
|
|
87
87
|
}
|
|
88
|
-
|
|
88
|
+
debug(`[${this.instanceId}][${this.sessionId}]: LEADER: Resetting SessionLive values in Store ${resetDelay === 0 ? "Immediately" : `after a delay=(${resetDelay}ms)`}`);
|
|
89
89
|
await timer(resetDelay);
|
|
90
90
|
await this.sessionLiveState.set("liveSegsForFollowers", null);
|
|
91
91
|
await this.sessionLiveState.set("lastRequestedMediaSeqRaw", null);
|
|
@@ -95,7 +95,7 @@ class SessionLive {
|
|
|
95
95
|
mediaSeqCount: null,
|
|
96
96
|
discSeqCount: null,
|
|
97
97
|
});
|
|
98
|
-
debug(`[${this.instanceId}][${this.sessionId}]: LEADER:
|
|
98
|
+
debug(`[${this.instanceId}][${this.sessionId}]: LEADER: SessionLive values in Store have now been reset!`);
|
|
99
99
|
}
|
|
100
100
|
|
|
101
101
|
async resetSession() {
|
|
@@ -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
|
-
|
|
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
|
-
|
|
261
|
-
|
|
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
|
-
|
|
278
|
+
if (!cueInExists) {
|
|
279
|
+
segments[bw][endIdx]["cue"] = { in: true };
|
|
280
|
+
}
|
|
264
281
|
}
|
|
265
282
|
}
|
|
266
283
|
} else {
|
|
@@ -545,6 +562,18 @@ class SessionLive {
|
|
|
545
562
|
let attempts = 10;
|
|
546
563
|
// CHECK AGAIN CASE 1: Store Empty
|
|
547
564
|
while (!leadersMediaSeqRaw && attempts > 0) {
|
|
565
|
+
if (!leadersMediaSeqRaw) {
|
|
566
|
+
isLeader = await this.sessionLiveStateStore.isLeader(this.instanceId);
|
|
567
|
+
if (isLeader) {
|
|
568
|
+
debug(`[${this.instanceId}]: I'm the new leader`);
|
|
569
|
+
return;
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
if (!this.allowedToSet) {
|
|
574
|
+
debug(`[${this.sessionId}]: We are about to switch away from LIVE. Abort fetching from Store`);
|
|
575
|
+
break;
|
|
576
|
+
}
|
|
548
577
|
const segDur = this._getAnyFirstSegmentDurationMs() || DEFAULT_PLAYHEAD_INTERVAL_MS;
|
|
549
578
|
const waitTimeMs = parseInt(segDur / 3, 10);
|
|
550
579
|
debug(`[${this.sessionId}]: FOLLOWER: Leader has not put anything in store... Will check again in ${waitTimeMs}ms (Tries left=[${attempts}])`);
|
|
@@ -555,19 +584,25 @@ class SessionLive {
|
|
|
555
584
|
}
|
|
556
585
|
|
|
557
586
|
if (!leadersMediaSeqRaw) {
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
debug(`[${this.instanceId}]: I'm the new leader`);
|
|
561
|
-
return;
|
|
562
|
-
} else {
|
|
563
|
-
debug(`[${this.instanceId}]: The leader is still alive`);
|
|
564
|
-
return;
|
|
565
|
-
}
|
|
587
|
+
debug(`[${this.instanceId}]: The leader is still alive`);
|
|
588
|
+
return;
|
|
566
589
|
}
|
|
567
590
|
|
|
568
591
|
attempts = 10;
|
|
569
592
|
// CHECK AGAIN CASE 2: Store Old
|
|
570
593
|
while (leadersMediaSeqRaw <= this.lastRequestedMediaSeqRaw && attempts > 0) {
|
|
594
|
+
if (!this.allowedToSet) {
|
|
595
|
+
debug(`[${this.sessionId}]: We are about to switch away from LIVE. Abort fetching from Store`);
|
|
596
|
+
break;
|
|
597
|
+
}
|
|
598
|
+
if (leadersMediaSeqRaw <= this.lastRequestedMediaSeqRaw) {
|
|
599
|
+
isLeader = await this.sessionLiveStateStore.isLeader(this.instanceId);
|
|
600
|
+
if (isLeader) {
|
|
601
|
+
debug(`[${this.instanceId}][${this.sessionId}]: I'm the new leader`);
|
|
602
|
+
return;
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
|
|
571
606
|
const segDur = this._getAnyFirstSegmentDurationMs() || DEFAULT_PLAYHEAD_INTERVAL_MS;
|
|
572
607
|
const waitTimeMs = parseInt(segDur / 3, 10);
|
|
573
608
|
debug(`[${this.sessionId}]: FOLLOWER: Cannot find anything NEW in store... Will check again in ${waitTimeMs}ms (Tries left=[${attempts}])`);
|
|
@@ -576,18 +611,10 @@ class SessionLive {
|
|
|
576
611
|
leadersMediaSeqRaw = await this.sessionLiveState.get("lastRequestedMediaSeqRaw");
|
|
577
612
|
attempts--;
|
|
578
613
|
}
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
if (isLeader) {
|
|
583
|
-
debug(`[${this.instanceId}][${this.sessionId}]: I'm the new leader`);
|
|
584
|
-
return;
|
|
585
|
-
} else {
|
|
586
|
-
debug(`[${this.instanceId}][${this.sessionId}]: The leader is still alive`);
|
|
587
|
-
return;
|
|
588
|
-
}
|
|
614
|
+
if(leadersMediaSeqRaw <= this.lastRequestedMediaSeqRaw) {
|
|
615
|
+
debug(`[${this.instanceId}][${this.sessionId}]: The leader is still alive`);
|
|
616
|
+
return;
|
|
589
617
|
}
|
|
590
|
-
|
|
591
618
|
// Follower updates its manifest building blocks (segment holders & counts)
|
|
592
619
|
this.lastRequestedMediaSeqRaw = leadersMediaSeqRaw;
|
|
593
620
|
this.liveSegsForFollowers = await this.sessionLiveState.get("liveSegsForFollowers");
|
|
@@ -601,7 +628,7 @@ class SessionLive {
|
|
|
601
628
|
// ---------------------------------
|
|
602
629
|
let FETCH_ATTEMPTS = 10;
|
|
603
630
|
this.liveSegsForFollowers = {};
|
|
604
|
-
|
|
631
|
+
let bandwidthsToSkipOnRetry = [];
|
|
605
632
|
while (FETCH_ATTEMPTS > 0) {
|
|
606
633
|
if (isLeader) {
|
|
607
634
|
debug(`[${this.sessionId}]: LEADER: Trying to fetch manifests for all bandwidths\n Attempts left=[${FETCH_ATTEMPTS}]`);
|
|
@@ -619,9 +646,15 @@ class SessionLive {
|
|
|
619
646
|
let manifestList = [];
|
|
620
647
|
this.pushAmount = 0;
|
|
621
648
|
try {
|
|
649
|
+
if (bandwidthsToSkipOnRetry.length > 0) {
|
|
650
|
+
debug(`[${this.sessionId}]: (X) Skipping loadMedia promises for bws ${JSON.stringify(bandwidthsToSkipOnRetry)}`);
|
|
651
|
+
}
|
|
622
652
|
// Collect Live Source Requesting Promises
|
|
623
653
|
for (let i = 0; i < Object.keys(this.mediaManifestURIs).length; i++) {
|
|
624
654
|
let bw = Object.keys(this.mediaManifestURIs)[i];
|
|
655
|
+
if (bandwidthsToSkipOnRetry.includes(bw)) {
|
|
656
|
+
continue;
|
|
657
|
+
}
|
|
625
658
|
livePromises.push(this._loadMediaManifest(bw));
|
|
626
659
|
debug(`[${this.sessionId}]: Pushed loadMedia promise for bw=[${bw}]`);
|
|
627
660
|
}
|
|
@@ -642,16 +675,28 @@ class SessionLive {
|
|
|
642
675
|
continue;
|
|
643
676
|
}
|
|
644
677
|
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
678
|
+
// Store the results locally
|
|
679
|
+
manifestList.forEach((variantItem) => {
|
|
680
|
+
const bw = variantItem.value.bandwidth;
|
|
681
|
+
if (!this.liveSourceM3Us[bw]) {
|
|
682
|
+
this.liveSourceM3Us[bw] = {};
|
|
648
683
|
}
|
|
649
|
-
|
|
684
|
+
this.liveSourceM3Us[bw] = variantItem.value;
|
|
650
685
|
});
|
|
651
686
|
|
|
687
|
+
const allStoredMediaSeqCounts = Object.keys(this.liveSourceM3Us).map((variant) => this.liveSourceM3Us[variant].mediaSeq);
|
|
688
|
+
|
|
652
689
|
// Handle if mediaSeqCounts are NOT synced up!
|
|
653
|
-
if (!
|
|
654
|
-
debug(`[${this.sessionId}]: Live Mseq counts=[${
|
|
690
|
+
if (!allStoredMediaSeqCounts.every((val, i, arr) => val === arr[0])) {
|
|
691
|
+
debug(`[${this.sessionId}]: Live Mseq counts=[${allStoredMediaSeqCounts}]`);
|
|
692
|
+
// Figure out what bw's are behind.
|
|
693
|
+
const higestMediaSeqCount = Math.max(...allStoredMediaSeqCounts);
|
|
694
|
+
bandwidthsToSkipOnRetry = Object.keys(this.liveSourceM3Us).filter((bw) => {
|
|
695
|
+
if (this.liveSourceM3Us[bw].mediaSeq === higestMediaSeqCount) {
|
|
696
|
+
return true;
|
|
697
|
+
}
|
|
698
|
+
return false;
|
|
699
|
+
});
|
|
655
700
|
// Decrement fetch counter
|
|
656
701
|
FETCH_ATTEMPTS--;
|
|
657
702
|
// Calculate retry delay time. Default=1000
|
|
@@ -672,7 +717,7 @@ class SessionLive {
|
|
|
672
717
|
continue;
|
|
673
718
|
}
|
|
674
719
|
|
|
675
|
-
currentMseqRaw =
|
|
720
|
+
currentMseqRaw = allStoredMediaSeqCounts[0];
|
|
676
721
|
|
|
677
722
|
if (!isLeader) {
|
|
678
723
|
let leadersFirstSeqCounts = await this.sessionLiveState.get("firstCounts");
|
|
@@ -733,7 +778,6 @@ class SessionLive {
|
|
|
733
778
|
if (currentMseqRaw === leadersFirstSeqCounts.liveSourceMseqCount) {
|
|
734
779
|
this.pushAmount = 1; // Follower from start
|
|
735
780
|
} else {
|
|
736
|
-
|
|
737
781
|
// TODO: To support and account for past discontinuity tags in the Live Source stream,
|
|
738
782
|
// we will need to get the real 'current' discontinuity-sequence count from Leader somehow.
|
|
739
783
|
|
|
@@ -773,7 +817,7 @@ class SessionLive {
|
|
|
773
817
|
const leadersCurrentMseqRaw = await this.sessionLiveState.get("lastRequestedMediaSeqRaw");
|
|
774
818
|
const counts = await this.sessionLiveState.get("firstCounts");
|
|
775
819
|
const leadersFirstMseqRaw = counts.liveSourceMseqCount;
|
|
776
|
-
if (leadersCurrentMseqRaw !== null && leadersCurrentMseqRaw
|
|
820
|
+
if (leadersCurrentMseqRaw !== null && leadersCurrentMseqRaw > currentMseqRaw) {
|
|
777
821
|
// if leader never had any segs from prev mseq
|
|
778
822
|
if (leadersFirstMseqRaw !== null && leadersFirstMseqRaw === leadersCurrentMseqRaw) {
|
|
779
823
|
// Follower updates it's manifest ingedients (segment holders & counts)
|
|
@@ -821,8 +865,8 @@ class SessionLive {
|
|
|
821
865
|
// Do not replace old data with empty data
|
|
822
866
|
if (segListSize > 0) {
|
|
823
867
|
debug(`[${this.sessionId}]: LEADER: Adding data to store!`);
|
|
824
|
-
await this.sessionLiveState.set("liveSegsForFollowers", this.liveSegsForFollowers);
|
|
825
868
|
await this.sessionLiveState.set("lastRequestedMediaSeqRaw", this.lastRequestedMediaSeqRaw);
|
|
869
|
+
await this.sessionLiveState.set("liveSegsForFollowers", this.liveSegsForFollowers);
|
|
826
870
|
}
|
|
827
871
|
}
|
|
828
872
|
|
|
@@ -1030,8 +1074,8 @@ class SessionLive {
|
|
|
1030
1074
|
const resolveObj = {
|
|
1031
1075
|
M3U: m3u,
|
|
1032
1076
|
mediaSeq: m3u.get("mediaSequence"),
|
|
1077
|
+
bandwidth: liveTargetBandwidth,
|
|
1033
1078
|
};
|
|
1034
|
-
this.liveSourceM3Us[liveTargetBandwidth] = resolveObj;
|
|
1035
1079
|
resolve(resolveObj);
|
|
1036
1080
|
} catch (exc) {
|
|
1037
1081
|
debug(`[${this.sessionId}]: Error when parsing latest manifest`);
|
|
@@ -307,9 +307,6 @@ class StreamSwitcher {
|
|
|
307
307
|
liveSegments = await sessionLive.getCurrentMediaSequenceSegments();
|
|
308
308
|
liveCounts = await sessionLive.getCurrentMediaAndDiscSequenceCount();
|
|
309
309
|
|
|
310
|
-
await sessionLive.resetSession();
|
|
311
|
-
sessionLive.resetLiveStoreAsync(RESET_DELAY); // In parallel
|
|
312
|
-
|
|
313
310
|
if (scheduleObj && !scheduleObj.duration) {
|
|
314
311
|
debug(`[${this.sessionId}]: Cannot switch VOD. No duration specified for schedule item: [${scheduleObj.assetId}]`);
|
|
315
312
|
}
|
|
@@ -331,6 +328,9 @@ class StreamSwitcher {
|
|
|
331
328
|
await session.setCurrentMediaAndDiscSequenceCount(liveCounts.mediaSeq, liveCounts.discSeq);
|
|
332
329
|
await session.setCurrentMediaSequenceSegments(liveSegments.currMseqSegs, liveSegments.segCount);
|
|
333
330
|
|
|
331
|
+
await sessionLive.resetSession();
|
|
332
|
+
sessionLive.resetLiveStoreAsync(RESET_DELAY); // In parallel
|
|
333
|
+
|
|
334
334
|
this.working = false;
|
|
335
335
|
this.streamTypeLive = false;
|
|
336
336
|
debug(`[${this.sessionId}]: [ Switched from LIVE->V2L ]`);
|
|
@@ -349,8 +349,6 @@ class StreamSwitcher {
|
|
|
349
349
|
this.eventId = scheduleObj.eventId;
|
|
350
350
|
liveSegments = await sessionLive.getCurrentMediaSequenceSegments();
|
|
351
351
|
liveCounts = await sessionLive.getCurrentMediaAndDiscSequenceCount();
|
|
352
|
-
await sessionLive.resetSession();
|
|
353
|
-
sessionLive.resetLiveStoreAsync(RESET_DELAY); // In parallel
|
|
354
352
|
|
|
355
353
|
eventSegments = await session.getTruncatedVodSegments(scheduleObj.uri, scheduleObj.duration / 1000);
|
|
356
354
|
if (!eventSegments) {
|
|
@@ -369,9 +367,11 @@ class StreamSwitcher {
|
|
|
369
367
|
const prerollSegments = this.prerollsCache[this.sessionId].segments;
|
|
370
368
|
eventSegments = this._mergeSegments(prerollSegments, eventSegments, true);
|
|
371
369
|
}
|
|
372
|
-
|
|
373
370
|
await session.setCurrentMediaSequenceSegments(eventSegments, 0, true);
|
|
374
371
|
|
|
372
|
+
await sessionLive.resetSession();
|
|
373
|
+
sessionLive.resetLiveStoreAsync(RESET_DELAY); // In parallel
|
|
374
|
+
|
|
375
375
|
this.working = false;
|
|
376
376
|
this.streamTypeLive = false;
|
|
377
377
|
debug(`[${this.sessionId}]: Switched from LIVE->VOD`);
|
|
@@ -626,7 +626,10 @@ 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
|
+
OUTPUT_SEGMENTS[bw] = toSegments[bw].concat(fromSegments[targetBw]);
|
|
631
|
+
} else if (lastSeg.discontinuity && !lastSeg.cue) {
|
|
632
|
+
toSegments[bw][toSegments[bw].length - 1].cue = { in: true }
|
|
630
633
|
OUTPUT_SEGMENTS[bw] = toSegments[bw].concat(fromSegments[targetBw]);
|
|
631
634
|
} else {
|
|
632
635
|
OUTPUT_SEGMENTS[bw] = toSegments[bw].concat(fromSegments[targetBw]);
|