eyevinn-channel-engine 4.0.1 → 4.0.3
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.js +100 -45
- package/dist/package.json +1 -1
- package/dist/server-demux.js +7 -4
- package/engine/session.js +83 -27
- package/package.json +1 -1
- package/server-demux.ts +7 -4
package/dist/engine/session.js
CHANGED
|
@@ -783,7 +783,7 @@ var Session = /** @class */ (function () {
|
|
|
783
783
|
};
|
|
784
784
|
Session.prototype.getCurrentMediaManifestAsync = function (bw, playbackSessionId) {
|
|
785
785
|
return __awaiter(this, void 0, void 0, function () {
|
|
786
|
-
var tries, sessionState, playheadState, state,
|
|
786
|
+
var tries, sessionState, playheadState, state, isLeader, diffMs, currentVod, manifestMseq, manifestDseq, mediaSequenceValue, m3u8_1, err_4;
|
|
787
787
|
return __generator(this, function (_a) {
|
|
788
788
|
switch (_a.label) {
|
|
789
789
|
case 0:
|
|
@@ -828,17 +828,10 @@ var Session = /** @class */ (function () {
|
|
|
828
828
|
playheadState = _a.sent();
|
|
829
829
|
return [3 /*break*/, 11];
|
|
830
830
|
case 9:
|
|
831
|
-
debug("[".concat(this._sessionId, "]: Recently Loaded Next Vod. PlayheadState not up-to-date.
|
|
832
|
-
return [4 /*yield*/,
|
|
831
|
+
debug("[".concat(this._sessionId, "]: Recently Loaded Next Vod. PlayheadState not up-to-date. Delay media-m3u8 Response by 1000ms"));
|
|
832
|
+
return [4 /*yield*/, timer(1000)];
|
|
833
833
|
case 10:
|
|
834
|
-
|
|
835
|
-
if (m3u8_1) {
|
|
836
|
-
this.prevVodMediaSeq.video = playheadState.vodMediaSeqVideo;
|
|
837
|
-
return [2 /*return*/, m3u8_1];
|
|
838
|
-
}
|
|
839
|
-
else {
|
|
840
|
-
debug("[".concat(this._sessionId, "]: We don't have any previously generated m3u8"));
|
|
841
|
-
}
|
|
834
|
+
_a.sent();
|
|
842
835
|
_a.label = 11;
|
|
843
836
|
case 11:
|
|
844
837
|
if (!(playheadState.vodMediaSeqVideo < 2 || playheadState.mediaSeq !== this.prevMediaSeqOffset.video)) return [3 /*break*/, 16];
|
|
@@ -891,11 +884,11 @@ var Session = /** @class */ (function () {
|
|
|
891
884
|
manifestMseq = playheadState.mediaSeq + mediaSequenceValue;
|
|
892
885
|
}
|
|
893
886
|
debug("[".concat(this._sessionId, "]: [").concat(playheadState.vodMediaSeqVideo, "]_[").concat(currentVod.getLiveMediaSequencesCount(), "]"));
|
|
894
|
-
|
|
887
|
+
m3u8_1 = currentVod.getLiveMediaSequences(playheadState.mediaSeq, bw, playheadState.vodMediaSeqVideo, sessionState.discSeq, this.targetDurationPadding, this.forceTargetDuration);
|
|
895
888
|
debug("[".concat(this._sessionId, "]: [").concat(manifestMseq, "][").concat(manifestDseq, "][+").concat(this.targetDurationPadding || 0, "] Current media manifest for ").concat(bw, " requested"));
|
|
896
889
|
this.prevVodMediaSeq.video = playheadState.vodMediaSeqVideo;
|
|
897
890
|
this.prevMediaSeqOffset.video = playheadState.mediaSeq;
|
|
898
|
-
return [2 /*return*/,
|
|
891
|
+
return [2 /*return*/, m3u8_1];
|
|
899
892
|
case 20:
|
|
900
893
|
err_4 = _a.sent();
|
|
901
894
|
logerror(this._sessionId, err_4);
|
|
@@ -912,50 +905,109 @@ var Session = /** @class */ (function () {
|
|
|
912
905
|
};
|
|
913
906
|
Session.prototype.getCurrentAudioManifestAsync = function (audioGroupId, audioLanguage, playbackSessionId) {
|
|
914
907
|
return __awaiter(this, void 0, void 0, function () {
|
|
915
|
-
var sessionState, playheadState,
|
|
908
|
+
var currentVod, sessionState, playheadState, state, AGE_THRESH, cacheAge, manifestMseq, manifestDseq, mediaSequenceValue, m3u8_2, err_5;
|
|
916
909
|
return __generator(this, function (_a) {
|
|
917
910
|
switch (_a.label) {
|
|
918
911
|
case 0:
|
|
919
912
|
if (!this._sessionState) {
|
|
920
913
|
throw new Error('Session not ready');
|
|
921
914
|
}
|
|
922
|
-
|
|
915
|
+
currentVod = null;
|
|
916
|
+
return [4 /*yield*/, this._sessionState.getValues(["discSeqAudio", "vodMediaSeqAudio"])];
|
|
923
917
|
case 1:
|
|
924
918
|
sessionState = _a.sent();
|
|
925
919
|
return [4 /*yield*/, this._playheadState.getValues(["mediaSeqAudio", "vodMediaSeqAudio"])];
|
|
926
920
|
case 2:
|
|
927
921
|
playheadState = _a.sent();
|
|
928
|
-
|
|
922
|
+
if (!(playheadState.vodMediaSeqAudio > sessionState.vodMediaSeqAudio ||
|
|
923
|
+
(playheadState.vodMediaSeqAudio < sessionState.vodMediaSeqAudio && playheadState.mediaSeqAudio === this.prevMediaSeqOffset.audio))) return [3 /*break*/, 9];
|
|
924
|
+
return [4 /*yield*/, this._sessionState.get("state")];
|
|
929
925
|
case 3:
|
|
930
|
-
|
|
931
|
-
if (!
|
|
932
|
-
|
|
926
|
+
state = _a.sent();
|
|
927
|
+
if (![SessionState.VOD_RELOAD_INIT, SessionState.VOD_RELOAD_INITIATING].includes(state)) return [3 /*break*/, 6];
|
|
928
|
+
debug("[".concat(this._sessionId, "]: Recently reloaded Vod. PlayheadState not up-to-date (").concat(playheadState.vodMediaSeqAudio, "_").concat(sessionState.vodMediaSeqAudio, ") AUDIO. Waiting 500ms before reading from store again"));
|
|
929
|
+
return [4 /*yield*/, timer(500)];
|
|
933
930
|
case 4:
|
|
934
|
-
_a.
|
|
935
|
-
|
|
931
|
+
_a.sent();
|
|
932
|
+
return [4 /*yield*/, this._playheadState.getValues(["mediaSeqAudio", "vodMediaSeqAudio"])];
|
|
933
|
+
case 5:
|
|
934
|
+
playheadState = _a.sent();
|
|
935
|
+
return [3 /*break*/, 9];
|
|
936
|
+
case 6:
|
|
937
|
+
debug("[".concat(this._sessionId, "]: Recently Loaded Next Vod. PlayheadState not up-to-date. Delay audio-m3u8 Response by 1000ms"));
|
|
938
|
+
return [4 /*yield*/, timer(1000)];
|
|
939
|
+
case 7:
|
|
940
|
+
_a.sent();
|
|
941
|
+
return [4 /*yield*/, this._playheadState.getValues(["mediaSeqAudio", "vodMediaSeqAudio"])];
|
|
942
|
+
case 8:
|
|
943
|
+
playheadState = _a.sent();
|
|
944
|
+
_a.label = 9;
|
|
945
|
+
case 9:
|
|
946
|
+
// local store the prev values
|
|
947
|
+
if (this.prevVodMediaSeq.audio === null) {
|
|
948
|
+
this.prevVodMediaSeq.audio = playheadState.vodMediaSeqAudio;
|
|
949
|
+
}
|
|
950
|
+
if (this.prevMediaSeqOffset.audio === null) {
|
|
951
|
+
this.prevMediaSeqOffset.audio = playheadState.mediaSeqAudio;
|
|
952
|
+
}
|
|
953
|
+
return [4 /*yield*/, this._sessionState.getCurrentVod()];
|
|
954
|
+
case 10:
|
|
955
|
+
currentVod = _a.sent();
|
|
956
|
+
if (!currentVod) return [3 /*break*/, 18];
|
|
957
|
+
if (!(playheadState.vodMediaSeqAudio < 2 || playheadState.mediaSeqAudio !== this.prevMediaSeqOffset.audio)) return [3 /*break*/, 14];
|
|
958
|
+
AGE_THRESH = 20 * 1000;
|
|
959
|
+
cacheAge = null;
|
|
960
|
+
if (this._sessionState.cache && this._sessionState.cache.currentVod.ts) {
|
|
961
|
+
cacheAge = Date.now() - this._sessionState.cache.currentVod.ts;
|
|
962
|
+
}
|
|
963
|
+
if (!(cacheAge !== null && cacheAge > AGE_THRESH)) return [3 /*break*/, 14];
|
|
964
|
+
return [4 /*yield*/, timer(500)];
|
|
965
|
+
case 11:
|
|
966
|
+
_a.sent();
|
|
967
|
+
debug("[".concat(this._sessionId, "]: While requesting audio manifest for ").concat(audioGroupId, "-").concat(audioLanguage, ", (mseq=").concat(playheadState.vodMediaSeqAudio, ")(vod cache age=").concat(cacheAge, ")"));
|
|
968
|
+
return [4 /*yield*/, this._sessionState.clearCurrentVodCache()];
|
|
969
|
+
case 12:
|
|
970
|
+
_a.sent(); // force reading up from shared store
|
|
971
|
+
return [4 /*yield*/, this._sessionState.getCurrentVod()];
|
|
972
|
+
case 13:
|
|
973
|
+
currentVod = _a.sent();
|
|
974
|
+
_a.label = 14;
|
|
975
|
+
case 14:
|
|
976
|
+
_a.trys.push([14, 15, , 17]);
|
|
977
|
+
manifestMseq = playheadState.mediaSeqAudio + playheadState.vodMediaSeqAudio;
|
|
978
|
+
manifestDseq = sessionState.discSeqAudio + currentVod.discontinuitiesAudio[playheadState.vodMediaSeqAudio];
|
|
979
|
+
if (currentVod.sequenceAlwaysContainNewSegments) {
|
|
980
|
+
mediaSequenceValue = currentVod.mediaSequenceValuesAudio[playheadState.vodMediaSeqAudio];
|
|
981
|
+
debug("[".concat(this._sessionId, "]: {").concat(mediaSequenceValue, "}_{").concat(currentVod.getLastSequenceMediaSequenceValueAudio(), "} AUDIO"));
|
|
982
|
+
manifestMseq = playheadState.mediaSeqAudio + mediaSequenceValue;
|
|
983
|
+
}
|
|
984
|
+
debug("[".concat(this._sessionId, "]: [").concat(playheadState.vodMediaSeqAudio, "]_[").concat(currentVod.getLiveMediaSequencesCount("audio"), "] AUDIO"));
|
|
985
|
+
m3u8_2 = currentVod.getLiveMediaAudioSequences(playheadState.mediaSeqAudio, audioGroupId, audioLanguage, playheadState.vodMediaSeqAudio, sessionState.discSeqAudio, this.targetDurationPadding, this.forceTargetDuration);
|
|
936
986
|
// # Case: current VOD does not have the selected track.
|
|
937
|
-
if (!
|
|
987
|
+
if (!m3u8_2) {
|
|
938
988
|
debug("[".concat(this._sessionId, "]: [").concat(playheadState.mediaSeqAudio + playheadState.vodMediaSeqAudio, "] Request Failed for current audio manifest for ").concat(audioGroupId, "-").concat(audioLanguage));
|
|
939
989
|
}
|
|
940
|
-
debug("[".concat(this._sessionId, "]: [").concat(
|
|
941
|
-
|
|
942
|
-
|
|
990
|
+
debug("[".concat(this._sessionId, "]: [").concat(manifestMseq, "][").concat(manifestDseq, "] Current audio manifest for ").concat(audioGroupId, "-").concat(audioLanguage, " requested"));
|
|
991
|
+
this.prevVodMediaSeq.audio = playheadState.vodMediaSeqAudio;
|
|
992
|
+
this.prevMediaSeqOffset.audio = playheadState.mediaSeqAudio;
|
|
993
|
+
return [2 /*return*/, m3u8_2];
|
|
994
|
+
case 15:
|
|
943
995
|
err_5 = _a.sent();
|
|
944
996
|
logerror(this._sessionId, err_5);
|
|
945
997
|
return [4 /*yield*/, this._sessionState.clearCurrentVodCache()];
|
|
946
|
-
case
|
|
998
|
+
case 16:
|
|
947
999
|
_a.sent(); // force reading up from shared store
|
|
948
1000
|
throw new Error("Failed to generate audio manifest: " + JSON.stringify(playheadState));
|
|
949
|
-
case
|
|
950
|
-
case
|
|
951
|
-
case
|
|
1001
|
+
case 17: return [3 /*break*/, 19];
|
|
1002
|
+
case 18: throw new Error("Engine not ready");
|
|
1003
|
+
case 19: return [2 /*return*/];
|
|
952
1004
|
}
|
|
953
1005
|
});
|
|
954
1006
|
});
|
|
955
1007
|
};
|
|
956
1008
|
Session.prototype.incrementAsync = function (incOpts) {
|
|
957
1009
|
return __awaiter(this, void 0, void 0, function () {
|
|
958
|
-
var isLeader, sessionState, playheadState, currentVod, _a, leaderAction, _b,
|
|
1010
|
+
var isLeader, sessionState, playheadState, currentVod, _a, leaderAction, _b, m3u8_3, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, mediaSequenceValue, diffMs, m3u8;
|
|
959
1011
|
return __generator(this, function (_o) {
|
|
960
1012
|
switch (_o.label) {
|
|
961
1013
|
case 0: return [4 /*yield*/, this._tickAsync()];
|
|
@@ -1006,9 +1058,9 @@ var Session = /** @class */ (function () {
|
|
|
1006
1058
|
debug("[".concat(this._sessionId, "]: Return the last generated m3u8 to give the leader some time"));
|
|
1007
1059
|
return [4 /*yield*/, this._playheadState.getLastM3u8()];
|
|
1008
1060
|
case 12:
|
|
1009
|
-
|
|
1010
|
-
if (
|
|
1011
|
-
return [2 /*return*/,
|
|
1061
|
+
m3u8_3 = _o.sent();
|
|
1062
|
+
if (m3u8_3) {
|
|
1063
|
+
return [2 /*return*/, m3u8_3];
|
|
1012
1064
|
}
|
|
1013
1065
|
else {
|
|
1014
1066
|
debug("[".concat(this._sessionId, "]: We don't have any previously generated m3u8"));
|
|
@@ -1110,6 +1162,10 @@ var Session = /** @class */ (function () {
|
|
|
1110
1162
|
// Update Value for Previous Sequence
|
|
1111
1163
|
this.prevVodMediaSeq.video = playheadState.vodMediaSeqVideo;
|
|
1112
1164
|
this.prevMediaSeqOffset.video = playheadState.mediaSeq;
|
|
1165
|
+
if (this.use_demuxed_audio) {
|
|
1166
|
+
this.prevVodMediaSeq.audio = playheadState.vodMediaSeqAudio;
|
|
1167
|
+
this.prevMediaSeqOffset.audio = playheadState.mediaSeqAudio;
|
|
1168
|
+
}
|
|
1113
1169
|
m3u8 = currentVod.getLiveMediaSequences(playheadState.mediaSeq, 180000, playheadState.vodMediaSeqVideo, sessionState.discSeq);
|
|
1114
1170
|
return [4 /*yield*/, this._playheadState.setLastM3u8(m3u8)];
|
|
1115
1171
|
case 34:
|
|
@@ -1303,7 +1359,7 @@ var Session = /** @class */ (function () {
|
|
|
1303
1359
|
};
|
|
1304
1360
|
Session.prototype.getMasterManifestAsync = function (filter) {
|
|
1305
1361
|
return __awaiter(this, void 0, void 0, function () {
|
|
1306
|
-
var m3u8, currentVod, audioGroupIds, defaultAudioGroupId, hasClosedCaptions, i, audioGroupId, j, audioTrack, sessionProfile
|
|
1362
|
+
var m3u8, currentVod, audioGroupIds, defaultAudioGroupId, hasClosedCaptions, i, audioGroupId, j, audioTrack, sessionProfile;
|
|
1307
1363
|
var _this = this;
|
|
1308
1364
|
return __generator(this, function (_a) {
|
|
1309
1365
|
switch (_a.label) {
|
|
@@ -1359,16 +1415,6 @@ var Session = /** @class */ (function () {
|
|
|
1359
1415
|
m3u8 += "master" + profile.bw + ".m3u8;session=" + _this._sessionId + "\n";
|
|
1360
1416
|
});
|
|
1361
1417
|
}
|
|
1362
|
-
if (this.use_demuxed_audio === true && this._audioTracks) {
|
|
1363
|
-
for (i = 0; i < audioGroupIds.length; i++) {
|
|
1364
|
-
audioGroupId = audioGroupIds[i];
|
|
1365
|
-
for (j = 0; j < this._audioTracks.length; j++) {
|
|
1366
|
-
audioTrack = this._audioTracks[j];
|
|
1367
|
-
m3u8 += "#EXT-X-STREAM-INF:BANDWIDTH=97000,CODECS=\"mp4a.40.2\",AUDIO=\"".concat(audioGroupId, "\"\n");
|
|
1368
|
-
m3u8 += "master-".concat(audioGroupId, "_").concat(audioTrack.language, ".m3u8;session=").concat(this._sessionId, "\n");
|
|
1369
|
-
}
|
|
1370
|
-
}
|
|
1371
|
-
}
|
|
1372
1418
|
this.produceEvent({
|
|
1373
1419
|
type: 'NOW_PLAYING',
|
|
1374
1420
|
data: {
|
|
@@ -1659,6 +1705,14 @@ var Session = /** @class */ (function () {
|
|
|
1659
1705
|
if (this.prevMediaSeqOffset.video === null) {
|
|
1660
1706
|
this.prevMediaSeqOffset.video = sessionState.mediaSeq;
|
|
1661
1707
|
}
|
|
1708
|
+
if (this.use_demuxed_audio) {
|
|
1709
|
+
if (this.prevVodMediaSeq.audio === null) {
|
|
1710
|
+
this.prevVodMediaSeq.audio = sessionState.vodMediaSeqAudio;
|
|
1711
|
+
}
|
|
1712
|
+
if (this.prevMediaSeqOffset.audio === null) {
|
|
1713
|
+
this.prevMediaSeqOffset.audio = sessionState.mediaSeqAudio;
|
|
1714
|
+
}
|
|
1715
|
+
}
|
|
1662
1716
|
if (!(sessionState.vodMediaSeqVideo < this.prevVodMediaSeq.video)) return [3 /*break*/, 30];
|
|
1663
1717
|
debug("[".concat(this._sessionId, "]: state=VOD_PLAYING, current[").concat(sessionState.vodMediaSeqVideo, "], prev[").concat(this.prevVodMediaSeq.video, "], total[").concat(currentVod.getLiveMediaSequencesCount(), "]"));
|
|
1664
1718
|
return [4 /*yield*/, this._sessionState.clearCurrentVodCache()];
|
|
@@ -1668,11 +1722,12 @@ var Session = /** @class */ (function () {
|
|
|
1668
1722
|
case 29:
|
|
1669
1723
|
currentVod = _2.sent();
|
|
1670
1724
|
this.prevVodMediaSeq.video = sessionState.vodMediaSeqVideo;
|
|
1725
|
+
this.prevVodMediaSeq.audio = sessionState.vodMediaSeqAudio;
|
|
1671
1726
|
_2.label = 30;
|
|
1672
1727
|
case 30: return [3 /*break*/, 32];
|
|
1673
1728
|
case 31:
|
|
1674
1729
|
// Handle edge case where Leader loaded next vod but Follower remained in state=VOD_PLAYING
|
|
1675
|
-
if (this.prevMediaSeqOffset.video !== null & sessionState.mediaSeq !== this.prevMediaSeqOffset.video) {
|
|
1730
|
+
if ((this.prevMediaSeqOffset.video !== null) & (sessionState.mediaSeq !== this.prevMediaSeqOffset.video)) {
|
|
1676
1731
|
debug("[".concat(this._sessionId, "]: state=VOD_PLAYING, current[").concat(sessionState.vodMediaSeqVideo, "], prev[").concat(this.prevVodMediaSeq.video, "], total[").concat(currentVod.getLiveMediaSequencesCount(), "]"));
|
|
1677
1732
|
debug("[".concat(this._sessionId, "]: mediaSeq offsets -> current[").concat(sessionState.vodMediaSeqVideo, "], prev[").concat(this.prevVodMediaSeq.video, "]"));
|
|
1678
1733
|
// Allow Follower to clear VodCache...
|
package/dist/package.json
CHANGED
package/dist/server-demux.js
CHANGED
|
@@ -10,8 +10,8 @@ var RefAssetManager = /** @class */ (function () {
|
|
|
10
10
|
1: [
|
|
11
11
|
{
|
|
12
12
|
id: 1,
|
|
13
|
-
title: "
|
|
14
|
-
uri: "https://
|
|
13
|
+
title: "Sintel",
|
|
14
|
+
uri: "https://cdn.bitmovin.com/content/assets/sintel/hls/playlist.m3u8",
|
|
15
15
|
},
|
|
16
16
|
{
|
|
17
17
|
id: 2,
|
|
@@ -21,7 +21,7 @@ var RefAssetManager = /** @class */ (function () {
|
|
|
21
21
|
],
|
|
22
22
|
};
|
|
23
23
|
this.pos = {
|
|
24
|
-
1:
|
|
24
|
+
1: 0,
|
|
25
25
|
};
|
|
26
26
|
}
|
|
27
27
|
/**
|
|
@@ -80,7 +80,10 @@ var RefChannelManager = /** @class */ (function () {
|
|
|
80
80
|
];
|
|
81
81
|
};
|
|
82
82
|
RefChannelManager.prototype._getAudioTracks = function () {
|
|
83
|
-
return [
|
|
83
|
+
return [
|
|
84
|
+
{ language: "en", name: "English" },
|
|
85
|
+
{ language: "sp", name: "Spanish" }
|
|
86
|
+
];
|
|
84
87
|
};
|
|
85
88
|
return RefChannelManager;
|
|
86
89
|
}());
|
package/engine/session.js
CHANGED
|
@@ -207,10 +207,10 @@ class Session {
|
|
|
207
207
|
let incrementValue = 1;
|
|
208
208
|
let index = 0;
|
|
209
209
|
const audioSeqLastIdx = currentVod.getLiveMediaSequencesCount("audio") - 1;
|
|
210
|
-
const thresh = 0.5
|
|
210
|
+
const thresh = 0.5;
|
|
211
211
|
let direction = 0;
|
|
212
212
|
do {
|
|
213
|
-
const audioPosition = (await this._getAudioPlayheadPosition(sessionState.vodMediaSeqAudio + index)) * 1000;
|
|
213
|
+
const audioPosition = (await this._getAudioPlayheadPosition(sessionState.vodMediaSeqAudio + index)) * 1000;
|
|
214
214
|
posDiff = position - audioPosition;
|
|
215
215
|
if (posDiff > thresh && direction >= 0) {
|
|
216
216
|
index++;
|
|
@@ -582,14 +582,8 @@ class Session {
|
|
|
582
582
|
await timer(500);
|
|
583
583
|
playheadState = await this._playheadState.getValues(["mediaSeq", "vodMediaSeqVideo"]);
|
|
584
584
|
} else {
|
|
585
|
-
debug(`[${this._sessionId}]: Recently Loaded Next Vod. PlayheadState not up-to-date.
|
|
586
|
-
|
|
587
|
-
if (m3u8) {
|
|
588
|
-
this.prevVodMediaSeq.video = playheadState.vodMediaSeqVideo;
|
|
589
|
-
return m3u8;
|
|
590
|
-
} else {
|
|
591
|
-
debug(`[${this._sessionId}]: We don't have any previously generated m3u8`);
|
|
592
|
-
}
|
|
585
|
+
debug(`[${this._sessionId}]: Recently Loaded Next Vod. PlayheadState not up-to-date. Delay media-m3u8 Response by 1000ms`);
|
|
586
|
+
await timer(1000);
|
|
593
587
|
}
|
|
594
588
|
}
|
|
595
589
|
|
|
@@ -654,18 +648,76 @@ class Session {
|
|
|
654
648
|
if (!this._sessionState) {
|
|
655
649
|
throw new Error('Session not ready');
|
|
656
650
|
}
|
|
651
|
+
let currentVod = null;
|
|
652
|
+
const sessionState = await this._sessionState.getValues(["discSeqAudio", "vodMediaSeqAudio"]);
|
|
653
|
+
let playheadState = await this._playheadState.getValues(["mediaSeqAudio", "vodMediaSeqAudio"]);
|
|
654
|
+
|
|
655
|
+
if (
|
|
656
|
+
playheadState.vodMediaSeqAudio > sessionState.vodMediaSeqAudio ||
|
|
657
|
+
(playheadState.vodMediaSeqAudio < sessionState.vodMediaSeqAudio && playheadState.mediaSeqAudio === this.prevMediaSeqOffset.audio)
|
|
658
|
+
) {
|
|
659
|
+
const state = await this._sessionState.get("state");
|
|
660
|
+
if ([SessionState.VOD_RELOAD_INIT, SessionState.VOD_RELOAD_INITIATING].includes(state)) {
|
|
661
|
+
debug(
|
|
662
|
+
`[${this._sessionId}]: Recently reloaded Vod. PlayheadState not up-to-date (${playheadState.vodMediaSeqAudio}_${sessionState.vodMediaSeqAudio}) AUDIO. Waiting 500ms before reading from store again`
|
|
663
|
+
);
|
|
664
|
+
await timer(500);
|
|
665
|
+
playheadState = await this._playheadState.getValues(["mediaSeqAudio", "vodMediaSeqAudio"]);
|
|
666
|
+
} else {
|
|
667
|
+
debug(`[${this._sessionId}]: Recently Loaded Next Vod. PlayheadState not up-to-date. Delay audio-m3u8 Response by 1000ms`);
|
|
668
|
+
await timer(1000);
|
|
669
|
+
playheadState = await this._playheadState.getValues(["mediaSeqAudio", "vodMediaSeqAudio"]);
|
|
670
|
+
}
|
|
671
|
+
}
|
|
657
672
|
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
673
|
+
// local store the prev values
|
|
674
|
+
if (this.prevVodMediaSeq.audio === null) {
|
|
675
|
+
this.prevVodMediaSeq.audio = playheadState.vodMediaSeqAudio;
|
|
676
|
+
}
|
|
677
|
+
if (this.prevMediaSeqOffset.audio === null) {
|
|
678
|
+
this.prevMediaSeqOffset.audio = playheadState.mediaSeqAudio;
|
|
679
|
+
}
|
|
680
|
+
currentVod = await this._sessionState.getCurrentVod();
|
|
661
681
|
if (currentVod) {
|
|
682
|
+
// condition suggesting that a new vod should exist
|
|
683
|
+
if (playheadState.vodMediaSeqAudio < 2 || playheadState.mediaSeqAudio !== this.prevMediaSeqOffset.audio) {
|
|
684
|
+
const AGE_THRESH = 20 * 1000;
|
|
685
|
+
let cacheAge = null;
|
|
686
|
+
if (this._sessionState.cache && this._sessionState.cache.currentVod.ts) {
|
|
687
|
+
cacheAge = Date.now() - this._sessionState.cache.currentVod.ts;
|
|
688
|
+
}
|
|
689
|
+
if (cacheAge !== null && cacheAge > AGE_THRESH) {
|
|
690
|
+
await timer(500);
|
|
691
|
+
debug(`[${this._sessionId}]: While requesting audio manifest for ${audioGroupId}-${audioLanguage}, (mseq=${playheadState.vodMediaSeqAudio})(vod cache age=${cacheAge})`);
|
|
692
|
+
await this._sessionState.clearCurrentVodCache(); // force reading up from shared store
|
|
693
|
+
currentVod = await this._sessionState.getCurrentVod();
|
|
694
|
+
}
|
|
695
|
+
}
|
|
662
696
|
try {
|
|
663
|
-
|
|
697
|
+
let manifestMseq = playheadState.mediaSeqAudio + playheadState.vodMediaSeqAudio;
|
|
698
|
+
let manifestDseq = sessionState.discSeqAudio + currentVod.discontinuitiesAudio[playheadState.vodMediaSeqAudio];
|
|
699
|
+
if (currentVod.sequenceAlwaysContainNewSegments) {
|
|
700
|
+
const mediaSequenceValue = currentVod.mediaSequenceValuesAudio[playheadState.vodMediaSeqAudio];
|
|
701
|
+
debug(`[${this._sessionId}]: {${mediaSequenceValue}}_{${currentVod.getLastSequenceMediaSequenceValueAudio()}} AUDIO`);
|
|
702
|
+
manifestMseq = playheadState.mediaSeqAudio + mediaSequenceValue;
|
|
703
|
+
}
|
|
704
|
+
debug(`[${this._sessionId}]: [${playheadState.vodMediaSeqAudio}]_[${currentVod.getLiveMediaSequencesCount("audio")}] AUDIO`);
|
|
705
|
+
const m3u8 = currentVod.getLiveMediaAudioSequences(
|
|
706
|
+
playheadState.mediaSeqAudio,
|
|
707
|
+
audioGroupId,
|
|
708
|
+
audioLanguage,
|
|
709
|
+
playheadState.vodMediaSeqAudio,
|
|
710
|
+
sessionState.discSeqAudio,
|
|
711
|
+
this.targetDurationPadding,
|
|
712
|
+
this.forceTargetDuration
|
|
713
|
+
);
|
|
664
714
|
// # Case: current VOD does not have the selected track.
|
|
665
715
|
if (!m3u8) {
|
|
666
716
|
debug(`[${this._sessionId}]: [${playheadState.mediaSeqAudio + playheadState.vodMediaSeqAudio}] Request Failed for current audio manifest for ${audioGroupId}-${audioLanguage}`);
|
|
667
717
|
}
|
|
668
|
-
debug(`[${this._sessionId}]: [${
|
|
718
|
+
debug(`[${this._sessionId}]: [${manifestMseq}][${manifestDseq}] Current audio manifest for ${audioGroupId}-${audioLanguage} requested`);
|
|
719
|
+
this.prevVodMediaSeq.audio = playheadState.vodMediaSeqAudio;
|
|
720
|
+
this.prevMediaSeqOffset.audio = playheadState.mediaSeqAudio;
|
|
669
721
|
return m3u8;
|
|
670
722
|
} catch (err) {
|
|
671
723
|
logerror(this._sessionId, err);
|
|
@@ -715,7 +767,7 @@ class Session {
|
|
|
715
767
|
}
|
|
716
768
|
this.isAllowedToClearVodCache = true;
|
|
717
769
|
}
|
|
718
|
-
} else {
|
|
770
|
+
} else {
|
|
719
771
|
sessionState.vodMediaSeqVideo = await this._sessionState.increment("vodMediaSeqVideo");
|
|
720
772
|
if (incOpts) {
|
|
721
773
|
sessionState.vodMediaSeqAudio = await this._sessionState.increment("vodMediaSeqAudio", incOpts.audio);
|
|
@@ -776,6 +828,10 @@ class Session {
|
|
|
776
828
|
// Update Value for Previous Sequence
|
|
777
829
|
this.prevVodMediaSeq.video = playheadState.vodMediaSeqVideo;
|
|
778
830
|
this.prevMediaSeqOffset.video = playheadState.mediaSeq;
|
|
831
|
+
if (this.use_demuxed_audio) {
|
|
832
|
+
this.prevVodMediaSeq.audio = playheadState.vodMediaSeqAudio;
|
|
833
|
+
this.prevMediaSeqOffset.audio = playheadState.mediaSeqAudio;
|
|
834
|
+
}
|
|
779
835
|
|
|
780
836
|
let m3u8 = currentVod.getLiveMediaSequences(playheadState.mediaSeq, 180000, playheadState.vodMediaSeqVideo, sessionState.discSeq);
|
|
781
837
|
await this._playheadState.setLastM3u8(m3u8);
|
|
@@ -941,16 +997,7 @@ class Session {
|
|
|
941
997
|
m3u8 += "master" + profile.bw + ".m3u8;session=" + this._sessionId + "\n";
|
|
942
998
|
});
|
|
943
999
|
}
|
|
944
|
-
|
|
945
|
-
for (let i = 0; i < audioGroupIds.length; i++) {
|
|
946
|
-
let audioGroupId = audioGroupIds[i];
|
|
947
|
-
for (let j = 0; j < this._audioTracks.length; j++) {
|
|
948
|
-
let audioTrack = this._audioTracks[j];
|
|
949
|
-
m3u8 += `#EXT-X-STREAM-INF:BANDWIDTH=97000,CODECS="mp4a.40.2",AUDIO="${audioGroupId}"\n`;
|
|
950
|
-
m3u8 += `master-${audioGroupId}_${audioTrack.language}.m3u8;session=${this._sessionId}\n`;
|
|
951
|
-
}
|
|
952
|
-
}
|
|
953
|
-
}
|
|
1000
|
+
|
|
954
1001
|
this.produceEvent({
|
|
955
1002
|
type: 'NOW_PLAYING',
|
|
956
1003
|
data: {
|
|
@@ -1145,16 +1192,25 @@ class Session {
|
|
|
1145
1192
|
if (this.prevMediaSeqOffset.video === null) {
|
|
1146
1193
|
this.prevMediaSeqOffset.video = sessionState.mediaSeq;
|
|
1147
1194
|
}
|
|
1195
|
+
if (this.use_demuxed_audio) {
|
|
1196
|
+
if (this.prevVodMediaSeq.audio === null) {
|
|
1197
|
+
this.prevVodMediaSeq.audio = sessionState.vodMediaSeqAudio;
|
|
1198
|
+
}
|
|
1199
|
+
if (this.prevMediaSeqOffset.audio === null) {
|
|
1200
|
+
this.prevMediaSeqOffset.audio = sessionState.mediaSeqAudio;
|
|
1201
|
+
}
|
|
1202
|
+
}
|
|
1148
1203
|
// Clear Cache if prev count is HIGHER than current...
|
|
1149
1204
|
if (sessionState.vodMediaSeqVideo < this.prevVodMediaSeq.video) {
|
|
1150
1205
|
debug(`[${this._sessionId}]: state=VOD_PLAYING, current[${sessionState.vodMediaSeqVideo}], prev[${this.prevVodMediaSeq.video}], total[${currentVod.getLiveMediaSequencesCount()}]`);
|
|
1151
1206
|
await this._sessionState.clearCurrentVodCache();
|
|
1152
1207
|
currentVod = await this._sessionState.getCurrentVod();
|
|
1153
1208
|
this.prevVodMediaSeq.video = sessionState.vodMediaSeqVideo;
|
|
1209
|
+
this.prevVodMediaSeq.audio = sessionState.vodMediaSeqAudio;
|
|
1154
1210
|
}
|
|
1155
1211
|
} else {
|
|
1156
1212
|
// Handle edge case where Leader loaded next vod but Follower remained in state=VOD_PLAYING
|
|
1157
|
-
if (this.prevMediaSeqOffset.video !== null & sessionState.mediaSeq !== this.prevMediaSeqOffset.video) {
|
|
1213
|
+
if ((this.prevMediaSeqOffset.video !== null) & (sessionState.mediaSeq !== this.prevMediaSeqOffset.video)) {
|
|
1158
1214
|
debug(`[${this._sessionId}]: state=VOD_PLAYING, current[${sessionState.vodMediaSeqVideo}], prev[${this.prevVodMediaSeq.video}], total[${currentVod.getLiveMediaSequencesCount()}]`);
|
|
1159
1215
|
debug(`[${this._sessionId}]: mediaSeq offsets -> current[${sessionState.vodMediaSeqVideo}], prev[${this.prevVodMediaSeq.video}]`);
|
|
1160
1216
|
// Allow Follower to clear VodCache...
|
package/package.json
CHANGED
package/server-demux.ts
CHANGED
|
@@ -22,8 +22,8 @@ class RefAssetManager implements IAssetManager {
|
|
|
22
22
|
1: [
|
|
23
23
|
{
|
|
24
24
|
id: 1,
|
|
25
|
-
title: "
|
|
26
|
-
uri: "https://
|
|
25
|
+
title: "Sintel",
|
|
26
|
+
uri: "https://cdn.bitmovin.com/content/assets/sintel/hls/playlist.m3u8",
|
|
27
27
|
},
|
|
28
28
|
{
|
|
29
29
|
id: 2,
|
|
@@ -33,7 +33,7 @@ class RefAssetManager implements IAssetManager {
|
|
|
33
33
|
],
|
|
34
34
|
};
|
|
35
35
|
this.pos = {
|
|
36
|
-
1:
|
|
36
|
+
1: 0,
|
|
37
37
|
};
|
|
38
38
|
}
|
|
39
39
|
|
|
@@ -90,7 +90,10 @@ class RefChannelManager implements IChannelManager {
|
|
|
90
90
|
];
|
|
91
91
|
}
|
|
92
92
|
_getAudioTracks(): AudioTracks[] {
|
|
93
|
-
return [
|
|
93
|
+
return [
|
|
94
|
+
{ language: "en", name: "English" },
|
|
95
|
+
{ language: "sp", name: "Spanish" }
|
|
96
|
+
];
|
|
94
97
|
}
|
|
95
98
|
}
|
|
96
99
|
|