eyevinn-channel-engine 3.1.5 → 3.1.8

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
@@ -43,7 +43,20 @@ class Session {
43
43
  this.playheadDiffThreshold = DEFAULT_PLAYHEAD_DIFF_THRESHOLD;
44
44
  this.maxTickInterval = DEFAULT_MAX_TICK_INTERVAL;
45
45
  this.diffCompensation = null;
46
+ this.prevVodMediaSeq = {
47
+ video: null,
48
+ audio: null
49
+ }
46
50
  this.waitingForNextVod = false;
51
+ this.leaderIsSettingNextVod = false;
52
+ this.isSwitchingBackToV2L = false;
53
+ this.switchDataForSession = {
54
+ mediaSeq: null,
55
+ discSeq: null,
56
+ mediaSeqOffset: null,
57
+ transitionSegments: null,
58
+ reloadBehind: null,
59
+ }
47
60
 
48
61
  if (config) {
49
62
  if (config.sessionId) {
@@ -137,7 +150,14 @@ class Session {
137
150
  state = await this._playheadState.getState();
138
151
 
139
152
  const isLeader = await this._sessionStateStore.isLeader(this._instanceId);
140
- if (isLeader && [SessionState.VOD_NEXT_INIT, SessionState.VOD_NEXT_INITIATING].indexOf(sessionState.state) !== -1) {
153
+ if (isLeader &&
154
+ [
155
+ SessionState.VOD_NEXT_INIT,
156
+ SessionState.VOD_NEXT_INITIATING,
157
+ SessionState.VOD_RELOAD_INIT,
158
+ SessionState.VOD_RELOAD_INITIATING
159
+ ].indexOf(sessionState.state) !== -1) {
160
+
141
161
  const firstDuration = await this._getFirstDuration(manifest);
142
162
  const tickInterval = firstDuration < 2 ? 2 : firstDuration;
143
163
  debug(`[${this._sessionId}]: I am the leader and updated tick interval to ${tickInterval} sec`);
@@ -150,13 +170,13 @@ class Session {
150
170
  } else {
151
171
  const reqTickInterval = playheadState.tickInterval;
152
172
  const timeSpentInIncrement = (tsIncrementEnd - tsIncrementBegin) / 1000;
153
- let tickInterval = (reqTickInterval) - timeSpentInIncrement;
173
+ let tickInterval = reqTickInterval - timeSpentInIncrement;
154
174
  const delta = await this._getCurrentDeltaTime();
155
175
  if (delta != 0) {
156
176
  debug(`[${this._sessionId}]: Delta time is != 0 need will adjust ${delta}sec to tick interval`);
157
177
  tickInterval += delta;
158
178
  }
159
- const position = await this._getCurrentPlayheadPosition() * 1000;
179
+ const position = (await this._getCurrentPlayheadPosition()) * 1000;
160
180
  const timePosition = Date.now() - playheadState.playheadRef;
161
181
  const diff = position - timePosition;
162
182
  debug(`[${this._sessionId}]: ${timePosition}:${position}:${diff > 0 ? '+' : ''}${diff}ms`);
@@ -212,7 +232,7 @@ class Session {
212
232
  if (this.disabledPlayhead) {
213
233
  return {
214
234
  sessionId: this._sessionId,
215
- }
235
+ };
216
236
  } else {
217
237
  const playheadState = await this._playheadState.getValues(["tickMs", "mediaSeq", "vodMediaSeqVideo"]);
218
238
  const state = await this._playheadState.getState();
@@ -241,11 +261,16 @@ class Session {
241
261
  await this._playheadStateStore.reset(this._sessionId);
242
262
  }
243
263
 
264
+ async getSessionState() {
265
+ const state = await this._sessionState.get("state");
266
+ return state;
267
+ }
268
+
244
269
  async getTruncatedVodSegments(vodUri, duration) {
245
270
  try {
246
271
  const hlsVod = await this._truncateSlate(null, duration, vodUri);
247
272
  let vodSegments = hlsVod.getMediaSegments();
248
- Object.keys(vodSegments).forEach(bw => vodSegments[bw].unshift({ discontinuity: true, cue: { in: true } }));
273
+ Object.keys(vodSegments).forEach((bw) => vodSegments[bw].unshift({ discontinuity: true, cue: { in: true } }));
249
274
  return vodSegments;
250
275
  } catch (exc) {
251
276
  debug(`[${this._sessionId}]: Failed to generate truncated VOD!`);
@@ -255,18 +280,25 @@ class Session {
255
280
 
256
281
  async setCurrentMediaSequenceSegments(segments, mSeqOffset, reloadBehind) {
257
282
  if (!this._sessionState) {
258
- throw new Error('Session not ready');
283
+ throw new Error("Session not ready");
259
284
  }
285
+ this.isSwitchingBackToV2L = true;
286
+
287
+ this.switchDataForSession.reloadBehind = reloadBehind;
288
+ this.switchDataForSession.transitionSegments = segments;
289
+ this.switchDataForSession.mediaSeqOffset = mSeqOffset;
260
290
 
261
291
  let isLeader = await this._sessionStateStore.isLeader(this._instanceId);
262
292
  if (!isLeader) {
263
293
  debug(`[${this._sessionId}]: FOLLOWER: Invalidate cache to ensure having the correct VOD!`);
264
294
  await this._sessionState.clearCurrentVodCache();
295
+
265
296
  let vodReloaded = await this._sessionState.get("vodReloaded");
266
297
  let attempts = 9;
267
298
  while (!isLeader && !vodReloaded && attempts > 0) {
268
299
  debug(`[${this._sessionId}]: FOLLOWER: I arrived before LEADER. Waiting (1000ms) for LEADER to reload currentVod in store! (tries left=${attempts})`);
269
300
  await timer(1000);
301
+ await this._sessionStateStore.clearLeaderCache();
270
302
  isLeader = await this._sessionStateStore.isLeader(this._instanceId);
271
303
  vodReloaded = await this._sessionState.get("vodReloaded");
272
304
  attempts--;
@@ -280,38 +312,23 @@ class Session {
280
312
  await this._sessionState.clearCurrentVodCache();
281
313
  return;
282
314
  }
283
- }
315
+ debug(`[${this._sessionId}]: NEW LEADER: Setting state=VOD_RELOAD_INIT`);
316
+ this.isSwitchingBackToV2L = true;
317
+ await this._sessionState.set("state", SessionState.VOD_RELOAD_INIT)
284
318
 
285
- if (isLeader) {
286
- let state = await this._sessionState.get("state");
287
- let ATTEMPTS = 5;
288
- // Do Not want to reload when session is loading next Vod
289
- while (state !== SessionState.VOD_PLAYING && ATTEMPTS > 0) {
290
- debug(`[${this._sessionId}]: LEADER: Wait for session to initialize next VOD. (tries left=${ATTEMPTS})`);
319
+ } else {
320
+ let vodReloaded = await this._sessionState.get("vodReloaded");
321
+ let attempts = 9;
322
+ while (!vodReloaded && attempts > 0) {
323
+ debug(`[${this._sessionId}]: LEADER: Waiting (1000ms) to buy some time reloading vod and adding it to store! (tries left=${attempts})`);
291
324
  await timer(1000);
292
- state = await this._sessionState.get("state");
293
- ATTEMPTS--;
294
- }
295
- if (ATTEMPTS === 0) {
296
- throw new Error("Failed to reload currentVod! Need a new LEADER!");
325
+ vodReloaded = await this._sessionState.get("vodReloaded");
326
+ attempts--;
297
327
  }
298
-
299
- debug(`[${this._sessionId}]: LEADER: making changes to current VOD. I will also update currentVod in store.`);
300
- const playheadState = await this._playheadState.getValues(["vodMediaSeqVideo"]);
301
- let currentVod = await this._sessionState.getCurrentVod();
302
- let currentMseq = playheadState.vodMediaSeqVideo + mSeqOffset;
303
- if (currentMseq > currentVod.getLiveMediaSequencesCount() - 1) {
304
- currentMseq = currentVod.getLiveMediaSequencesCount() - 1;
328
+ if (attempts === 0) {
329
+ debug(`[${this._sessionId}]: LEADER: WARNING! Vod was never Reloaded!`);
330
+ return;
305
331
  }
306
- // TODO: Support reloading with audioSegments as well
307
- await currentVod.reload(currentMseq, segments, null, reloadBehind);
308
- await this._sessionState.setCurrentVod(currentVod, { ttl: (currentVod.getDuration() * 1000) });
309
- await this._sessionState.set("vodReloaded", 1);
310
- await this._sessionState.set("vodMediaSeqVideo", 0);
311
- await this._sessionState.set("vodMediaSeqAudio", 0);
312
- await this._playheadState.set("vodMediaSeqVideo", 0);
313
- await this._playheadState.set("vodMediaSeqAudio", 0);
314
- await this._playheadState.set("playheadRef", Date.now());
315
332
  }
316
333
  }
317
334
 
@@ -323,6 +340,18 @@ class Session {
323
340
  if (isLeader) {
324
341
  await this._sessionState.set("vodReloaded", 0);
325
342
  }
343
+
344
+ // Only read data from store if state is VOD_PLAYING
345
+ let state = await this.getSessionState();
346
+ let tries = 12;
347
+ while (state !== SessionState.VOD_PLAYING && tries > 0) {
348
+ const waitTimeMs = 500;
349
+ debug(`[${this._sessionId}]: state=${state} - Waiting ${waitTimeMs}ms_${tries} until Leader has finished loading next vod.`);
350
+ await timer(waitTimeMs);
351
+ tries--;
352
+ state = await this.getSessionState();
353
+ }
354
+
326
355
  const playheadState = await this._playheadState.getValues(["mediaSeq", "vodMediaSeqVideo"]);
327
356
  if (playheadState.vodMediaSeqVideo === 0) {
328
357
  if (!isLeader) {
@@ -334,7 +363,7 @@ class Session {
334
363
  if (currentVod) {
335
364
  try {
336
365
  const mediaSegments = currentVod.getLiveMediaSequenceSegments(playheadState.vodMediaSeqVideo);
337
- debug(`[${this._sessionId}]: Requesting all segments from Media Sequence: ${playheadState.vodMediaSeqVideo}`);
366
+ debug(`[${this._sessionId}]: Requesting all segments from Media Sequence: ${playheadState.vodMediaSeqVideo}_${currentVod.getLiveMediaSequencesCount()}`);
338
367
  return mediaSegments;
339
368
  } catch (err) {
340
369
  logerror(this._sessionId, err);
@@ -348,21 +377,31 @@ class Session {
348
377
 
349
378
  async setCurrentMediaAndDiscSequenceCount(_mediaSeq, _discSeq) {
350
379
  if (!this._sessionState) {
351
- throw new Error('Session not ready');
352
- }
353
- const isLeader = await this._sessionStateStore.isLeader(this._instanceId);
354
- if (isLeader) {
355
- await this._sessionState.set("mediaSeq", _mediaSeq);
356
- await this._playheadState.set("mediaSeq", _mediaSeq);
357
- await this._sessionState.set("discSeq", _discSeq);
358
- debug(`[${this._sessionId}]: Setting current media and discontinuity count -> [${_mediaSeq}]:[${_discSeq}]`);
380
+ throw new Error("Session not ready");
359
381
  }
382
+
383
+ this.isSwitchingBackToV2L = true;
384
+
385
+ this.switchDataForSession.mediaSeq = _mediaSeq;
386
+ this.switchDataForSession.discSeq = _discSeq;
360
387
  }
361
388
 
362
389
  async getCurrentMediaAndDiscSequenceCount() {
363
390
  if (!this._sessionState) {
364
391
  throw new Error('Session not ready');
365
392
  }
393
+
394
+ // Only read data from store if state is VOD_PLAYING
395
+ let state = await this.getSessionState();
396
+ let tries = 12;
397
+ while (state !== SessionState.VOD_PLAYING && tries > 0) {
398
+ const waitTimeMs = 500;
399
+ debug(`[${this._sessionId}]: state=${state} - Waiting ${waitTimeMs}ms_${tries} until Leader has finished loading next vod.`);
400
+ await timer(waitTimeMs);
401
+ tries--;
402
+ state = await this.getSessionState();
403
+ }
404
+
366
405
  const playheadState = await this._playheadState.getValues(["mediaSeq", "vodMediaSeqVideo"]);
367
406
  const discSeqOffset = await this._sessionState.get("discSeq");
368
407
  if (playheadState.vodMediaSeqVideo === 0) {
@@ -395,33 +434,49 @@ class Session {
395
434
  if (!this._sessionState) {
396
435
  throw new Error('Session not ready');
397
436
  }
437
+ // Be sure that the leader is not in the middle of setting new vod data in store.
438
+ // Followers will never run this part...
439
+ let tries = 12;
440
+ while (tries > 0 && this.leaderIsSettingNextVod) {
441
+ debug(`[${this._sessionId}]: Leader is setting the next vod. Waiting 500ms_${tries}`);
442
+ await timer(500);
443
+ tries--;
444
+ }
445
+
398
446
  const sessionState = await this._sessionState.getValues(["vodMediaSeqVideo", "discSeq"]);
399
447
  const playheadState = await this._playheadState.getValues(["mediaSeq", "vodMediaSeqVideo"]);
400
448
 
449
+ if (this.prevVodMediaSeq.video !== null) {
450
+ this.prevVodMediaSeq.video = playheadState.vodMediaSeqVideo;
451
+ }
452
+
401
453
  if (playheadState.vodMediaSeqVideo > sessionState.vodMediaSeqVideo) {
402
454
  debug(`[${this._sessionId}]: Recently Loaded Next Vod. PlayheadState not up-to-date. Return the last generated m3u8`);
403
455
  const m3u8 = await this._playheadState.getLastM3u8();
404
456
  if (m3u8) {
457
+ this.prevVodMediaSeq.video = playheadState.vodMediaSeqVideo;
405
458
  return m3u8;
406
459
  } else {
407
460
  debug(`[${this._sessionId}]: We don't have any previously generated m3u8`);
408
461
  }
409
462
  }
410
463
 
411
- if (playheadState.vodMediaSeqVideo < 2) {
464
+ if (playheadState.vodMediaSeqVideo < 2 || playheadState.vodMediaSeqVideo < this.prevVodMediaSeq.video) {
465
+ debug(`[${this._sessionId}]: current[${playheadState.vodMediaSeqVideo}]_prev[${this.prevVodMediaSeq.video}]`);
412
466
  const isLeader = await this._sessionStateStore.isLeader(this._instanceId);
413
467
  if (!isLeader) {
414
468
  debug(`[${this._sessionId}]: Not a leader and first|second media sequence in a VOD is requested. Invalidate cache to ensure having the correct VOD.`);
415
469
  await this._sessionState.clearCurrentVodCache(); // force reading up from shared store
416
470
  }
417
471
  }
418
-
472
+
419
473
  const currentVod = await this._sessionState.getCurrentVod();
420
474
  if (currentVod) {
421
475
  try {
422
476
  debug(`[${this._sessionId}]: [${playheadState.vodMediaSeqVideo}]_[${currentVod.getLiveMediaSequencesCount()}]`);
423
477
  const m3u8 = currentVod.getLiveMediaSequences(playheadState.mediaSeq, bw, playheadState.vodMediaSeqVideo, sessionState.discSeq, this.targetDurationPadding, this.forceTargetDuration);
424
478
  debug(`[${this._sessionId}]: [${playheadState.mediaSeq + playheadState.vodMediaSeqVideo}][${sessionState.discSeq}][+${this.targetDurationPadding || 0}] Current media manifest for ${bw} requested`);
479
+ this.prevVodMediaSeq.video = playheadState.vodMediaSeqVideo;
425
480
  return m3u8;
426
481
  } catch (err) {
427
482
  logerror(this._sessionId, err);
@@ -463,6 +518,7 @@ class Session {
463
518
  async incrementAsync() {
464
519
  await this._tickAsync();
465
520
  const isLeader = await this._sessionStateStore.isLeader(this._instanceId);
521
+
466
522
  let sessionState = await this._sessionState.getValues(
467
523
  ["state", "mediaSeq", "discSeq", "vodMediaSeqVideo", "vodMediaSeqAudio"]);
468
524
  let playheadState = await this._playheadState.getValues(["mediaSeq", "vodMediaSeqVideo", "vodMediaSeqAudio"]);
@@ -475,15 +531,17 @@ class Session {
475
531
  sessionState.discSeq === null) {
476
532
  debug(`[${this._sessionId}]: Session is not ready yet`);
477
533
  debug(sessionState);
534
+ await this._sessionState.clearCurrentVodCache();
478
535
  if (isLeader) {
479
536
  debug(`[${this._sessionId}]: I am the leader, trying to initiate the session`);
480
537
  sessionState.state = await this._sessionState.set("state", SessionState.VOD_INIT);
481
538
  }
482
539
  return null;
483
540
  }
484
- if (sessionState.state === SessionState.VOD_NEXT_INITIATING) {
541
+ if (sessionState.state === SessionState.VOD_NEXT_INITIATING || sessionState.state === SessionState.VOD_RELOAD_INITIATING) {
485
542
  if (isLeader) {
486
- debug(`[${this._sessionId}]: I am the leader and have just initiated next VOD, let's move to VOD_PLAYING`);
543
+ const leaderAction = sessionState.state === SessionState.VOD_NEXT_INITIATING ? "initiated" : "reloaded";
544
+ debug(`[${this._sessionId}]: I am the leader and have just ${leaderAction} next VOD, let's move to VOD_PLAYING`);
487
545
  sessionState.state = await this._sessionState.set("state", SessionState.VOD_PLAYING);
488
546
  } else {
489
547
  debug(`[${this._sessionId}]: Return the last generated m3u8 to give the leader some time`);
@@ -498,13 +556,18 @@ class Session {
498
556
  sessionState.vodMediaSeqVideo = await this._sessionState.increment("vodMediaSeqVideo");
499
557
  sessionState.vodMediaSeqAudio = await this._sessionState.increment("vodMediaSeqAudio");
500
558
  }
501
-
559
+
502
560
  if (sessionState.vodMediaSeqVideo >= currentVod.getLiveMediaSequencesCount() - 1) {
503
561
  sessionState.vodMediaSeqVideo = await this._sessionState.set("vodMediaSeqVideo", currentVod.getLiveMediaSequencesCount() - 1);
504
562
  sessionState.vodMediaSeqAudio = await this._sessionState.set("vodMediaSeqAudio", currentVod.getLiveMediaSequencesCount() - 1);
505
563
  sessionState.state = await this._sessionState.set("state", SessionState.VOD_NEXT_INIT);
506
564
  }
507
565
 
566
+ if (this.isSwitchingBackToV2L) {
567
+ sessionState.state = await this._sessionState.set("state", SessionState.VOD_RELOAD_INIT);
568
+ this.isSwitchingBackToV2L = false;
569
+ }
570
+
508
571
  playheadState.mediaSeq = await this._playheadState.set("mediaSeq", sessionState.mediaSeq);
509
572
  playheadState.vodMediaSeqVideo = await this._playheadState.set("vodMediaSeqVideo", sessionState.vodMediaSeqVideo);
510
573
  playheadState.vodMediaSeqAudio = await this._playheadState.set("vodMediaSeqAudio", sessionState.vodMediaSeqAudio);
@@ -782,6 +845,10 @@ class Session {
782
845
  case SessionState.VOD_INIT:
783
846
  case SessionState.VOD_INIT_BY_ID:
784
847
  try {
848
+ // Needed if store was reset
849
+ await this._sessionStateStore.clearLeaderCache();
850
+ isLeader = await this._sessionStateStore.isLeader(this._instanceId);
851
+
785
852
  let nextVodPromise;
786
853
  if (sessionState.state === SessionState.VOD_INIT) {
787
854
  debug(`[${this._sessionId}]: state=VOD_INIT`);
@@ -871,6 +938,17 @@ class Session {
871
938
  currentVod = await this._sessionState.getCurrentVod();
872
939
  this.waitingForNextVod = false;
873
940
  }
941
+ } else {
942
+ // Handle edge case where store has been reset, but leader has not cleared cache.
943
+ if (this.prevVodMediaSeq.video !== null) {
944
+ this.prevVodMediaSeq.video = sessionState.vodMediaSeqVideo;
945
+ }
946
+ if (this.prevVodMediaSeq.video < sessionState.vodMediaSeqVideo) {
947
+ debug(`[${this._sessionId}]: current[${sessionState.vodMediaSeqVideo}], prev[${this.prevVodMediaSeq.video}], total[${currentVod.getLiveMediaSequencesCount()}]`);
948
+ await this._sessionState.clearCurrentVodCache();
949
+ currentVod = await this._sessionState.getCurrentVod();
950
+ this.prevVodMediaSeq.video = sessionState.vodMediaSeqVideo;
951
+ }
874
952
  }
875
953
  debug(`[${this._sessionId}]: state=VOD_PLAYING (${sessionState.vodMediaSeqVideo}_${sessionState.vodMediaSeqAudio}, ${currentVod.getLiveMediaSequencesCount()})`);
876
954
  return;
@@ -943,16 +1021,19 @@ class Session {
943
1021
  await ChaosMonkey.loadVod(loadPromise);
944
1022
  cloudWatchLog(!this.cloudWatchLogging, 'engine-session',
945
1023
  { event: 'loadVod', channel: this._sessionId, loadTimeMs: Date.now() - loadStart });
1024
+ this.leaderIsSettingNextVod = true;
946
1025
  debug(`[${this._sessionId}]: next VOD loaded (${newVod.getDeltaTimes()})`);
947
1026
  debug(`[${this._sessionId}]: ${newVod.getPlayheadPositions()}`);
948
1027
  currentVod = newVod;
949
1028
  debug(`[${this._sessionId}]: msequences=${currentVod.getLiveMediaSequencesCount()}`);
950
- await this._sessionState.remove("nextVod");
951
- sessionState.currentVod = await this._sessionState.setCurrentVod(currentVod, { ttl: currentVod.getDuration() * 1000 });
952
1029
  sessionState.vodMediaSeqVideo = await this._sessionState.set("vodMediaSeqVideo", 0);
953
1030
  sessionState.vodMediaSeqAudio = await this._sessionState.set("vodMediaSeqAudio", 0);
954
1031
  sessionState.mediaSeq = await this._sessionState.set("mediaSeq", sessionState.mediaSeq + length);
955
1032
  sessionState.discSeq = await this._sessionState.set("discSeq", sessionState.discSeq + lastDiscontinuity);
1033
+ debug(`[${this._sessionId}]: new sequence data set in store [${sessionState.mediaSeq}][${sessionState.discSeq}]`);
1034
+ await this._sessionState.remove("nextVod");
1035
+ sessionState.currentVod = await this._sessionState.setCurrentVod(currentVod, { ttl: currentVod.getDuration() * 1000 });
1036
+ this.leaderIsSettingNextVod = false;
956
1037
  await this._playheadState.set("playheadRef", Date.now());
957
1038
  this.produceEvent({
958
1039
  type: 'NOW_PLAYING',
@@ -984,6 +1065,77 @@ class Session {
984
1065
  }
985
1066
  }
986
1067
  break;
1068
+ case SessionState.VOD_RELOAD_INIT:
1069
+ try {
1070
+ debug(`[${this._sessionId}]: state=VOD_RELOAD_INIT`);
1071
+ if (isLeader) {
1072
+
1073
+ const startTS = Date.now();
1074
+
1075
+ // 1) To tell Follower that, Leader is working on it!
1076
+ sessionState.state = await this._sessionState.set("state", SessionState.VOD_RELOAD_INITIATING);
1077
+
1078
+ // 2) Set new 'offset' sequences, to carry on the continuity from session-live
1079
+ const mSeq = this.switchDataForSession.mediaSeq;
1080
+ const dSeq = this.switchDataForSession.discSeq;
1081
+ const mSeqOffset = this.switchDataForSession.mediaSeqOffset;
1082
+ const reloadBehind = this.switchDataForSession.reloadBehind;
1083
+ const segments = this.switchDataForSession.transitionSegments;
1084
+
1085
+ if ([mSeq,dSeq,mSeqOffset,reloadBehind,segments].includes(null)) {
1086
+ debug(`[${this._sessionId}]: LEADER: Cannot Reload VOD, missing switch-back data`);
1087
+ return;
1088
+ }
1089
+
1090
+ await this._sessionState.set("mediaSeq", mSeq);
1091
+ await this._playheadState.set("mediaSeq", mSeq);
1092
+ await this._sessionState.set("discSeq", dSeq);
1093
+ debug(`[${this._sessionId}]: Setting current media and discontinuity count -> [${mSeq}]:[${dSeq}]`);
1094
+
1095
+ // 3) Set new media segments/currentVod, to carry on the continuity from session-live
1096
+ debug(`[${this._sessionId}]: LEADER: making changes to current VOD. I will also update currentVod in store.`);
1097
+ const playheadState = await this._playheadState.getValues(["vodMediaSeqVideo"]);
1098
+ let currentVod = await this._sessionState.getCurrentVod();
1099
+ let currentMseq = playheadState.vodMediaSeqVideo + mSeqOffset;
1100
+ if (currentMseq > currentVod.getLiveMediaSequencesCount() - 1) {
1101
+ currentMseq = currentVod.getLiveMediaSequencesCount() - 1;
1102
+ }
1103
+
1104
+ // TODO: Support reloading with audioSegments as well
1105
+
1106
+ await currentVod.reload(currentMseq, segments, null, reloadBehind);
1107
+ await this._sessionState.setCurrentVod(currentVod, { ttl: currentVod.getDuration() * 1000 });
1108
+ await this._sessionState.set("vodReloaded", 1);
1109
+ await this._sessionState.set("vodMediaSeqVideo", 0);
1110
+ await this._sessionState.set("vodMediaSeqAudio", 0);
1111
+ await this._playheadState.set("vodMediaSeqVideo", 0);
1112
+ await this._playheadState.set("vodMediaSeqAudio", 0);
1113
+ await this._playheadState.set("playheadRef", Date.now());
1114
+ debug(`[${this._sessionId}]: LEADER: Set new Reloaded VOD and vodMediaSeq counts in store.`);
1115
+ // 4) emit cloudwatch event object
1116
+ cloudWatchLog(!this.cloudWatchLogging, "engine-session", { event: "switchback", channel: this._sessionId, reqTimeMs: Date.now() - startTS });
1117
+
1118
+ return;
1119
+ } else {
1120
+ debug(`[${this._sessionId}]: not a leader so will go directly to state VOD_RELOAD_INITIATING`);
1121
+ sessionState.state = await this._sessionState.set("state", SessionState.VOD_RELOAD_INITIATING);
1122
+ }
1123
+ } catch (err) {
1124
+ debug("Failed to init reload vod");
1125
+ throw err;
1126
+ }
1127
+ break;
1128
+ case SessionState.VOD_RELOAD_INITIATING:
1129
+ debug(`[${this._sessionId}]: state=VOD_RELOAD_INITIATING (${sessionState.vodMediaSeqVideo}_${sessionState.vodMediaSeqAudio}, ${currentVod.getLiveMediaSequencesCount()})`);
1130
+ if (!isLeader) {
1131
+ debug(`[${this._sessionId}]: not the leader so just waiting for the VOD to be reloaded`);
1132
+ if (sessionState.vodMediaSeqVideo === 0 || this.waitingForNextVod) {
1133
+ debug(`[${this._sessionId}]: First mediasequence in VOD and I am not the leader so invalidate current VOD cache and fetch the new one from the leader`);
1134
+ await this._sessionState.clearCurrentVodCache();
1135
+ }
1136
+ this.waitingForNextVod = true;
1137
+ }
1138
+ return;
987
1139
  default:
988
1140
  throw new Error("Invalid state: " + sessionState.state);
989
1141
  }