eyevinn-channel-engine 3.3.11 → 3.4.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.
Files changed (53) hide show
  1. package/.github/workflows/publish.yml +5 -3
  2. package/dist/engine/ad_request.d.ts +14 -0
  3. package/dist/engine/ad_request.js +121 -0
  4. package/dist/engine/chaos_monkey.d.ts +1 -0
  5. package/dist/engine/chaos_monkey.js +55 -0
  6. package/dist/engine/event_stream.d.ts +6 -0
  7. package/dist/engine/event_stream.js +20 -0
  8. package/dist/engine/index.d.ts +0 -0
  9. package/dist/engine/index.js +0 -0
  10. package/dist/engine/memcached_state_store.d.ts +12 -0
  11. package/dist/engine/memcached_state_store.js +164 -0
  12. package/dist/engine/memory_state_store.d.ts +11 -0
  13. package/dist/engine/memory_state_store.js +105 -0
  14. package/dist/engine/playhead_state.d.ts +26 -0
  15. package/dist/engine/playhead_state.js +156 -0
  16. package/dist/engine/redis_state_store.d.ts +12 -0
  17. package/dist/engine/redis_state_store.js +236 -0
  18. package/dist/engine/server.d.ts +125 -0
  19. package/dist/engine/server.js +1113 -0
  20. package/dist/engine/session.d.ts +109 -0
  21. package/dist/engine/session.js +2194 -0
  22. package/dist/engine/session_live.d.ts +119 -0
  23. package/dist/engine/session_live.js +1723 -0
  24. package/dist/engine/session_live_state.d.ts +24 -0
  25. package/dist/engine/session_live_state.js +231 -0
  26. package/dist/engine/session_state.d.ts +45 -0
  27. package/dist/engine/session_state.js +365 -0
  28. package/dist/engine/shared_state_store.d.ts +21 -0
  29. package/dist/engine/shared_state_store.js +170 -0
  30. package/dist/engine/stream_switcher.d.ts +29 -0
  31. package/dist/engine/stream_switcher.js +813 -0
  32. package/dist/engine/util.d.ts +19 -0
  33. package/dist/engine/util.js +281 -0
  34. package/dist/index.d.ts +1 -0
  35. package/dist/index.js +5 -0
  36. package/dist/package.json +47 -0
  37. package/dist/server-demux.d.ts +1 -0
  38. package/dist/server-demux.js +103 -0
  39. package/dist/server-livemix.d.ts +1 -0
  40. package/dist/server-livemix.js +196 -0
  41. package/dist/server.d.ts +1 -0
  42. package/dist/server.js +101 -0
  43. package/engine/index.ts +0 -0
  44. package/engine/{server.js → server.ts} +128 -6
  45. package/index.ts +12 -0
  46. package/package.json +11 -7
  47. package/{server-demux.js → server-demux.ts} +16 -10
  48. package/{server-livemix.js → server-livemix.ts} +21 -13
  49. package/{server.js → server.ts} +13 -8
  50. package/spec/engine/engine_spec.js +1 -1
  51. package/spec/engine/interface_spec.js +1 -1
  52. package/tsconfig.json +10 -0
  53. package/index.js +0 -3
@@ -0,0 +1,2194 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ var __generator = (this && this.__generator) || function (thisArg, body) {
11
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
12
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
13
+ function verb(n) { return function (v) { return step([n, v]); }; }
14
+ function step(op) {
15
+ if (f) throw new TypeError("Generator is already executing.");
16
+ while (_) try {
17
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
18
+ if (y = 0, t) op = [op[0] & 2, t.value];
19
+ switch (op[0]) {
20
+ case 0: case 1: t = op; break;
21
+ case 4: _.label++; return { value: op[1], done: false };
22
+ case 5: _.label++; y = op[1]; op = [0]; continue;
23
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
24
+ default:
25
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
26
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
27
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
28
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
29
+ if (t[2]) _.ops.pop();
30
+ _.trys.pop(); continue;
31
+ }
32
+ op = body.call(thisArg, _);
33
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
34
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
35
+ }
36
+ };
37
+ var crypto = require('crypto');
38
+ var debug = require('debug')('engine-session');
39
+ var HLSVod = require('@eyevinn/hls-vodtolive');
40
+ var m3u8 = require('@eyevinn/m3u8');
41
+ var HLSRepeatVod = require('@eyevinn/hls-repeat');
42
+ var HLSTruncateVod = require('@eyevinn/hls-truncate');
43
+ var Readable = require('stream').Readable;
44
+ var SessionState = require('./session_state.js').SessionState;
45
+ var PlayheadState = require('./playhead_state.js').PlayheadState;
46
+ var _a = require('./util.js'), applyFilter = _a.applyFilter, cloudWatchLog = _a.cloudWatchLog, m3u8Header = _a.m3u8Header, logerror = _a.logerror;
47
+ var ChaosMonkey = require('./chaos_monkey.js');
48
+ var AVERAGE_SEGMENT_DURATION = 3000;
49
+ var DEFAULT_PLAYHEAD_DIFF_THRESHOLD = 1000;
50
+ var DEFAULT_MAX_TICK_INTERVAL = 10000;
51
+ var DEFAULT_DIFF_COMPENSATION_RATE = 0.5;
52
+ var timer = function (ms) { return new Promise(function (res) { return setTimeout(res, ms); }); };
53
+ var Session = /** @class */ (function () {
54
+ /**
55
+ *
56
+ * config: {
57
+ * startWithId,
58
+ * }
59
+ *
60
+ */
61
+ function Session(assetManager, config, sessionStore) {
62
+ this._assetManager = assetManager;
63
+ this._sessionId = crypto.randomBytes(20).toString('hex');
64
+ this._sessionStateStore = sessionStore.sessionStateStore;
65
+ this._playheadStateStore = sessionStore.playheadStateStore;
66
+ this._instanceId = sessionStore.instanceId;
67
+ //this.currentVod;
68
+ this.currentMetadata = {};
69
+ this._events = [];
70
+ this.averageSegmentDuration = AVERAGE_SEGMENT_DURATION;
71
+ this.use_demuxed_audio = false;
72
+ this.cloudWatchLogging = false;
73
+ this.playheadDiffThreshold = DEFAULT_PLAYHEAD_DIFF_THRESHOLD;
74
+ this.maxTickInterval = DEFAULT_MAX_TICK_INTERVAL;
75
+ this.maxTickIntervalIsDefault = true;
76
+ this.diffCompensationRate = DEFAULT_DIFF_COMPENSATION_RATE;
77
+ this.diffCompensation = null;
78
+ this.timePositionOffset = 0;
79
+ this.prevVodMediaSeq = {
80
+ video: null,
81
+ audio: null
82
+ };
83
+ this.prevMediaSeqOffset = {
84
+ video: null,
85
+ audio: null
86
+ };
87
+ this.waitingForNextVod = false;
88
+ this.leaderIsSettingNextVod = false;
89
+ this.isSwitchingBackToV2L = false;
90
+ this.switchDataForSession = {
91
+ mediaSeq: null,
92
+ discSeq: null,
93
+ mediaSeqOffset: null,
94
+ transitionSegments: null,
95
+ reloadBehind: null,
96
+ };
97
+ this.isAllowedToClearVodCache = null;
98
+ this.alwaysNewSegments = null;
99
+ if (config) {
100
+ if (config.alwaysNewSegments) {
101
+ this.alwaysNewSegments = config.alwaysNewSegments;
102
+ }
103
+ if (config.sessionId) {
104
+ this._sessionId = config.sessionId;
105
+ }
106
+ if (config.category) {
107
+ this._category = config.category;
108
+ }
109
+ if (config.averageSegmentDuration) {
110
+ this.averageSegmentDuration = config.averageSegmentDuration;
111
+ }
112
+ if (config.useDemuxedAudio) {
113
+ this.use_demuxed_audio = true;
114
+ }
115
+ if (config.startWithId) {
116
+ this.startWithId = config.startWithId;
117
+ }
118
+ if (config.profile) {
119
+ this._sessionProfile = config.profile;
120
+ }
121
+ if (config.audioTracks) {
122
+ this._audioTracks = config.audioTracks;
123
+ }
124
+ if (config.closedCaptions) {
125
+ this._closedCaptions = config.closedCaptions;
126
+ }
127
+ if (config.slateUri) {
128
+ this.slateUri = config.slateUri;
129
+ this.slateRepetitions = config.slateRepetitions || 10;
130
+ this.slateDuration = config.slateDuration || 4000;
131
+ debug("Will use slate URI ".concat(this.slateUri, " (").concat(this.slateRepetitions, " ").concat(this.slateDuration, "ms)"));
132
+ }
133
+ if (config.cloudWatchMetrics) {
134
+ this.cloudWatchLogging = true;
135
+ }
136
+ if (config.playheadDiffThreshold) {
137
+ this.playheadDiffThreshold = config.playheadDiffThreshold;
138
+ }
139
+ if (config.maxTickInterval) {
140
+ this.maxTickInterval = config.maxTickInterval;
141
+ this.maxTickIntervalIsDefault = false;
142
+ }
143
+ if (config.disabledPlayhead) {
144
+ this.disabledPlayhead = true;
145
+ }
146
+ if (config.targetDurationPadding) {
147
+ this.targetDurationPadding = config.targetDurationPadding;
148
+ }
149
+ if (config.forceTargetDuration) {
150
+ this.forceTargetDuration = config.forceTargetDuration;
151
+ }
152
+ if (config.diffCompensationRate) {
153
+ this.diffCompensationRate = config.diffCompensationRate;
154
+ }
155
+ }
156
+ }
157
+ Session.prototype.initAsync = function () {
158
+ return __awaiter(this, void 0, void 0, function () {
159
+ var _a, _b;
160
+ return __generator(this, function (_c) {
161
+ switch (_c.label) {
162
+ case 0:
163
+ _a = this;
164
+ return [4 /*yield*/, this._sessionStateStore.create(this._sessionId, this._instanceId)];
165
+ case 1:
166
+ _a._sessionState = _c.sent();
167
+ _b = this;
168
+ return [4 /*yield*/, this._playheadStateStore.create(this._sessionId)];
169
+ case 2:
170
+ _b._playheadState = _c.sent();
171
+ if (!this.startWithId) return [3 /*break*/, 5];
172
+ return [4 /*yield*/, this._sessionState.set("state", SessionState.VOD_INIT_BY_ID)];
173
+ case 3:
174
+ _c.sent();
175
+ return [4 /*yield*/, this._sessionState.set("assetId", this.startWithId)];
176
+ case 4:
177
+ _c.sent();
178
+ _c.label = 5;
179
+ case 5: return [2 /*return*/];
180
+ }
181
+ });
182
+ });
183
+ };
184
+ Object.defineProperty(Session.prototype, "sessionId", {
185
+ get: function () {
186
+ return this._sessionId;
187
+ },
188
+ enumerable: false,
189
+ configurable: true
190
+ });
191
+ Session.prototype.startPlayheadAsync = function () {
192
+ return __awaiter(this, void 0, void 0, function () {
193
+ var playheadState, state, numberOfLargeTicks, tsIncrementBegin, manifest, tsIncrementEnd, sessionState, isLeader, firstDuration, tickInterval, reqTickInterval, timeSpentInIncrement, tickInterval, delta, position, timePosition, diff, timeToAdd, timeToAdd, DIFF_COMPENSATION, changeMaxTick, tsTickEnd, lastDuration, nextTickInterval, err_1;
194
+ return __generator(this, function (_a) {
195
+ switch (_a.label) {
196
+ case 0:
197
+ debug("[".concat(this._sessionId, "]: Playhead consumer started:"));
198
+ debug("[".concat(this._sessionId, "]: diffThreshold=").concat(this.playheadDiffThreshold));
199
+ debug("[".concat(this._sessionId, "]: maxTickInterval=").concat(this.maxTickInterval));
200
+ debug("[".concat(this._sessionId, "]: averageSegmentDuration=").concat(this.averageSegmentDuration));
201
+ this.disabledPlayhead = false;
202
+ return [4 /*yield*/, this._playheadState.getValues(["state"])];
203
+ case 1:
204
+ playheadState = _a.sent();
205
+ return [4 /*yield*/, this._playheadState.setState(PlayheadState.RUNNING)];
206
+ case 2:
207
+ state = _a.sent();
208
+ numberOfLargeTicks = 0;
209
+ _a.label = 3;
210
+ case 3:
211
+ if (!(state !== PlayheadState.CRASHED)) return [3 /*break*/, 25];
212
+ _a.label = 4;
213
+ case 4:
214
+ _a.trys.push([4, 22, , 24]);
215
+ tsIncrementBegin = Date.now();
216
+ return [4 /*yield*/, this.incrementAsync()];
217
+ case 5:
218
+ manifest = _a.sent();
219
+ if (!!manifest) return [3 /*break*/, 7];
220
+ debug("[".concat(this._sessionId, "]: No manifest available yet, will try again after 1000ms"));
221
+ return [4 /*yield*/, timer(1000)];
222
+ case 6:
223
+ _a.sent();
224
+ return [3 /*break*/, 3];
225
+ case 7:
226
+ tsIncrementEnd = Date.now();
227
+ return [4 /*yield*/, this._sessionState.getValues(["state"])];
228
+ case 8:
229
+ sessionState = _a.sent();
230
+ return [4 /*yield*/, this._playheadState.getValues(["tickInterval", "playheadRef", "tickMs"])];
231
+ case 9:
232
+ playheadState = _a.sent();
233
+ return [4 /*yield*/, this._playheadState.getState()];
234
+ case 10:
235
+ state = _a.sent();
236
+ return [4 /*yield*/, this._sessionStateStore.isLeader(this._instanceId)];
237
+ case 11:
238
+ isLeader = _a.sent();
239
+ if (!(isLeader &&
240
+ [
241
+ SessionState.VOD_NEXT_INIT,
242
+ SessionState.VOD_NEXT_INITIATING,
243
+ SessionState.VOD_RELOAD_INIT,
244
+ SessionState.VOD_RELOAD_INITIATING
245
+ ].indexOf(sessionState.state) !== -1)) return [3 /*break*/, 13];
246
+ return [4 /*yield*/, this._getFirstDuration(manifest)];
247
+ case 12:
248
+ firstDuration = _a.sent();
249
+ tickInterval = firstDuration < 2 ? 2 : firstDuration;
250
+ debug("[".concat(this._sessionId, "]: I am the leader and updated tick interval to ").concat(tickInterval, " sec"));
251
+ cloudWatchLog(!this.cloudWatchLogging, 'engine-session', { event: 'tickIntervalUpdated', channel: this._sessionId, tickIntervalSec: tickInterval });
252
+ this._playheadState.set("tickInterval", tickInterval);
253
+ return [3 /*break*/, 21];
254
+ case 13:
255
+ if (!(state == PlayheadState.STOPPED)) return [3 /*break*/, 14];
256
+ debug("[".concat(this._sessionId, "]: Stopping playhead"));
257
+ return [2 /*return*/];
258
+ case 14:
259
+ reqTickInterval = playheadState.tickInterval;
260
+ timeSpentInIncrement = (tsIncrementEnd - tsIncrementBegin) / 1000;
261
+ tickInterval = reqTickInterval - timeSpentInIncrement;
262
+ return [4 /*yield*/, this._getCurrentDeltaTime()];
263
+ case 15:
264
+ delta = _a.sent();
265
+ if (delta != 0) {
266
+ tickInterval += delta;
267
+ debug("[".concat(this._sessionId, "]: Delta time is != 0 need will adjust ").concat(delta, "sec to tick interval. tick=").concat(tickInterval));
268
+ }
269
+ return [4 /*yield*/, this._getCurrentPlayheadPosition()];
270
+ case 16:
271
+ position = (_a.sent()) * 1000;
272
+ timePosition = Date.now() - playheadState.playheadRef;
273
+ // Apply time position offset if set, only after external diff compensation has concluded.
274
+ if (this.timePositionOffset && this.diffCompensation <= 0 && this.alwaysNewSegments) {
275
+ timePosition -= this.timePositionOffset;
276
+ cloudWatchLog(!this.cloudWatchLogging, 'engine-session', { event: 'applyTimePositionOffset', channel: this._sessionId, offsetMs: this.timePositionOffset });
277
+ }
278
+ diff = position - timePosition;
279
+ debug("[".concat(this._sessionId, "]: ").concat(timePosition, ":").concat(position, ":").concat(diff > 0 ? '+' : '').concat(diff, "ms"));
280
+ cloudWatchLog(!this.cloudWatchLogging, 'engine-session', { event: 'playheadDiff', channel: this._sessionId, diffMs: diff });
281
+ if (this.alwaysNewSegments) {
282
+ // Apply Playhead diff compensation, only after external diff compensation has concluded.
283
+ if (this.diffCompensation <= 0) {
284
+ timeToAdd = this._getPlayheadDiffCompesationValue(diff, this.playheadDiffThreshold);
285
+ tickInterval += timeToAdd;
286
+ }
287
+ }
288
+ else {
289
+ timeToAdd = this._getPlayheadDiffCompesationValue(diff, this.playheadDiffThreshold);
290
+ tickInterval += timeToAdd;
291
+ }
292
+ // Apply external diff compensation if available.
293
+ if (this.diffCompensation && this.diffCompensation > 0) {
294
+ DIFF_COMPENSATION = (reqTickInterval * this.diffCompensationRate).toFixed(2) * 1000;
295
+ debug("[".concat(this._sessionId, "]: Adding ").concat(DIFF_COMPENSATION, "msec to tickInterval to compensate for schedule diff (current=").concat(this.diffCompensation, "msec)"));
296
+ tickInterval += (DIFF_COMPENSATION / 1000);
297
+ this.diffCompensation -= DIFF_COMPENSATION;
298
+ }
299
+ // Keep tickInterval within upper and lower limits.
300
+ debug("[".concat(this._sessionId, "]: Requested tickInterval=").concat(tickInterval, "s (max=").concat(this.maxTickInterval / 1000, "s, diffThreshold=").concat(this.playheadDiffThreshold, "msec)"));
301
+ if (tickInterval <= 0.5) {
302
+ tickInterval = 0.5;
303
+ }
304
+ else if (tickInterval > (this.maxTickInterval / 1000)) {
305
+ changeMaxTick = Math.ceil(Math.abs(tickInterval * 1000 - (this.maxTickInterval))) + 1000;
306
+ if (this.maxTickIntervalIsDefault) {
307
+ if (numberOfLargeTicks > 2) {
308
+ this.maxTickInterval += changeMaxTick;
309
+ numberOfLargeTicks = 0;
310
+ }
311
+ else {
312
+ numberOfLargeTicks++;
313
+ }
314
+ }
315
+ else {
316
+ console.warn("[".concat(this._sessionId, "]: Playhead tick interval went over Max tick interval by ").concat(changeMaxTick, "ms.\n If the value keeps increasing, consider increasing the 'maxTickInterval' in engineOptions"));
317
+ }
318
+ tickInterval = this.maxTickInterval / 1000;
319
+ }
320
+ debug("[".concat(this._sessionId, "]: (").concat((new Date()).toISOString(), ") ").concat(timeSpentInIncrement, "sec in increment. Next tick in ").concat(tickInterval, " seconds"));
321
+ return [4 /*yield*/, timer((tickInterval * 1000) - 50)];
322
+ case 17:
323
+ _a.sent();
324
+ tsTickEnd = Date.now();
325
+ return [4 /*yield*/, this._playheadState.set("tickMs", (tsTickEnd - tsIncrementBegin))];
326
+ case 18:
327
+ _a.sent();
328
+ cloudWatchLog(!this.cloudWatchLogging, 'engine-session', { event: 'tickInterval', channel: this._sessionId, tickTimeMs: (tsTickEnd - tsIncrementBegin) });
329
+ if (!this.alwaysNewSegments) return [3 /*break*/, 21];
330
+ return [4 /*yield*/, this._getLastDuration(manifest)];
331
+ case 19:
332
+ lastDuration = _a.sent();
333
+ nextTickInterval = lastDuration < 2 ? 2 : lastDuration;
334
+ return [4 /*yield*/, this._playheadState.set("tickInterval", nextTickInterval)];
335
+ case 20:
336
+ _a.sent();
337
+ cloudWatchLog(!this.cloudWatchLogging, "engine-session", { event: "tickIntervalUpdated", channel: this._sessionId, tickIntervalSec: nextTickInterval });
338
+ _a.label = 21;
339
+ case 21: return [3 /*break*/, 24];
340
+ case 22:
341
+ err_1 = _a.sent();
342
+ debug("[".concat(this._sessionId, "]: Playhead consumer crashed (1)"));
343
+ console.error("[".concat(this._sessionId, "]: ").concat(err_1.message));
344
+ cloudWatchLog(!this.cloudWatchLogging, 'engine-session', { event: 'error', on: 'playhead', channel: this._sessionId, err: err_1 });
345
+ debug(err_1);
346
+ return [4 /*yield*/, this._playheadState.setState(PlayheadState.CRASHED)];
347
+ case 23:
348
+ state = _a.sent();
349
+ return [3 /*break*/, 24];
350
+ case 24: return [3 /*break*/, 3];
351
+ case 25: return [2 /*return*/];
352
+ }
353
+ });
354
+ });
355
+ };
356
+ Session.prototype.restartPlayheadAsync = function () {
357
+ return __awaiter(this, void 0, void 0, function () {
358
+ return __generator(this, function (_a) {
359
+ switch (_a.label) {
360
+ case 0: return [4 /*yield*/, this._sessionState.set("state", SessionState.VOD_NEXT_INIT)];
361
+ case 1:
362
+ _a.sent();
363
+ debug("[".concat(this._sessionId, "]: Restarting playhead consumer"));
364
+ return [4 /*yield*/, this.startPlayheadAsync()];
365
+ case 2:
366
+ _a.sent();
367
+ return [2 /*return*/];
368
+ }
369
+ });
370
+ });
371
+ };
372
+ Session.prototype.stopPlayheadAsync = function () {
373
+ return __awaiter(this, void 0, void 0, function () {
374
+ return __generator(this, function (_a) {
375
+ switch (_a.label) {
376
+ case 0:
377
+ debug("[".concat(this._sessionId, "]: Stopping playhead consumer"));
378
+ return [4 /*yield*/, this._playheadState.set("state", PlayheadState.STOPPED)];
379
+ case 1:
380
+ _a.sent();
381
+ return [2 /*return*/];
382
+ }
383
+ });
384
+ });
385
+ };
386
+ Session.prototype.getStatusAsync = function () {
387
+ return __awaiter(this, void 0, void 0, function () {
388
+ var playheadState, state, sessionState, playheadStateMap, status_1;
389
+ return __generator(this, function (_a) {
390
+ switch (_a.label) {
391
+ case 0:
392
+ if (!this.disabledPlayhead) return [3 /*break*/, 1];
393
+ return [2 /*return*/, {
394
+ sessionId: this._sessionId,
395
+ }];
396
+ case 1: return [4 /*yield*/, this._playheadState.getValues(["tickMs", "mediaSeq", "vodMediaSeqVideo"])];
397
+ case 2:
398
+ playheadState = _a.sent();
399
+ return [4 /*yield*/, this._playheadState.getState()];
400
+ case 3:
401
+ state = _a.sent();
402
+ return [4 /*yield*/, this._sessionState.getValues(["slateCount"])];
403
+ case 4:
404
+ sessionState = _a.sent();
405
+ playheadStateMap = {};
406
+ playheadStateMap[PlayheadState.IDLE] = 'idle';
407
+ playheadStateMap[PlayheadState.RUNNING] = 'running';
408
+ playheadStateMap[PlayheadState.CRASHED] = 'crashed';
409
+ playheadStateMap[PlayheadState.STOPPED] = 'stopped';
410
+ status_1 = {
411
+ sessionId: this._sessionId,
412
+ playhead: {
413
+ state: playheadStateMap[state],
414
+ tickMs: playheadState.tickMs,
415
+ mediaSeq: playheadState.mediaSeq + playheadState.vodMediaSeqVideo,
416
+ },
417
+ slateInserted: sessionState.slateCount,
418
+ };
419
+ return [2 /*return*/, status_1];
420
+ }
421
+ });
422
+ });
423
+ };
424
+ Session.prototype.resetAsync = function () {
425
+ return __awaiter(this, void 0, void 0, function () {
426
+ return __generator(this, function (_a) {
427
+ switch (_a.label) {
428
+ case 0: return [4 /*yield*/, this._sessionStateStore.reset(this._sessionId)];
429
+ case 1:
430
+ _a.sent();
431
+ return [4 /*yield*/, this._playheadStateStore.reset(this._sessionId)];
432
+ case 2:
433
+ _a.sent();
434
+ return [2 /*return*/];
435
+ }
436
+ });
437
+ });
438
+ };
439
+ Session.prototype.getSessionState = function () {
440
+ return __awaiter(this, void 0, void 0, function () {
441
+ var state;
442
+ return __generator(this, function (_a) {
443
+ switch (_a.label) {
444
+ case 0: return [4 /*yield*/, this._sessionState.get("state")];
445
+ case 1:
446
+ state = _a.sent();
447
+ return [2 /*return*/, state];
448
+ }
449
+ });
450
+ });
451
+ };
452
+ Session.prototype.getTruncatedVodSegments = function (vodUri, duration) {
453
+ return __awaiter(this, void 0, void 0, function () {
454
+ var hlsVod, vodSegments_1, exc_1;
455
+ return __generator(this, function (_a) {
456
+ switch (_a.label) {
457
+ case 0:
458
+ _a.trys.push([0, 2, , 3]);
459
+ return [4 /*yield*/, this._truncateSlate(null, duration, vodUri)];
460
+ case 1:
461
+ hlsVod = _a.sent();
462
+ vodSegments_1 = hlsVod.getMediaSegments();
463
+ Object.keys(vodSegments_1).forEach(function (bw) { return vodSegments_1[bw].unshift({ discontinuity: true, cue: { in: true } }); });
464
+ return [2 /*return*/, vodSegments_1];
465
+ case 2:
466
+ exc_1 = _a.sent();
467
+ debug("[".concat(this._sessionId, "]: Failed to generate truncated VOD!"));
468
+ return [2 /*return*/, null];
469
+ case 3: return [2 /*return*/];
470
+ }
471
+ });
472
+ });
473
+ };
474
+ Session.prototype.setCurrentMediaSequenceSegments = function (segments, mSeqOffset, reloadBehind) {
475
+ return __awaiter(this, void 0, void 0, function () {
476
+ var waitTimeMs, i, isLeader, vodReloaded, attempts, vodReloaded, attempts;
477
+ return __generator(this, function (_a) {
478
+ switch (_a.label) {
479
+ case 0:
480
+ if (!this._sessionState) {
481
+ throw new Error("Session not ready");
482
+ }
483
+ this.isSwitchingBackToV2L = true;
484
+ this.switchDataForSession.reloadBehind = reloadBehind;
485
+ this.switchDataForSession.transitionSegments = segments;
486
+ this.switchDataForSession.mediaSeqOffset = mSeqOffset;
487
+ waitTimeMs = 2000;
488
+ for (i = segments[Object.keys(segments)[0]].length - 1; 0 < i; i--) {
489
+ if (segments[Object.keys(segments)[0]][i].duration) {
490
+ waitTimeMs = parseInt(1000 * (segments[Object.keys(segments)[0]][i].duration / 3), 10);
491
+ break;
492
+ }
493
+ }
494
+ return [4 /*yield*/, this._sessionStateStore.isLeader(this._instanceId)];
495
+ case 1:
496
+ isLeader = _a.sent();
497
+ if (!!isLeader) return [3 /*break*/, 13];
498
+ debug("[".concat(this._sessionId, "]: FOLLOWER: Invalidate cache to ensure having the correct VOD!"));
499
+ return [4 /*yield*/, this._sessionState.clearCurrentVodCache()];
500
+ case 2:
501
+ _a.sent();
502
+ return [4 /*yield*/, this._sessionState.get("vodReloaded")];
503
+ case 3:
504
+ vodReloaded = _a.sent();
505
+ attempts = 9;
506
+ _a.label = 4;
507
+ case 4:
508
+ if (!(!isLeader && !vodReloaded && attempts > 0)) return [3 /*break*/, 9];
509
+ debug("[".concat(this._sessionId, "]: FOLLOWER: I arrived before LEADER. Waiting (1000ms) for LEADER to reload currentVod in store! (tries left=").concat(attempts, ")"));
510
+ return [4 /*yield*/, timer(1000)];
511
+ case 5:
512
+ _a.sent();
513
+ return [4 /*yield*/, this._sessionStateStore.clearLeaderCache()];
514
+ case 6:
515
+ _a.sent();
516
+ return [4 /*yield*/, this._sessionStateStore.isLeader(this._instanceId)];
517
+ case 7:
518
+ isLeader = _a.sent();
519
+ return [4 /*yield*/, this._sessionState.get("vodReloaded")];
520
+ case 8:
521
+ vodReloaded = _a.sent();
522
+ attempts--;
523
+ return [3 /*break*/, 4];
524
+ case 9:
525
+ if (attempts === 0) {
526
+ debug("[".concat(this._sessionId, "]: FOLLOWER: WARNING! Attempts=0 - Risk of using wrong currentVod"));
527
+ }
528
+ if (!(!isLeader || vodReloaded)) return [3 /*break*/, 11];
529
+ debug("[".concat(this._sessionId, "]: FOLLOWER: leader is alive, and has presumably updated currentVod. Clearing the cache now"));
530
+ return [4 /*yield*/, this._sessionState.clearCurrentVodCache()];
531
+ case 10:
532
+ _a.sent();
533
+ return [2 /*return*/];
534
+ case 11:
535
+ debug("[".concat(this._sessionId, "]: NEW LEADER: Setting state=VOD_RELOAD_INIT"));
536
+ this.isSwitchingBackToV2L = true;
537
+ return [4 /*yield*/, this._sessionState.set("state", SessionState.VOD_RELOAD_INIT)];
538
+ case 12:
539
+ _a.sent();
540
+ return [3 /*break*/, 19];
541
+ case 13: return [4 /*yield*/, this._sessionState.get("vodReloaded")];
542
+ case 14:
543
+ vodReloaded = _a.sent();
544
+ attempts = 12;
545
+ _a.label = 15;
546
+ case 15:
547
+ if (!(!vodReloaded && attempts > 0)) return [3 /*break*/, 18];
548
+ debug("[".concat(this._sessionId, "]: LEADER: Waiting (").concat(waitTimeMs, "ms) to buy some time reloading vod and adding it to store! (tries left=").concat(attempts, ")"));
549
+ return [4 /*yield*/, timer(waitTimeMs)];
550
+ case 16:
551
+ _a.sent();
552
+ return [4 /*yield*/, this._sessionState.get("vodReloaded")];
553
+ case 17:
554
+ vodReloaded = _a.sent();
555
+ attempts--;
556
+ return [3 /*break*/, 15];
557
+ case 18:
558
+ if (attempts === 0) {
559
+ debug("[".concat(this._sessionId, "]: LEADER: WARNING! Vod was never Reloaded!"));
560
+ return [2 /*return*/];
561
+ }
562
+ _a.label = 19;
563
+ case 19: return [2 /*return*/];
564
+ }
565
+ });
566
+ });
567
+ };
568
+ Session.prototype.getCurrentMediaSequenceSegments = function (opts) {
569
+ return __awaiter(this, void 0, void 0, function () {
570
+ var isLeader, state, tries, waitTimeMs, playheadState, _a, currentVod, mediaSegments, mediaSequenceValue, err_2;
571
+ return __generator(this, function (_b) {
572
+ switch (_b.label) {
573
+ case 0:
574
+ if (!this._sessionState) {
575
+ throw new Error('Session not ready');
576
+ }
577
+ return [4 /*yield*/, this._sessionStateStore.isLeader(this._instanceId)];
578
+ case 1:
579
+ isLeader = _b.sent();
580
+ if (!isLeader) return [3 /*break*/, 3];
581
+ return [4 /*yield*/, this._sessionState.set("vodReloaded", 0)];
582
+ case 2:
583
+ _b.sent();
584
+ _b.label = 3;
585
+ case 3: return [4 /*yield*/, this.getSessionState()];
586
+ case 4:
587
+ state = _b.sent();
588
+ tries = 12;
589
+ _b.label = 5;
590
+ case 5:
591
+ if (!(state !== SessionState.VOD_PLAYING && tries > 0)) return [3 /*break*/, 8];
592
+ waitTimeMs = 500;
593
+ debug("[".concat(this._sessionId, "]: state=").concat(state, " - Waiting ").concat(waitTimeMs, "ms_").concat(tries, " until Leader has finished loading next vod."));
594
+ return [4 /*yield*/, timer(waitTimeMs)];
595
+ case 6:
596
+ _b.sent();
597
+ tries--;
598
+ return [4 /*yield*/, this.getSessionState()];
599
+ case 7:
600
+ state = _b.sent();
601
+ return [3 /*break*/, 5];
602
+ case 8:
603
+ playheadState = {
604
+ vodMediaSeqVideo: null
605
+ };
606
+ if (!(opts && opts.targetMseq !== undefined)) return [3 /*break*/, 9];
607
+ playheadState.vodMediaSeqVideo = opts.targetMseq;
608
+ return [3 /*break*/, 11];
609
+ case 9:
610
+ _a = playheadState;
611
+ return [4 /*yield*/, this._playheadState.get("vodMediaSeqVideo")];
612
+ case 10:
613
+ _a.vodMediaSeqVideo = _b.sent();
614
+ _b.label = 11;
615
+ case 11: return [4 /*yield*/, this._sessionState.getCurrentVod()];
616
+ case 12:
617
+ currentVod = _b.sent();
618
+ if (!currentVod) return [3 /*break*/, 17];
619
+ _b.label = 13;
620
+ case 13:
621
+ _b.trys.push([13, 14, , 16]);
622
+ mediaSegments = currentVod.getLiveMediaSequenceSegments(playheadState.vodMediaSeqVideo);
623
+ mediaSequenceValue = 0;
624
+ if (currentVod.sequenceAlwaysContainNewSegments) {
625
+ mediaSequenceValue = currentVod.mediaSequenceValues[playheadState.vodMediaSeqVideo];
626
+ debug("[".concat(this._sessionId, "]: {").concat(mediaSequenceValue, "}_{").concat(currentVod.getLastSequenceMediaSequenceValue(), "}"));
627
+ }
628
+ else {
629
+ mediaSequenceValue = playheadState.vodMediaSeqVideo;
630
+ }
631
+ debug("[".concat(this._sessionId, "]: Requesting all segments from Media Sequence: ").concat(playheadState.vodMediaSeqVideo, "(").concat(mediaSequenceValue, ")_").concat(currentVod.getLiveMediaSequencesCount()));
632
+ return [2 /*return*/, mediaSegments];
633
+ case 14:
634
+ err_2 = _b.sent();
635
+ logerror(this._sessionId, err_2);
636
+ return [4 /*yield*/, this._sessionState.clearCurrentVodCache()];
637
+ case 15:
638
+ _b.sent(); // force reading up from shared store
639
+ throw new Error("Failed to get all current Media segments: " + JSON.stringify(playheadState));
640
+ case 16: return [3 /*break*/, 18];
641
+ case 17: throw new Error("Engine not ready");
642
+ case 18: return [2 /*return*/];
643
+ }
644
+ });
645
+ });
646
+ };
647
+ Session.prototype.setCurrentMediaAndDiscSequenceCount = function (_mediaSeq, _discSeq) {
648
+ return __awaiter(this, void 0, void 0, function () {
649
+ return __generator(this, function (_a) {
650
+ if (!this._sessionState) {
651
+ throw new Error("Session not ready");
652
+ }
653
+ this.isSwitchingBackToV2L = true;
654
+ this.switchDataForSession.mediaSeq = _mediaSeq;
655
+ this.switchDataForSession.discSeq = _discSeq;
656
+ return [2 /*return*/];
657
+ });
658
+ });
659
+ };
660
+ Session.prototype.getCurrentMediaAndDiscSequenceCount = function () {
661
+ return __awaiter(this, void 0, void 0, function () {
662
+ var state, tries, waitTimeMs, playheadState, discSeqOffset, isLeader, currentVod, mediaSequenceValue, discSeqCount, err_3;
663
+ return __generator(this, function (_a) {
664
+ switch (_a.label) {
665
+ case 0:
666
+ if (!this._sessionState) {
667
+ throw new Error('Session not ready');
668
+ }
669
+ return [4 /*yield*/, this.getSessionState()];
670
+ case 1:
671
+ state = _a.sent();
672
+ tries = 12;
673
+ _a.label = 2;
674
+ case 2:
675
+ if (!(state !== SessionState.VOD_PLAYING && tries > 0)) return [3 /*break*/, 5];
676
+ waitTimeMs = 500;
677
+ debug("[".concat(this._sessionId, "]: state=").concat(state, " - Waiting ").concat(waitTimeMs, "ms_").concat(tries, " until Leader has finished loading next vod."));
678
+ return [4 /*yield*/, timer(waitTimeMs)];
679
+ case 3:
680
+ _a.sent();
681
+ tries--;
682
+ return [4 /*yield*/, this.getSessionState()];
683
+ case 4:
684
+ state = _a.sent();
685
+ return [3 /*break*/, 2];
686
+ case 5: return [4 /*yield*/, this._playheadState.getValues(["mediaSeq", "vodMediaSeqVideo"])];
687
+ case 6:
688
+ playheadState = _a.sent();
689
+ return [4 /*yield*/, this._sessionState.get("discSeq")];
690
+ case 7:
691
+ discSeqOffset = _a.sent();
692
+ if (!(playheadState.vodMediaSeqVideo === 0)) return [3 /*break*/, 10];
693
+ return [4 /*yield*/, this._sessionStateStore.isLeader(this._instanceId)];
694
+ case 8:
695
+ isLeader = _a.sent();
696
+ if (!!isLeader) return [3 /*break*/, 10];
697
+ debug("[".concat(this._sessionId, "]: Not a leader, about to switch, and first media sequence in a VOD is requested. Invalidate cache to ensure having the correct VOD."));
698
+ return [4 /*yield*/, this._sessionState.clearCurrentVodCache()];
699
+ case 9:
700
+ _a.sent(); // force reading up from shared store
701
+ _a.label = 10;
702
+ case 10: return [4 /*yield*/, this._sessionState.getCurrentVod()];
703
+ case 11:
704
+ currentVod = _a.sent();
705
+ if (!currentVod) return [3 /*break*/, 16];
706
+ _a.label = 12;
707
+ case 12:
708
+ _a.trys.push([12, 13, , 15]);
709
+ mediaSequenceValue = 0;
710
+ if (currentVod.sequenceAlwaysContainNewSegments) {
711
+ mediaSequenceValue = currentVod.mediaSequenceValues[playheadState.vodMediaSeqVideo];
712
+ debug("[".concat(this._sessionId, "]: seqIndex=").concat(playheadState.vodMediaSeqVideo, "_seqValue=").concat(mediaSequenceValue));
713
+ }
714
+ else {
715
+ mediaSequenceValue = playheadState.vodMediaSeqVideo;
716
+ }
717
+ discSeqCount = discSeqOffset + currentVod.discontinuities[playheadState.vodMediaSeqVideo];
718
+ debug("[".concat(this._sessionId, "]: MediaSeq: (").concat(playheadState.mediaSeq, "+").concat(mediaSequenceValue, "=").concat((playheadState.mediaSeq + mediaSequenceValue), ") and DiscSeq: (").concat(discSeqCount, ") requested "));
719
+ return [2 /*return*/, {
720
+ 'mediaSeq': (playheadState.mediaSeq + mediaSequenceValue),
721
+ 'discSeq': discSeqCount,
722
+ 'vodMediaSeqVideo': playheadState.vodMediaSeqVideo,
723
+ }];
724
+ case 13:
725
+ err_3 = _a.sent();
726
+ logerror(this._sessionId, err_3);
727
+ return [4 /*yield*/, this._sessionState.clearCurrentVodCache()];
728
+ case 14:
729
+ _a.sent(); // force reading up from shared store
730
+ throw new Error("Failed to get states: " + JSON.stringify(playheadState));
731
+ case 15: return [3 /*break*/, 17];
732
+ case 16: throw new Error("Engine not ready");
733
+ case 17: return [2 /*return*/];
734
+ }
735
+ });
736
+ });
737
+ };
738
+ Session.prototype.getCurrentMediaManifestAsync = function (bw, playbackSessionId) {
739
+ return __awaiter(this, void 0, void 0, function () {
740
+ var tries, sessionState, playheadState, state, m3u8_1, isLeader, diffMs, currentVod, manifestMseq, manifestDseq, mediaSequenceValue, m3u8_2, err_4;
741
+ return __generator(this, function (_a) {
742
+ switch (_a.label) {
743
+ case 0:
744
+ if (!this._sessionState) {
745
+ throw new Error('Session not ready');
746
+ }
747
+ tries = 12;
748
+ _a.label = 1;
749
+ case 1:
750
+ if (!(tries > 0 && this.leaderIsSettingNextVod)) return [3 /*break*/, 3];
751
+ debug("[".concat(this._sessionId, "]: Leader is setting the next vod. Waiting 500ms_").concat(tries));
752
+ return [4 /*yield*/, timer(500)];
753
+ case 2:
754
+ _a.sent();
755
+ tries--;
756
+ return [3 /*break*/, 1];
757
+ case 3: return [4 /*yield*/, this._sessionState.getValues(["vodMediaSeqVideo", "discSeq"])];
758
+ case 4:
759
+ sessionState = _a.sent();
760
+ return [4 /*yield*/, this._playheadState.getValues(["mediaSeq", "vodMediaSeqVideo"])];
761
+ case 5:
762
+ playheadState = _a.sent();
763
+ if (this.prevVodMediaSeq.video === null) {
764
+ this.prevVodMediaSeq.video = playheadState.vodMediaSeqVideo;
765
+ }
766
+ if (this.prevMediaSeqOffset.video === null) {
767
+ this.prevMediaSeqOffset.video = playheadState.mediaSeq;
768
+ }
769
+ if (!(playheadState.vodMediaSeqVideo > sessionState.vodMediaSeqVideo ||
770
+ (playheadState.vodMediaSeqVideo < sessionState.vodMediaSeqVideo &&
771
+ playheadState.mediaSeq === this.prevMediaSeqOffset.video))) return [3 /*break*/, 11];
772
+ return [4 /*yield*/, this._sessionState.get("state")];
773
+ case 6:
774
+ state = _a.sent();
775
+ if (![SessionState.VOD_RELOAD_INIT, SessionState.VOD_RELOAD_INITIATING].includes(state)) return [3 /*break*/, 9];
776
+ debug("[".concat(this._sessionId, "]: Recently reloaded Vod. PlayheadState not up-to-date (").concat(playheadState.vodMediaSeqVideo, "_").concat(sessionState.vodMediaSeqVideo, "). Waiting 500ms before reading from store again"));
777
+ return [4 /*yield*/, timer(500)];
778
+ case 7:
779
+ _a.sent();
780
+ return [4 /*yield*/, this._playheadState.getValues(["mediaSeq", "vodMediaSeqVideo"])];
781
+ case 8:
782
+ playheadState = _a.sent();
783
+ return [3 /*break*/, 11];
784
+ case 9:
785
+ debug("[".concat(this._sessionId, "]: Recently Loaded Next Vod. PlayheadState not up-to-date. Return the last generated m3u8"));
786
+ return [4 /*yield*/, this._playheadState.getLastM3u8()];
787
+ case 10:
788
+ m3u8_1 = _a.sent();
789
+ if (m3u8_1) {
790
+ this.prevVodMediaSeq.video = playheadState.vodMediaSeqVideo;
791
+ return [2 /*return*/, m3u8_1];
792
+ }
793
+ else {
794
+ debug("[".concat(this._sessionId, "]: We don't have any previously generated m3u8"));
795
+ }
796
+ _a.label = 11;
797
+ case 11:
798
+ if (!(playheadState.vodMediaSeqVideo < 2 || playheadState.mediaSeq !== this.prevMediaSeqOffset.video)) return [3 /*break*/, 16];
799
+ debug("[".concat(this._sessionId, "]: current[").concat(playheadState.vodMediaSeqVideo, "]_prev[").concat(this.prevVodMediaSeq.video, "]"));
800
+ debug("[".concat(this._sessionId, "]: current-offset[").concat(playheadState.mediaSeq, "]_prev-offset[").concat(this.prevMediaSeqOffset.video, "]"));
801
+ // If true, then we have not updated the prev-values and not cleared the cache yet.
802
+ if (playheadState.vodMediaSeqVideo < this.prevVodMediaSeq.video || playheadState.mediaSeq !== this.prevMediaSeqOffset.video) {
803
+ this.isAllowedToClearVodCache = true;
804
+ }
805
+ return [4 /*yield*/, this._sessionStateStore.isLeader(this._instanceId)];
806
+ case 12:
807
+ isLeader = _a.sent();
808
+ if (!(!isLeader && this.isAllowedToClearVodCache)) return [3 /*break*/, 15];
809
+ debug("[".concat(this._sessionId, "]: Not a leader and first|second media sequence in a VOD is requested. Invalidate cache to ensure having the correct VOD."));
810
+ return [4 /*yield*/, this._sessionState.clearCurrentVodCache()];
811
+ case 13:
812
+ _a.sent();
813
+ this.isAllowedToClearVodCache = false;
814
+ return [4 /*yield*/, this._playheadState.get("diffCompensation")];
815
+ case 14:
816
+ diffMs = _a.sent();
817
+ if (diffMs) {
818
+ this.diffCompensation = diffMs;
819
+ debug("[".concat(this._sessionId, "]: Setting diffCompensation->").concat(this.diffCompensation));
820
+ if (this.diffCompensation) {
821
+ this.timePositionOffset = this.diffCompensation;
822
+ cloudWatchLog(!this.cloudWatchLogging, 'engine-session', { event: 'timePositionOffsetUpdated', channel: this._sessionId, offsetMs: this.timePositionOffset });
823
+ }
824
+ else {
825
+ this.timePositionOffset = 0;
826
+ }
827
+ }
828
+ _a.label = 15;
829
+ case 15: return [3 /*break*/, 17];
830
+ case 16:
831
+ this.isAllowedToClearVodCache = true;
832
+ _a.label = 17;
833
+ case 17: return [4 /*yield*/, this._sessionState.getCurrentVod()];
834
+ case 18:
835
+ currentVod = _a.sent();
836
+ if (!currentVod) return [3 /*break*/, 23];
837
+ _a.label = 19;
838
+ case 19:
839
+ _a.trys.push([19, 20, , 22]);
840
+ manifestMseq = playheadState.mediaSeq + playheadState.vodMediaSeqVideo;
841
+ manifestDseq = sessionState.discSeq + currentVod.discontinuities[playheadState.vodMediaSeqVideo];
842
+ if (currentVod.sequenceAlwaysContainNewSegments) {
843
+ mediaSequenceValue = currentVod.mediaSequenceValues[playheadState.vodMediaSeqVideo];
844
+ debug("[".concat(this._sessionId, "]: {").concat(mediaSequenceValue, "}_{").concat(currentVod.getLastSequenceMediaSequenceValue(), "}"));
845
+ manifestMseq = playheadState.mediaSeq + mediaSequenceValue;
846
+ }
847
+ debug("[".concat(this._sessionId, "]: [").concat(playheadState.vodMediaSeqVideo, "]_[").concat(currentVod.getLiveMediaSequencesCount(), "]"));
848
+ m3u8_2 = currentVod.getLiveMediaSequences(playheadState.mediaSeq, bw, playheadState.vodMediaSeqVideo, sessionState.discSeq, this.targetDurationPadding, this.forceTargetDuration);
849
+ debug("[".concat(this._sessionId, "]: [").concat(manifestMseq, "][").concat(manifestDseq, "][+").concat(this.targetDurationPadding || 0, "] Current media manifest for ").concat(bw, " requested"));
850
+ this.prevVodMediaSeq.video = playheadState.vodMediaSeqVideo;
851
+ this.prevMediaSeqOffset.video = playheadState.mediaSeq;
852
+ return [2 /*return*/, m3u8_2];
853
+ case 20:
854
+ err_4 = _a.sent();
855
+ logerror(this._sessionId, err_4);
856
+ return [4 /*yield*/, this._sessionState.clearCurrentVodCache()];
857
+ case 21:
858
+ _a.sent(); // force reading up from shared store
859
+ throw new Error("Failed to generate manifest: " + JSON.stringify(playheadState));
860
+ case 22: return [3 /*break*/, 24];
861
+ case 23: throw new Error("Engine not ready");
862
+ case 24: return [2 /*return*/];
863
+ }
864
+ });
865
+ });
866
+ };
867
+ Session.prototype.getCurrentAudioManifestAsync = function (audioGroupId, audioLanguage, playbackSessionId) {
868
+ return __awaiter(this, void 0, void 0, function () {
869
+ var sessionState, playheadState, currentVod, m3u8_3, err_5;
870
+ return __generator(this, function (_a) {
871
+ switch (_a.label) {
872
+ case 0:
873
+ if (!this._sessionState) {
874
+ throw new Error('Session not ready');
875
+ }
876
+ return [4 /*yield*/, this._sessionState.getValues(["discSeq"])];
877
+ case 1:
878
+ sessionState = _a.sent();
879
+ return [4 /*yield*/, this._playheadState.getValues(["mediaSeq", "vodMediaSeqAudio"])];
880
+ case 2:
881
+ playheadState = _a.sent();
882
+ return [4 /*yield*/, this._sessionState.getCurrentVod()];
883
+ case 3:
884
+ currentVod = _a.sent();
885
+ if (!currentVod) return [3 /*break*/, 8];
886
+ _a.label = 4;
887
+ case 4:
888
+ _a.trys.push([4, 5, , 7]);
889
+ m3u8_3 = currentVod.getLiveMediaAudioSequences(playheadState.mediaSeq, audioGroupId, audioLanguage, playheadState.vodMediaSeqAudio, sessionState.discSeq, this.targetDurationPadding, this.forceTargetDuration);
890
+ // # Case: current VOD does not have the selected track.
891
+ if (!m3u8_3) {
892
+ debug("[".concat(this._sessionId, "]: [").concat(playheadState.mediaSeq + playheadState.vodMediaSeqAudio, "] Request Failed for current audio manifest for ").concat(audioGroupId, "-").concat(audioLanguage));
893
+ }
894
+ debug("[".concat(this._sessionId, "]: [").concat(playheadState.mediaSeq + playheadState.vodMediaSeqAudio, "] Current audio manifest for ").concat(audioGroupId, "-").concat(audioLanguage, " requested"));
895
+ return [2 /*return*/, m3u8_3];
896
+ case 5:
897
+ err_5 = _a.sent();
898
+ logerror(this._sessionId, err_5);
899
+ return [4 /*yield*/, this._sessionState.clearCurrentVodCache()];
900
+ case 6:
901
+ _a.sent(); // force reading up from shared store
902
+ throw new Error("Failed to generate audio manifest: " + JSON.stringify(playheadState));
903
+ case 7: return [3 /*break*/, 9];
904
+ case 8: throw new Error("Engine not ready");
905
+ case 9: return [2 /*return*/];
906
+ }
907
+ });
908
+ });
909
+ };
910
+ Session.prototype.incrementAsync = function () {
911
+ return __awaiter(this, void 0, void 0, function () {
912
+ var isLeader, sessionState, playheadState, currentVod, _a, leaderAction, _b, m3u8_4, _c, _d, _e, _f, _g, _h, _j, _k, _l, mediaSequenceValue, diffMs, m3u8;
913
+ return __generator(this, function (_m) {
914
+ switch (_m.label) {
915
+ case 0: return [4 /*yield*/, this._tickAsync()];
916
+ case 1:
917
+ _m.sent();
918
+ return [4 /*yield*/, this._sessionStateStore.isLeader(this._instanceId)];
919
+ case 2:
920
+ isLeader = _m.sent();
921
+ return [4 /*yield*/, this._sessionState.getValues(["state", "mediaSeq", "discSeq", "vodMediaSeqVideo", "vodMediaSeqAudio"])];
922
+ case 3:
923
+ sessionState = _m.sent();
924
+ return [4 /*yield*/, this._playheadState.getValues(["mediaSeq", "vodMediaSeqVideo", "vodMediaSeqAudio"])];
925
+ case 4:
926
+ playheadState = _m.sent();
927
+ return [4 /*yield*/, this._sessionState.getCurrentVod()];
928
+ case 5:
929
+ currentVod = _m.sent();
930
+ if (!(!currentVod ||
931
+ sessionState.vodMediaSeqVideo === null ||
932
+ sessionState.vodMediaSeqAudio === null ||
933
+ sessionState.state === null ||
934
+ sessionState.mediaSeq === null ||
935
+ sessionState.discSeq === null)) return [3 /*break*/, 9];
936
+ debug("[".concat(this._sessionId, "]: Session is not ready yet"));
937
+ debug(sessionState);
938
+ return [4 /*yield*/, this._sessionState.clearCurrentVodCache()];
939
+ case 6:
940
+ _m.sent();
941
+ if (!isLeader) return [3 /*break*/, 8];
942
+ debug("[".concat(this._sessionId, "]: I am the leader, trying to initiate the session"));
943
+ _a = sessionState;
944
+ return [4 /*yield*/, this._sessionState.set("state", SessionState.VOD_INIT)];
945
+ case 7:
946
+ _a.state = _m.sent();
947
+ _m.label = 8;
948
+ case 8: return [2 /*return*/, null];
949
+ case 9:
950
+ if (!(sessionState.state === SessionState.VOD_NEXT_INITIATING || sessionState.state === SessionState.VOD_RELOAD_INITIATING)) return [3 /*break*/, 14];
951
+ if (!isLeader) return [3 /*break*/, 11];
952
+ leaderAction = sessionState.state === SessionState.VOD_NEXT_INITIATING ? "initiated" : "reloaded";
953
+ debug("[".concat(this._sessionId, "]: I am the leader and have just ").concat(leaderAction, " next VOD, let's move to VOD_PLAYING"));
954
+ _b = sessionState;
955
+ return [4 /*yield*/, this._sessionState.set("state", SessionState.VOD_PLAYING)];
956
+ case 10:
957
+ _b.state = _m.sent();
958
+ return [3 /*break*/, 13];
959
+ case 11:
960
+ debug("[".concat(this._sessionId, "]: Return the last generated m3u8 to give the leader some time"));
961
+ return [4 /*yield*/, this._playheadState.getLastM3u8()];
962
+ case 12:
963
+ m3u8_4 = _m.sent();
964
+ if (m3u8_4) {
965
+ return [2 /*return*/, m3u8_4];
966
+ }
967
+ else {
968
+ debug("[".concat(this._sessionId, "]: We don't have any previously generated m3u8"));
969
+ }
970
+ this.isAllowedToClearVodCache = true;
971
+ _m.label = 13;
972
+ case 13: return [3 /*break*/, 17];
973
+ case 14:
974
+ _c = sessionState;
975
+ return [4 /*yield*/, this._sessionState.increment("vodMediaSeqVideo")];
976
+ case 15:
977
+ _c.vodMediaSeqVideo = _m.sent();
978
+ _d = sessionState;
979
+ return [4 /*yield*/, this._sessionState.increment("vodMediaSeqAudio")];
980
+ case 16:
981
+ _d.vodMediaSeqAudio = _m.sent();
982
+ _m.label = 17;
983
+ case 17:
984
+ if (!(sessionState.vodMediaSeqVideo >= currentVod.getLiveMediaSequencesCount() - 1)) return [3 /*break*/, 21];
985
+ _e = sessionState;
986
+ return [4 /*yield*/, this._sessionState.set("vodMediaSeqVideo", currentVod.getLiveMediaSequencesCount() - 1)];
987
+ case 18:
988
+ _e.vodMediaSeqVideo = _m.sent();
989
+ _f = sessionState;
990
+ return [4 /*yield*/, this._sessionState.set("vodMediaSeqAudio", currentVod.getLiveMediaSequencesCount() - 1)];
991
+ case 19:
992
+ _f.vodMediaSeqAudio = _m.sent();
993
+ _g = sessionState;
994
+ return [4 /*yield*/, this._sessionState.set("state", SessionState.VOD_NEXT_INIT)];
995
+ case 20:
996
+ _g.state = _m.sent();
997
+ _m.label = 21;
998
+ case 21:
999
+ if (!this.isSwitchingBackToV2L) return [3 /*break*/, 23];
1000
+ _h = sessionState;
1001
+ return [4 /*yield*/, this._sessionState.set("state", SessionState.VOD_RELOAD_INIT)];
1002
+ case 22:
1003
+ _h.state = _m.sent();
1004
+ this.isSwitchingBackToV2L = false;
1005
+ _m.label = 23;
1006
+ case 23:
1007
+ _j = playheadState;
1008
+ return [4 /*yield*/, this._playheadState.set("mediaSeq", sessionState.mediaSeq)];
1009
+ case 24:
1010
+ _j.mediaSeq = _m.sent();
1011
+ _k = playheadState;
1012
+ return [4 /*yield*/, this._playheadState.set("vodMediaSeqVideo", sessionState.vodMediaSeqVideo)];
1013
+ case 25:
1014
+ _k.vodMediaSeqVideo = _m.sent();
1015
+ _l = playheadState;
1016
+ return [4 /*yield*/, this._playheadState.set("vodMediaSeqAudio", sessionState.vodMediaSeqAudio)];
1017
+ case 26:
1018
+ _l.vodMediaSeqAudio = _m.sent();
1019
+ if (currentVod.sequenceAlwaysContainNewSegments) {
1020
+ mediaSequenceValue = currentVod.mediaSequenceValues[playheadState.vodMediaSeqVideo];
1021
+ debug("[".concat(this._sessionId, "]: Session can now serve mseq={").concat(playheadState.mediaSeq + mediaSequenceValue, "}"));
1022
+ }
1023
+ debug("[".concat(this._sessionId, "]: INCREMENT (mseq=").concat(playheadState.mediaSeq + playheadState.vodMediaSeqVideo, ") vodMediaSeq=(").concat(playheadState.vodMediaSeqVideo, "_").concat(playheadState.vodMediaSeqAudio, " of ").concat(currentVod.getLiveMediaSequencesCount(), ")"));
1024
+ if (!(playheadState.vodMediaSeqVideo < 2 || playheadState.mediaSeq !== this.prevMediaSeqOffset.video)) return [3 /*break*/, 31];
1025
+ debug("[".concat(this._sessionId, "]: current[").concat(playheadState.vodMediaSeqVideo, "]_prev[").concat(this.prevVodMediaSeq.video, "]"));
1026
+ debug("[".concat(this._sessionId, "]: current-offset[").concat(playheadState.mediaSeq, "]_prev-offset[").concat(this.prevMediaSeqOffset.video, "]"));
1027
+ if (playheadState.vodMediaSeqVideo < this.prevVodMediaSeq.video || playheadState.mediaSeq !== this.prevMediaSeqOffset.video) {
1028
+ this.isAllowedToClearVodCache = true;
1029
+ }
1030
+ if (!(!isLeader && this.isAllowedToClearVodCache)) return [3 /*break*/, 30];
1031
+ debug("[".concat(this._sessionId, "]: Not a leader and have just set 'playheadState.vodMediaSeqVideo' to 0|1. Invalidate cache to ensure having the correct VOD."));
1032
+ return [4 /*yield*/, this._sessionState.clearCurrentVodCache()];
1033
+ case 27:
1034
+ _m.sent();
1035
+ return [4 /*yield*/, this._sessionState.getCurrentVod()];
1036
+ case 28:
1037
+ currentVod = _m.sent();
1038
+ return [4 /*yield*/, this._playheadState.get("diffCompensation")];
1039
+ case 29:
1040
+ diffMs = _m.sent();
1041
+ if (diffMs) {
1042
+ this.diffCompensation = diffMs;
1043
+ debug("[".concat(this._sessionId, "]: Setting diffCompensation->").concat(this.diffCompensation));
1044
+ if (this.diffCompensation) {
1045
+ this.timePositionOffset = this.diffCompensation;
1046
+ cloudWatchLog(!this.cloudWatchLogging, 'engine-session', { event: 'timePositionOffsetUpdated', channel: this._sessionId, offsetMs: this.timePositionOffset });
1047
+ }
1048
+ else {
1049
+ this.timePositionOffset = 0;
1050
+ }
1051
+ }
1052
+ this.isAllowedToClearVodCache = false;
1053
+ _m.label = 30;
1054
+ case 30: return [3 /*break*/, 32];
1055
+ case 31:
1056
+ this.isAllowedToClearVodCache = true;
1057
+ _m.label = 32;
1058
+ case 32:
1059
+ // Update Value for Previous Sequence
1060
+ this.prevVodMediaSeq.video = playheadState.vodMediaSeqVideo;
1061
+ this.prevMediaSeqOffset.video = playheadState.mediaSeq;
1062
+ m3u8 = currentVod.getLiveMediaSequences(playheadState.mediaSeq, 180000, playheadState.vodMediaSeqVideo, sessionState.discSeq);
1063
+ return [4 /*yield*/, this._playheadState.setLastM3u8(m3u8)];
1064
+ case 33:
1065
+ _m.sent();
1066
+ return [2 /*return*/, m3u8];
1067
+ }
1068
+ });
1069
+ });
1070
+ };
1071
+ Session.prototype.getMediaManifestAsync = function (bw, opts) {
1072
+ return __awaiter(this, void 0, void 0, function () {
1073
+ var tsLastRequestVideo, timeSinceLastRequest, sessionState, currentVod, _a, sequencesToIncrement, _b, _c, _d, m3u8, lastM3u8, _e, _f, _g, tsLastRequestVideo_1, timeSinceLastRequest_1, sessionState_1, _h, lastM3u8_1, _j, _k, _l;
1074
+ return __generator(this, function (_m) {
1075
+ switch (_m.label) {
1076
+ case 0: return [4 /*yield*/, this._tickAsync()];
1077
+ case 1:
1078
+ _m.sent();
1079
+ return [4 /*yield*/, this._sessionState.get("tsLastRequestVideo")];
1080
+ case 2:
1081
+ tsLastRequestVideo = _m.sent();
1082
+ timeSinceLastRequest = (tsLastRequestVideo === null) ? 0 : Date.now() - tsLastRequestVideo;
1083
+ return [4 /*yield*/, this._sessionState.getValues(["state", "vodMediaSeqVideo", "mediaSeq", "discSeq", "lastM3u8"])];
1084
+ case 3:
1085
+ sessionState = _m.sent();
1086
+ return [4 /*yield*/, this._sessionState.getCurrentVod()];
1087
+ case 4:
1088
+ currentVod = _m.sent();
1089
+ if (!currentVod) {
1090
+ throw new Error('Session not ready');
1091
+ }
1092
+ if (!(sessionState.state === SessionState.VOD_NEXT_INITIATING)) return [3 /*break*/, 6];
1093
+ _a = sessionState;
1094
+ return [4 /*yield*/, this._sessionState.set("state", SessionState.VOD_PLAYING)];
1095
+ case 5:
1096
+ _a.state = _m.sent();
1097
+ return [3 /*break*/, 8];
1098
+ case 6:
1099
+ sequencesToIncrement = Math.ceil(timeSinceLastRequest / this.averageSegmentDuration);
1100
+ _b = sessionState;
1101
+ return [4 /*yield*/, this._sessionState.increment("vodMediaSeqVideo", sequencesToIncrement)];
1102
+ case 7:
1103
+ _b.vodMediaSeqVideo = _m.sent();
1104
+ _m.label = 8;
1105
+ case 8:
1106
+ if (!(sessionState.vodMediaSeqVideo >= currentVod.getLiveMediaSequencesCount() - 1)) return [3 /*break*/, 11];
1107
+ _c = sessionState;
1108
+ return [4 /*yield*/, this._sessionState.set("vodMediaSeqVideo", currentVod.getLiveMediaSequencesCount() - 1)];
1109
+ case 9:
1110
+ _c.vodMediaSeqVideo = _m.sent();
1111
+ _d = sessionState;
1112
+ return [4 /*yield*/, this._sessionState.set("state", SessionState.VOD_NEXT_INIT)];
1113
+ case 10:
1114
+ _d.state = _m.sent();
1115
+ _m.label = 11;
1116
+ case 11:
1117
+ debug("[".concat(this._sessionId, "]: VIDEO ").concat(timeSinceLastRequest, " (").concat(this.averageSegmentDuration, ") bandwidth=").concat(bw, " vodMediaSeq=(").concat(sessionState.vodMediaSeqVideo, "_").concat(sessionState.vodMediaSeqAudio, ")"));
1118
+ try {
1119
+ m3u8 = currentVod.getLiveMediaSequences(sessionState.mediaSeq, bw, sessionState.vodMediaSeqVideo, sessionState.discSeq);
1120
+ }
1121
+ catch (exc) {
1122
+ if (sessionState.lastM3u8[bw]) {
1123
+ m3u8 = sessionState.lastM3u8[bw];
1124
+ }
1125
+ else {
1126
+ logerror(this._sessionId, exc);
1127
+ throw new Error('Failed to generate media manifest');
1128
+ }
1129
+ }
1130
+ lastM3u8 = sessionState.lastM3u8;
1131
+ lastM3u8[bw] = m3u8;
1132
+ _e = sessionState;
1133
+ return [4 /*yield*/, this._sessionState.set("lastM3u8", lastM3u8)];
1134
+ case 12:
1135
+ _e.lastM3u8 = _m.sent();
1136
+ _f = sessionState;
1137
+ return [4 /*yield*/, this._sessionState.set("lastServedM3u8", m3u8)];
1138
+ case 13:
1139
+ _f.lastServedM3u8 = _m.sent();
1140
+ _g = sessionState;
1141
+ return [4 /*yield*/, this._sessionState.set("tsLastRequestVideo", Date.now())];
1142
+ case 14:
1143
+ _g.tsLastRequestVideo = _m.sent();
1144
+ if (!(sessionState.state === SessionState.VOD_NEXT_INIT)) return [3 /*break*/, 23];
1145
+ return [4 /*yield*/, this._tickAsync()];
1146
+ case 15:
1147
+ _m.sent();
1148
+ return [4 /*yield*/, this._sessionState.get("tsLastRequestVideo")];
1149
+ case 16:
1150
+ tsLastRequestVideo_1 = _m.sent();
1151
+ timeSinceLastRequest_1 = (tsLastRequestVideo_1 === null) ? 0 : Date.now() - tsLastRequestVideo_1;
1152
+ return [4 /*yield*/, this._sessionState.getValues(["state", "vodMediaSeqVideo", "mediaSeq", "discSeq", "lastM3u8"])];
1153
+ case 17:
1154
+ sessionState_1 = _m.sent();
1155
+ if (!(sessionState_1.state === SessionState.VOD_NEXT_INITIATING)) return [3 /*break*/, 19];
1156
+ _h = sessionState_1;
1157
+ return [4 /*yield*/, this._sessionState.set("state", SessionState.VOD_PLAYING)];
1158
+ case 18:
1159
+ _h.state = _m.sent();
1160
+ _m.label = 19;
1161
+ case 19:
1162
+ debug("[".concat(this._sessionId, "]: VIDEO ").concat(timeSinceLastRequest_1, " (").concat(this.averageSegmentDuration, ") bandwidth=").concat(bw, " vodMediaSeq=(").concat(sessionState_1.vodMediaSeqVideo, "_").concat(sessionState_1.vodMediaSeqAudio, ")"));
1163
+ try {
1164
+ m3u8 = currentVod.getLiveMediaSequences(sessionState_1.mediaSeq, bw, sessionState_1.vodMediaSeqVideo, sessionState_1.discSeq);
1165
+ }
1166
+ catch (exc) {
1167
+ if (sessionState_1.lastM3u8[bw]) {
1168
+ m3u8 = sessionState_1.lastM3u8[bw];
1169
+ }
1170
+ else {
1171
+ logerror(this._sessionId, exc);
1172
+ throw new Error('Failed to generate media manifest');
1173
+ }
1174
+ }
1175
+ lastM3u8_1 = sessionState_1.lastM3u8;
1176
+ lastM3u8_1[bw] = m3u8;
1177
+ _j = sessionState_1;
1178
+ return [4 /*yield*/, this._sessionState.set("lastM3u8", lastM3u8_1)];
1179
+ case 20:
1180
+ _j.lastM3u8 = _m.sent();
1181
+ _k = sessionState_1;
1182
+ return [4 /*yield*/, this._sessionState.set("lastServedM3u8", m3u8)];
1183
+ case 21:
1184
+ _k.lastServedM3u8 = _m.sent();
1185
+ _l = sessionState_1;
1186
+ return [4 /*yield*/, this._sessionState.set("tsLastRequestVideo", Date.now())];
1187
+ case 22:
1188
+ _l.tsLastRequestVideo = _m.sent();
1189
+ return [2 /*return*/, m3u8];
1190
+ case 23: return [2 /*return*/, m3u8];
1191
+ }
1192
+ });
1193
+ });
1194
+ };
1195
+ Session.prototype.getAudioManifestAsync = function (audioGroupId, audioLanguage, opts) {
1196
+ return __awaiter(this, void 0, void 0, function () {
1197
+ var tsLastRequestAudio, timeSinceLastRequest, sessionState, currentVod, sequencesToIncrement, _a, _b, m3u8, lastM3u8, _c, _d;
1198
+ return __generator(this, function (_e) {
1199
+ switch (_e.label) {
1200
+ case 0: return [4 /*yield*/, this._sessionState.get("tsLastRequestAudio")];
1201
+ case 1:
1202
+ tsLastRequestAudio = _e.sent();
1203
+ timeSinceLastRequest = (tsLastRequestAudio === null) ? 0 : Date.now() - tsLastRequestAudio;
1204
+ return [4 /*yield*/, this._sessionState.getValues(["state", "vodMediaSeqVideo", "vodMediaSeqAudio", "mediaSeq", "discSeq", "lastM3u8"])];
1205
+ case 2:
1206
+ sessionState = _e.sent();
1207
+ return [4 /*yield*/, this._sessionState.getCurrentVod()];
1208
+ case 3:
1209
+ currentVod = _e.sent();
1210
+ if (!(sessionState.state !== SessionState.VOD_NEXT_INITIATING)) return [3 /*break*/, 6];
1211
+ sequencesToIncrement = Math.ceil(timeSinceLastRequest / this.averageSegmentDuration);
1212
+ if (!(sessionState.vodMediaSeqAudio < sessionState.vodMediaSeqVideo)) return [3 /*break*/, 6];
1213
+ _a = sessionState;
1214
+ return [4 /*yield*/, this._sessionState.increment("vodMediaSeqAudio", sequencesToIncrement)];
1215
+ case 4:
1216
+ _a.vodMediaSeqAudio = _e.sent();
1217
+ if (!(sessionState.vodMediaSeqAudio >= currentVod.getLiveMediaSequencesCount() - 1)) return [3 /*break*/, 6];
1218
+ _b = sessionState;
1219
+ return [4 /*yield*/, this._sessionState.set("vodMediaSeqAudio", currentVod.getLiveMediaSequencesCount() - 1)];
1220
+ case 5:
1221
+ _b.vodMediaSeqAudio = _e.sent();
1222
+ _e.label = 6;
1223
+ case 6:
1224
+ debug("[".concat(this._sessionId, "]: AUDIO ").concat(timeSinceLastRequest, " (").concat(this.averageSegmentDuration, ") audioGroupId=").concat(audioGroupId, " audioLanguage=").concat(audioLanguage, " vodMediaSeq=(").concat(sessionState.vodMediaSeqVideo, "_").concat(sessionState.vodMediaSeqAudio, ")"));
1225
+ try {
1226
+ m3u8 = currentVod.getLiveMediaAudioSequences(sessionState.mediaSeq, audioGroupId, audioLanguage, sessionState.vodMediaSeqAudio, sessionState.discSeq);
1227
+ }
1228
+ catch (exc) {
1229
+ if (sessionState.lastM3u8[audioGroupId][audioLanguage]) {
1230
+ m3u8 = sessionState.lastM3u8[audioGroupId][audioLanguage];
1231
+ }
1232
+ else {
1233
+ logerror(this._sessionId, exc);
1234
+ throw new Error('Failed to generate audio manifest');
1235
+ }
1236
+ }
1237
+ lastM3u8 = sessionState.lastM3u8;
1238
+ lastM3u8[audioGroupId] = {};
1239
+ lastM3u8[audioGroupId][audioLanguage] = m3u8;
1240
+ _c = sessionState;
1241
+ return [4 /*yield*/, this._sessionState.set("lastM3u8", lastM3u8)];
1242
+ case 7:
1243
+ _c.lastM3u8 = _e.sent();
1244
+ _d = sessionState;
1245
+ return [4 /*yield*/, this._sessionState.set("tsLastRequestAudio", Date.now())];
1246
+ case 8:
1247
+ _d.tsLastRequestAudio = _e.sent();
1248
+ return [2 /*return*/, m3u8];
1249
+ }
1250
+ });
1251
+ });
1252
+ };
1253
+ Session.prototype.getMasterManifestAsync = function (filter) {
1254
+ return __awaiter(this, void 0, void 0, function () {
1255
+ var m3u8, currentVod, audioGroupIds, defaultAudioGroupId, hasClosedCaptions, i, audioGroupId, j, audioTrack, sessionProfile, i, audioGroupId, j, audioTrack;
1256
+ var _this = this;
1257
+ return __generator(this, function (_a) {
1258
+ switch (_a.label) {
1259
+ case 0:
1260
+ m3u8 = "#EXTM3U\n";
1261
+ m3u8 += "#EXT-X-VERSION:4\n";
1262
+ m3u8 += m3u8Header(this._instanceId);
1263
+ m3u8 += "#EXT-X-SESSION-DATA:DATA-ID=\"eyevinn.tv.session.id\",VALUE=\"".concat(this._sessionId, "\"\n");
1264
+ m3u8 += "#EXT-X-SESSION-DATA:DATA-ID=\"eyevinn.tv.eventstream\",VALUE=\"/eventstream/".concat(this._sessionId, "\"\n");
1265
+ return [4 /*yield*/, this._sessionState.getCurrentVod()];
1266
+ case 1:
1267
+ currentVod = _a.sent();
1268
+ if (!currentVod) {
1269
+ throw new Error('Session not ready');
1270
+ }
1271
+ audioGroupIds = currentVod.getAudioGroups();
1272
+ hasClosedCaptions = this._closedCaptions && this._closedCaptions.length > 0;
1273
+ if (hasClosedCaptions) {
1274
+ this._closedCaptions.forEach(function (cc) {
1275
+ m3u8 += "#EXT-X-MEDIA:TYPE=CLOSED-CAPTIONS,GROUP-ID=\"cc\",LANGUAGE=\"".concat(cc.lang, "\",NAME=\"").concat(cc.name, "\",DEFAULT=").concat(cc.default ? "YES" : "NO", ",AUTOSELECT=").concat(cc.auto ? "YES" : "NO", ",INSTREAM-ID=\"").concat(cc.id, "\"\n");
1276
+ });
1277
+ }
1278
+ if (this.use_demuxed_audio === true && this._audioTracks) {
1279
+ if (audioGroupIds.length > 0) {
1280
+ m3u8 += "# AUDIO groups\n";
1281
+ for (i = 0; i < audioGroupIds.length; i++) {
1282
+ audioGroupId = audioGroupIds[i];
1283
+ for (j = 0; j < this._audioTracks.length; j++) {
1284
+ audioTrack = this._audioTracks[j];
1285
+ // Make default track if set property is true.
1286
+ if (audioTrack.default) {
1287
+ m3u8 += "#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID=\"".concat(audioGroupId, "\",LANGUAGE=\"").concat(audioTrack.language, "\", NAME=\"").concat(audioTrack.name, "\",AUTOSELECT=YES,DEFAULT=YES,CHANNELS=\"2\",URI=\"master-").concat(audioGroupId, "_").concat(audioTrack.language, ".m3u8;session=").concat(this._sessionId, "\"\n");
1288
+ }
1289
+ else {
1290
+ m3u8 += "#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID=\"".concat(audioGroupId, "\",LANGUAGE=\"").concat(audioTrack.language, "\", NAME=\"").concat(audioTrack.name, "\",AUTOSELECT=YES,DEFAULT=NO,CHANNELS=\"2\",URI=\"master-").concat(audioGroupId, "_").concat(audioTrack.language, ".m3u8;session=").concat(this._sessionId, "\"\n");
1291
+ }
1292
+ }
1293
+ }
1294
+ // As of now, by default set StreamItem's AUDIO attribute to <first audio group-id>
1295
+ defaultAudioGroupId = audioGroupIds[0];
1296
+ }
1297
+ }
1298
+ if (this._sessionProfile) {
1299
+ sessionProfile = filter ? applyFilter(this._sessionProfile, filter) : this._sessionProfile;
1300
+ sessionProfile.forEach(function (profile) {
1301
+ m3u8 += '#EXT-X-STREAM-INF:BANDWIDTH=' + profile.bw + ',RESOLUTION=' + profile.resolution[0] + 'x' + profile.resolution[1] + ',CODECS="' + profile.codecs + '"' + (defaultAudioGroupId ? ",AUDIO=\"".concat(defaultAudioGroupId, "\"") : '') + (hasClosedCaptions ? ',CLOSED-CAPTIONS="cc"' : '') + '\n';
1302
+ m3u8 += "master" + profile.bw + ".m3u8;session=" + _this._sessionId + "\n";
1303
+ });
1304
+ }
1305
+ else {
1306
+ currentVod.getUsageProfiles().forEach(function (profile) {
1307
+ m3u8 += '#EXT-X-STREAM-INF:BANDWIDTH=' + profile.bw + ',RESOLUTION=' + profile.resolution + ',CODECS="' + profile.codecs + '"' + (defaultAudioGroupId ? ",AUDIO=\"".concat(defaultAudioGroupId, "\"") : '') + (hasClosedCaptions ? ',CLOSED-CAPTIONS="cc"' : '') + '\n';
1308
+ m3u8 += "master" + profile.bw + ".m3u8;session=" + _this._sessionId + "\n";
1309
+ });
1310
+ }
1311
+ if (this.use_demuxed_audio === true && this._audioTracks) {
1312
+ for (i = 0; i < audioGroupIds.length; i++) {
1313
+ audioGroupId = audioGroupIds[i];
1314
+ for (j = 0; j < this._audioTracks.length; j++) {
1315
+ audioTrack = this._audioTracks[j];
1316
+ m3u8 += "#EXT-X-STREAM-INF:BANDWIDTH=97000,CODECS=\"mp4a.40.2\",AUDIO=\"".concat(audioGroupId, "\"\n");
1317
+ m3u8 += "master-".concat(audioGroupId, "_").concat(audioTrack.language, ".m3u8;session=").concat(this._sessionId, "\n");
1318
+ }
1319
+ }
1320
+ }
1321
+ this.produceEvent({
1322
+ type: 'NOW_PLAYING',
1323
+ data: {
1324
+ id: this.currentMetadata.id,
1325
+ title: this.currentMetadata.title,
1326
+ }
1327
+ });
1328
+ this._sessionState.set("tsLastRequestMaster", Date.now());
1329
+ return [2 /*return*/, m3u8];
1330
+ }
1331
+ });
1332
+ });
1333
+ };
1334
+ Session.prototype.getAudioGroupsAndLangs = function () {
1335
+ return __awaiter(this, void 0, void 0, function () {
1336
+ var currentVod, audioGroupIds, allAudioGroupsAndTheirLanguages;
1337
+ return __generator(this, function (_a) {
1338
+ switch (_a.label) {
1339
+ case 0: return [4 /*yield*/, this._sessionState.getCurrentVod()];
1340
+ case 1:
1341
+ currentVod = _a.sent();
1342
+ if (!currentVod) {
1343
+ throw new Error('Session not ready');
1344
+ }
1345
+ audioGroupIds = currentVod.getAudioGroups();
1346
+ allAudioGroupsAndTheirLanguages = {};
1347
+ audioGroupIds.forEach(function (groupId) {
1348
+ allAudioGroupsAndTheirLanguages[groupId] =
1349
+ currentVod.getAudioLangsForAudioGroup(groupId);
1350
+ });
1351
+ return [2 /*return*/, allAudioGroupsAndTheirLanguages];
1352
+ }
1353
+ });
1354
+ });
1355
+ };
1356
+ Session.prototype.consumeEvent = function () {
1357
+ return this._events.shift();
1358
+ };
1359
+ Session.prototype.produceEvent = function (event) {
1360
+ this._events.push(event);
1361
+ };
1362
+ Session.prototype.hasPlayhead = function () {
1363
+ return !this.disabledPlayhead;
1364
+ };
1365
+ Session.prototype._insertSlate = function (currentVod) {
1366
+ return __awaiter(this, void 0, void 0, function () {
1367
+ var slateVod, sessionState, endValue, lastDiscontinuity;
1368
+ return __generator(this, function (_a) {
1369
+ switch (_a.label) {
1370
+ case 0:
1371
+ if (!this.slateUri) return [3 /*break*/, 11];
1372
+ console.error("[".concat(this._sessionId, "]: Will insert slate"));
1373
+ return [4 /*yield*/, this._loadSlate(currentVod)];
1374
+ case 1:
1375
+ slateVod = _a.sent();
1376
+ debug("[".concat(this._sessionId, "]: slate loaded"));
1377
+ return [4 /*yield*/, this._sessionState.getValues(["slateCount", "mediaSeq", "discSeq"])];
1378
+ case 2:
1379
+ sessionState = _a.sent();
1380
+ endValue = 0;
1381
+ lastDiscontinuity = 0;
1382
+ if (currentVod) {
1383
+ if (currentVod.sequenceAlwaysContainNewSegments) {
1384
+ endValue = currentVod.getLastSequenceMediaSequenceValue();
1385
+ }
1386
+ else {
1387
+ endValue = currentVod.getLiveMediaSequencesCount();
1388
+ }
1389
+ lastDiscontinuity = currentVod.getLastDiscontinuity();
1390
+ }
1391
+ return [4 /*yield*/, this._sessionState.set("vodMediaSeqVideo", 0)];
1392
+ case 3:
1393
+ _a.sent();
1394
+ return [4 /*yield*/, this._sessionState.set("vodMediaSeqAudio", 0)];
1395
+ case 4:
1396
+ _a.sent();
1397
+ return [4 /*yield*/, this._sessionState.set("state", SessionState.VOD_NEXT_INITIATING)];
1398
+ case 5:
1399
+ _a.sent();
1400
+ return [4 /*yield*/, this._sessionState.setCurrentVod(slateVod)];
1401
+ case 6:
1402
+ _a.sent();
1403
+ return [4 /*yield*/, this._sessionState.set("mediaSeq", sessionState.mediaSeq + endValue)];
1404
+ case 7:
1405
+ _a.sent();
1406
+ return [4 /*yield*/, this._sessionState.set("discSeq", sessionState.discSeq + lastDiscontinuity)];
1407
+ case 8:
1408
+ _a.sent();
1409
+ return [4 /*yield*/, this._sessionState.set("slateCount", sessionState.slateCount + 1)];
1410
+ case 9:
1411
+ _a.sent();
1412
+ return [4 /*yield*/, this._playheadState.set("playheadRef", Date.now())];
1413
+ case 10:
1414
+ _a.sent();
1415
+ cloudWatchLog(!this.cloudWatchLogging, 'engine-session', { event: 'slateInserted', channel: this._sessionId });
1416
+ return [2 /*return*/, slateVod];
1417
+ case 11: return [2 /*return*/, null];
1418
+ }
1419
+ });
1420
+ });
1421
+ };
1422
+ Session.prototype._tickAsync = function () {
1423
+ return __awaiter(this, void 0, void 0, function () {
1424
+ var newVod, sessionState, isLeader, currentVod, vodResponse, _a, nextVodPromise, nextVodStart, _b, loadPromise, hlsOpts, loadStart, _c, _d, _e, _f, _g, _h, _j, _k, err_6, _l, length_1, endMseqValue, lastDiscontinuity, _m, vodPromise, gracePeriod, nextVodStart, _o, loadPromise, hlsOpts, loadStart, _p, _q, _r, _s, _t, _u, _v, diffMs, err_7, startTS, _w, mSeq, currentVod_1, dSeq, mSeqOffset, reloadBehind, segments, playheadState, nextMseq, _x, err_8;
1425
+ var _this = this;
1426
+ return __generator(this, function (_y) {
1427
+ switch (_y.label) {
1428
+ case 0: return [4 /*yield*/, this._sessionState.getValues(["state", "assetId", "vodMediaSeqVideo", "vodMediaSeqAudio", "mediaSeq", "discSeq", "nextVod"])];
1429
+ case 1:
1430
+ sessionState = _y.sent();
1431
+ return [4 /*yield*/, this._sessionStateStore.isLeader(this._instanceId)];
1432
+ case 2:
1433
+ isLeader = _y.sent();
1434
+ return [4 /*yield*/, this._sessionState.getCurrentVod()];
1435
+ case 3:
1436
+ currentVod = _y.sent();
1437
+ if (!sessionState.state) {
1438
+ sessionState.state = SessionState.VOD_INIT;
1439
+ }
1440
+ _a = sessionState.state;
1441
+ switch (_a) {
1442
+ case SessionState.VOD_INIT: return [3 /*break*/, 4];
1443
+ case SessionState.VOD_INIT_BY_ID: return [3 /*break*/, 4];
1444
+ case SessionState.VOD_PLAYING: return [3 /*break*/, 25];
1445
+ case SessionState.VOD_NEXT_INITIATING: return [3 /*break*/, 31];
1446
+ case SessionState.VOD_NEXT_INIT: return [3 /*break*/, 32];
1447
+ case SessionState.VOD_RELOAD_INIT: return [3 /*break*/, 58];
1448
+ case SessionState.VOD_RELOAD_INITIATING: return [3 /*break*/, 78];
1449
+ }
1450
+ return [3 /*break*/, 82];
1451
+ case 4:
1452
+ _y.trys.push([4, 22, , 25]);
1453
+ // Needed if store was reset
1454
+ return [4 /*yield*/, this._sessionStateStore.clearLeaderCache()];
1455
+ case 5:
1456
+ // Needed if store was reset
1457
+ _y.sent();
1458
+ return [4 /*yield*/, this._sessionStateStore.isLeader(this._instanceId)];
1459
+ case 6:
1460
+ isLeader = _y.sent();
1461
+ nextVodPromise = void 0;
1462
+ if (sessionState.state === SessionState.VOD_INIT) {
1463
+ debug("[".concat(this._sessionId, "]: state=VOD_INIT"));
1464
+ nextVodPromise = this._getNextVod();
1465
+ }
1466
+ else if (sessionState.state === SessionState.VOD_INIT_BY_ID) {
1467
+ debug("[".concat(this._sessionId, "]: state=VOD_INIT_BY_ID ").concat(sessionState.assetId));
1468
+ nextVodPromise = this._getNextVodById(sessionState.assetId);
1469
+ }
1470
+ if (!isLeader) return [3 /*break*/, 18];
1471
+ nextVodStart = Date.now();
1472
+ return [4 /*yield*/, nextVodPromise];
1473
+ case 7:
1474
+ vodResponse = _y.sent();
1475
+ _b = sessionState;
1476
+ return [4 /*yield*/, this._sessionState.set("nextVod", vodResponse)];
1477
+ case 8:
1478
+ _b.nextVod = _y.sent();
1479
+ cloudWatchLog(!this.cloudWatchLogging, 'engine-session', { event: 'nextVod', channel: this._sessionId, reqTimeMs: Date.now() - nextVodStart });
1480
+ loadPromise = void 0;
1481
+ if (!vodResponse.type) {
1482
+ debug("[".concat(this._sessionId, "]: got first VOD uri=").concat(vodResponse.uri, ":").concat(vodResponse.offset || 0));
1483
+ hlsOpts = { sequenceAlwaysContainNewSegments: this.alwaysNewSegments };
1484
+ newVod = new HLSVod(vodResponse.uri, [], null, vodResponse.offset * 1000, m3u8Header(this._instanceId), hlsOpts);
1485
+ if (vodResponse.timedMetadata) {
1486
+ Object.keys(vodResponse.timedMetadata).map(function (k) {
1487
+ newVod.addMetadata(k, vodResponse.timedMetadata[k]);
1488
+ });
1489
+ }
1490
+ currentVod = newVod;
1491
+ loadPromise = currentVod.load();
1492
+ }
1493
+ else {
1494
+ if (vodResponse.type === 'gap') {
1495
+ loadPromise = new Promise(function (resolve, reject) {
1496
+ _this._fillGap(null, vodResponse.desiredDuration)
1497
+ .then(function (gapVod) {
1498
+ currentVod = gapVod;
1499
+ resolve(gapVod);
1500
+ }).catch(reject);
1501
+ });
1502
+ }
1503
+ }
1504
+ loadStart = Date.now();
1505
+ return [4 /*yield*/, loadPromise];
1506
+ case 9:
1507
+ _y.sent();
1508
+ cloudWatchLog(!this.cloudWatchLogging, 'engine-session', { event: 'loadVod', channel: this._sessionId, loadTimeMs: Date.now() - loadStart });
1509
+ debug("[".concat(this._sessionId, "]: first VOD loaded"));
1510
+ debug("[".concat(this._sessionId, "]: ").concat(currentVod.getDeltaTimes()));
1511
+ debug("[".concat(this._sessionId, "]: ").concat(currentVod.getPlayheadPositions()));
1512
+ //debug(newVod);
1513
+ _c = sessionState;
1514
+ return [4 /*yield*/, this._sessionState.set("mediaSeq", 0)];
1515
+ case 10:
1516
+ //debug(newVod);
1517
+ _c.mediaSeq = _y.sent();
1518
+ _d = sessionState;
1519
+ return [4 /*yield*/, this._sessionState.set("discSeq", 0)];
1520
+ case 11:
1521
+ _d.discSeq = _y.sent();
1522
+ _e = sessionState;
1523
+ return [4 /*yield*/, this._sessionState.set("vodMediaSeqVideo", 0)];
1524
+ case 12:
1525
+ _e.vodMediaSeqVideo = _y.sent();
1526
+ _f = sessionState;
1527
+ return [4 /*yield*/, this._sessionState.set("vodMediaSeqAudio", 0)];
1528
+ case 13:
1529
+ _f.vodMediaSeqAudio = _y.sent();
1530
+ return [4 /*yield*/, this._playheadState.set("playheadRef", Date.now())];
1531
+ case 14:
1532
+ _y.sent();
1533
+ this.produceEvent({
1534
+ type: 'NOW_PLAYING',
1535
+ data: {
1536
+ id: this.currentMetadata.id,
1537
+ title: this.currentMetadata.title,
1538
+ }
1539
+ });
1540
+ _g = sessionState;
1541
+ return [4 /*yield*/, this._sessionState.set("state", SessionState.VOD_PLAYING)];
1542
+ case 15:
1543
+ _g.state = _y.sent();
1544
+ _h = sessionState;
1545
+ return [4 /*yield*/, this._sessionState.setCurrentVod(currentVod, { ttl: currentVod.getDuration() * 1000 })];
1546
+ case 16:
1547
+ _h.currentVod = _y.sent();
1548
+ return [4 /*yield*/, this._sessionState.remove("nextVod")];
1549
+ case 17:
1550
+ _y.sent();
1551
+ return [2 /*return*/];
1552
+ case 18:
1553
+ debug("[".concat(this._sessionId, "]: not a leader so will go directly to state VOD_PLAYING"));
1554
+ _j = sessionState;
1555
+ return [4 /*yield*/, this._sessionState.set("state", SessionState.VOD_PLAYING)];
1556
+ case 19:
1557
+ _j.state = _y.sent();
1558
+ _k = sessionState;
1559
+ return [4 /*yield*/, this._sessionState.getCurrentVod()];
1560
+ case 20:
1561
+ _k.currentVod = _y.sent();
1562
+ return [2 /*return*/];
1563
+ case 21: return [3 /*break*/, 25];
1564
+ case 22:
1565
+ err_6 = _y.sent();
1566
+ console.error("[".concat(this._sessionId, "]: Failed to init first VOD"));
1567
+ if (this._assetManager.handleError) {
1568
+ this._assetManager.handleError(new Error("Failed to init first VOD"), vodResponse);
1569
+ }
1570
+ cloudWatchLog(!this.cloudWatchLogging, 'engine-session', { event: 'error', on: 'firstvod', channel: this._sessionId, err: err_6, vod: vodResponse });
1571
+ debug(err_6);
1572
+ return [4 /*yield*/, this._sessionState.remove("nextVod")];
1573
+ case 23:
1574
+ _y.sent();
1575
+ return [4 /*yield*/, this._insertSlate(currentVod)];
1576
+ case 24:
1577
+ currentVod = _y.sent();
1578
+ if (!currentVod) {
1579
+ debug("No slate to load");
1580
+ throw err_6;
1581
+ }
1582
+ return [3 /*break*/, 25];
1583
+ case 25:
1584
+ if (!isLeader) return [3 /*break*/, 29];
1585
+ // Handle edge case where store has been reset, but leader has not cleared cache.
1586
+ if (this.prevVodMediaSeq.video === null) {
1587
+ this.prevVodMediaSeq.video = sessionState.vodMediaSeqVideo;
1588
+ }
1589
+ if (this.prevMediaSeqOffset.video === null) {
1590
+ this.prevMediaSeqOffset.video = sessionState.mediaSeq;
1591
+ }
1592
+ if (!(sessionState.vodMediaSeqVideo < this.prevVodMediaSeq.video)) return [3 /*break*/, 28];
1593
+ debug("[".concat(this._sessionId, "]: state=VOD_PLAYING, current[").concat(sessionState.vodMediaSeqVideo, "], prev[").concat(this.prevVodMediaSeq.video, "], total[").concat(currentVod.getLiveMediaSequencesCount(), "]"));
1594
+ return [4 /*yield*/, this._sessionState.clearCurrentVodCache()];
1595
+ case 26:
1596
+ _y.sent();
1597
+ return [4 /*yield*/, this._sessionState.getCurrentVod()];
1598
+ case 27:
1599
+ currentVod = _y.sent();
1600
+ this.prevVodMediaSeq.video = sessionState.vodMediaSeqVideo;
1601
+ _y.label = 28;
1602
+ case 28: return [3 /*break*/, 30];
1603
+ case 29:
1604
+ // Handle edge case where Leader loaded next vod but Follower remained in state=VOD_PLAYING
1605
+ if (this.prevMediaSeqOffset.video !== null & sessionState.mediaSeq !== this.prevMediaSeqOffset.video) {
1606
+ debug("[".concat(this._sessionId, "]: state=VOD_PLAYING, current[").concat(sessionState.vodMediaSeqVideo, "], prev[").concat(this.prevVodMediaSeq.video, "], total[").concat(currentVod.getLiveMediaSequencesCount(), "]"));
1607
+ debug("[".concat(this._sessionId, "]: mediaSeq offsets -> current[").concat(sessionState.vodMediaSeqVideo, "], prev[").concat(this.prevVodMediaSeq.video, "]"));
1608
+ // Allow Follower to clear VodCache...
1609
+ this.isAllowedToClearVodCache = true;
1610
+ }
1611
+ _y.label = 30;
1612
+ case 30:
1613
+ debug("[".concat(this._sessionId, "]: state=VOD_PLAYING (").concat(sessionState.vodMediaSeqVideo, "_").concat(sessionState.vodMediaSeqAudio, ", ").concat(currentVod.getLiveMediaSequencesCount(), ")"));
1614
+ return [2 /*return*/];
1615
+ case 31:
1616
+ debug("[".concat(this._sessionId, "]: state=VOD_NEXT_INITIATING (").concat(sessionState.vodMediaSeqVideo, "_").concat(sessionState.vodMediaSeqAudio, ", ").concat(currentVod.getLiveMediaSequencesCount(), ")"));
1617
+ if (!isLeader) {
1618
+ debug("[".concat(this._sessionId, "]: not the leader so just waiting for the VOD to be initiated"));
1619
+ }
1620
+ // Allow Leader|Follower to clear vodCache...
1621
+ this.isAllowedToClearVodCache = true;
1622
+ return [2 /*return*/];
1623
+ case 32:
1624
+ _y.trys.push([32, 54, , 57]);
1625
+ debug("[".concat(this._sessionId, "]: state=VOD_NEXT_INIT"));
1626
+ if (!isLeader) return [3 /*break*/, 49];
1627
+ if (!!currentVod) return [3 /*break*/, 34];
1628
+ debug("[".concat(this._sessionId, "]: no VOD to append to, assume first VOD to init"));
1629
+ _l = sessionState;
1630
+ return [4 /*yield*/, this._sessionState.set("state", SessionState.VOD_INIT)];
1631
+ case 33:
1632
+ _l.state = _y.sent();
1633
+ return [2 /*return*/];
1634
+ case 34:
1635
+ length_1 = currentVod.getLiveMediaSequencesCount();
1636
+ endMseqValue = void 0;
1637
+ if (currentVod.sequenceAlwaysContainNewSegments) {
1638
+ endMseqValue = currentVod.getLastSequenceMediaSequenceValue();
1639
+ }
1640
+ else {
1641
+ endMseqValue = currentVod.getLiveMediaSequencesCount();
1642
+ }
1643
+ lastDiscontinuity = currentVod.getLastDiscontinuity();
1644
+ _m = sessionState;
1645
+ return [4 /*yield*/, this._sessionState.set("state", SessionState.VOD_NEXT_INITIATING)];
1646
+ case 35:
1647
+ _m.state = _y.sent();
1648
+ vodPromise = this._getNextVod();
1649
+ if (!(length_1 === 1)) return [3 /*break*/, 37];
1650
+ gracePeriod = (this.averageSegmentDuration / 2);
1651
+ debug("[".concat(this._sessionId, "]: adding a grace period before calling nextVod: ").concat(gracePeriod, "ms"));
1652
+ return [4 /*yield*/, timer(gracePeriod)];
1653
+ case 36:
1654
+ _y.sent();
1655
+ _y.label = 37;
1656
+ case 37:
1657
+ nextVodStart = Date.now();
1658
+ return [4 /*yield*/, vodPromise];
1659
+ case 38:
1660
+ vodResponse = _y.sent();
1661
+ _o = sessionState;
1662
+ return [4 /*yield*/, this._sessionState.set("nextVod", vodResponse)];
1663
+ case 39:
1664
+ _o.nextVod = _y.sent();
1665
+ cloudWatchLog(!this.cloudWatchLogging, 'engine-session', { event: 'nextVod', channel: this._sessionId, reqTimeMs: Date.now() - nextVodStart });
1666
+ loadPromise = void 0;
1667
+ if (!vodResponse.type) {
1668
+ debug("[".concat(this._sessionId, "]: got next VOD uri=").concat(vodResponse.uri, ":").concat(vodResponse.offset));
1669
+ hlsOpts = { sequenceAlwaysContainNewSegments: this.alwaysNewSegments };
1670
+ newVod = new HLSVod(vodResponse.uri, null, null, vodResponse.offset * 1000, m3u8Header(this._instanceId), hlsOpts);
1671
+ if (vodResponse.timedMetadata) {
1672
+ Object.keys(vodResponse.timedMetadata).map(function (k) {
1673
+ newVod.addMetadata(k, vodResponse.timedMetadata[k]);
1674
+ });
1675
+ }
1676
+ this.produceEvent({
1677
+ type: 'NEXT_VOD_SELECTED',
1678
+ data: {
1679
+ id: this.currentMetadata.id,
1680
+ uri: vodResponse.uri,
1681
+ title: this.currentMetadata.title || '',
1682
+ }
1683
+ });
1684
+ loadPromise = newVod.loadAfter(currentVod);
1685
+ if (vodResponse.diffMs) {
1686
+ this.diffCompensation = vodResponse.diffMs;
1687
+ if (this.diffCompensation) {
1688
+ this.timePositionOffset = this.diffCompensation;
1689
+ cloudWatchLog(!this.cloudWatchLogging, 'engine-session', { event: 'timePositionOffsetUpdated', channel: this._sessionId, offsetMs: this.timePositionOffset });
1690
+ }
1691
+ else {
1692
+ this.timePositionOffset = 0;
1693
+ }
1694
+ }
1695
+ }
1696
+ else {
1697
+ loadPromise = new Promise(function (resolve, reject) {
1698
+ _this._fillGap(currentVod, vodResponse.desiredDuration)
1699
+ .then(function (gapVod) {
1700
+ newVod = gapVod;
1701
+ resolve(newVod);
1702
+ }).catch(reject);
1703
+ });
1704
+ }
1705
+ loadStart = Date.now();
1706
+ return [4 /*yield*/, ChaosMonkey.loadVod(loadPromise)];
1707
+ case 40:
1708
+ _y.sent();
1709
+ cloudWatchLog(!this.cloudWatchLogging, 'engine-session', { event: 'loadVod', channel: this._sessionId, loadTimeMs: Date.now() - loadStart });
1710
+ this.leaderIsSettingNextVod = true;
1711
+ debug("[".concat(this._sessionId, "]: next VOD loaded (").concat(newVod.getDeltaTimes(), ")"));
1712
+ debug("[".concat(this._sessionId, "]: ").concat(newVod.getPlayheadPositions()));
1713
+ currentVod = newVod;
1714
+ debug("[".concat(this._sessionId, "]: msequences=").concat(currentVod.getLiveMediaSequencesCount()));
1715
+ _p = sessionState;
1716
+ return [4 /*yield*/, this._sessionState.set("vodMediaSeqVideo", 0)];
1717
+ case 41:
1718
+ _p.vodMediaSeqVideo = _y.sent();
1719
+ _q = sessionState;
1720
+ return [4 /*yield*/, this._sessionState.set("vodMediaSeqAudio", 0)];
1721
+ case 42:
1722
+ _q.vodMediaSeqAudio = _y.sent();
1723
+ _r = sessionState;
1724
+ return [4 /*yield*/, this._sessionState.set("mediaSeq", sessionState.mediaSeq + endMseqValue)];
1725
+ case 43:
1726
+ _r.mediaSeq = _y.sent();
1727
+ _s = sessionState;
1728
+ return [4 /*yield*/, this._sessionState.set("discSeq", sessionState.discSeq + lastDiscontinuity)];
1729
+ case 44:
1730
+ _s.discSeq = _y.sent();
1731
+ debug("[".concat(this._sessionId, "]: new sequence data set in store [").concat(sessionState.mediaSeq, "][").concat(sessionState.discSeq, "]"));
1732
+ return [4 /*yield*/, this._sessionState.remove("nextVod")];
1733
+ case 45:
1734
+ _y.sent();
1735
+ _t = sessionState;
1736
+ return [4 /*yield*/, this._sessionState.setCurrentVod(currentVod, { ttl: currentVod.getDuration() * 1000 })];
1737
+ case 46:
1738
+ _t.currentVod = _y.sent();
1739
+ this.leaderIsSettingNextVod = false;
1740
+ return [4 /*yield*/, this._playheadState.set("playheadRef", Date.now())];
1741
+ case 47:
1742
+ _y.sent();
1743
+ return [4 /*yield*/, this._playheadState.set("diffCompensation", this.diffCompensation)];
1744
+ case 48:
1745
+ _y.sent();
1746
+ debug("[".concat(this._sessionId, "]: sharing durrent vods diffCompensation=").concat(this.diffCompensation));
1747
+ this.produceEvent({
1748
+ type: 'NOW_PLAYING',
1749
+ data: {
1750
+ id: this.currentMetadata.id,
1751
+ title: this.currentMetadata.title,
1752
+ }
1753
+ });
1754
+ return [2 /*return*/];
1755
+ case 49:
1756
+ debug("[".concat(this._sessionId, "]: not a leader so will go directly to state VOD_NEXT_INITIATING"));
1757
+ this.waitingForNextVod = true;
1758
+ _u = sessionState;
1759
+ return [4 /*yield*/, this._sessionState.set("state", SessionState.VOD_NEXT_INITIATING)];
1760
+ case 50:
1761
+ _u.state = _y.sent();
1762
+ // Allow Leader|Follower to clear vodCache...
1763
+ this.isAllowedToClearVodCache = true;
1764
+ _v = sessionState;
1765
+ return [4 /*yield*/, this._sessionState.getCurrentVod()];
1766
+ case 51:
1767
+ _v.currentVod = _y.sent();
1768
+ return [4 /*yield*/, this._playheadState.get("diffCompensation")];
1769
+ case 52:
1770
+ diffMs = _y.sent();
1771
+ if (diffMs) {
1772
+ this.diffCompensation = diffMs;
1773
+ debug("[".concat(this._sessionId, "]: Setting diffCompensation=").concat(this.diffCompensation));
1774
+ if (this.diffCompensation) {
1775
+ this.timePositionOffset = this.diffCompensation;
1776
+ cloudWatchLog(!this.cloudWatchLogging, 'engine-session', { event: 'timePositionOffsetUpdated', channel: this._sessionId, offsetMs: this.timePositionOffset });
1777
+ }
1778
+ else {
1779
+ this.timePositionOffset = 0;
1780
+ }
1781
+ }
1782
+ _y.label = 53;
1783
+ case 53: return [3 /*break*/, 57];
1784
+ case 54:
1785
+ err_7 = _y.sent();
1786
+ console.error("[".concat(this._sessionId, "]: Failed to init next VOD"));
1787
+ debug("[".concat(this._sessionId, "]: ").concat(err_7));
1788
+ if (this._assetManager.handleError) {
1789
+ this._assetManager.handleError(new Error("Failed to init next VOD"), vodResponse);
1790
+ }
1791
+ cloudWatchLog(!this.cloudWatchLogging, 'engine-session', { event: 'error', on: 'nextvod', channel: this._sessionId, err: err_7, vod: vodResponse });
1792
+ return [4 /*yield*/, this._sessionState.remove("nextVod")];
1793
+ case 55:
1794
+ _y.sent();
1795
+ return [4 /*yield*/, this._insertSlate(currentVod)];
1796
+ case 56:
1797
+ currentVod = _y.sent();
1798
+ if (!currentVod) {
1799
+ debug("No slate to load");
1800
+ throw err_7;
1801
+ }
1802
+ // Allow Leader|Follower to clear vodCache...
1803
+ this.isAllowedToClearVodCache = true;
1804
+ return [3 /*break*/, 57];
1805
+ case 57: return [3 /*break*/, 83];
1806
+ case 58:
1807
+ _y.trys.push([58, 76, , 77]);
1808
+ debug("[".concat(this._sessionId, "]: state=VOD_RELOAD_INIT"));
1809
+ if (!isLeader) return [3 /*break*/, 73];
1810
+ startTS = Date.now();
1811
+ // 1) To tell Follower that, Leader is working on it!
1812
+ _w = sessionState;
1813
+ return [4 /*yield*/, this._sessionState.set("state", SessionState.VOD_RELOAD_INITIATING)];
1814
+ case 59:
1815
+ // 1) To tell Follower that, Leader is working on it!
1816
+ _w.state = _y.sent();
1817
+ mSeq = this.switchDataForSession.mediaSeq;
1818
+ return [4 /*yield*/, this._sessionState.getCurrentVod()];
1819
+ case 60:
1820
+ currentVod_1 = _y.sent();
1821
+ if (currentVod_1.sequenceAlwaysContainNewSegments) {
1822
+ // (!) will need to compensate if using this setting on HLSVod Object.
1823
+ Object.keys(this.switchDataForSession.transitionSegments).forEach(function (bw) {
1824
+ var shiftedSeg = _this.switchDataForSession.transitionSegments[bw].shift();
1825
+ if (shiftedSeg && shiftedSeg.discontinuity) {
1826
+ shiftedSeg = _this.switchDataForSession.transitionSegments[bw].shift();
1827
+ }
1828
+ });
1829
+ }
1830
+ dSeq = this.switchDataForSession.discSeq;
1831
+ mSeqOffset = this.switchDataForSession.mediaSeqOffset;
1832
+ reloadBehind = this.switchDataForSession.reloadBehind;
1833
+ segments = this.switchDataForSession.transitionSegments;
1834
+ if ([mSeq, dSeq, mSeqOffset, reloadBehind, segments].includes(null)) {
1835
+ debug("[".concat(this._sessionId, "]: LEADER: Cannot Reload VOD, missing switch-back data"));
1836
+ return [2 /*return*/];
1837
+ }
1838
+ return [4 /*yield*/, this._sessionState.set("mediaSeq", mSeq)];
1839
+ case 61:
1840
+ _y.sent();
1841
+ return [4 /*yield*/, this._playheadState.set("mediaSeq", mSeq)];
1842
+ case 62:
1843
+ _y.sent();
1844
+ return [4 /*yield*/, this._sessionState.set("discSeq", dSeq)];
1845
+ case 63:
1846
+ _y.sent();
1847
+ debug("[".concat(this._sessionId, "]: Setting current media and discontinuity count -> [").concat(mSeq, "]:[").concat(dSeq, "]"));
1848
+ // 3) Set new media segments/currentVod, to carry on the continuity from session-live
1849
+ debug("[".concat(this._sessionId, "]: LEADER: making changes to current VOD. I will also update currentVod in store."));
1850
+ return [4 /*yield*/, this._playheadState.getValues(["vodMediaSeqVideo"])];
1851
+ case 64:
1852
+ playheadState = _y.sent();
1853
+ nextMseq = playheadState.vodMediaSeqVideo + 1;
1854
+ if (nextMseq > currentVod_1.getLiveMediaSequencesCount() - 1) {
1855
+ nextMseq = currentVod_1.getLiveMediaSequencesCount() - 1;
1856
+ }
1857
+ // ---------------------------------------------------.
1858
+ // TODO: Support reloading with audioSegments as well |
1859
+ // ---------------------------------------------------'
1860
+ return [4 /*yield*/, currentVod_1.reload(nextMseq, segments, null, reloadBehind)];
1861
+ case 65:
1862
+ // ---------------------------------------------------.
1863
+ // TODO: Support reloading with audioSegments as well |
1864
+ // ---------------------------------------------------'
1865
+ _y.sent();
1866
+ return [4 /*yield*/, this._sessionState.setCurrentVod(currentVod_1, { ttl: currentVod_1.getDuration() * 1000 })];
1867
+ case 66:
1868
+ _y.sent();
1869
+ return [4 /*yield*/, this._sessionState.set("vodReloaded", 1)];
1870
+ case 67:
1871
+ _y.sent();
1872
+ return [4 /*yield*/, this._sessionState.set("vodMediaSeqVideo", 0)];
1873
+ case 68:
1874
+ _y.sent();
1875
+ return [4 /*yield*/, this._sessionState.set("vodMediaSeqAudio", 0)];
1876
+ case 69:
1877
+ _y.sent();
1878
+ return [4 /*yield*/, this._playheadState.set("vodMediaSeqVideo", 0)];
1879
+ case 70:
1880
+ _y.sent();
1881
+ return [4 /*yield*/, this._playheadState.set("vodMediaSeqAudio", 0)];
1882
+ case 71:
1883
+ _y.sent();
1884
+ return [4 /*yield*/, this._playheadState.set("playheadRef", Date.now())];
1885
+ case 72:
1886
+ _y.sent();
1887
+ // 4) Log to debug and cloudwatch
1888
+ debug("[".concat(this._sessionId, "]: LEADER: Set new Reloaded VOD and vodMediaSeq counts in store."));
1889
+ debug("[".concat(this._sessionId, "]: next VOD Reloaded (").concat(currentVod_1.getDeltaTimes(), ")"));
1890
+ debug("[".concat(this._sessionId, "]: ").concat(currentVod_1.getPlayheadPositions()));
1891
+ debug("[".concat(this._sessionId, "]: msequences=").concat(currentVod_1.getLiveMediaSequencesCount()));
1892
+ cloudWatchLog(!this.cloudWatchLogging, "engine-session", { event: "switchback", channel: this._sessionId, reqTimeMs: Date.now() - startTS });
1893
+ return [2 /*return*/];
1894
+ case 73:
1895
+ debug("[".concat(this._sessionId, "]: not a leader so will go directly to state VOD_RELOAD_INITIATING"));
1896
+ _x = sessionState;
1897
+ return [4 /*yield*/, this._sessionState.set("state", SessionState.VOD_RELOAD_INITIATING)];
1898
+ case 74:
1899
+ _x.state = _y.sent();
1900
+ _y.label = 75;
1901
+ case 75: return [3 /*break*/, 77];
1902
+ case 76:
1903
+ err_8 = _y.sent();
1904
+ debug("Failed to init reload vod");
1905
+ throw err_8;
1906
+ case 77: return [3 /*break*/, 83];
1907
+ case 78:
1908
+ debug("[".concat(this._sessionId, "]: state=VOD_RELOAD_INITIATING (").concat(sessionState.vodMediaSeqVideo, "_").concat(sessionState.vodMediaSeqAudio, ", ").concat(currentVod.getLiveMediaSequencesCount(), ")"));
1909
+ if (!!isLeader) return [3 /*break*/, 81];
1910
+ debug("[".concat(this._sessionId, "]: not the leader so just waiting for the VOD to be reloaded"));
1911
+ if (!(sessionState.vodMediaSeqVideo === 0 || this.waitingForNextVod)) return [3 /*break*/, 80];
1912
+ debug("[".concat(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"));
1913
+ return [4 /*yield*/, this._sessionState.clearCurrentVodCache()];
1914
+ case 79:
1915
+ _y.sent();
1916
+ _y.label = 80;
1917
+ case 80:
1918
+ this.waitingForNextVod = true;
1919
+ _y.label = 81;
1920
+ case 81:
1921
+ // Allow Leader|Follower to clear vodCache...
1922
+ this.isAllowedToClearVodCache = true;
1923
+ return [2 /*return*/];
1924
+ case 82: throw new Error("Invalid state: " + sessionState.state);
1925
+ case 83: return [2 /*return*/];
1926
+ }
1927
+ });
1928
+ });
1929
+ };
1930
+ Session.prototype._getNextVod = function () {
1931
+ var _this = this;
1932
+ return new Promise(function (resolve, reject) {
1933
+ var nextVodPromise;
1934
+ nextVodPromise = _this._assetManager.getNextVod({
1935
+ sessionId: _this._sessionId,
1936
+ category: _this._category,
1937
+ playlistId: _this._sessionId
1938
+ });
1939
+ nextVodPromise.then(function (nextVod) {
1940
+ if (nextVod && nextVod.uri) {
1941
+ _this.currentMetadata = {
1942
+ id: nextVod.id,
1943
+ title: nextVod.title || '',
1944
+ };
1945
+ resolve(nextVod);
1946
+ }
1947
+ else if (nextVod && nextVod.type === 'gap') {
1948
+ _this.currentMetadata = {
1949
+ id: 'GAP',
1950
+ title: 'GAP of ' + Math.floor(nextVod.desiredDuration) + ' sec',
1951
+ };
1952
+ resolve(nextVod);
1953
+ }
1954
+ else {
1955
+ console.error("Invalid VOD:", nextVod);
1956
+ reject("Invalid VOD from asset manager");
1957
+ }
1958
+ })
1959
+ .catch(reject);
1960
+ });
1961
+ };
1962
+ Session.prototype._loadSlate = function (afterVod, reps) {
1963
+ var _this = this;
1964
+ return new Promise(function (resolve, reject) {
1965
+ try {
1966
+ var slateVod_1 = new HLSRepeatVod(_this.slateUri, reps || _this.slateRepetitions);
1967
+ var hlsVod_1;
1968
+ slateVod_1.load()
1969
+ .then(function () {
1970
+ var hlsOpts = { sequenceAlwaysContainNewSegments: _this.alwaysNewSegments };
1971
+ hlsVod_1 = new HLSVod(_this.slateUri, null, null, null, m3u8Header(_this._instanceId), hlsOpts);
1972
+ var timestamp = Date.now();
1973
+ hlsVod_1.addMetadata('id', "slate-".concat(timestamp));
1974
+ hlsVod_1.addMetadata('start-date', new Date(timestamp).toISOString());
1975
+ hlsVod_1.addMetadata('planned-duration', ((reps || _this.slateRepetitions) * _this.slateDuration) / 1000);
1976
+ var slateMediaManifestLoader = function (bw) {
1977
+ var mediaManifestStream = new Readable();
1978
+ mediaManifestStream.push(slateVod_1.getMediaManifest(bw));
1979
+ mediaManifestStream.push(null);
1980
+ return mediaManifestStream;
1981
+ };
1982
+ if (afterVod) {
1983
+ return hlsVod_1.loadAfter(afterVod, null, slateMediaManifestLoader);
1984
+ }
1985
+ else {
1986
+ return hlsVod_1.load(null, slateMediaManifestLoader);
1987
+ }
1988
+ })
1989
+ .then(function () {
1990
+ resolve(hlsVod_1);
1991
+ })
1992
+ .catch(function (err) {
1993
+ debug(err);
1994
+ reject(err);
1995
+ });
1996
+ }
1997
+ catch (err) {
1998
+ reject(err);
1999
+ }
2000
+ });
2001
+ };
2002
+ Session.prototype._truncateSlate = function (afterVod, requestedDuration, vodUri) {
2003
+ var _this = this;
2004
+ return new Promise(function (resolve, reject) {
2005
+ var nexVodUri = null;
2006
+ try {
2007
+ if (vodUri) {
2008
+ nexVodUri = vodUri;
2009
+ }
2010
+ else {
2011
+ nexVodUri = _this.slateUri;
2012
+ }
2013
+ var slateVod_2 = new HLSTruncateVod(nexVodUri, requestedDuration);
2014
+ var hlsVod_2;
2015
+ slateVod_2.load()
2016
+ .then(function () {
2017
+ var hlsOpts = { sequenceAlwaysContainNewSegments: _this.alwaysNewSegments };
2018
+ hlsVod_2 = new HLSVod(nexVodUri, null, null, null, m3u8Header(_this._instanceId), hlsOpts);
2019
+ var timestamp = Date.now();
2020
+ hlsVod_2.addMetadata('id', "slate-".concat(timestamp));
2021
+ hlsVod_2.addMetadata('start-date', new Date(timestamp).toISOString());
2022
+ hlsVod_2.addMetadata('planned-duration', requestedDuration);
2023
+ var slateMediaManifestLoader = function (bw) {
2024
+ var mediaManifestStream = new Readable();
2025
+ mediaManifestStream.push(slateVod_2.getMediaManifest(bw));
2026
+ mediaManifestStream.push(null);
2027
+ return mediaManifestStream;
2028
+ };
2029
+ if (afterVod) {
2030
+ return hlsVod_2.loadAfter(afterVod, null, slateMediaManifestLoader);
2031
+ }
2032
+ else {
2033
+ return hlsVod_2.load(null, slateMediaManifestLoader);
2034
+ }
2035
+ })
2036
+ .then(function () {
2037
+ resolve(hlsVod_2);
2038
+ })
2039
+ .catch(function (err) {
2040
+ debug(err);
2041
+ reject(err);
2042
+ });
2043
+ }
2044
+ catch (err) {
2045
+ reject(err);
2046
+ }
2047
+ });
2048
+ };
2049
+ Session.prototype._fillGap = function (afterVod, desiredDuration) {
2050
+ var _this = this;
2051
+ return new Promise(function (resolve, reject) {
2052
+ var loadSlatePromise;
2053
+ var durationMs;
2054
+ if (desiredDuration > _this.slateDuration) {
2055
+ var reps = Math.floor(desiredDuration / _this.slateDuration);
2056
+ debug("[".concat(_this._sessionId, "]: Trying to fill a gap of ").concat(desiredDuration, " milliseconds (").concat(reps, " repetitions)"));
2057
+ loadSlatePromise = _this._loadSlate(afterVod, reps);
2058
+ durationMs = (reps || _this.slateRepetitions) * _this.slateDuration;
2059
+ }
2060
+ else {
2061
+ debug("[".concat(_this._sessionId, "]: Trying to fill a gap of ").concat(desiredDuration, " milliseconds by truncating filler slate (").concat(_this.slateDuration, ")"));
2062
+ loadSlatePromise = _this._truncateSlate(afterVod, desiredDuration / 1000);
2063
+ durationMs = desiredDuration;
2064
+ }
2065
+ loadSlatePromise.then(function (hlsVod) {
2066
+ cloudWatchLog(!_this.cloudWatchLogging, 'engine-session', { event: 'filler', channel: _this._sessionId, durationMs: durationMs });
2067
+ resolve(hlsVod);
2068
+ }).catch(reject);
2069
+ });
2070
+ };
2071
+ Session.prototype._getNextVodById = function (id) {
2072
+ var _this = this;
2073
+ return new Promise(function (resolve, reject) {
2074
+ _this._assetManager.getNextVodById(_this._sessionId, id)
2075
+ .then(function (nextVod) {
2076
+ //debug(nextVod);
2077
+ _this.currentMetadata = {
2078
+ id: nextVod.id,
2079
+ title: nextVod.title || '',
2080
+ };
2081
+ resolve(nextVod);
2082
+ })
2083
+ .catch(reject);
2084
+ });
2085
+ };
2086
+ Session.prototype._getFirstDuration = function (manifest) {
2087
+ return new Promise(function (resolve, reject) {
2088
+ try {
2089
+ var parser = m3u8.createStream();
2090
+ var manifestStream = new Readable();
2091
+ manifestStream.push(manifest);
2092
+ manifestStream.push(null);
2093
+ manifestStream.pipe(parser);
2094
+ parser.on('m3u', function (m3u) {
2095
+ if (m3u.items.PlaylistItem[0]) {
2096
+ var firstDuration = m3u.items.PlaylistItem[0].get("duration");
2097
+ resolve(firstDuration);
2098
+ }
2099
+ else {
2100
+ console.error("Empty media playlist");
2101
+ console.error(manifest);
2102
+ reject('Empty media playlist!');
2103
+ }
2104
+ });
2105
+ }
2106
+ catch (err) {
2107
+ reject(err);
2108
+ }
2109
+ });
2110
+ };
2111
+ Session.prototype._getCurrentDeltaTime = function () {
2112
+ return __awaiter(this, void 0, void 0, function () {
2113
+ var sessionState, currentVod, deltaTimes;
2114
+ return __generator(this, function (_a) {
2115
+ switch (_a.label) {
2116
+ case 0: return [4 /*yield*/, this._sessionState.getValues(["vodMediaSeqVideo"])];
2117
+ case 1:
2118
+ sessionState = _a.sent();
2119
+ return [4 /*yield*/, this._sessionState.getCurrentVod()];
2120
+ case 2:
2121
+ currentVod = _a.sent();
2122
+ deltaTimes = currentVod.getDeltaTimes();
2123
+ debug("[".concat(this._sessionId, "]: Current delta time (").concat(sessionState.vodMediaSeqVideo, "): ").concat(deltaTimes[sessionState.vodMediaSeqVideo]));
2124
+ if (deltaTimes[sessionState.vodMediaSeqVideo]) {
2125
+ return [2 /*return*/, deltaTimes[sessionState.vodMediaSeqVideo]];
2126
+ }
2127
+ return [2 /*return*/, 0];
2128
+ }
2129
+ });
2130
+ });
2131
+ };
2132
+ Session.prototype._getCurrentPlayheadPosition = function () {
2133
+ return __awaiter(this, void 0, void 0, function () {
2134
+ var sessionState, currentVod, playheadPositions;
2135
+ return __generator(this, function (_a) {
2136
+ switch (_a.label) {
2137
+ case 0: return [4 /*yield*/, this._sessionState.getValues(["vodMediaSeqVideo"])];
2138
+ case 1:
2139
+ sessionState = _a.sent();
2140
+ return [4 /*yield*/, this._sessionState.getCurrentVod()];
2141
+ case 2:
2142
+ currentVod = _a.sent();
2143
+ playheadPositions = currentVod.getPlayheadPositions();
2144
+ debug("[".concat(this._sessionId, "]: Current playhead position (").concat(sessionState.vodMediaSeqVideo, "): ").concat(playheadPositions[sessionState.vodMediaSeqVideo]));
2145
+ return [2 /*return*/, playheadPositions[sessionState.vodMediaSeqVideo]];
2146
+ }
2147
+ });
2148
+ });
2149
+ };
2150
+ Session.prototype._getLastDuration = function (manifest) {
2151
+ return new Promise(function (resolve, reject) {
2152
+ try {
2153
+ var parser = m3u8.createStream();
2154
+ var manifestStream = new Readable();
2155
+ manifestStream.push(manifest);
2156
+ manifestStream.push(null);
2157
+ manifestStream.pipe(parser);
2158
+ parser.on('m3u', function (m3u) {
2159
+ if (m3u.items.PlaylistItem.length > 0) {
2160
+ var endIdx = m3u.items.PlaylistItem.length - 1;
2161
+ var bottomDuration = m3u.items.PlaylistItem[endIdx].get("duration");
2162
+ resolve(bottomDuration);
2163
+ }
2164
+ else {
2165
+ console.error("Empty media playlist");
2166
+ console.error(manifest);
2167
+ reject('Empty media playlist!');
2168
+ }
2169
+ });
2170
+ }
2171
+ catch (err) {
2172
+ reject(err);
2173
+ }
2174
+ });
2175
+ };
2176
+ Session.prototype._getPlayheadDiffCompesationValue = function (diffMs, thresholdMs) {
2177
+ var compensationSec = 0;
2178
+ if (diffMs > thresholdMs) {
2179
+ compensationSec = (diffMs / 1000) - (thresholdMs / 1000);
2180
+ debug("[".concat(this._sessionId, "]: Playhead stepping msequences too early. Need to wait longer. adding ").concat(compensationSec, "s"));
2181
+ return compensationSec;
2182
+ }
2183
+ else if (diffMs < -thresholdMs) {
2184
+ compensationSec = (diffMs / 1000) + (thresholdMs / 1000);
2185
+ debug("[".concat(this._sessionId, "]: Playhead stepping msequences too LATE. Need to fast-forward. adding ").concat(compensationSec, "s"));
2186
+ return compensationSec;
2187
+ }
2188
+ else {
2189
+ return compensationSec;
2190
+ }
2191
+ };
2192
+ return Session;
2193
+ }());
2194
+ module.exports = Session;