eyevinn-channel-engine 4.3.7 → 4.3.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -123,4 +123,9 @@ declare class Session {
123
123
  _getLastDuration(manifest: any): Promise<any>;
124
124
  _getPlayheadDiffCompensationValue(diffMs: any, thresholdMs: any): number;
125
125
  _isOldVod(refTs: any, vodDur: any): boolean;
126
+ _determineExtraMediaIncrement(_extraType: any, _currentPosVideo: any, _extraSeqFinalIndex: any, _vodMediaSeqExtra: any, _getExtraPlayheadPositionAsyncFn: any): Promise<{
127
+ increment: number;
128
+ position: number;
129
+ diff: string;
130
+ }>;
126
131
  }
@@ -1087,24 +1087,24 @@ var Session = /** @class */ (function () {
1087
1087
  };
1088
1088
  Session.prototype.incrementAsync = function () {
1089
1089
  return __awaiter(this, void 0, void 0, function () {
1090
- var isLeader, sessionState, playheadState, currentVod, _a, isOldVod, nextState, leaderAction, leaderState, _b, m3u8_4, _c, audioIncrement, positionV, positionA, position, currentVod_1, sessionState_1, posDiff, incrementValue, index, audioSeqLastIdx, thresh, maxAcceptableDiff, audioPosition, _d, _e, newSessionState, updatedValues, updatedPlayhead, mediaSequenceValue, audioInfo, mediaSequenceValueAudio, diffMs, m3u8;
1091
- return __generator(this, function (_f) {
1092
- switch (_f.label) {
1090
+ var isLeader, sessionState, playheadState, currentVod, _a, isOldVod, nextState, leaderAction, leaderState, _b, m3u8_4, _c, playheadPosVideoMs, playheadAudio, playheadSubtitle, audioSeqLastIdx, sessionStateObj, _d, playheadPosVideo, _e, subtitleSeqLastIdx, sessionStateObj, _f, newSessionState, updatedValues, updatedPlayhead, mediaSequenceValue, audioInfo, mediaSequenceValueAudio, diffMs, m3u8;
1091
+ return __generator(this, function (_g) {
1092
+ switch (_g.label) {
1093
1093
  case 0: return [4 /*yield*/, this._tickAsync()];
1094
1094
  case 1:
1095
- _f.sent();
1095
+ _g.sent();
1096
1096
  return [4 /*yield*/, this._sessionStateStore.isLeader(this._instanceId)];
1097
1097
  case 2:
1098
- isLeader = _f.sent();
1098
+ isLeader = _g.sent();
1099
1099
  return [4 /*yield*/, this._sessionState.getValues(["state", "mediaSeq", "mediaSeqAudio", "mediaSeqSubtitle", "discSeq", "discSeqAudio", "discSeqSubtitle", "vodMediaSeqVideo", "vodMediaSeqAudio", "vodMediaSeqSubtitle"])];
1100
1100
  case 3:
1101
- sessionState = _f.sent();
1101
+ sessionState = _g.sent();
1102
1102
  return [4 /*yield*/, this._playheadState.getValues(["mediaSeq", "mediaSeqAudio", "mediaSeqSubtitle", "vodMediaSeqVideo", "vodMediaSeqAudio", "vodMediaSubtitle", "playheadRef"])];
1103
1103
  case 4:
1104
- playheadState = _f.sent();
1104
+ playheadState = _g.sent();
1105
1105
  return [4 /*yield*/, this._sessionState.getCurrentVod()];
1106
1106
  case 5:
1107
- currentVod = _f.sent();
1107
+ currentVod = _g.sent();
1108
1108
  if (!(!currentVod ||
1109
1109
  sessionState.vodMediaSeqVideo === null ||
1110
1110
  sessionState.vodMediaSeqAudio === null ||
@@ -1116,14 +1116,14 @@ var Session = /** @class */ (function () {
1116
1116
  debug(sessionState);
1117
1117
  return [4 /*yield*/, this._sessionState.clearCurrentVodCache()];
1118
1118
  case 6:
1119
- _f.sent();
1119
+ _g.sent();
1120
1120
  if (!isLeader) return [3 /*break*/, 8];
1121
1121
  debug("[".concat(this._sessionId, "]: I am the leader, trying to initiate the session"));
1122
1122
  _a = sessionState;
1123
1123
  return [4 /*yield*/, this._sessionState.set("state", SessionState.VOD_INIT)];
1124
1124
  case 7:
1125
- _a.state = _f.sent();
1126
- _f.label = 8;
1125
+ _a.state = _g.sent();
1126
+ _g.label = 8;
1127
1127
  case 8: return [2 /*return*/, null];
1128
1128
  case 9:
1129
1129
  if (!(sessionState.state === SessionState.VOD_NEXT_INITIATING || sessionState.state === SessionState.VOD_RELOAD_INITIATING)) return [3 /*break*/, 14];
@@ -1139,13 +1139,13 @@ var Session = /** @class */ (function () {
1139
1139
  _b = sessionState;
1140
1140
  return [4 /*yield*/, this._sessionState.set("state", nextState)];
1141
1141
  case 10:
1142
- _b.state = _f.sent();
1142
+ _b.state = _g.sent();
1143
1143
  return [3 /*break*/, 13];
1144
1144
  case 11:
1145
1145
  debug("[".concat(this._sessionId, "]: Return the last generated m3u8 to give the leader some time"));
1146
1146
  return [4 /*yield*/, this._playheadState.getLastM3u8()];
1147
1147
  case 12:
1148
- m3u8_4 = _f.sent();
1148
+ m3u8_4 = _g.sent();
1149
1149
  if (m3u8_4) {
1150
1150
  return [2 /*return*/, m3u8_4];
1151
1151
  }
@@ -1153,78 +1153,65 @@ var Session = /** @class */ (function () {
1153
1153
  debug("[".concat(this._sessionId, "]: We don't have any previously generated m3u8"));
1154
1154
  }
1155
1155
  this.isAllowedToClearVodCache = true;
1156
- _f.label = 13;
1157
- case 13: return [3 /*break*/, 26];
1156
+ _g.label = 13;
1157
+ case 13: return [3 /*break*/, 28];
1158
1158
  case 14:
1159
1159
  _c = sessionState;
1160
1160
  return [4 /*yield*/, this._sessionState.increment("vodMediaSeqVideo", 1)];
1161
1161
  case 15:
1162
- _c.vodMediaSeqVideo = _f.sent();
1163
- audioIncrement = void 0;
1164
- if (!this.use_demuxed_audio) return [3 /*break*/, 23];
1165
- positionV = 0;
1166
- positionA = 0;
1162
+ _c.vodMediaSeqVideo = _g.sent();
1163
+ playheadPosVideoMs = void 0;
1164
+ playheadAudio = void 0;
1165
+ playheadSubtitle = void 0;
1166
+ if (!(this.use_demuxed_audio || this.use_vtt_subtitles)) return [3 /*break*/, 17];
1167
1167
  return [4 /*yield*/, this._getCurrentPlayheadPosition()];
1168
1168
  case 16:
1169
- position = (_f.sent()) * 1000;
1170
- positionV = position ? position / 1000 : 0;
1171
- return [4 /*yield*/, this._sessionState.getCurrentVod()];
1169
+ playheadPosVideoMs = (_g.sent()) * 1000;
1170
+ _g.label = 17;
1172
1171
  case 17:
1173
- currentVod_1 = _f.sent();
1172
+ if (!this.use_demuxed_audio) return [3 /*break*/, 21];
1173
+ audioSeqLastIdx = currentVod.getLiveMediaSequencesCount("audio") - 1;
1174
1174
  return [4 /*yield*/, this._sessionState.getValues(["vodMediaSeqAudio"])];
1175
1175
  case 18:
1176
- sessionState_1 = _f.sent();
1177
- posDiff = void 0;
1178
- incrementValue = 1;
1179
- index = 0;
1180
- audioSeqLastIdx = currentVod_1.getLiveMediaSequencesCount("audio") - 1;
1181
- thresh = 0.5;
1182
- maxAcceptableDiff = 0.001;
1183
- debug("[".concat(this._sessionId, "]: About to determine audio increment"));
1184
- _f.label = 19;
1185
- case 19: return [4 /*yield*/, this._getAudioPlayheadPosition(sessionState_1.vodMediaSeqAudio + index)];
1176
+ sessionStateObj = _g.sent();
1177
+ return [4 /*yield*/, this._determineExtraMediaIncrement("audio", playheadPosVideoMs, audioSeqLastIdx, sessionStateObj.vodMediaSeqAudio, this._getAudioPlayheadPosition.bind(this))];
1178
+ case 19:
1179
+ playheadAudio = _g.sent();
1180
+ // Perform the Increment
1181
+ debug("[".concat(this._sessionId, "]: Will increment audio with ").concat(playheadAudio.increment));
1182
+ _d = sessionState;
1183
+ return [4 /*yield*/, this._sessionState.increment("vodMediaSeqAudio", playheadAudio.increment)];
1186
1184
  case 20:
1187
- audioPosition = (_f.sent()) * 1000;
1188
- positionA = audioPosition ? audioPosition / 1000 : 0;
1189
- posDiff = (positionV - positionA).toFixed(3);
1190
- debug("[".concat(this._sessionId, "]: positionV=").concat(positionV, ";positionA=").concat(positionA, ";posDiff=").concat(posDiff));
1191
- if (posDiff <= maxAcceptableDiff) {
1192
- return [3 /*break*/, 22];
1193
- }
1194
- if (posDiff > thresh) {
1195
- index++;
1196
- incrementValue++;
1197
- }
1198
- else if (posDiff > maxAcceptableDiff) {
1199
- index = incrementValue;
1200
- debug("[".concat(this._sessionId, "]: Audio Stepping index set to = ").concat(index));
1201
- return [3 /*break*/, 22];
1202
- }
1203
- if (sessionState_1.vodMediaSeqAudio + index > audioSeqLastIdx) {
1204
- return [3 /*break*/, 22];
1205
- }
1206
- _f.label = 21;
1185
+ _d.vodMediaSeqAudio = _g.sent();
1186
+ _g.label = 21;
1207
1187
  case 21:
1208
- if (!(-thresh < posDiff && posDiff < thresh) && !isNaN(posDiff)) return [3 /*break*/, 19];
1209
- _f.label = 22;
1188
+ if (!this.use_vtt_subtitles) return [3 /*break*/, 27];
1189
+ _e = playheadPosVideo;
1190
+ if (_e) return [3 /*break*/, 23];
1191
+ return [4 /*yield*/, this._getCurrentPlayheadPosition()];
1210
1192
  case 22:
1211
- audioIncrement = index;
1212
- debug("[".concat(this._sessionId, "]: Current VOD Playhead Positions are to be: [").concat(positionV.toFixed(3), "][").concat(positionA.toFixed(3), "] (").concat(posDiff, ")"));
1213
- _f.label = 23;
1193
+ _e = (_g.sent()) * 1000;
1194
+ _g.label = 23;
1214
1195
  case 23:
1215
- debug("[".concat(this._sessionId, "]: Will increment audio with ").concat(audioIncrement));
1216
- _d = sessionState;
1217
- return [4 /*yield*/, this._sessionState.increment("vodMediaSeqAudio", audioIncrement)];
1196
+ playheadPosVideo = _e;
1197
+ subtitleSeqLastIdx = currentVod.getLiveMediaSequencesCount("subtitle") - 1;
1198
+ return [4 /*yield*/, this._sessionState.getValues(["vodMediaSeqSubtitle"])];
1218
1199
  case 24:
1219
- _d.vodMediaSeqAudio = _f.sent();
1220
- if (!this.use_vtt_subtitles) return [3 /*break*/, 26];
1221
- debug("[".concat(this._sessionId, "]: Will increment subtitle with 1"));
1222
- _e = sessionState;
1223
- return [4 /*yield*/, this._sessionState.increment("vodMediaSeqSubtitle", 1)];
1200
+ sessionStateObj = _g.sent();
1201
+ return [4 /*yield*/, this._determineExtraMediaIncrement("subtitle", playheadPosVideoMs, subtitleSeqLastIdx, sessionStateObj.vodMediaSeqSubtitle, this._getSubtitlePlayheadPosition.bind(this))];
1224
1202
  case 25:
1225
- _e.vodMediaSeqSubtitle = _f.sent();
1226
- _f.label = 26;
1203
+ playheadSubtitle = _g.sent();
1204
+ // Perform the Increment
1205
+ debug("[".concat(this._sessionId, "]: Will increment subtitle with ").concat(playheadSubtitle.increment));
1206
+ _f = sessionState;
1207
+ return [4 /*yield*/, this._sessionState.increment("vodMediaSeqSubtitle", playheadSubtitle.increment)];
1227
1208
  case 26:
1209
+ _f.vodMediaSeqSubtitle = _g.sent();
1210
+ _g.label = 27;
1211
+ case 27:
1212
+ debug("[".concat(this._sessionId, "]: Current VOD Playhead Positions are to be V[").concat((playheadPosVideoMs / 1000).toFixed(3), "]").concat(playheadAudio ? "A[".concat((playheadAudio.position).toFixed(3), "]") : "").concat(playheadSubtitle ? "S[".concat((playheadSubtitle.position).toFixed(3), ")]") : "").concat(playheadAudio ? " (".concat(playheadAudio.diff, ")") : "").concat(playheadSubtitle ? " (".concat(playheadSubtitle.diff, ")") : ""));
1213
+ _g.label = 28;
1214
+ case 28:
1228
1215
  newSessionState = {};
1229
1216
  if (sessionState.vodMediaSeqVideo >= currentVod.getLiveMediaSequencesCount() - 1) {
1230
1217
  newSessionState.vodMediaSeqVideo = currentVod.getLiveMediaSequencesCount() - 1;
@@ -1241,8 +1228,8 @@ var Session = /** @class */ (function () {
1241
1228
  this.isSwitchingBackToV2L = false;
1242
1229
  }
1243
1230
  return [4 /*yield*/, this._sessionState.setValues(newSessionState)];
1244
- case 27:
1245
- updatedValues = _f.sent();
1231
+ case 29:
1232
+ updatedValues = _g.sent();
1246
1233
  sessionState = __assign(__assign({}, sessionState), updatedValues);
1247
1234
  if (isLeader) {
1248
1235
  debug("[".concat(this._sessionId, "]: I am the leader, updating PlayheadState values"));
@@ -1255,8 +1242,8 @@ var Session = /** @class */ (function () {
1255
1242
  "vodMediaSeqAudio": sessionState.vodMediaSeqAudio,
1256
1243
  "vodMediaSeqSubtitle": sessionState.vodMediaSeqSubtitle
1257
1244
  }, isLeader)];
1258
- case 28:
1259
- updatedPlayhead = _f.sent();
1245
+ case 30:
1246
+ updatedPlayhead = _g.sent();
1260
1247
  playheadState = __assign(__assign({}, playheadState), updatedPlayhead);
1261
1248
  if (currentVod.sequenceAlwaysContainNewSegments) {
1262
1249
  mediaSequenceValue = currentVod.mediaSequenceValues[playheadState.vodMediaSeqVideo];
@@ -1268,23 +1255,23 @@ var Session = /** @class */ (function () {
1268
1255
  debug("[".concat(this._sessionId, "]: Session can now serve mseq[V]={").concat(playheadState.mediaSeq + mediaSequenceValue, "}") + audioInfo);
1269
1256
  }
1270
1257
  debug("[".concat(this._sessionId, "]: INCREMENT (mseq=").concat(playheadState.mediaSeq + playheadState.vodMediaSeqVideo, ") vodMediaSeq=(").concat(playheadState.vodMediaSeqVideo, "_").concat(playheadState.vodMediaSeqAudio, " of ").concat(currentVod.getLiveMediaSequencesCount(), "_").concat(currentVod.getLiveMediaSequencesCount("audio"), ")"));
1271
- if (!(playheadState.vodMediaSeqVideo < 2 || playheadState.mediaSeq !== this.prevMediaSeqOffset.video)) return [3 /*break*/, 33];
1258
+ if (!(playheadState.vodMediaSeqVideo < 2 || playheadState.mediaSeq !== this.prevMediaSeqOffset.video)) return [3 /*break*/, 35];
1272
1259
  debug("[".concat(this._sessionId, "]: current[").concat(playheadState.vodMediaSeqVideo, "]_prev[").concat(this.prevVodMediaSeq.video, "]"));
1273
1260
  debug("[".concat(this._sessionId, "]: current-offset[").concat(playheadState.mediaSeq, "]_prev-offset[").concat(this.prevMediaSeqOffset.video, "]"));
1274
1261
  if (playheadState.vodMediaSeqVideo < this.prevVodMediaSeq.video || playheadState.mediaSeq !== this.prevMediaSeqOffset.video) {
1275
1262
  this.isAllowedToClearVodCache = true;
1276
1263
  }
1277
- if (!(!isLeader && this.isAllowedToClearVodCache)) return [3 /*break*/, 32];
1264
+ if (!(!isLeader && this.isAllowedToClearVodCache)) return [3 /*break*/, 34];
1278
1265
  debug("[".concat(this._sessionId, "]: Not a leader and have just set 'playheadState.vodMediaSeqVideo' to 0|1. Invalidate cache to ensure having the correct VOD."));
1279
1266
  return [4 /*yield*/, this._sessionState.clearCurrentVodCache()];
1280
- case 29:
1281
- _f.sent();
1267
+ case 31:
1268
+ _g.sent();
1282
1269
  return [4 /*yield*/, this._sessionState.getCurrentVod()];
1283
- case 30:
1284
- currentVod = _f.sent();
1270
+ case 32:
1271
+ currentVod = _g.sent();
1285
1272
  return [4 /*yield*/, this._playheadState.get("diffCompensation")];
1286
- case 31:
1287
- diffMs = _f.sent();
1273
+ case 33:
1274
+ diffMs = _g.sent();
1288
1275
  if (diffMs) {
1289
1276
  this.diffCompensation = diffMs;
1290
1277
  debug("[".concat(this._sessionId, "]: Setting diffCompensation->").concat(this.diffCompensation));
@@ -1297,12 +1284,12 @@ var Session = /** @class */ (function () {
1297
1284
  }
1298
1285
  }
1299
1286
  this.isAllowedToClearVodCache = false;
1300
- _f.label = 32;
1301
- case 32: return [3 /*break*/, 34];
1302
- case 33:
1287
+ _g.label = 34;
1288
+ case 34: return [3 /*break*/, 36];
1289
+ case 35:
1303
1290
  this.isAllowedToClearVodCache = true;
1304
- _f.label = 34;
1305
- case 34:
1291
+ _g.label = 36;
1292
+ case 36:
1306
1293
  // Update Value for Previous Sequence
1307
1294
  this.prevVodMediaSeq.video = playheadState.vodMediaSeqVideo;
1308
1295
  this.prevMediaSeqOffset.video = playheadState.mediaSeq;
@@ -1316,8 +1303,8 @@ var Session = /** @class */ (function () {
1316
1303
  }
1317
1304
  m3u8 = currentVod.getLiveMediaSequences(playheadState.mediaSeq, 180000, playheadState.vodMediaSeqVideo, sessionState.discSeq);
1318
1305
  return [4 /*yield*/, this._playheadState.setLastM3u8(m3u8)];
1319
- case 35:
1320
- _f.sent();
1306
+ case 37:
1307
+ _g.sent();
1321
1308
  return [2 /*return*/, m3u8];
1322
1309
  }
1323
1310
  });
@@ -1325,7 +1312,7 @@ var Session = /** @class */ (function () {
1325
1312
  };
1326
1313
  Session.prototype.getMediaManifestAsync = function (bw, opts) {
1327
1314
  return __awaiter(this, void 0, void 0, function () {
1328
- var tsLastRequestVideo, timeSinceLastRequest, sessionState, currentVod, _a, sequencesToIncrement, _b, _c, _d, m3u8, lastM3u8, _e, _f, _g, tsLastRequestVideo_1, timeSinceLastRequest_1, sessionState_2, _h, lastM3u8_1, _j, _k, _l;
1315
+ 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;
1329
1316
  return __generator(this, function (_m) {
1330
1317
  switch (_m.label) {
1331
1318
  case 0: // this function is no longer used and should be removed comment added 5/5-2023
@@ -1407,38 +1394,38 @@ var Session = /** @class */ (function () {
1407
1394
  timeSinceLastRequest_1 = (tsLastRequestVideo_1 === null) ? 0 : Date.now() - tsLastRequestVideo_1;
1408
1395
  return [4 /*yield*/, this._sessionState.getValues(["state", "vodMediaSeqVideo", "mediaSeq", "discSeq", "lastM3u8"])];
1409
1396
  case 17:
1410
- sessionState_2 = _m.sent();
1411
- if (!(sessionState_2.state === SessionState.VOD_NEXT_INITIATING)) return [3 /*break*/, 19];
1412
- _h = sessionState_2;
1397
+ sessionState_1 = _m.sent();
1398
+ if (!(sessionState_1.state === SessionState.VOD_NEXT_INITIATING)) return [3 /*break*/, 19];
1399
+ _h = sessionState_1;
1413
1400
  return [4 /*yield*/, this._sessionState.set("state", SessionState.VOD_PLAYING)];
1414
1401
  case 18:
1415
1402
  _h.state = _m.sent();
1416
1403
  _m.label = 19;
1417
1404
  case 19:
1418
- debug("[".concat(this._sessionId, "]: VIDEO ").concat(timeSinceLastRequest_1, " (").concat(this.averageSegmentDuration, ") bandwidth=").concat(bw, " vodMediaSeq=(").concat(sessionState_2.vodMediaSeqVideo, "_").concat(sessionState_2.vodMediaSeqAudio, ")"));
1405
+ debug("[".concat(this._sessionId, "]: VIDEO ").concat(timeSinceLastRequest_1, " (").concat(this.averageSegmentDuration, ") bandwidth=").concat(bw, " vodMediaSeq=(").concat(sessionState_1.vodMediaSeqVideo, "_").concat(sessionState_1.vodMediaSeqAudio, ")"));
1419
1406
  try {
1420
- m3u8 = currentVod.getLiveMediaSequences(sessionState_2.mediaSeq, bw, sessionState_2.vodMediaSeqVideo, sessionState_2.discSeq);
1407
+ m3u8 = currentVod.getLiveMediaSequences(sessionState_1.mediaSeq, bw, sessionState_1.vodMediaSeqVideo, sessionState_1.discSeq);
1421
1408
  }
1422
1409
  catch (exc) {
1423
- if (sessionState_2.lastM3u8[bw]) {
1424
- m3u8 = sessionState_2.lastM3u8[bw];
1410
+ if (sessionState_1.lastM3u8[bw]) {
1411
+ m3u8 = sessionState_1.lastM3u8[bw];
1425
1412
  }
1426
1413
  else {
1427
1414
  logerror(this._sessionId, exc);
1428
1415
  throw new Error('Failed to generate media manifest');
1429
1416
  }
1430
1417
  }
1431
- lastM3u8_1 = sessionState_2.lastM3u8;
1418
+ lastM3u8_1 = sessionState_1.lastM3u8;
1432
1419
  lastM3u8_1[bw] = m3u8;
1433
- _j = sessionState_2;
1420
+ _j = sessionState_1;
1434
1421
  return [4 /*yield*/, this._sessionState.set("lastM3u8", lastM3u8_1)];
1435
1422
  case 20:
1436
1423
  _j.lastM3u8 = _m.sent();
1437
- _k = sessionState_2;
1424
+ _k = sessionState_1;
1438
1425
  return [4 /*yield*/, this._sessionState.set("lastServedM3u8", m3u8)];
1439
1426
  case 21:
1440
1427
  _k.lastServedM3u8 = _m.sent();
1441
- _l = sessionState_2;
1428
+ _l = sessionState_1;
1442
1429
  return [4 /*yield*/, this._sessionState.set("tsLastRequestVideo", Date.now())];
1443
1430
  case 22:
1444
1431
  _l.tsLastRequestVideo = _m.sent();
@@ -1764,7 +1751,7 @@ var Session = /** @class */ (function () {
1764
1751
  };
1765
1752
  Session.prototype._tickAsync = function () {
1766
1753
  return __awaiter(this, void 0, void 0, function () {
1767
- var newVod, sessionState, isLeader, currentVod, vodResponse, _a, nextVodPromise, nextVodStart, _b, loadPromise, hlsOpts, _c, mediaManifestLoader, audioManifestLoader, loadStart, updatedSessionState, _d, _e, _f, _g, err_7, _h, length_1, endMseqValue, endMseqValueAudio, endMseqValueSubtitle, lastDiscontinuity, lastDiscontinuityAudio, lastDiscontinuitySubtitle, _j, vodPromise, gracePeriod, nextVodStart, _k, loadPromise, hlsOpts, _l, mediaManifestLoader, audioManifestLoader, loadStart, _m, _o, updatedSessionState, _p, _q, diffMs, err_8, startTS, _r, mSeq, currentVod_2, dSeq, mSeqOffset, reloadBehind, segments, playheadState, nextMseq, _s, _t, err_9;
1754
+ var newVod, sessionState, isLeader, currentVod, vodResponse, _a, nextVodPromise, nextVodStart, _b, loadPromise, hlsOpts, _c, mediaManifestLoader, audioManifestLoader, loadStart, updatedSessionState, _d, _e, _f, _g, err_7, _h, length_1, endMseqValue, endMseqValueAudio, endMseqValueSubtitle, lastDiscontinuity, lastDiscontinuityAudio, lastDiscontinuitySubtitle, _j, vodPromise, gracePeriod, nextVodStart, _k, loadPromise, hlsOpts, _l, mediaManifestLoader, audioManifestLoader, loadStart, _m, _o, updatedSessionState, _p, _q, diffMs, err_8, startTS, _r, mSeq, currentVod_1, dSeq, mSeqOffset, reloadBehind, segments, playheadState, nextMseq, _s, _t, err_9;
1768
1755
  var _this = this;
1769
1756
  return __generator(this, function (_u) {
1770
1757
  switch (_u.label) {
@@ -1870,6 +1857,7 @@ var Session = /** @class */ (function () {
1870
1857
  debug("[".concat(this._sessionId, "]: ").concat(currentVod.getDeltaTimes()));
1871
1858
  debug("[".concat(this._sessionId, "]: playhead positions [V]=").concat(currentVod.getPlayheadPositions("video")));
1872
1859
  debug("[".concat(this._sessionId, "]: playhead positions [A]=").concat(currentVod.getPlayheadPositions("audio")));
1860
+ debug("[".concat(this._sessionId, "]: playhead positions [S]=").concat(currentVod.getPlayheadPositions("subtitle")));
1873
1861
  return [4 /*yield*/, this._sessionState.setValues({
1874
1862
  "mediaSeq": 0,
1875
1863
  "mediaSeqAudio": 0,
@@ -2110,6 +2098,7 @@ var Session = /** @class */ (function () {
2110
2098
  debug("[".concat(this._sessionId, "]: next VOD loaded (").concat(newVod.getDeltaTimes(), ")"));
2111
2099
  debug("[".concat(this._sessionId, "]: playhead positions [V]=").concat(newVod.getPlayheadPositions("video")));
2112
2100
  debug("[".concat(this._sessionId, "]: playhead positions [A]=").concat(newVod.getPlayheadPositions("audio")));
2101
+ debug("[".concat(this._sessionId, "]: playhead positions [S]=").concat(newVod.getPlayheadPositions("subtitle")));
2113
2102
  currentVod = newVod;
2114
2103
  debug("[".concat(this._sessionId, "]: msequences=").concat(currentVod.getLiveMediaSequencesCount(), "; audio msequences=").concat(currentVod.getLiveMediaSequencesCount("audio"), "; subtitle msequences=").concat(currentVod.getLiveMediaSequencesCount("subtitle")));
2115
2104
  _m = sessionState;
@@ -2216,8 +2205,8 @@ var Session = /** @class */ (function () {
2216
2205
  mSeq = this.switchDataForSession.mediaSeq;
2217
2206
  return [4 /*yield*/, this._sessionState.getCurrentVod()];
2218
2207
  case 63:
2219
- currentVod_2 = _u.sent();
2220
- if (currentVod_2.sequenceAlwaysContainNewSegments) {
2208
+ currentVod_1 = _u.sent();
2209
+ if (currentVod_1.sequenceAlwaysContainNewSegments) {
2221
2210
  // (!) will need to compensate if using this setting on HLSVod Object.
2222
2211
  Object.keys(this.switchDataForSession.transitionSegments).forEach(function (bw) {
2223
2212
  var shiftedSeg = _this.switchDataForSession.transitionSegments[bw].shift();
@@ -2251,19 +2240,19 @@ var Session = /** @class */ (function () {
2251
2240
  case 67:
2252
2241
  playheadState = _u.sent();
2253
2242
  nextMseq = playheadState.vodMediaSeqVideo + 1;
2254
- if (nextMseq > currentVod_2.getLiveMediaSequencesCount() - 1) {
2255
- nextMseq = currentVod_2.getLiveMediaSequencesCount() - 1;
2243
+ if (nextMseq > currentVod_1.getLiveMediaSequencesCount() - 1) {
2244
+ nextMseq = currentVod_1.getLiveMediaSequencesCount() - 1;
2256
2245
  }
2257
2246
  // ---------------------------------------------------.
2258
2247
  // TODO: Support reloading with audioSegments and SubtitleSegments as well |
2259
2248
  // ---------------------------------------------------'
2260
- return [4 /*yield*/, currentVod_2.reload(nextMseq, segments, null, reloadBehind)];
2249
+ return [4 /*yield*/, currentVod_1.reload(nextMseq, segments, null, reloadBehind)];
2261
2250
  case 68:
2262
2251
  // ---------------------------------------------------.
2263
2252
  // TODO: Support reloading with audioSegments and SubtitleSegments as well |
2264
2253
  // ---------------------------------------------------'
2265
2254
  _u.sent();
2266
- return [4 /*yield*/, this._sessionState.setCurrentVod(currentVod_2, { ttl: currentVod_2.getDuration() * 1000 })];
2255
+ return [4 /*yield*/, this._sessionState.setCurrentVod(currentVod_1, { ttl: currentVod_1.getDuration() * 1000 })];
2267
2256
  case 69:
2268
2257
  _u.sent();
2269
2258
  return [4 /*yield*/, this._sessionState.set("vodReloaded", 1)];
@@ -2293,9 +2282,9 @@ var Session = /** @class */ (function () {
2293
2282
  _s.currentPlayheadRef = _u.sent();
2294
2283
  // 4) Log to debug and cloudwatch
2295
2284
  debug("[".concat(this._sessionId, "]: LEADER: Set new Reloaded VOD and vodMediaSeq counts in store."));
2296
- debug("[".concat(this._sessionId, "]: next VOD Reloaded (").concat(currentVod_2.getDeltaTimes(), ")"));
2297
- debug("[".concat(this._sessionId, "]: ").concat(currentVod_2.getPlayheadPositions()));
2298
- debug("[".concat(this._sessionId, "]: msequences=").concat(currentVod_2.getLiveMediaSequencesCount()));
2285
+ debug("[".concat(this._sessionId, "]: next VOD Reloaded (").concat(currentVod_1.getDeltaTimes(), ")"));
2286
+ debug("[".concat(this._sessionId, "]: ").concat(currentVod_1.getPlayheadPositions()));
2287
+ debug("[".concat(this._sessionId, "]: msequences=").concat(currentVod_1.getLiveMediaSequencesCount()));
2299
2288
  cloudWatchLog(!this.cloudWatchLogging, "engine-session", { event: "switchback", channel: this._sessionId, reqTimeMs: Date.now() - startTS });
2300
2289
  return [2 /*return*/];
2301
2290
  case 78:
@@ -2727,6 +2716,50 @@ var Session = /** @class */ (function () {
2727
2716
  }
2728
2717
  return false;
2729
2718
  };
2719
+ Session.prototype._determineExtraMediaIncrement = function (_extraType, _currentPosVideo, _extraSeqFinalIndex, _vodMediaSeqExtra, _getExtraPlayheadPositionAsyncFn) {
2720
+ return __awaiter(this, void 0, void 0, function () {
2721
+ var extraMediaIncrement, positionV, positionX, posDiff, threshold, currentPosExtraMedia, difference;
2722
+ return __generator(this, function (_a) {
2723
+ switch (_a.label) {
2724
+ case 0:
2725
+ debug("[".concat(this._sessionId, "]: About to determine ").concat(_extraType, " increment. Video increment has already been executed."));
2726
+ extraMediaIncrement = 0;
2727
+ positionV = _currentPosVideo ? _currentPosVideo / 1000 : 0;
2728
+ threshold = 0.250;
2729
+ _a.label = 1;
2730
+ case 1:
2731
+ if (!(extraMediaIncrement < _extraSeqFinalIndex)) return [3 /*break*/, 3];
2732
+ return [4 /*yield*/, _getExtraPlayheadPositionAsyncFn(_vodMediaSeqExtra + extraMediaIncrement)];
2733
+ case 2:
2734
+ currentPosExtraMedia = (_a.sent()) * 1000;
2735
+ positionX = currentPosExtraMedia ? currentPosExtraMedia / 1000 : 0;
2736
+ posDiff = (positionV - positionX).toFixed(3);
2737
+ debug("[".concat(this._sessionId, "]: positionV=").concat(positionV, ";position").concat(_extraType === "audio" ? "A" : "S", "=").concat(positionX, ";posDiff=").concat(posDiff));
2738
+ if (isNaN(posDiff)) {
2739
+ return [3 /*break*/, 3];
2740
+ }
2741
+ if (positionX >= positionV) {
2742
+ return [3 /*break*/, 3];
2743
+ }
2744
+ difference = Math.abs(posDiff);
2745
+ if (difference > threshold && difference > Number.EPSILON) {
2746
+ // Video position ahead of audio|sub position, further increment needed...
2747
+ extraMediaIncrement++;
2748
+ }
2749
+ else {
2750
+ debug("[".concat(this._sessionId, "]: Difference(").concat(difference, ") is acceptable; IncrementValue=").concat(extraMediaIncrement));
2751
+ return [3 /*break*/, 3];
2752
+ }
2753
+ return [3 /*break*/, 1];
2754
+ case 3: return [2 /*return*/, {
2755
+ increment: extraMediaIncrement,
2756
+ position: positionX,
2757
+ diff: posDiff
2758
+ }];
2759
+ }
2760
+ });
2761
+ });
2762
+ };
2730
2763
  return Session;
2731
2764
  }());
2732
2765
  module.exports = Session;
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eyevinn-channel-engine",
3
- "version": "4.3.7",
3
+ "version": "4.3.8",
4
4
  "description": "OTT TV Channel Engine",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/engine/session.js CHANGED
@@ -834,51 +834,51 @@ class Session {
834
834
  }
835
835
  } else {
836
836
  sessionState.vodMediaSeqVideo = await this._sessionState.increment("vodMediaSeqVideo", 1);
837
- let audioIncrement;
837
+ let playheadPosVideoMs;
838
+ let playheadAudio;
839
+ let playheadSubtitle;
840
+ if (this.use_demuxed_audio || this.use_vtt_subtitles) {
841
+ playheadPosVideoMs = (await this._getCurrentPlayheadPosition()) * 1000;
842
+ }
843
+
838
844
  if (this.use_demuxed_audio) {
839
- let positionV = 0;
840
- let positionA = 0;
841
- const position = (await this._getCurrentPlayheadPosition()) * 1000;
842
- positionV = position ? position / 1000 : 0;
843
- let currentVod = await this._sessionState.getCurrentVod();
844
- const sessionState = await this._sessionState.getValues(["vodMediaSeqAudio"]);
845
- let posDiff;
846
- let incrementValue = 1;
847
- let index = 0;
848
845
  const audioSeqLastIdx = currentVod.getLiveMediaSequencesCount("audio") - 1;
849
- const thresh = 0.5;
850
- const maxAcceptableDiff = 0.001;
851
- debug(`[${this._sessionId}]: About to determine audio increment`);
852
- do {
853
- const audioPosition = (await this._getAudioPlayheadPosition(sessionState.vodMediaSeqAudio + index)) * 1000;
854
- positionA = audioPosition ? audioPosition / 1000 : 0;
855
- posDiff = (positionV - positionA).toFixed(3);
856
- debug(`[${this._sessionId}]: positionV=${positionV};positionA=${positionA};posDiff=${posDiff}`);
857
- if (posDiff <= maxAcceptableDiff) {
858
- break;
859
- }
860
- if (posDiff > thresh) {
861
- index++;
862
- incrementValue++;
863
- } else if (posDiff > maxAcceptableDiff) {
864
- index = incrementValue;
865
- debug(`[${this._sessionId}]: Audio Stepping index set to = ${index}`);
866
- break;
867
- }
868
- if (sessionState.vodMediaSeqAudio + index > audioSeqLastIdx) {
869
- break;
870
- }
871
- } while (!(-thresh < posDiff && posDiff < thresh) && !isNaN(posDiff));
872
- audioIncrement = index;
873
- debug(`[${this._sessionId}]: Current VOD Playhead Positions are to be: [${positionV.toFixed(3)}][${positionA.toFixed(3)}] (${posDiff})`);
846
+ const sessionStateObj = await this._sessionState.getValues(["vodMediaSeqAudio"]);
847
+ playheadAudio = await this._determineExtraMediaIncrement(
848
+ "audio",
849
+ playheadPosVideoMs,
850
+ audioSeqLastIdx,
851
+ sessionStateObj.vodMediaSeqAudio,
852
+ this._getAudioPlayheadPosition.bind(this)
853
+ );
854
+ // Perform the Increment
855
+ debug(`[${this._sessionId}]: Will increment audio with ${playheadAudio.increment}`);
856
+ sessionState.vodMediaSeqAudio = await this._sessionState.increment("vodMediaSeqAudio", playheadAudio.increment);
874
857
  }
875
- debug(`[${this._sessionId}]: Will increment audio with ${audioIncrement}`);
876
- sessionState.vodMediaSeqAudio = await this._sessionState.increment("vodMediaSeqAudio", audioIncrement);
877
-
878
858
  if (this.use_vtt_subtitles) {
879
- debug(`[${this._sessionId}]: Will increment subtitle with 1`);
880
- sessionState.vodMediaSeqSubtitle = await this._sessionState.increment("vodMediaSeqSubtitle", 1);
859
+ const playheadPosVideo = playheadPosVideo || (await this._getCurrentPlayheadPosition()) * 1000;
860
+ const subtitleSeqLastIdx = currentVod.getLiveMediaSequencesCount("subtitle") - 1;
861
+ const sessionStateObj = await this._sessionState.getValues(["vodMediaSeqSubtitle"]);
862
+ playheadSubtitle = await this._determineExtraMediaIncrement(
863
+ "subtitle",
864
+ playheadPosVideoMs,
865
+ subtitleSeqLastIdx,
866
+ sessionStateObj.vodMediaSeqSubtitle,
867
+ this._getSubtitlePlayheadPosition.bind(this)
868
+ );
869
+ // Perform the Increment
870
+ debug(`[${this._sessionId}]: Will increment subtitle with ${playheadSubtitle.increment}`);
871
+ sessionState.vodMediaSeqSubtitle = await this._sessionState.increment("vodMediaSeqSubtitle", playheadSubtitle.increment);
881
872
  }
873
+ debug(`[${this._sessionId}]: Current VOD Playhead Positions are to be V[${(playheadPosVideoMs/1000).toFixed(3)}]${
874
+ playheadAudio ? `A[${(playheadAudio.position).toFixed(3)}]` : ""
875
+ }${
876
+ playheadSubtitle ? `S[${(playheadSubtitle.position).toFixed(3)})]` : ""
877
+ }${
878
+ playheadAudio ? ` (${playheadAudio.diff})` : ""
879
+ }${
880
+ playheadSubtitle ? ` (${playheadSubtitle.diff})` : ""
881
+ }`);
882
882
  }
883
883
 
884
884
  let newSessionState = {};
@@ -1388,6 +1388,7 @@ class Session {
1388
1388
  debug(`[${this._sessionId}]: ${currentVod.getDeltaTimes()}`);
1389
1389
  debug(`[${this._sessionId}]: playhead positions [V]=${currentVod.getPlayheadPositions("video")}`);
1390
1390
  debug(`[${this._sessionId}]: playhead positions [A]=${currentVod.getPlayheadPositions("audio")}`);
1391
+ debug(`[${this._sessionId}]: playhead positions [S]=${currentVod.getPlayheadPositions("subtitle")}`);
1391
1392
  //debug(newVod);
1392
1393
  const updatedSessionState = await this._sessionState.setValues({
1393
1394
  "mediaSeq": 0,
@@ -1584,6 +1585,7 @@ class Session {
1584
1585
  debug(`[${this._sessionId}]: next VOD loaded (${newVod.getDeltaTimes()})`);
1585
1586
  debug(`[${this._sessionId}]: playhead positions [V]=${newVod.getPlayheadPositions("video")}`);
1586
1587
  debug(`[${this._sessionId}]: playhead positions [A]=${newVod.getPlayheadPositions("audio")}`);
1588
+ debug(`[${this._sessionId}]: playhead positions [S]=${newVod.getPlayheadPositions("subtitle")}`);
1587
1589
  currentVod = newVod;
1588
1590
  debug(`[${this._sessionId}]: msequences=${currentVod.getLiveMediaSequencesCount()}; audio msequences=${currentVod.getLiveMediaSequencesCount("audio")}; subtitle msequences=${currentVod.getLiveMediaSequencesCount("subtitle")}`);
1589
1591
  sessionState.currentVod = await this._sessionState.setCurrentVod(currentVod, { ttl: currentVod.getDuration() * 1000 });
@@ -2089,6 +2091,40 @@ class Session {
2089
2091
  }
2090
2092
  return false;
2091
2093
  }
2094
+
2095
+ async _determineExtraMediaIncrement(_extraType, _currentPosVideo, _extraSeqFinalIndex, _vodMediaSeqExtra, _getExtraPlayheadPositionAsyncFn) {
2096
+ debug(`[${this._sessionId}]: About to determine ${_extraType} increment. Video increment has already been executed.`);
2097
+ let extraMediaIncrement = 0;
2098
+ let positionV = _currentPosVideo ? _currentPosVideo / 1000 : 0;
2099
+ let positionX;
2100
+ let posDiff;
2101
+ const threshold = 0.250;
2102
+ while (extraMediaIncrement < _extraSeqFinalIndex) {
2103
+ const currentPosExtraMedia = (await _getExtraPlayheadPositionAsyncFn(_vodMediaSeqExtra + extraMediaIncrement)) * 1000;
2104
+ positionX = currentPosExtraMedia ? currentPosExtraMedia / 1000 : 0;
2105
+ posDiff = (positionV - positionX).toFixed(3);
2106
+ debug(`[${this._sessionId}]: positionV=${positionV};position${_extraType === "audio" ? "A" : "S"}=${positionX};posDiff=${posDiff}`);
2107
+ if (isNaN(posDiff)) {
2108
+ break;
2109
+ }
2110
+ if (positionX >= positionV) {
2111
+ break;
2112
+ }
2113
+ const difference = Math.abs(posDiff);
2114
+ if (difference > threshold && difference > Number.EPSILON) {
2115
+ // Video position ahead of audio|sub position, further increment needed...
2116
+ extraMediaIncrement++;
2117
+ } else {
2118
+ debug(`[${this._sessionId}]: Difference(${difference}) is acceptable; IncrementValue=${extraMediaIncrement}`);
2119
+ break;
2120
+ }
2121
+ }
2122
+ return {
2123
+ increment: extraMediaIncrement,
2124
+ position: positionX,
2125
+ diff: posDiff
2126
+ };
2127
+ }
2092
2128
  }
2093
2129
 
2094
2130
  module.exports = Session;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eyevinn-channel-engine",
3
- "version": "4.3.7",
3
+ "version": "4.3.8",
4
4
  "description": "OTT TV Channel Engine",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -1,20 +1,116 @@
1
- const Session = require('../../engine/session.js');
1
+ const Session = require("../../engine/session.js");
2
2
 
3
- const { SessionStateStore } = require('../../engine/session_state.js');
4
- const { PlayheadStateStore } = require('../../engine/playhead_state.js');
3
+ const { SessionStateStore } = require("../../engine/session_state.js");
4
+ const { PlayheadStateStore } = require("../../engine/playhead_state.js");
5
5
 
6
6
  describe("Session", () => {
7
7
  let sessionLiveStore = undefined;
8
8
  beforeEach(() => {
9
9
  sessionLiveStore = {
10
10
  sessionStateStore: new SessionStateStore(),
11
- playheadStateStore: new PlayheadStateStore()
12
- };
11
+ playheadStateStore: new PlayheadStateStore(),
12
+ };
13
13
  });
14
14
 
15
15
  it("creates a unique session ID", () => {
16
- const id1 = new Session('dummy', null, sessionLiveStore).sessionId;
17
- const id2 = new Session('dummy', null, sessionLiveStore).sessionId;
16
+ const id1 = new Session("dummy", null, sessionLiveStore).sessionId;
17
+ const id2 = new Session("dummy", null, sessionLiveStore).sessionId;
18
18
  expect(id1).not.toEqual(id2);
19
19
  });
20
- });
20
+
21
+ it("for demuxed, returns the appropriate audio increment value when desync is within acceptable limit, case I", async () => {
22
+ const session = new Session("dummy", null, sessionLiveStore);
23
+ const mockFinalAudioIdx = 50; // current Vod has 50 media sequences to serve.
24
+ const mockCurrentVideoPosition = 200.0 * 1000; // Video is 200s deep into its content.
25
+ const mockMseqAudio = 25; // current mseq for audio on vod, 25 out of 50.
26
+ const mock_getAudioPlayheadPosition = async (pos_n_current) => {
27
+ const mockPositions = [196.0, 199.84, 203.68, 207.52];
28
+ return mockPositions[pos_n_current - mockMseqAudio];
29
+ };
30
+ const output = await session._determineExtraMediaIncrement(
31
+ "audio",
32
+ mockCurrentVideoPosition,
33
+ mockFinalAudioIdx,
34
+ mockMseqAudio,
35
+ mock_getAudioPlayheadPosition,
36
+ 24
37
+ );
38
+ expect(output.increment).toBe(1);
39
+ });
40
+
41
+ it("for demuxed, returns the appropriate audio increment value when desync is within acceptable limit, case II", async () => {
42
+ const session = new Session("dummy", null, sessionLiveStore);
43
+ const mockFinalAudioIdx = 50; // current Vod has 50 media sequences to serve.
44
+ const mockCurrentVideoPosition = 200.0 * 1000; // Video is 200s deep into its content.
45
+ const mockMseqAudio = 25; // current mseq for audio on vod, 25 out of 50.
46
+ const mock_getAudioPlayheadPosition = async (pos_n_current) => {
47
+ const mockPositions = [192.16, 196.0, 199.84, 203.68, 207.52];
48
+ return mockPositions[pos_n_current - mockMseqAudio];
49
+ };
50
+ const output = await session._determineExtraMediaIncrement(
51
+ "audio",
52
+ mockCurrentVideoPosition,
53
+ mockFinalAudioIdx,
54
+ mockMseqAudio,
55
+ mock_getAudioPlayheadPosition,
56
+ 24
57
+ );
58
+ expect(output.increment).toBe(2);
59
+ });
60
+
61
+ it("for demuxed, returns the appropriate audio increment value when they are in sync but there is a floating point error", async () => {
62
+ const session = new Session("dummy", null, sessionLiveStore);
63
+ const mockFinalAudioIdx = 50;
64
+ const mockCurrentVideoPosition = 441.7599999999981697 * 1000;
65
+ const mockMseqAudio = 25;
66
+ const mock_getAudioPlayheadPosition = async (pos_n_current) => {
67
+ const mockPositions = [437.919999999999, 441.75999999999897];
68
+ return mockPositions[pos_n_current - mockMseqAudio];
69
+ };
70
+ const output = await session._determineExtraMediaIncrement(
71
+ "audio",
72
+ mockCurrentVideoPosition,
73
+ mockFinalAudioIdx,
74
+ mockMseqAudio,
75
+ mock_getAudioPlayheadPosition,
76
+ 24
77
+ );
78
+ expect(output.increment).toBe(1);
79
+ });
80
+ it("for demuxed, returns the appropriate audio increment value, normal case I", async () => {
81
+ const session = new Session("dummy", null, sessionLiveStore);
82
+ const mockFinalAudioIdx = 50;
83
+ const mockCurrentVideoPosition = 3.840 * 8 * 1000;
84
+ const mockMseqAudio = 5;
85
+ const mock_getAudioPlayheadPosition = async (pos_n_current) => {
86
+ const mockPositions = [0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52];
87
+ return mockPositions[pos_n_current];
88
+ };
89
+ const output = await session._determineExtraMediaIncrement(
90
+ "audio",
91
+ mockCurrentVideoPosition,
92
+ mockFinalAudioIdx,
93
+ mockMseqAudio,
94
+ mock_getAudioPlayheadPosition
95
+ );
96
+ expect(output.increment).toBe(3);
97
+ });
98
+ it("for demuxed, returns the appropriate audio increment value, normal case II", async () => {
99
+ const session = new Session("dummy", null, sessionLiveStore);
100
+ const mockFinalAudioIdx = 50;
101
+ const mockCurrentVideoPosition = 14 * 1000;
102
+ const mockMseqAudio = 0;
103
+ const mock_getAudioPlayheadPosition = async (pos_n_current) => {
104
+ const mockPositions = [0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52];
105
+ return mockPositions[pos_n_current];
106
+ };
107
+ const output = await session._determineExtraMediaIncrement(
108
+ "subtitle",
109
+ mockCurrentVideoPosition,
110
+ mockFinalAudioIdx,
111
+ mockMseqAudio,
112
+ mock_getAudioPlayheadPosition
113
+ );
114
+ expect(output.increment).toBe(4);
115
+ });
116
+ });