eyevinn-channel-engine 4.3.7 → 4.3.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/engine/session.d.ts +5 -0
- package/dist/engine/session.js +150 -112
- package/dist/package.json +2 -2
- package/engine/session.js +87 -42
- package/package.json +2 -2
- package/spec/engine/session_spec.js +104 -8
package/dist/engine/session.d.ts
CHANGED
|
@@ -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
|
}
|
package/dist/engine/session.js
CHANGED
|
@@ -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,
|
|
1091
|
-
return __generator(this, function (
|
|
1092
|
-
switch (
|
|
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, subsInfo, mediaSequenceValueSubtitle, 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
|
-
|
|
1095
|
+
_g.sent();
|
|
1096
1096
|
return [4 /*yield*/, this._sessionStateStore.isLeader(this._instanceId)];
|
|
1097
1097
|
case 2:
|
|
1098
|
-
isLeader =
|
|
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 =
|
|
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 =
|
|
1104
|
+
playheadState = _g.sent();
|
|
1105
1105
|
return [4 /*yield*/, this._sessionState.getCurrentVod()];
|
|
1106
1106
|
case 5:
|
|
1107
|
-
currentVod =
|
|
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
|
-
|
|
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 =
|
|
1126
|
-
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
1157
|
-
case 13: return [3 /*break*/,
|
|
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 =
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
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
|
-
|
|
1170
|
-
|
|
1171
|
-
return [4 /*yield*/, this._sessionState.getCurrentVod()];
|
|
1169
|
+
playheadPosVideoMs = (_g.sent()) * 1000;
|
|
1170
|
+
_g.label = 17;
|
|
1172
1171
|
case 17:
|
|
1173
|
-
|
|
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
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
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
|
-
|
|
1188
|
-
|
|
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 (!
|
|
1209
|
-
|
|
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
|
-
|
|
1212
|
-
|
|
1213
|
-
_f.label = 23;
|
|
1193
|
+
_e = (_g.sent()) * 1000;
|
|
1194
|
+
_g.label = 23;
|
|
1214
1195
|
case 23:
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
return [4 /*yield*/, this._sessionState.
|
|
1196
|
+
playheadPosVideo = _e;
|
|
1197
|
+
subtitleSeqLastIdx = currentVod.getLiveMediaSequencesCount("subtitle") - 1;
|
|
1198
|
+
return [4 /*yield*/, this._sessionState.getValues(["vodMediaSeqSubtitle"])];
|
|
1218
1199
|
case 24:
|
|
1219
|
-
|
|
1220
|
-
|
|
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
|
-
|
|
1226
|
-
|
|
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
|
|
1245
|
-
updatedValues =
|
|
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
|
|
1259
|
-
updatedPlayhead =
|
|
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];
|
|
@@ -1265,26 +1252,31 @@ var Session = /** @class */ (function () {
|
|
|
1265
1252
|
mediaSequenceValueAudio = currentVod.mediaSequenceValuesAudio[playheadState.vodMediaSeqAudio];
|
|
1266
1253
|
audioInfo = " mseq[A]={".concat(playheadState.mediaSeqAudio + mediaSequenceValueAudio, "}");
|
|
1267
1254
|
}
|
|
1268
|
-
|
|
1255
|
+
subsInfo = "";
|
|
1256
|
+
if (this.use_vtt_subtitles) {
|
|
1257
|
+
mediaSequenceValueSubtitle = currentVod.mediaSequenceValuesSubtitle[playheadState.vodMediaSeqSubtitle];
|
|
1258
|
+
subsInfo = " mseq[S]={".concat(playheadState.mediaSeqSubtitle + mediaSequenceValueSubtitle, "}");
|
|
1259
|
+
}
|
|
1260
|
+
debug("[".concat(this._sessionId, "]: Session can now serve mseq[V]={").concat(playheadState.mediaSeq + mediaSequenceValue, "}") + audioInfo + subsInfo);
|
|
1269
1261
|
}
|
|
1270
|
-
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*/,
|
|
1262
|
+
debug("[".concat(this._sessionId, "]: INCREMENT (mseq=").concat(playheadState.mediaSeq + playheadState.vodMediaSeqVideo, ") vodMediaSeq=(").concat(playheadState.vodMediaSeqVideo, "_").concat(playheadState.vodMediaSeqAudio).concat(this.use_vtt_subtitles ? "_".concat(playheadState.vodMediaSeqSubtitle) : "", " of ").concat(currentVod.getLiveMediaSequencesCount(), "_").concat(currentVod.getLiveMediaSequencesCount("audio")).concat(this.use_vtt_subtitles ? "_".concat(currentVod.getLiveMediaSequencesCount("subtitle"), ")") : ")"));
|
|
1263
|
+
if (!(playheadState.vodMediaSeqVideo < 2 || playheadState.mediaSeq !== this.prevMediaSeqOffset.video)) return [3 /*break*/, 35];
|
|
1272
1264
|
debug("[".concat(this._sessionId, "]: current[").concat(playheadState.vodMediaSeqVideo, "]_prev[").concat(this.prevVodMediaSeq.video, "]"));
|
|
1273
1265
|
debug("[".concat(this._sessionId, "]: current-offset[").concat(playheadState.mediaSeq, "]_prev-offset[").concat(this.prevMediaSeqOffset.video, "]"));
|
|
1274
1266
|
if (playheadState.vodMediaSeqVideo < this.prevVodMediaSeq.video || playheadState.mediaSeq !== this.prevMediaSeqOffset.video) {
|
|
1275
1267
|
this.isAllowedToClearVodCache = true;
|
|
1276
1268
|
}
|
|
1277
|
-
if (!(!isLeader && this.isAllowedToClearVodCache)) return [3 /*break*/,
|
|
1269
|
+
if (!(!isLeader && this.isAllowedToClearVodCache)) return [3 /*break*/, 34];
|
|
1278
1270
|
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
1271
|
return [4 /*yield*/, this._sessionState.clearCurrentVodCache()];
|
|
1280
|
-
case
|
|
1281
|
-
|
|
1272
|
+
case 31:
|
|
1273
|
+
_g.sent();
|
|
1282
1274
|
return [4 /*yield*/, this._sessionState.getCurrentVod()];
|
|
1283
|
-
case
|
|
1284
|
-
currentVod =
|
|
1275
|
+
case 32:
|
|
1276
|
+
currentVod = _g.sent();
|
|
1285
1277
|
return [4 /*yield*/, this._playheadState.get("diffCompensation")];
|
|
1286
|
-
case
|
|
1287
|
-
diffMs =
|
|
1278
|
+
case 33:
|
|
1279
|
+
diffMs = _g.sent();
|
|
1288
1280
|
if (diffMs) {
|
|
1289
1281
|
this.diffCompensation = diffMs;
|
|
1290
1282
|
debug("[".concat(this._sessionId, "]: Setting diffCompensation->").concat(this.diffCompensation));
|
|
@@ -1297,12 +1289,12 @@ var Session = /** @class */ (function () {
|
|
|
1297
1289
|
}
|
|
1298
1290
|
}
|
|
1299
1291
|
this.isAllowedToClearVodCache = false;
|
|
1300
|
-
|
|
1301
|
-
case
|
|
1302
|
-
case
|
|
1292
|
+
_g.label = 34;
|
|
1293
|
+
case 34: return [3 /*break*/, 36];
|
|
1294
|
+
case 35:
|
|
1303
1295
|
this.isAllowedToClearVodCache = true;
|
|
1304
|
-
|
|
1305
|
-
case
|
|
1296
|
+
_g.label = 36;
|
|
1297
|
+
case 36:
|
|
1306
1298
|
// Update Value for Previous Sequence
|
|
1307
1299
|
this.prevVodMediaSeq.video = playheadState.vodMediaSeqVideo;
|
|
1308
1300
|
this.prevMediaSeqOffset.video = playheadState.mediaSeq;
|
|
@@ -1316,8 +1308,8 @@ var Session = /** @class */ (function () {
|
|
|
1316
1308
|
}
|
|
1317
1309
|
m3u8 = currentVod.getLiveMediaSequences(playheadState.mediaSeq, 180000, playheadState.vodMediaSeqVideo, sessionState.discSeq);
|
|
1318
1310
|
return [4 /*yield*/, this._playheadState.setLastM3u8(m3u8)];
|
|
1319
|
-
case
|
|
1320
|
-
|
|
1311
|
+
case 37:
|
|
1312
|
+
_g.sent();
|
|
1321
1313
|
return [2 /*return*/, m3u8];
|
|
1322
1314
|
}
|
|
1323
1315
|
});
|
|
@@ -1325,7 +1317,7 @@ var Session = /** @class */ (function () {
|
|
|
1325
1317
|
};
|
|
1326
1318
|
Session.prototype.getMediaManifestAsync = function (bw, opts) {
|
|
1327
1319
|
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,
|
|
1320
|
+
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
1321
|
return __generator(this, function (_m) {
|
|
1330
1322
|
switch (_m.label) {
|
|
1331
1323
|
case 0: // this function is no longer used and should be removed comment added 5/5-2023
|
|
@@ -1407,38 +1399,38 @@ var Session = /** @class */ (function () {
|
|
|
1407
1399
|
timeSinceLastRequest_1 = (tsLastRequestVideo_1 === null) ? 0 : Date.now() - tsLastRequestVideo_1;
|
|
1408
1400
|
return [4 /*yield*/, this._sessionState.getValues(["state", "vodMediaSeqVideo", "mediaSeq", "discSeq", "lastM3u8"])];
|
|
1409
1401
|
case 17:
|
|
1410
|
-
|
|
1411
|
-
if (!(
|
|
1412
|
-
_h =
|
|
1402
|
+
sessionState_1 = _m.sent();
|
|
1403
|
+
if (!(sessionState_1.state === SessionState.VOD_NEXT_INITIATING)) return [3 /*break*/, 19];
|
|
1404
|
+
_h = sessionState_1;
|
|
1413
1405
|
return [4 /*yield*/, this._sessionState.set("state", SessionState.VOD_PLAYING)];
|
|
1414
1406
|
case 18:
|
|
1415
1407
|
_h.state = _m.sent();
|
|
1416
1408
|
_m.label = 19;
|
|
1417
1409
|
case 19:
|
|
1418
|
-
debug("[".concat(this._sessionId, "]: VIDEO ").concat(timeSinceLastRequest_1, " (").concat(this.averageSegmentDuration, ") bandwidth=").concat(bw, " vodMediaSeq=(").concat(
|
|
1410
|
+
debug("[".concat(this._sessionId, "]: VIDEO ").concat(timeSinceLastRequest_1, " (").concat(this.averageSegmentDuration, ") bandwidth=").concat(bw, " vodMediaSeq=(").concat(sessionState_1.vodMediaSeqVideo, "_").concat(sessionState_1.vodMediaSeqAudio, ")"));
|
|
1419
1411
|
try {
|
|
1420
|
-
m3u8 = currentVod.getLiveMediaSequences(
|
|
1412
|
+
m3u8 = currentVod.getLiveMediaSequences(sessionState_1.mediaSeq, bw, sessionState_1.vodMediaSeqVideo, sessionState_1.discSeq);
|
|
1421
1413
|
}
|
|
1422
1414
|
catch (exc) {
|
|
1423
|
-
if (
|
|
1424
|
-
m3u8 =
|
|
1415
|
+
if (sessionState_1.lastM3u8[bw]) {
|
|
1416
|
+
m3u8 = sessionState_1.lastM3u8[bw];
|
|
1425
1417
|
}
|
|
1426
1418
|
else {
|
|
1427
1419
|
logerror(this._sessionId, exc);
|
|
1428
1420
|
throw new Error('Failed to generate media manifest');
|
|
1429
1421
|
}
|
|
1430
1422
|
}
|
|
1431
|
-
lastM3u8_1 =
|
|
1423
|
+
lastM3u8_1 = sessionState_1.lastM3u8;
|
|
1432
1424
|
lastM3u8_1[bw] = m3u8;
|
|
1433
|
-
_j =
|
|
1425
|
+
_j = sessionState_1;
|
|
1434
1426
|
return [4 /*yield*/, this._sessionState.set("lastM3u8", lastM3u8_1)];
|
|
1435
1427
|
case 20:
|
|
1436
1428
|
_j.lastM3u8 = _m.sent();
|
|
1437
|
-
_k =
|
|
1429
|
+
_k = sessionState_1;
|
|
1438
1430
|
return [4 /*yield*/, this._sessionState.set("lastServedM3u8", m3u8)];
|
|
1439
1431
|
case 21:
|
|
1440
1432
|
_k.lastServedM3u8 = _m.sent();
|
|
1441
|
-
_l =
|
|
1433
|
+
_l = sessionState_1;
|
|
1442
1434
|
return [4 /*yield*/, this._sessionState.set("tsLastRequestVideo", Date.now())];
|
|
1443
1435
|
case 22:
|
|
1444
1436
|
_l.tsLastRequestVideo = _m.sent();
|
|
@@ -1764,7 +1756,7 @@ var Session = /** @class */ (function () {
|
|
|
1764
1756
|
};
|
|
1765
1757
|
Session.prototype._tickAsync = function () {
|
|
1766
1758
|
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,
|
|
1759
|
+
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
1760
|
var _this = this;
|
|
1769
1761
|
return __generator(this, function (_u) {
|
|
1770
1762
|
switch (_u.label) {
|
|
@@ -1870,6 +1862,7 @@ var Session = /** @class */ (function () {
|
|
|
1870
1862
|
debug("[".concat(this._sessionId, "]: ").concat(currentVod.getDeltaTimes()));
|
|
1871
1863
|
debug("[".concat(this._sessionId, "]: playhead positions [V]=").concat(currentVod.getPlayheadPositions("video")));
|
|
1872
1864
|
debug("[".concat(this._sessionId, "]: playhead positions [A]=").concat(currentVod.getPlayheadPositions("audio")));
|
|
1865
|
+
debug("[".concat(this._sessionId, "]: playhead positions [S]=").concat(currentVod.getPlayheadPositions("subtitle")));
|
|
1873
1866
|
return [4 /*yield*/, this._sessionState.setValues({
|
|
1874
1867
|
"mediaSeq": 0,
|
|
1875
1868
|
"mediaSeqAudio": 0,
|
|
@@ -2110,6 +2103,7 @@ var Session = /** @class */ (function () {
|
|
|
2110
2103
|
debug("[".concat(this._sessionId, "]: next VOD loaded (").concat(newVod.getDeltaTimes(), ")"));
|
|
2111
2104
|
debug("[".concat(this._sessionId, "]: playhead positions [V]=").concat(newVod.getPlayheadPositions("video")));
|
|
2112
2105
|
debug("[".concat(this._sessionId, "]: playhead positions [A]=").concat(newVod.getPlayheadPositions("audio")));
|
|
2106
|
+
debug("[".concat(this._sessionId, "]: playhead positions [S]=").concat(newVod.getPlayheadPositions("subtitle")));
|
|
2113
2107
|
currentVod = newVod;
|
|
2114
2108
|
debug("[".concat(this._sessionId, "]: msequences=").concat(currentVod.getLiveMediaSequencesCount(), "; audio msequences=").concat(currentVod.getLiveMediaSequencesCount("audio"), "; subtitle msequences=").concat(currentVod.getLiveMediaSequencesCount("subtitle")));
|
|
2115
2109
|
_m = sessionState;
|
|
@@ -2216,8 +2210,8 @@ var Session = /** @class */ (function () {
|
|
|
2216
2210
|
mSeq = this.switchDataForSession.mediaSeq;
|
|
2217
2211
|
return [4 /*yield*/, this._sessionState.getCurrentVod()];
|
|
2218
2212
|
case 63:
|
|
2219
|
-
|
|
2220
|
-
if (
|
|
2213
|
+
currentVod_1 = _u.sent();
|
|
2214
|
+
if (currentVod_1.sequenceAlwaysContainNewSegments) {
|
|
2221
2215
|
// (!) will need to compensate if using this setting on HLSVod Object.
|
|
2222
2216
|
Object.keys(this.switchDataForSession.transitionSegments).forEach(function (bw) {
|
|
2223
2217
|
var shiftedSeg = _this.switchDataForSession.transitionSegments[bw].shift();
|
|
@@ -2251,19 +2245,19 @@ var Session = /** @class */ (function () {
|
|
|
2251
2245
|
case 67:
|
|
2252
2246
|
playheadState = _u.sent();
|
|
2253
2247
|
nextMseq = playheadState.vodMediaSeqVideo + 1;
|
|
2254
|
-
if (nextMseq >
|
|
2255
|
-
nextMseq =
|
|
2248
|
+
if (nextMseq > currentVod_1.getLiveMediaSequencesCount() - 1) {
|
|
2249
|
+
nextMseq = currentVod_1.getLiveMediaSequencesCount() - 1;
|
|
2256
2250
|
}
|
|
2257
2251
|
// ---------------------------------------------------.
|
|
2258
2252
|
// TODO: Support reloading with audioSegments and SubtitleSegments as well |
|
|
2259
2253
|
// ---------------------------------------------------'
|
|
2260
|
-
return [4 /*yield*/,
|
|
2254
|
+
return [4 /*yield*/, currentVod_1.reload(nextMseq, segments, null, reloadBehind)];
|
|
2261
2255
|
case 68:
|
|
2262
2256
|
// ---------------------------------------------------.
|
|
2263
2257
|
// TODO: Support reloading with audioSegments and SubtitleSegments as well |
|
|
2264
2258
|
// ---------------------------------------------------'
|
|
2265
2259
|
_u.sent();
|
|
2266
|
-
return [4 /*yield*/, this._sessionState.setCurrentVod(
|
|
2260
|
+
return [4 /*yield*/, this._sessionState.setCurrentVod(currentVod_1, { ttl: currentVod_1.getDuration() * 1000 })];
|
|
2267
2261
|
case 69:
|
|
2268
2262
|
_u.sent();
|
|
2269
2263
|
return [4 /*yield*/, this._sessionState.set("vodReloaded", 1)];
|
|
@@ -2293,9 +2287,9 @@ var Session = /** @class */ (function () {
|
|
|
2293
2287
|
_s.currentPlayheadRef = _u.sent();
|
|
2294
2288
|
// 4) Log to debug and cloudwatch
|
|
2295
2289
|
debug("[".concat(this._sessionId, "]: LEADER: Set new Reloaded VOD and vodMediaSeq counts in store."));
|
|
2296
|
-
debug("[".concat(this._sessionId, "]: next VOD Reloaded (").concat(
|
|
2297
|
-
debug("[".concat(this._sessionId, "]: ").concat(
|
|
2298
|
-
debug("[".concat(this._sessionId, "]: msequences=").concat(
|
|
2290
|
+
debug("[".concat(this._sessionId, "]: next VOD Reloaded (").concat(currentVod_1.getDeltaTimes(), ")"));
|
|
2291
|
+
debug("[".concat(this._sessionId, "]: ").concat(currentVod_1.getPlayheadPositions()));
|
|
2292
|
+
debug("[".concat(this._sessionId, "]: msequences=").concat(currentVod_1.getLiveMediaSequencesCount()));
|
|
2299
2293
|
cloudWatchLog(!this.cloudWatchLogging, "engine-session", { event: "switchback", channel: this._sessionId, reqTimeMs: Date.now() - startTS });
|
|
2300
2294
|
return [2 /*return*/];
|
|
2301
2295
|
case 78:
|
|
@@ -2727,6 +2721,50 @@ var Session = /** @class */ (function () {
|
|
|
2727
2721
|
}
|
|
2728
2722
|
return false;
|
|
2729
2723
|
};
|
|
2724
|
+
Session.prototype._determineExtraMediaIncrement = function (_extraType, _currentPosVideo, _extraSeqFinalIndex, _vodMediaSeqExtra, _getExtraPlayheadPositionAsyncFn) {
|
|
2725
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
2726
|
+
var extraMediaIncrement, positionV, positionX, posDiff, threshold, currentPosExtraMedia, difference;
|
|
2727
|
+
return __generator(this, function (_a) {
|
|
2728
|
+
switch (_a.label) {
|
|
2729
|
+
case 0:
|
|
2730
|
+
debug("[".concat(this._sessionId, "]: About to determine ").concat(_extraType, " increment. Video increment has already been executed."));
|
|
2731
|
+
extraMediaIncrement = 0;
|
|
2732
|
+
positionV = _currentPosVideo ? _currentPosVideo / 1000 : 0;
|
|
2733
|
+
threshold = 0.500;
|
|
2734
|
+
_a.label = 1;
|
|
2735
|
+
case 1:
|
|
2736
|
+
if (!(extraMediaIncrement < _extraSeqFinalIndex)) return [3 /*break*/, 3];
|
|
2737
|
+
return [4 /*yield*/, _getExtraPlayheadPositionAsyncFn(_vodMediaSeqExtra + extraMediaIncrement)];
|
|
2738
|
+
case 2:
|
|
2739
|
+
currentPosExtraMedia = (_a.sent()) * 1000;
|
|
2740
|
+
positionX = currentPosExtraMedia ? currentPosExtraMedia / 1000 : 0;
|
|
2741
|
+
posDiff = (positionV - positionX).toFixed(3);
|
|
2742
|
+
debug("[".concat(this._sessionId, "]: positionV=").concat(positionV, ";position").concat(_extraType === "audio" ? "A" : "S", "=").concat(positionX, ";posDiff=").concat(posDiff));
|
|
2743
|
+
if (isNaN(posDiff)) {
|
|
2744
|
+
return [3 /*break*/, 3];
|
|
2745
|
+
}
|
|
2746
|
+
if (positionX >= positionV) {
|
|
2747
|
+
return [3 /*break*/, 3];
|
|
2748
|
+
}
|
|
2749
|
+
difference = Math.abs(posDiff);
|
|
2750
|
+
if (difference > threshold && difference > Number.EPSILON) {
|
|
2751
|
+
// Video position ahead of audio|sub position, further increment needed...
|
|
2752
|
+
extraMediaIncrement++;
|
|
2753
|
+
}
|
|
2754
|
+
else {
|
|
2755
|
+
debug("[".concat(this._sessionId, "]: Difference(").concat(difference, ") is acceptable; IncrementValue=").concat(extraMediaIncrement));
|
|
2756
|
+
return [3 /*break*/, 3];
|
|
2757
|
+
}
|
|
2758
|
+
return [3 /*break*/, 1];
|
|
2759
|
+
case 3: return [2 /*return*/, {
|
|
2760
|
+
increment: extraMediaIncrement,
|
|
2761
|
+
position: positionX,
|
|
2762
|
+
diff: posDiff
|
|
2763
|
+
}];
|
|
2764
|
+
}
|
|
2765
|
+
});
|
|
2766
|
+
});
|
|
2767
|
+
};
|
|
2730
2768
|
return Session;
|
|
2731
2769
|
}());
|
|
2732
2770
|
module.exports = Session;
|
package/dist/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eyevinn-channel-engine",
|
|
3
|
-
"version": "4.3.
|
|
3
|
+
"version": "4.3.9",
|
|
4
4
|
"description": "OTT TV Channel Engine",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"dependencies": {
|
|
31
31
|
"@eyevinn/hls-repeat": "^0.2.0",
|
|
32
32
|
"@eyevinn/hls-truncate": "^0.3.0",
|
|
33
|
-
"@eyevinn/hls-vodtolive": "^4.1.
|
|
33
|
+
"@eyevinn/hls-vodtolive": "^4.1.1",
|
|
34
34
|
"@eyevinn/m3u8": "^0.5.3",
|
|
35
35
|
"abort-controller": "^3.0.0",
|
|
36
36
|
"debug": "^3.2.7",
|
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
|
|
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
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
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
|
-
|
|
880
|
-
|
|
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 = {};
|
|
@@ -923,10 +923,19 @@ class Session {
|
|
|
923
923
|
const mediaSequenceValueAudio = currentVod.mediaSequenceValuesAudio[playheadState.vodMediaSeqAudio];
|
|
924
924
|
audioInfo = ` mseq[A]={${playheadState.mediaSeqAudio + mediaSequenceValueAudio}}`
|
|
925
925
|
}
|
|
926
|
-
|
|
926
|
+
let subsInfo = "";
|
|
927
|
+
if (this.use_vtt_subtitles) {
|
|
928
|
+
const mediaSequenceValueSubtitle = currentVod.mediaSequenceValuesSubtitle[playheadState.vodMediaSeqSubtitle];
|
|
929
|
+
subsInfo = ` mseq[S]={${playheadState.mediaSeqSubtitle + mediaSequenceValueSubtitle}}`
|
|
930
|
+
}
|
|
931
|
+
debug(`[${this._sessionId}]: Session can now serve mseq[V]={${playheadState.mediaSeq + mediaSequenceValue}}` + audioInfo + subsInfo);
|
|
927
932
|
}
|
|
928
933
|
|
|
929
|
-
debug(`[${this._sessionId}]: INCREMENT (mseq=${playheadState.mediaSeq + playheadState.vodMediaSeqVideo}) vodMediaSeq=(${playheadState.vodMediaSeqVideo}_${playheadState.vodMediaSeqAudio}
|
|
934
|
+
debug(`[${this._sessionId}]: INCREMENT (mseq=${playheadState.mediaSeq + playheadState.vodMediaSeqVideo}) vodMediaSeq=(${playheadState.vodMediaSeqVideo}_${playheadState.vodMediaSeqAudio}${
|
|
935
|
+
this.use_vtt_subtitles ? `_${playheadState.vodMediaSeqSubtitle}` : ""
|
|
936
|
+
} of ${currentVod.getLiveMediaSequencesCount()}_${currentVod.getLiveMediaSequencesCount("audio")}${
|
|
937
|
+
this.use_vtt_subtitles ? `_${currentVod.getLiveMediaSequencesCount("subtitle")})` : ")"
|
|
938
|
+
}`);
|
|
930
939
|
|
|
931
940
|
// As a FOLLOWER, we might need to read up from shared store...
|
|
932
941
|
if (playheadState.vodMediaSeqVideo < 2 || playheadState.mediaSeq !== this.prevMediaSeqOffset.video) {
|
|
@@ -1388,6 +1397,7 @@ class Session {
|
|
|
1388
1397
|
debug(`[${this._sessionId}]: ${currentVod.getDeltaTimes()}`);
|
|
1389
1398
|
debug(`[${this._sessionId}]: playhead positions [V]=${currentVod.getPlayheadPositions("video")}`);
|
|
1390
1399
|
debug(`[${this._sessionId}]: playhead positions [A]=${currentVod.getPlayheadPositions("audio")}`);
|
|
1400
|
+
debug(`[${this._sessionId}]: playhead positions [S]=${currentVod.getPlayheadPositions("subtitle")}`);
|
|
1391
1401
|
//debug(newVod);
|
|
1392
1402
|
const updatedSessionState = await this._sessionState.setValues({
|
|
1393
1403
|
"mediaSeq": 0,
|
|
@@ -1584,6 +1594,7 @@ class Session {
|
|
|
1584
1594
|
debug(`[${this._sessionId}]: next VOD loaded (${newVod.getDeltaTimes()})`);
|
|
1585
1595
|
debug(`[${this._sessionId}]: playhead positions [V]=${newVod.getPlayheadPositions("video")}`);
|
|
1586
1596
|
debug(`[${this._sessionId}]: playhead positions [A]=${newVod.getPlayheadPositions("audio")}`);
|
|
1597
|
+
debug(`[${this._sessionId}]: playhead positions [S]=${newVod.getPlayheadPositions("subtitle")}`);
|
|
1587
1598
|
currentVod = newVod;
|
|
1588
1599
|
debug(`[${this._sessionId}]: msequences=${currentVod.getLiveMediaSequencesCount()}; audio msequences=${currentVod.getLiveMediaSequencesCount("audio")}; subtitle msequences=${currentVod.getLiveMediaSequencesCount("subtitle")}`);
|
|
1589
1600
|
sessionState.currentVod = await this._sessionState.setCurrentVod(currentVod, { ttl: currentVod.getDuration() * 1000 });
|
|
@@ -2089,6 +2100,40 @@ class Session {
|
|
|
2089
2100
|
}
|
|
2090
2101
|
return false;
|
|
2091
2102
|
}
|
|
2103
|
+
|
|
2104
|
+
async _determineExtraMediaIncrement(_extraType, _currentPosVideo, _extraSeqFinalIndex, _vodMediaSeqExtra, _getExtraPlayheadPositionAsyncFn) {
|
|
2105
|
+
debug(`[${this._sessionId}]: About to determine ${_extraType} increment. Video increment has already been executed.`);
|
|
2106
|
+
let extraMediaIncrement = 0;
|
|
2107
|
+
let positionV = _currentPosVideo ? _currentPosVideo / 1000 : 0;
|
|
2108
|
+
let positionX;
|
|
2109
|
+
let posDiff;
|
|
2110
|
+
const threshold = 0.500;
|
|
2111
|
+
while (extraMediaIncrement < _extraSeqFinalIndex) {
|
|
2112
|
+
const currentPosExtraMedia = (await _getExtraPlayheadPositionAsyncFn(_vodMediaSeqExtra + extraMediaIncrement)) * 1000;
|
|
2113
|
+
positionX = currentPosExtraMedia ? currentPosExtraMedia / 1000 : 0;
|
|
2114
|
+
posDiff = (positionV - positionX).toFixed(3);
|
|
2115
|
+
debug(`[${this._sessionId}]: positionV=${positionV};position${_extraType === "audio" ? "A" : "S"}=${positionX};posDiff=${posDiff}`);
|
|
2116
|
+
if (isNaN(posDiff)) {
|
|
2117
|
+
break;
|
|
2118
|
+
}
|
|
2119
|
+
if (positionX >= positionV) {
|
|
2120
|
+
break;
|
|
2121
|
+
}
|
|
2122
|
+
const difference = Math.abs(posDiff);
|
|
2123
|
+
if (difference > threshold && difference > Number.EPSILON) {
|
|
2124
|
+
// Video position ahead of audio|sub position, further increment needed...
|
|
2125
|
+
extraMediaIncrement++;
|
|
2126
|
+
} else {
|
|
2127
|
+
debug(`[${this._sessionId}]: Difference(${difference}) is acceptable; IncrementValue=${extraMediaIncrement}`);
|
|
2128
|
+
break;
|
|
2129
|
+
}
|
|
2130
|
+
}
|
|
2131
|
+
return {
|
|
2132
|
+
increment: extraMediaIncrement,
|
|
2133
|
+
position: positionX,
|
|
2134
|
+
diff: posDiff
|
|
2135
|
+
};
|
|
2136
|
+
}
|
|
2092
2137
|
}
|
|
2093
2138
|
|
|
2094
2139
|
module.exports = Session;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eyevinn-channel-engine",
|
|
3
|
-
"version": "4.3.
|
|
3
|
+
"version": "4.3.9",
|
|
4
4
|
"description": "OTT TV Channel Engine",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"dependencies": {
|
|
31
31
|
"@eyevinn/hls-repeat": "^0.2.0",
|
|
32
32
|
"@eyevinn/hls-truncate": "^0.3.0",
|
|
33
|
-
"@eyevinn/hls-vodtolive": "^4.1.
|
|
33
|
+
"@eyevinn/hls-vodtolive": "^4.1.1",
|
|
34
34
|
"@eyevinn/m3u8": "^0.5.3",
|
|
35
35
|
"abort-controller": "^3.0.0",
|
|
36
36
|
"debug": "^3.2.7",
|
|
@@ -1,20 +1,116 @@
|
|
|
1
|
-
const Session = require(
|
|
1
|
+
const Session = require("../../engine/session.js");
|
|
2
2
|
|
|
3
|
-
const { SessionStateStore } = require(
|
|
4
|
-
const { PlayheadStateStore } = require(
|
|
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(
|
|
17
|
-
const id2 = new Session(
|
|
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
|
+
});
|