eyevinn-channel-engine 4.0.5 → 4.0.7
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/server.d.ts +2 -0
- package/dist/engine/server.js +1 -1
- package/dist/engine/session.d.ts +1 -1
- package/dist/engine/session.js +161 -176
- package/dist/package.json +1 -1
- package/dist/server-multicodec.d.ts +1 -0
- package/dist/server-multicodec.js +96 -0
- package/engine/server.ts +3 -1
- package/engine/session.js +50 -68
- package/package.json +1 -1
- package/server-multicodec.ts +104 -0
- package/tsconfig.json +1 -1
package/dist/engine/server.d.ts
CHANGED
package/dist/engine/server.js
CHANGED
|
@@ -818,7 +818,7 @@ var ChannelEngine = /** @class */ (function () {
|
|
|
818
818
|
"Access-Control-Allow-Origin": "*",
|
|
819
819
|
"Access-Control-Allow-Headers": "X-Session-Id",
|
|
820
820
|
"Access-Control-Expose-Headers": "X-Session-Id",
|
|
821
|
-
"Cache-Control": "
|
|
821
|
+
"Cache-Control": "max-age=300",
|
|
822
822
|
"X-Session-Id": session.sessionId,
|
|
823
823
|
"X-Instance-Id": this.instanceId + "<".concat(version, ">"),
|
|
824
824
|
});
|
package/dist/engine/session.d.ts
CHANGED
|
@@ -87,7 +87,7 @@ declare class Session {
|
|
|
87
87
|
}>;
|
|
88
88
|
getCurrentMediaManifestAsync(bw: any, playbackSessionId: any): Promise<any>;
|
|
89
89
|
getCurrentAudioManifestAsync(audioGroupId: any, audioLanguage: any, playbackSessionId: any): Promise<any>;
|
|
90
|
-
incrementAsync(
|
|
90
|
+
incrementAsync(): Promise<any>;
|
|
91
91
|
getMediaManifestAsync(bw: any, opts: any): Promise<any>;
|
|
92
92
|
getAudioManifestAsync(audioGroupId: any, audioLanguage: any, opts: any): Promise<any>;
|
|
93
93
|
getMasterManifestAsync(filter: any): Promise<string>;
|
package/dist/engine/session.js
CHANGED
|
@@ -193,7 +193,7 @@ var Session = /** @class */ (function () {
|
|
|
193
193
|
});
|
|
194
194
|
Session.prototype.startPlayheadAsync = function () {
|
|
195
195
|
return __awaiter(this, void 0, void 0, function () {
|
|
196
|
-
var playheadState, state, numberOfLargeTicks, audioIncrement, tsIncrementBegin, manifest, tsIncrementEnd, sessionState, isLeader, firstDuration, tickInterval, reqTickInterval, timeSpentInIncrement, tickInterval, delta, position,
|
|
196
|
+
var playheadState, state, numberOfLargeTicks, audioIncrement, tsIncrementBegin, manifest, tsIncrementEnd, sessionState, isLeader, firstDuration, tickInterval, reqTickInterval, timeSpentInIncrement, tickInterval, delta, position, timePosition, diff, timeToAdd, timeToAdd, DIFF_COMPENSATION, changeMaxTick, tsTickEnd, lastDuration, nextTickInterval, err_1;
|
|
197
197
|
return __generator(this, function (_a) {
|
|
198
198
|
switch (_a.label) {
|
|
199
199
|
case 0:
|
|
@@ -212,14 +212,12 @@ var Session = /** @class */ (function () {
|
|
|
212
212
|
audioIncrement = 1;
|
|
213
213
|
_a.label = 3;
|
|
214
214
|
case 3:
|
|
215
|
-
if (!(state !== PlayheadState.CRASHED)) return [3 /*break*/,
|
|
215
|
+
if (!(state !== PlayheadState.CRASHED)) return [3 /*break*/, 25];
|
|
216
216
|
_a.label = 4;
|
|
217
217
|
case 4:
|
|
218
|
-
_a.trys.push([4,
|
|
218
|
+
_a.trys.push([4, 22, , 24]);
|
|
219
219
|
tsIncrementBegin = Date.now();
|
|
220
|
-
return [4 /*yield*/, this.incrementAsync(
|
|
221
|
-
audio: audioIncrement
|
|
222
|
-
})];
|
|
220
|
+
return [4 /*yield*/, this.incrementAsync()];
|
|
223
221
|
case 5:
|
|
224
222
|
manifest = _a.sent();
|
|
225
223
|
if (!!manifest) return [3 /*break*/, 7];
|
|
@@ -256,7 +254,7 @@ var Session = /** @class */ (function () {
|
|
|
256
254
|
debug("[".concat(this._sessionId, "]: I am the leader and updated tick interval to ").concat(tickInterval, " sec"));
|
|
257
255
|
cloudWatchLog(!this.cloudWatchLogging, 'engine-session', { event: 'tickIntervalUpdated', channel: this._sessionId, tickIntervalSec: tickInterval });
|
|
258
256
|
this._playheadState.set("tickInterval", tickInterval);
|
|
259
|
-
return [3 /*break*/,
|
|
257
|
+
return [3 /*break*/, 21];
|
|
260
258
|
case 13:
|
|
261
259
|
if (!(state == PlayheadState.STOPPED)) return [3 /*break*/, 14];
|
|
262
260
|
debug("[".concat(this._sessionId, "]: Stopping playhead"));
|
|
@@ -275,49 +273,6 @@ var Session = /** @class */ (function () {
|
|
|
275
273
|
return [4 /*yield*/, this._getCurrentPlayheadPosition()];
|
|
276
274
|
case 16:
|
|
277
275
|
position = (_a.sent()) * 1000;
|
|
278
|
-
if (!this.use_demuxed_audio) return [3 /*break*/, 23];
|
|
279
|
-
return [4 /*yield*/, this._sessionState.getCurrentVod()];
|
|
280
|
-
case 17:
|
|
281
|
-
currentVod = _a.sent();
|
|
282
|
-
return [4 /*yield*/, this._sessionState.getValues(["vodMediaSeqAudio"])];
|
|
283
|
-
case 18:
|
|
284
|
-
sessionState_1 = _a.sent();
|
|
285
|
-
posDiff = void 0;
|
|
286
|
-
incrementValue = 1;
|
|
287
|
-
index = 0;
|
|
288
|
-
audioSeqLastIdx = currentVod.getLiveMediaSequencesCount("audio") - 1;
|
|
289
|
-
thresh = 0.5;
|
|
290
|
-
direction = 0;
|
|
291
|
-
_a.label = 19;
|
|
292
|
-
case 19: return [4 /*yield*/, this._getAudioPlayheadPosition(sessionState_1.vodMediaSeqAudio + index)];
|
|
293
|
-
case 20:
|
|
294
|
-
audioPosition = (_a.sent()) * 1000;
|
|
295
|
-
posDiff = position - audioPosition;
|
|
296
|
-
if (posDiff > thresh && direction >= 0) {
|
|
297
|
-
index++;
|
|
298
|
-
incrementValue++;
|
|
299
|
-
direction = 1;
|
|
300
|
-
}
|
|
301
|
-
else if (posDiff < -thresh && direction <= 0) {
|
|
302
|
-
incrementValue = 0;
|
|
303
|
-
index--;
|
|
304
|
-
direction = -1;
|
|
305
|
-
return [3 /*break*/, 22];
|
|
306
|
-
}
|
|
307
|
-
else if (direction > 0 && posDiff < 0) {
|
|
308
|
-
return [3 /*break*/, 22];
|
|
309
|
-
}
|
|
310
|
-
if (sessionState_1.vodMediaSeqAudio + index > audioSeqLastIdx || sessionState_1.vodMediaSeqAudio + index < 0) {
|
|
311
|
-
return [3 /*break*/, 22];
|
|
312
|
-
}
|
|
313
|
-
_a.label = 21;
|
|
314
|
-
case 21:
|
|
315
|
-
if (!(-thresh < posDiff && posDiff < thresh)) return [3 /*break*/, 19];
|
|
316
|
-
_a.label = 22;
|
|
317
|
-
case 22:
|
|
318
|
-
audioIncrement = incrementValue;
|
|
319
|
-
_a.label = 23;
|
|
320
|
-
case 23:
|
|
321
276
|
timePosition = Date.now() - playheadState.playheadRef;
|
|
322
277
|
// Apply time position offset if set, only after external diff compensation has concluded.
|
|
323
278
|
if (this.timePositionOffset && this.diffCompensation <= 0 && this.alwaysNewSegments) {
|
|
@@ -368,36 +323,36 @@ var Session = /** @class */ (function () {
|
|
|
368
323
|
}
|
|
369
324
|
debug("[".concat(this._sessionId, "]: (").concat((new Date()).toISOString(), ") ").concat(timeSpentInIncrement, "sec in increment. Next tick in ").concat(tickInterval, " seconds"));
|
|
370
325
|
return [4 /*yield*/, timer((tickInterval * 1000) - 50)];
|
|
371
|
-
case
|
|
326
|
+
case 17:
|
|
372
327
|
_a.sent();
|
|
373
328
|
tsTickEnd = Date.now();
|
|
374
329
|
return [4 /*yield*/, this._playheadState.set("tickMs", (tsTickEnd - tsIncrementBegin))];
|
|
375
|
-
case
|
|
330
|
+
case 18:
|
|
376
331
|
_a.sent();
|
|
377
332
|
cloudWatchLog(!this.cloudWatchLogging, 'engine-session', { event: 'tickInterval', channel: this._sessionId, tickTimeMs: (tsTickEnd - tsIncrementBegin) });
|
|
378
|
-
if (!this.alwaysNewSegments) return [3 /*break*/,
|
|
333
|
+
if (!this.alwaysNewSegments) return [3 /*break*/, 21];
|
|
379
334
|
return [4 /*yield*/, this._getLastDuration(manifest)];
|
|
380
|
-
case
|
|
335
|
+
case 19:
|
|
381
336
|
lastDuration = _a.sent();
|
|
382
337
|
nextTickInterval = lastDuration < 2 ? 2 : lastDuration;
|
|
383
338
|
return [4 /*yield*/, this._playheadState.set("tickInterval", nextTickInterval)];
|
|
384
|
-
case
|
|
339
|
+
case 20:
|
|
385
340
|
_a.sent();
|
|
386
341
|
cloudWatchLog(!this.cloudWatchLogging, "engine-session", { event: "tickIntervalUpdated", channel: this._sessionId, tickIntervalSec: nextTickInterval });
|
|
387
|
-
_a.label =
|
|
388
|
-
case
|
|
389
|
-
case
|
|
342
|
+
_a.label = 21;
|
|
343
|
+
case 21: return [3 /*break*/, 24];
|
|
344
|
+
case 22:
|
|
390
345
|
err_1 = _a.sent();
|
|
391
346
|
debug("[".concat(this._sessionId, "]: Playhead consumer crashed (1)"));
|
|
392
347
|
console.error("[".concat(this._sessionId, "]: ").concat(err_1.message));
|
|
393
348
|
cloudWatchLog(!this.cloudWatchLogging, 'engine-session', { event: 'error', on: 'playhead', channel: this._sessionId, err: err_1 });
|
|
394
349
|
debug(err_1);
|
|
395
350
|
return [4 /*yield*/, this._playheadState.setState(PlayheadState.CRASHED)];
|
|
396
|
-
case
|
|
351
|
+
case 23:
|
|
397
352
|
state = _a.sent();
|
|
398
|
-
return [3 /*break*/,
|
|
399
|
-
case
|
|
400
|
-
case
|
|
353
|
+
return [3 /*break*/, 24];
|
|
354
|
+
case 24: return [3 /*break*/, 3];
|
|
355
|
+
case 25: return [2 /*return*/];
|
|
401
356
|
}
|
|
402
357
|
});
|
|
403
358
|
});
|
|
@@ -786,7 +741,7 @@ var Session = /** @class */ (function () {
|
|
|
786
741
|
};
|
|
787
742
|
Session.prototype.getCurrentMediaManifestAsync = function (bw, playbackSessionId) {
|
|
788
743
|
return __awaiter(this, void 0, void 0, function () {
|
|
789
|
-
var tries, sessionState, playheadState, state, isLeader, diffMs, currentVod, manifestMseq, manifestDseq, mediaSequenceValue, m3u8_1, err_4;
|
|
744
|
+
var tries, sessionState, playheadState, state, DELAY_TIME_MS, ACTION, isLeader, diffMs, currentVod, manifestMseq, manifestDseq, mediaSequenceValue, m3u8_1, err_4;
|
|
790
745
|
return __generator(this, function (_a) {
|
|
791
746
|
switch (_a.label) {
|
|
792
747
|
case 0:
|
|
@@ -815,29 +770,22 @@ var Session = /** @class */ (function () {
|
|
|
815
770
|
if (this.prevMediaSeqOffset.video === null) {
|
|
816
771
|
this.prevMediaSeqOffset.video = playheadState.mediaSeq;
|
|
817
772
|
}
|
|
818
|
-
if (!(playheadState.vodMediaSeqVideo > sessionState.vodMediaSeqVideo ||
|
|
819
|
-
(playheadState.vodMediaSeqVideo < sessionState.vodMediaSeqVideo &&
|
|
820
|
-
playheadState.mediaSeq === this.prevMediaSeqOffset.video))) return [3 /*break*/, 11];
|
|
773
|
+
if (!(playheadState.vodMediaSeqVideo > sessionState.vodMediaSeqVideo || (playheadState.vodMediaSeqVideo < sessionState.vodMediaSeqVideo && playheadState.mediaSeq === this.prevMediaSeqOffset.video))) return [3 /*break*/, 9];
|
|
821
774
|
return [4 /*yield*/, this._sessionState.get("state")];
|
|
822
775
|
case 6:
|
|
823
776
|
state = _a.sent();
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
777
|
+
DELAY_TIME_MS = 1000;
|
|
778
|
+
ACTION = [SessionState.VOD_RELOAD_INIT, SessionState.VOD_RELOAD_INITIATING].includes(state) ? "Reloaded" : "Loaded Next";
|
|
779
|
+
debug("[".concat(this._sessionId, "]: Recently ").concat(ACTION, " Vod. PlayheadState not up-to-date (").concat(playheadState.vodMediaSeqVideo, "_").concat(sessionState.vodMediaSeqVideo, "). Waiting ").concat(DELAY_TIME_MS, "ms before reading from store again"));
|
|
780
|
+
return [4 /*yield*/, timer(DELAY_TIME_MS)];
|
|
827
781
|
case 7:
|
|
828
782
|
_a.sent();
|
|
829
783
|
return [4 /*yield*/, this._playheadState.getValues(["mediaSeq", "vodMediaSeqVideo"])];
|
|
830
784
|
case 8:
|
|
831
785
|
playheadState = _a.sent();
|
|
832
|
-
|
|
786
|
+
_a.label = 9;
|
|
833
787
|
case 9:
|
|
834
|
-
|
|
835
|
-
return [4 /*yield*/, timer(1000)];
|
|
836
|
-
case 10:
|
|
837
|
-
_a.sent();
|
|
838
|
-
_a.label = 11;
|
|
839
|
-
case 11:
|
|
840
|
-
if (!(playheadState.vodMediaSeqVideo < 2 || playheadState.mediaSeq !== this.prevMediaSeqOffset.video)) return [3 /*break*/, 16];
|
|
788
|
+
if (!(playheadState.vodMediaSeqVideo < 2 || playheadState.mediaSeq !== this.prevMediaSeqOffset.video)) return [3 /*break*/, 14];
|
|
841
789
|
debug("[".concat(this._sessionId, "]: current[").concat(playheadState.vodMediaSeqVideo, "]_prev[").concat(this.prevVodMediaSeq.video, "]"));
|
|
842
790
|
debug("[".concat(this._sessionId, "]: current-offset[").concat(playheadState.mediaSeq, "]_prev-offset[").concat(this.prevMediaSeqOffset.video, "]"));
|
|
843
791
|
// If true, then we have not updated the prev-values and not cleared the cache yet.
|
|
@@ -845,16 +793,16 @@ var Session = /** @class */ (function () {
|
|
|
845
793
|
this.isAllowedToClearVodCache = true;
|
|
846
794
|
}
|
|
847
795
|
return [4 /*yield*/, this._sessionStateStore.isLeader(this._instanceId)];
|
|
848
|
-
case
|
|
796
|
+
case 10:
|
|
849
797
|
isLeader = _a.sent();
|
|
850
|
-
if (!(!isLeader && this.isAllowedToClearVodCache)) return [3 /*break*/,
|
|
798
|
+
if (!(!isLeader && this.isAllowedToClearVodCache)) return [3 /*break*/, 13];
|
|
851
799
|
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."));
|
|
852
800
|
return [4 /*yield*/, this._sessionState.clearCurrentVodCache()];
|
|
853
|
-
case
|
|
801
|
+
case 11:
|
|
854
802
|
_a.sent();
|
|
855
803
|
this.isAllowedToClearVodCache = false;
|
|
856
804
|
return [4 /*yield*/, this._playheadState.get("diffCompensation")];
|
|
857
|
-
case
|
|
805
|
+
case 12:
|
|
858
806
|
diffMs = _a.sent();
|
|
859
807
|
if (diffMs) {
|
|
860
808
|
this.diffCompensation = diffMs;
|
|
@@ -867,18 +815,18 @@ var Session = /** @class */ (function () {
|
|
|
867
815
|
this.timePositionOffset = 0;
|
|
868
816
|
}
|
|
869
817
|
}
|
|
818
|
+
_a.label = 13;
|
|
819
|
+
case 13: return [3 /*break*/, 15];
|
|
820
|
+
case 14:
|
|
821
|
+
this.isAllowedToClearVodCache = true;
|
|
870
822
|
_a.label = 15;
|
|
871
|
-
case 15: return [
|
|
823
|
+
case 15: return [4 /*yield*/, this._sessionState.getCurrentVod()];
|
|
872
824
|
case 16:
|
|
873
|
-
this.isAllowedToClearVodCache = true;
|
|
874
|
-
_a.label = 17;
|
|
875
|
-
case 17: return [4 /*yield*/, this._sessionState.getCurrentVod()];
|
|
876
|
-
case 18:
|
|
877
825
|
currentVod = _a.sent();
|
|
878
|
-
if (!currentVod) return [3 /*break*/,
|
|
879
|
-
_a.label =
|
|
880
|
-
case
|
|
881
|
-
_a.trys.push([
|
|
826
|
+
if (!currentVod) return [3 /*break*/, 21];
|
|
827
|
+
_a.label = 17;
|
|
828
|
+
case 17:
|
|
829
|
+
_a.trys.push([17, 18, , 20]);
|
|
882
830
|
manifestMseq = playheadState.mediaSeq + playheadState.vodMediaSeqVideo;
|
|
883
831
|
manifestDseq = sessionState.discSeq + currentVod.discontinuities[playheadState.vodMediaSeqVideo];
|
|
884
832
|
if (currentVod.sequenceAlwaysContainNewSegments) {
|
|
@@ -892,23 +840,23 @@ var Session = /** @class */ (function () {
|
|
|
892
840
|
this.prevVodMediaSeq.video = playheadState.vodMediaSeqVideo;
|
|
893
841
|
this.prevMediaSeqOffset.video = playheadState.mediaSeq;
|
|
894
842
|
return [2 /*return*/, m3u8_1];
|
|
895
|
-
case
|
|
843
|
+
case 18:
|
|
896
844
|
err_4 = _a.sent();
|
|
897
845
|
logerror(this._sessionId, err_4);
|
|
898
846
|
return [4 /*yield*/, this._sessionState.clearCurrentVodCache()];
|
|
899
|
-
case
|
|
847
|
+
case 19:
|
|
900
848
|
_a.sent(); // force reading up from shared store
|
|
901
849
|
throw new Error("Failed to generate manifest: " + JSON.stringify(playheadState));
|
|
902
|
-
case
|
|
903
|
-
case
|
|
904
|
-
case
|
|
850
|
+
case 20: return [3 /*break*/, 22];
|
|
851
|
+
case 21: throw new Error("Engine not ready");
|
|
852
|
+
case 22: return [2 /*return*/];
|
|
905
853
|
}
|
|
906
854
|
});
|
|
907
855
|
});
|
|
908
856
|
};
|
|
909
857
|
Session.prototype.getCurrentAudioManifestAsync = function (audioGroupId, audioLanguage, playbackSessionId) {
|
|
910
858
|
return __awaiter(this, void 0, void 0, function () {
|
|
911
|
-
var currentVod, sessionState, playheadState, state, AGE_THRESH, cacheAge, manifestMseq, manifestDseq, mediaSequenceValue, m3u8_2, err_5;
|
|
859
|
+
var currentVod, sessionState, playheadState, state, DELAY_TIME_MS, ACTION, AGE_THRESH, cacheAge, manifestMseq, manifestDseq, mediaSequenceValue, m3u8_2, err_5;
|
|
912
860
|
return __generator(this, function (_a) {
|
|
913
861
|
switch (_a.label) {
|
|
914
862
|
case 0:
|
|
@@ -922,30 +870,21 @@ var Session = /** @class */ (function () {
|
|
|
922
870
|
return [4 /*yield*/, this._playheadState.getValues(["mediaSeqAudio", "vodMediaSeqAudio"])];
|
|
923
871
|
case 2:
|
|
924
872
|
playheadState = _a.sent();
|
|
925
|
-
if (!(playheadState.vodMediaSeqAudio > sessionState.vodMediaSeqAudio ||
|
|
926
|
-
(playheadState.vodMediaSeqAudio < sessionState.vodMediaSeqAudio && playheadState.mediaSeqAudio === this.prevMediaSeqOffset.audio))) return [3 /*break*/, 9];
|
|
873
|
+
if (!(playheadState.vodMediaSeqAudio > sessionState.vodMediaSeqAudio || (playheadState.vodMediaSeqAudio < sessionState.vodMediaSeqAudio && playheadState.mediaSeqAudio === this.prevMediaSeqOffset.audio))) return [3 /*break*/, 6];
|
|
927
874
|
return [4 /*yield*/, this._sessionState.get("state")];
|
|
928
875
|
case 3:
|
|
929
876
|
state = _a.sent();
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
877
|
+
DELAY_TIME_MS = 1000;
|
|
878
|
+
ACTION = [SessionState.VOD_RELOAD_INIT, SessionState.VOD_RELOAD_INITIATING].includes(state) ? "Reloaded" : "Loaded Next";
|
|
879
|
+
debug("[".concat(this._sessionId, "]: Recently ").concat(ACTION, " Vod. PlayheadState not up-to-date (").concat(playheadState.vodMediaSeqAudio, "_").concat(sessionState.vodMediaSeqAudio, "). Waiting ").concat(DELAY_TIME_MS, "ms before reading from store again"));
|
|
880
|
+
return [4 /*yield*/, timer(DELAY_TIME_MS)];
|
|
933
881
|
case 4:
|
|
934
882
|
_a.sent();
|
|
935
883
|
return [4 /*yield*/, this._playheadState.getValues(["mediaSeqAudio", "vodMediaSeqAudio"])];
|
|
936
884
|
case 5:
|
|
937
885
|
playheadState = _a.sent();
|
|
938
|
-
|
|
886
|
+
_a.label = 6;
|
|
939
887
|
case 6:
|
|
940
|
-
debug("[".concat(this._sessionId, "]: Recently Loaded Next Vod. PlayheadState not up-to-date. Delay audio-m3u8 Response by 1000ms"));
|
|
941
|
-
return [4 /*yield*/, timer(1000)];
|
|
942
|
-
case 7:
|
|
943
|
-
_a.sent();
|
|
944
|
-
return [4 /*yield*/, this._playheadState.getValues(["mediaSeqAudio", "vodMediaSeqAudio"])];
|
|
945
|
-
case 8:
|
|
946
|
-
playheadState = _a.sent();
|
|
947
|
-
_a.label = 9;
|
|
948
|
-
case 9:
|
|
949
888
|
// local store the prev values
|
|
950
889
|
if (this.prevVodMediaSeq.audio === null) {
|
|
951
890
|
this.prevVodMediaSeq.audio = playheadState.vodMediaSeqAudio;
|
|
@@ -954,29 +893,29 @@ var Session = /** @class */ (function () {
|
|
|
954
893
|
this.prevMediaSeqOffset.audio = playheadState.mediaSeqAudio;
|
|
955
894
|
}
|
|
956
895
|
return [4 /*yield*/, this._sessionState.getCurrentVod()];
|
|
957
|
-
case
|
|
896
|
+
case 7:
|
|
958
897
|
currentVod = _a.sent();
|
|
959
|
-
if (!currentVod) return [3 /*break*/,
|
|
960
|
-
if (!(playheadState.vodMediaSeqAudio < 2 || playheadState.mediaSeqAudio !== this.prevMediaSeqOffset.audio)) return [3 /*break*/,
|
|
961
|
-
AGE_THRESH =
|
|
898
|
+
if (!currentVod) return [3 /*break*/, 15];
|
|
899
|
+
if (!(playheadState.vodMediaSeqAudio < 2 || playheadState.mediaSeqAudio !== this.prevMediaSeqOffset.audio)) return [3 /*break*/, 11];
|
|
900
|
+
AGE_THRESH = this.averageSegmentDuration * 2;
|
|
962
901
|
cacheAge = null;
|
|
963
902
|
if (this._sessionState.cache && this._sessionState.cache.currentVod.ts) {
|
|
964
903
|
cacheAge = Date.now() - this._sessionState.cache.currentVod.ts;
|
|
965
904
|
}
|
|
966
|
-
if (!(cacheAge !== null && cacheAge > AGE_THRESH)) return [3 /*break*/,
|
|
905
|
+
if (!(cacheAge !== null && cacheAge > AGE_THRESH)) return [3 /*break*/, 11];
|
|
967
906
|
return [4 /*yield*/, timer(500)];
|
|
968
|
-
case
|
|
907
|
+
case 8:
|
|
969
908
|
_a.sent();
|
|
970
909
|
debug("[".concat(this._sessionId, "]: While requesting audio manifest for ").concat(audioGroupId, "-").concat(audioLanguage, ", (mseq=").concat(playheadState.vodMediaSeqAudio, ")(vod cache age=").concat(cacheAge, ")"));
|
|
971
910
|
return [4 /*yield*/, this._sessionState.clearCurrentVodCache()];
|
|
972
|
-
case
|
|
911
|
+
case 9:
|
|
973
912
|
_a.sent(); // force reading up from shared store
|
|
974
913
|
return [4 /*yield*/, this._sessionState.getCurrentVod()];
|
|
975
|
-
case
|
|
914
|
+
case 10:
|
|
976
915
|
currentVod = _a.sent();
|
|
977
|
-
_a.label =
|
|
978
|
-
case
|
|
979
|
-
_a.trys.push([
|
|
916
|
+
_a.label = 11;
|
|
917
|
+
case 11:
|
|
918
|
+
_a.trys.push([11, 12, , 14]);
|
|
980
919
|
manifestMseq = playheadState.mediaSeqAudio + playheadState.vodMediaSeqAudio;
|
|
981
920
|
manifestDseq = sessionState.discSeqAudio + currentVod.discontinuitiesAudio[playheadState.vodMediaSeqAudio];
|
|
982
921
|
if (currentVod.sequenceAlwaysContainNewSegments) {
|
|
@@ -994,23 +933,23 @@ var Session = /** @class */ (function () {
|
|
|
994
933
|
this.prevVodMediaSeq.audio = playheadState.vodMediaSeqAudio;
|
|
995
934
|
this.prevMediaSeqOffset.audio = playheadState.mediaSeqAudio;
|
|
996
935
|
return [2 /*return*/, m3u8_2];
|
|
997
|
-
case
|
|
936
|
+
case 12:
|
|
998
937
|
err_5 = _a.sent();
|
|
999
938
|
logerror(this._sessionId, err_5);
|
|
1000
939
|
return [4 /*yield*/, this._sessionState.clearCurrentVodCache()];
|
|
1001
|
-
case
|
|
940
|
+
case 13:
|
|
1002
941
|
_a.sent(); // force reading up from shared store
|
|
1003
942
|
throw new Error("Failed to generate audio manifest: " + JSON.stringify(playheadState));
|
|
1004
|
-
case
|
|
1005
|
-
case
|
|
1006
|
-
case
|
|
943
|
+
case 14: return [3 /*break*/, 16];
|
|
944
|
+
case 15: throw new Error("Engine not ready");
|
|
945
|
+
case 16: return [2 /*return*/];
|
|
1007
946
|
}
|
|
1008
947
|
});
|
|
1009
948
|
});
|
|
1010
949
|
};
|
|
1011
|
-
Session.prototype.incrementAsync = function (
|
|
950
|
+
Session.prototype.incrementAsync = function () {
|
|
1012
951
|
return __awaiter(this, void 0, void 0, function () {
|
|
1013
|
-
var isLeader, sessionState, playheadState, currentVod, _a, leaderAction, _b, m3u8_3, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, mediaSequenceValue, diffMs, m3u8;
|
|
952
|
+
var isLeader, sessionState, playheadState, currentVod, _a, leaderAction, _b, m3u8_3, _c, audioIncrement, position, currentVod_1, sessionState_1, posDiff, incrementValue, index, audioSeqLastIdx, thresh, audioPosition, _d, _e, _f, _g, _h, _j, _k, _l, _m, mediaSequenceValue, diffMs, m3u8;
|
|
1014
953
|
return __generator(this, function (_o) {
|
|
1015
954
|
switch (_o.label) {
|
|
1016
955
|
case 0: return [4 /*yield*/, this._tickAsync()];
|
|
@@ -1070,82 +1009,124 @@ var Session = /** @class */ (function () {
|
|
|
1070
1009
|
}
|
|
1071
1010
|
this.isAllowedToClearVodCache = true;
|
|
1072
1011
|
_o.label = 13;
|
|
1073
|
-
case 13: return [3 /*break*/,
|
|
1012
|
+
case 13: return [3 /*break*/, 25];
|
|
1074
1013
|
case 14:
|
|
1075
1014
|
_c = sessionState;
|
|
1076
1015
|
return [4 /*yield*/, this._sessionState.increment("vodMediaSeqVideo")];
|
|
1077
1016
|
case 15:
|
|
1078
1017
|
_c.vodMediaSeqVideo = _o.sent();
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
return [4 /*yield*/, this.
|
|
1018
|
+
audioIncrement = void 0;
|
|
1019
|
+
if (!this.use_demuxed_audio) return [3 /*break*/, 23];
|
|
1020
|
+
return [4 /*yield*/, this._getCurrentPlayheadPosition()];
|
|
1082
1021
|
case 16:
|
|
1083
|
-
|
|
1084
|
-
|
|
1022
|
+
position = (_o.sent()) * 1000;
|
|
1023
|
+
return [4 /*yield*/, this._sessionState.getCurrentVod()];
|
|
1085
1024
|
case 17:
|
|
1086
|
-
|
|
1025
|
+
currentVod_1 = _o.sent();
|
|
1026
|
+
return [4 /*yield*/, this._sessionState.getValues(["vodMediaSeqAudio"])];
|
|
1027
|
+
case 18:
|
|
1028
|
+
sessionState_1 = _o.sent();
|
|
1029
|
+
posDiff = void 0;
|
|
1030
|
+
incrementValue = 1;
|
|
1031
|
+
index = 0;
|
|
1032
|
+
audioSeqLastIdx = currentVod_1.getLiveMediaSequencesCount("audio") - 1;
|
|
1033
|
+
thresh = 0.5;
|
|
1034
|
+
_o.label = 19;
|
|
1035
|
+
case 19: return [4 /*yield*/, this._getAudioPlayheadPosition(sessionState_1.vodMediaSeqAudio + index)];
|
|
1036
|
+
case 20:
|
|
1037
|
+
audioPosition = (_o.sent()) * 1000;
|
|
1038
|
+
posDiff = position - audioPosition;
|
|
1039
|
+
if (posDiff < 0) {
|
|
1040
|
+
return [3 /*break*/, 22];
|
|
1041
|
+
}
|
|
1042
|
+
if (posDiff > thresh) {
|
|
1043
|
+
index++;
|
|
1044
|
+
incrementValue++;
|
|
1045
|
+
}
|
|
1046
|
+
else {
|
|
1047
|
+
index = incrementValue;
|
|
1048
|
+
return [3 /*break*/, 22];
|
|
1049
|
+
}
|
|
1050
|
+
if (sessionState_1.vodMediaSeqAudio + index > audioSeqLastIdx) {
|
|
1051
|
+
return [3 /*break*/, 22];
|
|
1052
|
+
}
|
|
1053
|
+
_o.label = 21;
|
|
1054
|
+
case 21:
|
|
1055
|
+
if (!(-thresh < posDiff && posDiff < thresh)) return [3 /*break*/, 19];
|
|
1056
|
+
_o.label = 22;
|
|
1057
|
+
case 22:
|
|
1058
|
+
audioIncrement = index;
|
|
1059
|
+
_o.label = 23;
|
|
1060
|
+
case 23:
|
|
1061
|
+
_d = sessionState;
|
|
1062
|
+
return [4 /*yield*/, this._sessionState.increment("vodMediaSeqAudio", audioIncrement)];
|
|
1063
|
+
case 24:
|
|
1064
|
+
_d.vodMediaSeqAudio = _o.sent();
|
|
1065
|
+
_o.label = 25;
|
|
1066
|
+
case 25:
|
|
1067
|
+
if (!(sessionState.vodMediaSeqVideo >= currentVod.getLiveMediaSequencesCount() - 1)) return [3 /*break*/, 28];
|
|
1087
1068
|
_e = sessionState;
|
|
1088
1069
|
return [4 /*yield*/, this._sessionState.set("vodMediaSeqVideo", currentVod.getLiveMediaSequencesCount() - 1)];
|
|
1089
|
-
case
|
|
1070
|
+
case 26:
|
|
1090
1071
|
_e.vodMediaSeqVideo = _o.sent();
|
|
1091
1072
|
_f = sessionState;
|
|
1092
1073
|
return [4 /*yield*/, this._sessionState.set("state", SessionState.VOD_NEXT_INIT)];
|
|
1093
|
-
case
|
|
1074
|
+
case 27:
|
|
1094
1075
|
_f.state = _o.sent();
|
|
1095
|
-
_o.label =
|
|
1096
|
-
case
|
|
1097
|
-
if (!(sessionState.vodMediaSeqAudio >= currentVod.getLiveMediaSequencesCount("audio") - 1)) return [3 /*break*/,
|
|
1076
|
+
_o.label = 28;
|
|
1077
|
+
case 28:
|
|
1078
|
+
if (!(sessionState.vodMediaSeqAudio >= currentVod.getLiveMediaSequencesCount("audio") - 1)) return [3 /*break*/, 30];
|
|
1098
1079
|
_g = sessionState;
|
|
1099
1080
|
return [4 /*yield*/, this._sessionState.set("vodMediaSeqAudio", currentVod.getLiveMediaSequencesCount("audio") - 1)];
|
|
1100
|
-
case
|
|
1081
|
+
case 29:
|
|
1101
1082
|
_g.vodMediaSeqAudio = _o.sent();
|
|
1102
|
-
_o.label =
|
|
1103
|
-
case
|
|
1104
|
-
if (!this.isSwitchingBackToV2L) return [3 /*break*/,
|
|
1083
|
+
_o.label = 30;
|
|
1084
|
+
case 30:
|
|
1085
|
+
if (!this.isSwitchingBackToV2L) return [3 /*break*/, 32];
|
|
1105
1086
|
_h = sessionState;
|
|
1106
1087
|
return [4 /*yield*/, this._sessionState.set("state", SessionState.VOD_RELOAD_INIT)];
|
|
1107
|
-
case
|
|
1088
|
+
case 31:
|
|
1108
1089
|
_h.state = _o.sent();
|
|
1109
1090
|
this.isSwitchingBackToV2L = false;
|
|
1110
|
-
_o.label =
|
|
1111
|
-
case
|
|
1091
|
+
_o.label = 32;
|
|
1092
|
+
case 32:
|
|
1112
1093
|
_j = playheadState;
|
|
1113
1094
|
return [4 /*yield*/, this._playheadState.set("mediaSeq", sessionState.mediaSeq)];
|
|
1114
|
-
case
|
|
1095
|
+
case 33:
|
|
1115
1096
|
_j.mediaSeq = _o.sent();
|
|
1116
1097
|
_k = playheadState;
|
|
1117
1098
|
return [4 /*yield*/, this._playheadState.set("mediaSeqAudio", sessionState.mediaSeqAudio)];
|
|
1118
|
-
case
|
|
1099
|
+
case 34:
|
|
1119
1100
|
_k.mediaSeqAudio = _o.sent();
|
|
1120
1101
|
_l = playheadState;
|
|
1121
1102
|
return [4 /*yield*/, this._playheadState.set("vodMediaSeqVideo", sessionState.vodMediaSeqVideo)];
|
|
1122
|
-
case
|
|
1103
|
+
case 35:
|
|
1123
1104
|
_l.vodMediaSeqVideo = _o.sent();
|
|
1124
1105
|
_m = playheadState;
|
|
1125
1106
|
return [4 /*yield*/, this._playheadState.set("vodMediaSeqAudio", sessionState.vodMediaSeqAudio)];
|
|
1126
|
-
case
|
|
1107
|
+
case 36:
|
|
1127
1108
|
_m.vodMediaSeqAudio = _o.sent();
|
|
1128
1109
|
if (currentVod.sequenceAlwaysContainNewSegments) {
|
|
1129
1110
|
mediaSequenceValue = currentVod.mediaSequenceValues[playheadState.vodMediaSeqVideo];
|
|
1130
1111
|
debug("[".concat(this._sessionId, "]: Session can now serve mseq={").concat(playheadState.mediaSeq + mediaSequenceValue, "}"));
|
|
1131
1112
|
}
|
|
1132
1113
|
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"), ")"));
|
|
1133
|
-
if (!(playheadState.vodMediaSeqVideo < 2 || playheadState.mediaSeq !== this.prevMediaSeqOffset.video)) return [3 /*break*/,
|
|
1114
|
+
if (!(playheadState.vodMediaSeqVideo < 2 || playheadState.mediaSeq !== this.prevMediaSeqOffset.video)) return [3 /*break*/, 41];
|
|
1134
1115
|
debug("[".concat(this._sessionId, "]: current[").concat(playheadState.vodMediaSeqVideo, "]_prev[").concat(this.prevVodMediaSeq.video, "]"));
|
|
1135
1116
|
debug("[".concat(this._sessionId, "]: current-offset[").concat(playheadState.mediaSeq, "]_prev-offset[").concat(this.prevMediaSeqOffset.video, "]"));
|
|
1136
1117
|
if (playheadState.vodMediaSeqVideo < this.prevVodMediaSeq.video || playheadState.mediaSeq !== this.prevMediaSeqOffset.video) {
|
|
1137
1118
|
this.isAllowedToClearVodCache = true;
|
|
1138
1119
|
}
|
|
1139
|
-
if (!(!isLeader && this.isAllowedToClearVodCache)) return [3 /*break*/,
|
|
1120
|
+
if (!(!isLeader && this.isAllowedToClearVodCache)) return [3 /*break*/, 40];
|
|
1140
1121
|
debug("[".concat(this._sessionId, "]: Not a leader and have just set 'playheadState.vodMediaSeqVideo' to 0|1. Invalidate cache to ensure having the correct VOD."));
|
|
1141
1122
|
return [4 /*yield*/, this._sessionState.clearCurrentVodCache()];
|
|
1142
|
-
case
|
|
1123
|
+
case 37:
|
|
1143
1124
|
_o.sent();
|
|
1144
1125
|
return [4 /*yield*/, this._sessionState.getCurrentVod()];
|
|
1145
|
-
case
|
|
1126
|
+
case 38:
|
|
1146
1127
|
currentVod = _o.sent();
|
|
1147
1128
|
return [4 /*yield*/, this._playheadState.get("diffCompensation")];
|
|
1148
|
-
case
|
|
1129
|
+
case 39:
|
|
1149
1130
|
diffMs = _o.sent();
|
|
1150
1131
|
if (diffMs) {
|
|
1151
1132
|
this.diffCompensation = diffMs;
|
|
@@ -1159,12 +1140,12 @@ var Session = /** @class */ (function () {
|
|
|
1159
1140
|
}
|
|
1160
1141
|
}
|
|
1161
1142
|
this.isAllowedToClearVodCache = false;
|
|
1162
|
-
_o.label =
|
|
1163
|
-
case
|
|
1164
|
-
case
|
|
1143
|
+
_o.label = 40;
|
|
1144
|
+
case 40: return [3 /*break*/, 42];
|
|
1145
|
+
case 41:
|
|
1165
1146
|
this.isAllowedToClearVodCache = true;
|
|
1166
|
-
_o.label =
|
|
1167
|
-
case
|
|
1147
|
+
_o.label = 42;
|
|
1148
|
+
case 42:
|
|
1168
1149
|
// Update Value for Previous Sequence
|
|
1169
1150
|
this.prevVodMediaSeq.video = playheadState.vodMediaSeqVideo;
|
|
1170
1151
|
this.prevMediaSeqOffset.video = playheadState.mediaSeq;
|
|
@@ -1174,7 +1155,7 @@ var Session = /** @class */ (function () {
|
|
|
1174
1155
|
}
|
|
1175
1156
|
m3u8 = currentVod.getLiveMediaSequences(playheadState.mediaSeq, 180000, playheadState.vodMediaSeqVideo, sessionState.discSeq);
|
|
1176
1157
|
return [4 /*yield*/, this._playheadState.setLastM3u8(m3u8)];
|
|
1177
|
-
case
|
|
1158
|
+
case 43:
|
|
1178
1159
|
_o.sent();
|
|
1179
1160
|
return [2 /*return*/, m3u8];
|
|
1180
1161
|
}
|
|
@@ -1365,7 +1346,7 @@ var Session = /** @class */ (function () {
|
|
|
1365
1346
|
};
|
|
1366
1347
|
Session.prototype.getMasterManifestAsync = function (filter) {
|
|
1367
1348
|
return __awaiter(this, void 0, void 0, function () {
|
|
1368
|
-
var m3u8, currentVod, audioGroupIds, defaultAudioGroupId, hasClosedCaptions, i, audioGroupId, j, audioTrack, sessionProfile;
|
|
1349
|
+
var m3u8, currentVod, audioGroupIds, defaultAudioGroupId, hasClosedCaptions, i, audioGroupId, j, audioTrack, channels, sessionProfile;
|
|
1369
1350
|
var _this = this;
|
|
1370
1351
|
return __generator(this, function (_a) {
|
|
1371
1352
|
switch (_a.label) {
|
|
@@ -1397,12 +1378,13 @@ var Session = /** @class */ (function () {
|
|
|
1397
1378
|
audioGroupId = audioGroupIds[i];
|
|
1398
1379
|
for (j = 0; j < this._audioTracks.length; j++) {
|
|
1399
1380
|
audioTrack = this._audioTracks[j];
|
|
1381
|
+
channels = this._audioTracks[j].channels ? this._audioTracks[j].channels : 2;
|
|
1400
1382
|
// Make default track if set property is true.
|
|
1401
1383
|
if (audioTrack.default) {
|
|
1402
|
-
m3u8 += "#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID=\"".concat(audioGroupId, "\",LANGUAGE=\"").concat(audioTrack.language, "\", NAME=\"").concat(audioTrack.name, "\",AUTOSELECT=YES,DEFAULT=YES,CHANNELS=\"
|
|
1384
|
+
m3u8 += "#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID=\"".concat(audioGroupId, "\",LANGUAGE=\"").concat(audioTrack.language, "\", NAME=\"").concat(audioTrack.name, "\",AUTOSELECT=YES,DEFAULT=YES,CHANNELS=\"").concat(channels, "\",URI=\"master-").concat(audioGroupId, "_").concat(audioTrack.language, ".m3u8;session=").concat(this._sessionId, "\"\n");
|
|
1403
1385
|
}
|
|
1404
1386
|
else {
|
|
1405
|
-
m3u8 += "#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID=\"".concat(audioGroupId, "\",LANGUAGE=\"").concat(audioTrack.language, "\", NAME=\"").concat(audioTrack.name, "\",AUTOSELECT=YES,DEFAULT=NO,CHANNELS=\"
|
|
1387
|
+
m3u8 += "#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID=\"".concat(audioGroupId, "\",LANGUAGE=\"").concat(audioTrack.language, "\", NAME=\"").concat(audioTrack.name, "\",AUTOSELECT=YES,DEFAULT=NO,CHANNELS=\"").concat(channels, "\",URI=\"master-").concat(audioGroupId, "_").concat(audioTrack.language, ".m3u8;session=").concat(this._sessionId, "\"\n");
|
|
1406
1388
|
}
|
|
1407
1389
|
}
|
|
1408
1390
|
}
|
|
@@ -1537,7 +1519,7 @@ var Session = /** @class */ (function () {
|
|
|
1537
1519
|
};
|
|
1538
1520
|
Session.prototype._tickAsync = function () {
|
|
1539
1521
|
return __awaiter(this, void 0, void 0, function () {
|
|
1540
|
-
var newVod, sessionState, isLeader, currentVod, vodResponse, _a, nextVodPromise, nextVodStart, _b, loadPromise, hlsOpts, loadStart, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, err_6, _o, length_1, endMseqValue, endMseqValueAudio, lastDiscontinuity, lastDiscontinuityAudio, _p, vodPromise, gracePeriod, nextVodStart, _q, loadPromise, hlsOpts, loadStart, _r, _s, _t, _u, _v, _w, _x, _y, _z, diffMs, err_7, startTS, _0, mSeq,
|
|
1522
|
+
var newVod, sessionState, isLeader, currentVod, vodResponse, _a, nextVodPromise, nextVodStart, _b, loadPromise, hlsOpts, loadStart, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, err_6, _o, length_1, endMseqValue, endMseqValueAudio, lastDiscontinuity, lastDiscontinuityAudio, _p, vodPromise, gracePeriod, nextVodStart, _q, loadPromise, hlsOpts, loadStart, _r, _s, _t, _u, _v, _w, _x, _y, _z, diffMs, err_7, startTS, _0, mSeq, currentVod_2, dSeq, mSeqOffset, reloadBehind, segments, playheadState, nextMseq, _1, err_8;
|
|
1541
1523
|
var _this = this;
|
|
1542
1524
|
return __generator(this, function (_2) {
|
|
1543
1525
|
switch (_2.label) {
|
|
@@ -1962,8 +1944,8 @@ var Session = /** @class */ (function () {
|
|
|
1962
1944
|
mSeq = this.switchDataForSession.mediaSeq;
|
|
1963
1945
|
return [4 /*yield*/, this._sessionState.getCurrentVod()];
|
|
1964
1946
|
case 64:
|
|
1965
|
-
|
|
1966
|
-
if (
|
|
1947
|
+
currentVod_2 = _2.sent();
|
|
1948
|
+
if (currentVod_2.sequenceAlwaysContainNewSegments) {
|
|
1967
1949
|
// (!) will need to compensate if using this setting on HLSVod Object.
|
|
1968
1950
|
Object.keys(this.switchDataForSession.transitionSegments).forEach(function (bw) {
|
|
1969
1951
|
var shiftedSeg = _this.switchDataForSession.transitionSegments[bw].shift();
|
|
@@ -1997,19 +1979,19 @@ var Session = /** @class */ (function () {
|
|
|
1997
1979
|
case 68:
|
|
1998
1980
|
playheadState = _2.sent();
|
|
1999
1981
|
nextMseq = playheadState.vodMediaSeqVideo + 1;
|
|
2000
|
-
if (nextMseq >
|
|
2001
|
-
nextMseq =
|
|
1982
|
+
if (nextMseq > currentVod_2.getLiveMediaSequencesCount() - 1) {
|
|
1983
|
+
nextMseq = currentVod_2.getLiveMediaSequencesCount() - 1;
|
|
2002
1984
|
}
|
|
2003
1985
|
// ---------------------------------------------------.
|
|
2004
1986
|
// TODO: Support reloading with audioSegments as well |
|
|
2005
1987
|
// ---------------------------------------------------'
|
|
2006
|
-
return [4 /*yield*/,
|
|
1988
|
+
return [4 /*yield*/, currentVod_2.reload(nextMseq, segments, null, reloadBehind)];
|
|
2007
1989
|
case 69:
|
|
2008
1990
|
// ---------------------------------------------------.
|
|
2009
1991
|
// TODO: Support reloading with audioSegments as well |
|
|
2010
1992
|
// ---------------------------------------------------'
|
|
2011
1993
|
_2.sent();
|
|
2012
|
-
return [4 /*yield*/, this._sessionState.setCurrentVod(
|
|
1994
|
+
return [4 /*yield*/, this._sessionState.setCurrentVod(currentVod_2, { ttl: currentVod_2.getDuration() * 1000 })];
|
|
2013
1995
|
case 70:
|
|
2014
1996
|
_2.sent();
|
|
2015
1997
|
return [4 /*yield*/, this._sessionState.set("vodReloaded", 1)];
|
|
@@ -2032,9 +2014,9 @@ var Session = /** @class */ (function () {
|
|
|
2032
2014
|
_2.sent();
|
|
2033
2015
|
// 4) Log to debug and cloudwatch
|
|
2034
2016
|
debug("[".concat(this._sessionId, "]: LEADER: Set new Reloaded VOD and vodMediaSeq counts in store."));
|
|
2035
|
-
debug("[".concat(this._sessionId, "]: next VOD Reloaded (").concat(
|
|
2036
|
-
debug("[".concat(this._sessionId, "]: ").concat(
|
|
2037
|
-
debug("[".concat(this._sessionId, "]: msequences=").concat(
|
|
2017
|
+
debug("[".concat(this._sessionId, "]: next VOD Reloaded (").concat(currentVod_2.getDeltaTimes(), ")"));
|
|
2018
|
+
debug("[".concat(this._sessionId, "]: ").concat(currentVod_2.getPlayheadPositions()));
|
|
2019
|
+
debug("[".concat(this._sessionId, "]: msequences=").concat(currentVod_2.getLiveMediaSequencesCount()));
|
|
2038
2020
|
cloudWatchLog(!this.cloudWatchLogging, "engine-session", { event: "switchback", channel: this._sessionId, reqTimeMs: Date.now() - startTS });
|
|
2039
2021
|
return [2 /*return*/];
|
|
2040
2022
|
case 77:
|
|
@@ -2334,6 +2316,9 @@ var Session = /** @class */ (function () {
|
|
|
2334
2316
|
case 1:
|
|
2335
2317
|
currentVod = _a.sent();
|
|
2336
2318
|
playheadPositions = currentVod.getPlayheadPositions("audio");
|
|
2319
|
+
if (seqIdx >= playheadPositions.length - 1) {
|
|
2320
|
+
seqIdx = playheadPositions.length - 1;
|
|
2321
|
+
}
|
|
2337
2322
|
debug("[".concat(this._sessionId, "]: Current audio playhead position (").concat(seqIdx, "): ").concat(playheadPositions[seqIdx]));
|
|
2338
2323
|
return [2 /*return*/, playheadPositions[seqIdx]];
|
|
2339
2324
|
}
|
package/dist/package.json
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* Reference implementation of Channel Engine library
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
var index_1 = require("./index");
|
|
7
|
+
var RefAssetManager = /** @class */ (function () {
|
|
8
|
+
function RefAssetManager(opts) {
|
|
9
|
+
this.assets = {
|
|
10
|
+
1: [
|
|
11
|
+
{
|
|
12
|
+
id: 1,
|
|
13
|
+
title: "Sollevante",
|
|
14
|
+
uri: "https://testcontent.eyevinn.technology/dolby/index.m3u8",
|
|
15
|
+
}
|
|
16
|
+
],
|
|
17
|
+
};
|
|
18
|
+
this.pos = {
|
|
19
|
+
1: 0,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
*
|
|
24
|
+
* @param {Object} vodRequest
|
|
25
|
+
* {
|
|
26
|
+
* sessionId,
|
|
27
|
+
* category,
|
|
28
|
+
* playlistId
|
|
29
|
+
* }
|
|
30
|
+
*/
|
|
31
|
+
RefAssetManager.prototype.getNextVod = function (vodRequest) {
|
|
32
|
+
var _this = this;
|
|
33
|
+
console.log(this.assets);
|
|
34
|
+
return new Promise(function (resolve, reject) {
|
|
35
|
+
var channelId = vodRequest.playlistId;
|
|
36
|
+
if (_this.assets[channelId]) {
|
|
37
|
+
var vod = _this.assets[channelId][_this.pos[channelId]++];
|
|
38
|
+
if (_this.pos[channelId] > _this.assets[channelId].length - 1) {
|
|
39
|
+
_this.pos[channelId] = 0;
|
|
40
|
+
}
|
|
41
|
+
var vodResponse = {
|
|
42
|
+
id: vod.id,
|
|
43
|
+
title: vod.title,
|
|
44
|
+
uri: vod.uri,
|
|
45
|
+
};
|
|
46
|
+
resolve(vodResponse);
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
reject("Invalid channelId provided");
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
};
|
|
53
|
+
return RefAssetManager;
|
|
54
|
+
}());
|
|
55
|
+
var RefChannelManager = /** @class */ (function () {
|
|
56
|
+
function RefChannelManager() {
|
|
57
|
+
}
|
|
58
|
+
RefChannelManager.prototype.getChannels = function () {
|
|
59
|
+
//return [ { id: '1', profile: this._getProfile() }, { id: 'faulty', profile: this._getProfile() } ];
|
|
60
|
+
return [{
|
|
61
|
+
id: "1",
|
|
62
|
+
profile: this._getProfile(),
|
|
63
|
+
audioTracks: this._getAudioTracks(),
|
|
64
|
+
}];
|
|
65
|
+
};
|
|
66
|
+
RefChannelManager.prototype._getProfile = function () {
|
|
67
|
+
return [
|
|
68
|
+
{ resolution: [640, 360], bw: 3663471, codecs: "avc1.64001F,mp4a.40.2" },
|
|
69
|
+
{ resolution: [1280, 720], bw: 5841380, codecs: "avc1.64001F,mp4a.40.2" },
|
|
70
|
+
{ resolution: [1920, 1080], bw: 8973571, codecs: "avc1.64001F,mp4a.40.2" },
|
|
71
|
+
{ resolution: [640, 360], bw: 4301519, codecs: "avc1.64001F,ec-3" },
|
|
72
|
+
{ resolution: [1280, 720], bw: 6479428, codecs: "avc1.64001F,ec-3" },
|
|
73
|
+
{ resolution: [1920, 1080], bw: 9611619, codecs: "avc1.640032,ec-3" },
|
|
74
|
+
];
|
|
75
|
+
};
|
|
76
|
+
RefChannelManager.prototype._getAudioTracks = function () {
|
|
77
|
+
return [
|
|
78
|
+
{ language: "ja", "name": "日本語 stereo", channels: 2, codecs: "mp4a.40.2", default: true },
|
|
79
|
+
{ language: "ja", "name": "日本語 surround", channels: 16, codecs: "ec-3", default: false }
|
|
80
|
+
];
|
|
81
|
+
};
|
|
82
|
+
return RefChannelManager;
|
|
83
|
+
}());
|
|
84
|
+
var refAssetManager = new RefAssetManager();
|
|
85
|
+
var refChannelManager = new RefChannelManager();
|
|
86
|
+
var engineOptions = {
|
|
87
|
+
heartbeat: "/",
|
|
88
|
+
useDemuxedAudio: true,
|
|
89
|
+
averageSegmentDuration: 2000,
|
|
90
|
+
channelManager: refChannelManager,
|
|
91
|
+
slateRepetitions: 10,
|
|
92
|
+
redisUrl: process.env.REDIS_URL,
|
|
93
|
+
};
|
|
94
|
+
var engine = new index_1.ChannelEngine(refAssetManager, engineOptions);
|
|
95
|
+
engine.start();
|
|
96
|
+
engine.listen(process.env.PORT || 8000);
|
package/engine/server.ts
CHANGED
|
@@ -119,6 +119,8 @@ export interface ClosedCaptions {
|
|
|
119
119
|
export interface AudioTracks {
|
|
120
120
|
language: string;
|
|
121
121
|
name: string;
|
|
122
|
+
channels?: number;
|
|
123
|
+
codecs?: string;
|
|
122
124
|
default?: boolean;
|
|
123
125
|
}
|
|
124
126
|
|
|
@@ -659,7 +661,7 @@ export class ChannelEngine {
|
|
|
659
661
|
"Access-Control-Allow-Origin": "*",
|
|
660
662
|
"Access-Control-Allow-Headers": "X-Session-Id",
|
|
661
663
|
"Access-Control-Expose-Headers": "X-Session-Id",
|
|
662
|
-
"Cache-Control": "
|
|
664
|
+
"Cache-Control": "max-age=300",
|
|
663
665
|
"X-Session-Id": session.sessionId,
|
|
664
666
|
"X-Instance-Id": this.instanceId + `<${version}>`,
|
|
665
667
|
});
|
package/engine/session.js
CHANGED
|
@@ -160,9 +160,7 @@ class Session {
|
|
|
160
160
|
while (state !== PlayheadState.CRASHED) {
|
|
161
161
|
try {
|
|
162
162
|
const tsIncrementBegin = Date.now();
|
|
163
|
-
const manifest = await this.incrementAsync(
|
|
164
|
-
audio: audioIncrement
|
|
165
|
-
});
|
|
163
|
+
const manifest = await this.incrementAsync();
|
|
166
164
|
if (!manifest) {
|
|
167
165
|
debug(`[${this._sessionId}]: No manifest available yet, will try again after 1000ms`);
|
|
168
166
|
await timer(1000);
|
|
@@ -202,38 +200,6 @@ class Session {
|
|
|
202
200
|
debug(`[${this._sessionId}]: Delta time is != 0 need will adjust ${delta}sec to tick interval. tick=${tickInterval}`);
|
|
203
201
|
}
|
|
204
202
|
const position = (await this._getCurrentPlayheadPosition()) * 1000;
|
|
205
|
-
|
|
206
|
-
if (this.use_demuxed_audio) {
|
|
207
|
-
let currentVod = await this._sessionState.getCurrentVod();
|
|
208
|
-
const sessionState = await this._sessionState.getValues(["vodMediaSeqAudio"]);
|
|
209
|
-
let posDiff;
|
|
210
|
-
let incrementValue = 1;
|
|
211
|
-
let index = 0;
|
|
212
|
-
const audioSeqLastIdx = currentVod.getLiveMediaSequencesCount("audio") - 1;
|
|
213
|
-
const thresh = 0.5;
|
|
214
|
-
let direction = 0;
|
|
215
|
-
do {
|
|
216
|
-
const audioPosition = (await this._getAudioPlayheadPosition(sessionState.vodMediaSeqAudio + index)) * 1000;
|
|
217
|
-
posDiff = position - audioPosition;
|
|
218
|
-
if (posDiff > thresh && direction >= 0) {
|
|
219
|
-
index++;
|
|
220
|
-
incrementValue++;
|
|
221
|
-
direction = 1;
|
|
222
|
-
} else if (posDiff < -thresh && direction <= 0) {
|
|
223
|
-
incrementValue = 0;
|
|
224
|
-
index--;
|
|
225
|
-
direction = -1;
|
|
226
|
-
break;
|
|
227
|
-
} else if (direction > 0 && posDiff < 0) {
|
|
228
|
-
break;
|
|
229
|
-
}
|
|
230
|
-
if (sessionState.vodMediaSeqAudio + index > audioSeqLastIdx || sessionState.vodMediaSeqAudio + index < 0) {
|
|
231
|
-
break;
|
|
232
|
-
}
|
|
233
|
-
} while (!(-thresh < posDiff && posDiff < thresh));
|
|
234
|
-
audioIncrement = incrementValue;
|
|
235
|
-
}
|
|
236
|
-
|
|
237
203
|
let timePosition = Date.now() - playheadState.playheadRef;
|
|
238
204
|
// Apply time position offset if set, only after external diff compensation has concluded.
|
|
239
205
|
if (this.timePositionOffset && this.diffCompensation <= 0 && this.alwaysNewSegments) {
|
|
@@ -576,18 +542,13 @@ class Session {
|
|
|
576
542
|
this.prevMediaSeqOffset.video = playheadState.mediaSeq;
|
|
577
543
|
}
|
|
578
544
|
|
|
579
|
-
if (playheadState.vodMediaSeqVideo > sessionState.vodMediaSeqVideo ||
|
|
580
|
-
(playheadState.vodMediaSeqVideo < sessionState.vodMediaSeqVideo &&
|
|
581
|
-
playheadState.mediaSeq === this.prevMediaSeqOffset.video)) {
|
|
545
|
+
if (playheadState.vodMediaSeqVideo > sessionState.vodMediaSeqVideo || (playheadState.vodMediaSeqVideo < sessionState.vodMediaSeqVideo && playheadState.mediaSeq === this.prevMediaSeqOffset.video)) {
|
|
582
546
|
const state = await this._sessionState.get("state");
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
debug(`[${this._sessionId}]: Recently Loaded Next Vod. PlayheadState not up-to-date. Delay media-m3u8 Response by 1000ms`);
|
|
589
|
-
await timer(1000);
|
|
590
|
-
}
|
|
547
|
+
const DELAY_TIME_MS = 1000;
|
|
548
|
+
const ACTION = [SessionState.VOD_RELOAD_INIT, SessionState.VOD_RELOAD_INITIATING].includes(state) ? "Reloaded" : "Loaded Next";
|
|
549
|
+
debug(`[${this._sessionId}]: Recently ${ACTION} Vod. PlayheadState not up-to-date (${playheadState.vodMediaSeqVideo}_${sessionState.vodMediaSeqVideo}). Waiting ${DELAY_TIME_MS}ms before reading from store again`);
|
|
550
|
+
await timer(DELAY_TIME_MS);
|
|
551
|
+
playheadState = await this._playheadState.getValues(["mediaSeq", "vodMediaSeqVideo"]);
|
|
591
552
|
}
|
|
592
553
|
|
|
593
554
|
// Force reading up from store, but only once if the condition is right
|
|
@@ -655,24 +616,14 @@ class Session {
|
|
|
655
616
|
const sessionState = await this._sessionState.getValues(["discSeqAudio", "vodMediaSeqAudio"]);
|
|
656
617
|
let playheadState = await this._playheadState.getValues(["mediaSeqAudio", "vodMediaSeqAudio"]);
|
|
657
618
|
|
|
658
|
-
if (
|
|
659
|
-
playheadState.vodMediaSeqAudio > sessionState.vodMediaSeqAudio ||
|
|
660
|
-
(playheadState.vodMediaSeqAudio < sessionState.vodMediaSeqAudio && playheadState.mediaSeqAudio === this.prevMediaSeqOffset.audio)
|
|
661
|
-
) {
|
|
619
|
+
if (playheadState.vodMediaSeqAudio > sessionState.vodMediaSeqAudio || (playheadState.vodMediaSeqAudio < sessionState.vodMediaSeqAudio && playheadState.mediaSeqAudio === this.prevMediaSeqOffset.audio)) {
|
|
662
620
|
const state = await this._sessionState.get("state");
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
playheadState = await this._playheadState.getValues(["mediaSeqAudio", "vodMediaSeqAudio"]);
|
|
669
|
-
} else {
|
|
670
|
-
debug(`[${this._sessionId}]: Recently Loaded Next Vod. PlayheadState not up-to-date. Delay audio-m3u8 Response by 1000ms`);
|
|
671
|
-
await timer(1000);
|
|
672
|
-
playheadState = await this._playheadState.getValues(["mediaSeqAudio", "vodMediaSeqAudio"]);
|
|
673
|
-
}
|
|
621
|
+
const DELAY_TIME_MS = 1000;
|
|
622
|
+
const ACTION = [SessionState.VOD_RELOAD_INIT, SessionState.VOD_RELOAD_INITIATING].includes(state) ? "Reloaded" : "Loaded Next";
|
|
623
|
+
debug(`[${this._sessionId}]: Recently ${ACTION} Vod. PlayheadState not up-to-date (${playheadState.vodMediaSeqAudio}_${sessionState.vodMediaSeqAudio}). Waiting ${DELAY_TIME_MS}ms before reading from store again`);
|
|
624
|
+
await timer(DELAY_TIME_MS);
|
|
625
|
+
playheadState = await this._playheadState.getValues(["mediaSeqAudio", "vodMediaSeqAudio"]);
|
|
674
626
|
}
|
|
675
|
-
|
|
676
627
|
// local store the prev values
|
|
677
628
|
if (this.prevVodMediaSeq.audio === null) {
|
|
678
629
|
this.prevVodMediaSeq.audio = playheadState.vodMediaSeqAudio;
|
|
@@ -684,7 +635,7 @@ class Session {
|
|
|
684
635
|
if (currentVod) {
|
|
685
636
|
// condition suggesting that a new vod should exist
|
|
686
637
|
if (playheadState.vodMediaSeqAudio < 2 || playheadState.mediaSeqAudio !== this.prevMediaSeqOffset.audio) {
|
|
687
|
-
const AGE_THRESH =
|
|
638
|
+
const AGE_THRESH = this.averageSegmentDuration * 2;
|
|
688
639
|
let cacheAge = null;
|
|
689
640
|
if (this._sessionState.cache && this._sessionState.cache.currentVod.ts) {
|
|
690
641
|
cacheAge = Date.now() - this._sessionState.cache.currentVod.ts;
|
|
@@ -732,7 +683,7 @@ class Session {
|
|
|
732
683
|
}
|
|
733
684
|
}
|
|
734
685
|
|
|
735
|
-
async incrementAsync(
|
|
686
|
+
async incrementAsync() {
|
|
736
687
|
await this._tickAsync();
|
|
737
688
|
const isLeader = await this._sessionStateStore.isLeader(this._instanceId);
|
|
738
689
|
|
|
@@ -772,9 +723,36 @@ class Session {
|
|
|
772
723
|
}
|
|
773
724
|
} else {
|
|
774
725
|
sessionState.vodMediaSeqVideo = await this._sessionState.increment("vodMediaSeqVideo");
|
|
775
|
-
|
|
776
|
-
|
|
726
|
+
let audioIncrement;
|
|
727
|
+
if (this.use_demuxed_audio) {
|
|
728
|
+
const position = (await this._getCurrentPlayheadPosition()) * 1000;
|
|
729
|
+
let currentVod = await this._sessionState.getCurrentVod();
|
|
730
|
+
const sessionState = await this._sessionState.getValues(["vodMediaSeqAudio"]);
|
|
731
|
+
let posDiff;
|
|
732
|
+
let incrementValue = 1;
|
|
733
|
+
let index = 0;
|
|
734
|
+
const audioSeqLastIdx = currentVod.getLiveMediaSequencesCount("audio") - 1;
|
|
735
|
+
const thresh = 0.5;
|
|
736
|
+
do {
|
|
737
|
+
const audioPosition = (await this._getAudioPlayheadPosition(sessionState.vodMediaSeqAudio + index)) * 1000;
|
|
738
|
+
posDiff = position - audioPosition;
|
|
739
|
+
if (posDiff < 0) {
|
|
740
|
+
break;
|
|
741
|
+
}
|
|
742
|
+
if (posDiff > thresh) {
|
|
743
|
+
index++;
|
|
744
|
+
incrementValue++;
|
|
745
|
+
} else {
|
|
746
|
+
index = incrementValue;
|
|
747
|
+
break;
|
|
748
|
+
}
|
|
749
|
+
if (sessionState.vodMediaSeqAudio + index > audioSeqLastIdx) {
|
|
750
|
+
break;
|
|
751
|
+
}
|
|
752
|
+
} while (!(-thresh < posDiff && posDiff < thresh));
|
|
753
|
+
audioIncrement = index;
|
|
777
754
|
}
|
|
755
|
+
sessionState.vodMediaSeqAudio = await this._sessionState.increment("vodMediaSeqAudio", audioIncrement);
|
|
778
756
|
}
|
|
779
757
|
|
|
780
758
|
if (sessionState.vodMediaSeqVideo >= currentVod.getLiveMediaSequencesCount() - 1) {
|
|
@@ -981,11 +959,12 @@ class Session {
|
|
|
981
959
|
let audioGroupId = audioGroupIds[i];
|
|
982
960
|
for (let j = 0; j < this._audioTracks.length; j++) {
|
|
983
961
|
let audioTrack = this._audioTracks[j];
|
|
962
|
+
let channels = this._audioTracks[j].channels ? this._audioTracks[j].channels : 2;
|
|
984
963
|
// Make default track if set property is true.
|
|
985
964
|
if (audioTrack.default) {
|
|
986
|
-
m3u8 += `#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="${audioGroupId}",LANGUAGE="${audioTrack.language}", NAME="${audioTrack.name}",AUTOSELECT=YES,DEFAULT=YES,CHANNELS="
|
|
965
|
+
m3u8 += `#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="${audioGroupId}",LANGUAGE="${audioTrack.language}", NAME="${audioTrack.name}",AUTOSELECT=YES,DEFAULT=YES,CHANNELS="${channels}",URI="master-${audioGroupId}_${audioTrack.language}.m3u8;session=${this._sessionId}"\n`;
|
|
987
966
|
} else {
|
|
988
|
-
m3u8 += `#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="${audioGroupId}",LANGUAGE="${audioTrack.language}", NAME="${audioTrack.name}",AUTOSELECT=YES,DEFAULT=NO,CHANNELS="
|
|
967
|
+
m3u8 += `#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="${audioGroupId}",LANGUAGE="${audioTrack.language}", NAME="${audioTrack.name}",AUTOSELECT=YES,DEFAULT=NO,CHANNELS="${channels}",URI="master-${audioGroupId}_${audioTrack.language}.m3u8;session=${this._sessionId}"\n`;
|
|
989
968
|
}
|
|
990
969
|
}
|
|
991
970
|
}
|
|
@@ -1691,6 +1670,9 @@ class Session {
|
|
|
1691
1670
|
async _getAudioPlayheadPosition(seqIdx) {
|
|
1692
1671
|
const currentVod = await this._sessionState.getCurrentVod();
|
|
1693
1672
|
const playheadPositions = currentVod.getPlayheadPositions("audio");
|
|
1673
|
+
if (seqIdx >= playheadPositions.length - 1) {
|
|
1674
|
+
seqIdx = playheadPositions.length - 1
|
|
1675
|
+
}
|
|
1694
1676
|
debug(`[${this._sessionId}]: Current audio playhead position (${seqIdx}): ${playheadPositions[seqIdx]}`);
|
|
1695
1677
|
return playheadPositions[seqIdx];
|
|
1696
1678
|
}
|
package/package.json
CHANGED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Reference implementation of Channel Engine library
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { ChannelEngine, ChannelEngineOpts,
|
|
6
|
+
IAssetManager, IChannelManager,
|
|
7
|
+
VodRequest, VodResponse, Channel, ChannelProfile,
|
|
8
|
+
AudioTracks
|
|
9
|
+
} from "./index";
|
|
10
|
+
|
|
11
|
+
class RefAssetManager implements IAssetManager {
|
|
12
|
+
private assets;
|
|
13
|
+
private pos;
|
|
14
|
+
constructor(opts?) {
|
|
15
|
+
this.assets = {
|
|
16
|
+
1: [
|
|
17
|
+
{
|
|
18
|
+
id: 1,
|
|
19
|
+
title: "Sollevante",
|
|
20
|
+
uri: "https://testcontent.eyevinn.technology/dolby/index.m3u8",
|
|
21
|
+
}
|
|
22
|
+
],
|
|
23
|
+
};
|
|
24
|
+
this.pos = {
|
|
25
|
+
1: 0,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
*
|
|
31
|
+
* @param {Object} vodRequest
|
|
32
|
+
* {
|
|
33
|
+
* sessionId,
|
|
34
|
+
* category,
|
|
35
|
+
* playlistId
|
|
36
|
+
* }
|
|
37
|
+
*/
|
|
38
|
+
getNextVod(vodRequest: VodRequest): Promise<VodResponse> {
|
|
39
|
+
console.log(this.assets);
|
|
40
|
+
return new Promise((resolve, reject) => {
|
|
41
|
+
const channelId = vodRequest.playlistId;
|
|
42
|
+
if (this.assets[channelId]) {
|
|
43
|
+
let vod = this.assets[channelId][this.pos[channelId]++];
|
|
44
|
+
if (this.pos[channelId] > this.assets[channelId].length - 1) {
|
|
45
|
+
this.pos[channelId] = 0;
|
|
46
|
+
}
|
|
47
|
+
const vodResponse = {
|
|
48
|
+
id: vod.id,
|
|
49
|
+
title: vod.title,
|
|
50
|
+
uri: vod.uri,
|
|
51
|
+
};
|
|
52
|
+
resolve(vodResponse);
|
|
53
|
+
} else {
|
|
54
|
+
reject("Invalid channelId provided");
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
class RefChannelManager implements IChannelManager {
|
|
61
|
+
getChannels(): Channel[] {
|
|
62
|
+
//return [ { id: '1', profile: this._getProfile() }, { id: 'faulty', profile: this._getProfile() } ];
|
|
63
|
+
return [{
|
|
64
|
+
id: "1",
|
|
65
|
+
profile: this._getProfile(),
|
|
66
|
+
audioTracks: this._getAudioTracks(),
|
|
67
|
+
}];
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
_getProfile(): ChannelProfile[] {
|
|
71
|
+
return [
|
|
72
|
+
{ resolution: [640, 360], bw: 3663471, codecs: "avc1.64001F,mp4a.40.2" },
|
|
73
|
+
{ resolution: [1280, 720], bw: 5841380, codecs: "avc1.64001F,mp4a.40.2" },
|
|
74
|
+
{ resolution: [1920, 1080], bw: 8973571, codecs: "avc1.64001F,mp4a.40.2" },
|
|
75
|
+
|
|
76
|
+
{ resolution: [640, 360], bw: 4301519, codecs: "avc1.64001F,ec-3" },
|
|
77
|
+
{ resolution: [1280, 720], bw: 6479428, codecs: "avc1.64001F,ec-3" },
|
|
78
|
+
{ resolution: [1920, 1080], bw: 9611619, codecs: "avc1.640032,ec-3" },
|
|
79
|
+
];
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
_getAudioTracks(): AudioTracks[] {
|
|
83
|
+
return [
|
|
84
|
+
{ language: "ja", "name": "日本語 stereo", channels: 2, codecs: "mp4a.40.2", default: true },
|
|
85
|
+
{ language: "ja", "name": "日本語 surround", channels: 16, codecs: "ec-3", default: false }
|
|
86
|
+
];
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const refAssetManager = new RefAssetManager();
|
|
91
|
+
const refChannelManager = new RefChannelManager();
|
|
92
|
+
|
|
93
|
+
const engineOptions: ChannelEngineOpts = {
|
|
94
|
+
heartbeat: "/",
|
|
95
|
+
useDemuxedAudio: true,
|
|
96
|
+
averageSegmentDuration: 2000,
|
|
97
|
+
channelManager: refChannelManager,
|
|
98
|
+
slateRepetitions: 10,
|
|
99
|
+
redisUrl: process.env.REDIS_URL,
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
const engine = new ChannelEngine(refAssetManager, engineOptions);
|
|
103
|
+
engine.start();
|
|
104
|
+
engine.listen(process.env.PORT || 8000);
|
package/tsconfig.json
CHANGED