eyevinn-channel-engine 4.0.1 → 4.0.2
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 +97 -45
- package/dist/package.json +1 -1
- package/dist/server-demux.js +7 -4
- package/engine/session.js +82 -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,106 @@ 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*/, 8];
|
|
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*/, 8];
|
|
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
|
+
_a.label = 8;
|
|
942
|
+
case 8:
|
|
943
|
+
// local store the prev values
|
|
944
|
+
if (this.prevVodMediaSeq.audio === null) {
|
|
945
|
+
this.prevVodMediaSeq.audio = playheadState.vodMediaSeqAudio;
|
|
946
|
+
}
|
|
947
|
+
if (this.prevMediaSeqOffset.audio === null) {
|
|
948
|
+
this.prevMediaSeqOffset.audio = playheadState.mediaSeqAudio;
|
|
949
|
+
}
|
|
950
|
+
return [4 /*yield*/, this._sessionState.getCurrentVod()];
|
|
951
|
+
case 9:
|
|
952
|
+
currentVod = _a.sent();
|
|
953
|
+
if (!currentVod) return [3 /*break*/, 17];
|
|
954
|
+
if (!(playheadState.vodMediaSeqAudio < 2 || playheadState.mediaSeqAudio !== this.prevMediaSeqOffset.audio)) return [3 /*break*/, 13];
|
|
955
|
+
AGE_THRESH = 20 * 1000;
|
|
956
|
+
cacheAge = null;
|
|
957
|
+
if (this._sessionState.cache && this._sessionState.cache.currentVod.ts) {
|
|
958
|
+
cacheAge = Date.now() - this._sessionState.cache.currentVod.ts;
|
|
959
|
+
}
|
|
960
|
+
if (!(cacheAge !== null && cacheAge > AGE_THRESH)) return [3 /*break*/, 13];
|
|
961
|
+
return [4 /*yield*/, timer(500)];
|
|
962
|
+
case 10:
|
|
963
|
+
_a.sent();
|
|
964
|
+
debug("[".concat(this._sessionId, "]: While requesting audio manifest for ").concat(audioGroupId, "-").concat(audioLanguage, ", (mseq=").concat(playheadState.vodMediaSeqAudio, ")(vod cache age=").concat(cacheAge, ")"));
|
|
965
|
+
return [4 /*yield*/, this._sessionState.clearCurrentVodCache()];
|
|
966
|
+
case 11:
|
|
967
|
+
_a.sent(); // force reading up from shared store
|
|
968
|
+
return [4 /*yield*/, this._sessionState.getCurrentVod()];
|
|
969
|
+
case 12:
|
|
970
|
+
currentVod = _a.sent();
|
|
971
|
+
_a.label = 13;
|
|
972
|
+
case 13:
|
|
973
|
+
_a.trys.push([13, 14, , 16]);
|
|
974
|
+
manifestMseq = playheadState.mediaSeqAudio + playheadState.vodMediaSeqAudio;
|
|
975
|
+
manifestDseq = sessionState.discSeqAudio + currentVod.discontinuitiesAudio[playheadState.vodMediaSeqAudio];
|
|
976
|
+
if (currentVod.sequenceAlwaysContainNewSegments) {
|
|
977
|
+
mediaSequenceValue = currentVod.mediaSequenceValuesAudio[playheadState.vodMediaSeqAudio];
|
|
978
|
+
debug("[".concat(this._sessionId, "]: {").concat(mediaSequenceValue, "}_{").concat(currentVod.getLastSequenceMediaSequenceValueAudio(), "} AUDIO"));
|
|
979
|
+
manifestMseq = playheadState.mediaSeqAudio + mediaSequenceValue;
|
|
980
|
+
}
|
|
981
|
+
debug("[".concat(this._sessionId, "]: [").concat(playheadState.vodMediaSeqAudio, "]_[").concat(currentVod.getLiveMediaSequencesCount("audio"), "] AUDIO"));
|
|
982
|
+
m3u8_2 = currentVod.getLiveMediaAudioSequences(playheadState.mediaSeqAudio, audioGroupId, audioLanguage, playheadState.vodMediaSeqAudio, sessionState.discSeqAudio, this.targetDurationPadding, this.forceTargetDuration);
|
|
936
983
|
// # Case: current VOD does not have the selected track.
|
|
937
|
-
if (!
|
|
984
|
+
if (!m3u8_2) {
|
|
938
985
|
debug("[".concat(this._sessionId, "]: [").concat(playheadState.mediaSeqAudio + playheadState.vodMediaSeqAudio, "] Request Failed for current audio manifest for ").concat(audioGroupId, "-").concat(audioLanguage));
|
|
939
986
|
}
|
|
940
|
-
debug("[".concat(this._sessionId, "]: [").concat(
|
|
941
|
-
|
|
942
|
-
|
|
987
|
+
debug("[".concat(this._sessionId, "]: [").concat(manifestMseq, "][").concat(manifestDseq, "] Current audio manifest for ").concat(audioGroupId, "-").concat(audioLanguage, " requested"));
|
|
988
|
+
this.prevVodMediaSeq.audio = playheadState.vodMediaSeqAudio;
|
|
989
|
+
this.prevMediaSeqOffset.audio = playheadState.mediaSeqAudio;
|
|
990
|
+
return [2 /*return*/, m3u8_2];
|
|
991
|
+
case 14:
|
|
943
992
|
err_5 = _a.sent();
|
|
944
993
|
logerror(this._sessionId, err_5);
|
|
945
994
|
return [4 /*yield*/, this._sessionState.clearCurrentVodCache()];
|
|
946
|
-
case
|
|
995
|
+
case 15:
|
|
947
996
|
_a.sent(); // force reading up from shared store
|
|
948
997
|
throw new Error("Failed to generate audio manifest: " + JSON.stringify(playheadState));
|
|
949
|
-
case
|
|
950
|
-
case
|
|
951
|
-
case
|
|
998
|
+
case 16: return [3 /*break*/, 18];
|
|
999
|
+
case 17: throw new Error("Engine not ready");
|
|
1000
|
+
case 18: return [2 /*return*/];
|
|
952
1001
|
}
|
|
953
1002
|
});
|
|
954
1003
|
});
|
|
955
1004
|
};
|
|
956
1005
|
Session.prototype.incrementAsync = function (incOpts) {
|
|
957
1006
|
return __awaiter(this, void 0, void 0, function () {
|
|
958
|
-
var isLeader, sessionState, playheadState, currentVod, _a, leaderAction, _b,
|
|
1007
|
+
var isLeader, sessionState, playheadState, currentVod, _a, leaderAction, _b, m3u8_3, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, mediaSequenceValue, diffMs, m3u8;
|
|
959
1008
|
return __generator(this, function (_o) {
|
|
960
1009
|
switch (_o.label) {
|
|
961
1010
|
case 0: return [4 /*yield*/, this._tickAsync()];
|
|
@@ -1006,9 +1055,9 @@ var Session = /** @class */ (function () {
|
|
|
1006
1055
|
debug("[".concat(this._sessionId, "]: Return the last generated m3u8 to give the leader some time"));
|
|
1007
1056
|
return [4 /*yield*/, this._playheadState.getLastM3u8()];
|
|
1008
1057
|
case 12:
|
|
1009
|
-
|
|
1010
|
-
if (
|
|
1011
|
-
return [2 /*return*/,
|
|
1058
|
+
m3u8_3 = _o.sent();
|
|
1059
|
+
if (m3u8_3) {
|
|
1060
|
+
return [2 /*return*/, m3u8_3];
|
|
1012
1061
|
}
|
|
1013
1062
|
else {
|
|
1014
1063
|
debug("[".concat(this._sessionId, "]: We don't have any previously generated m3u8"));
|
|
@@ -1110,6 +1159,10 @@ var Session = /** @class */ (function () {
|
|
|
1110
1159
|
// Update Value for Previous Sequence
|
|
1111
1160
|
this.prevVodMediaSeq.video = playheadState.vodMediaSeqVideo;
|
|
1112
1161
|
this.prevMediaSeqOffset.video = playheadState.mediaSeq;
|
|
1162
|
+
if (this.use_demuxed_audio) {
|
|
1163
|
+
this.prevVodMediaSeq.audio = playheadState.vodMediaSeqAudio;
|
|
1164
|
+
this.prevMediaSeqOffset.audio = playheadState.mediaSeqAudio;
|
|
1165
|
+
}
|
|
1113
1166
|
m3u8 = currentVod.getLiveMediaSequences(playheadState.mediaSeq, 180000, playheadState.vodMediaSeqVideo, sessionState.discSeq);
|
|
1114
1167
|
return [4 /*yield*/, this._playheadState.setLastM3u8(m3u8)];
|
|
1115
1168
|
case 34:
|
|
@@ -1303,7 +1356,7 @@ var Session = /** @class */ (function () {
|
|
|
1303
1356
|
};
|
|
1304
1357
|
Session.prototype.getMasterManifestAsync = function (filter) {
|
|
1305
1358
|
return __awaiter(this, void 0, void 0, function () {
|
|
1306
|
-
var m3u8, currentVod, audioGroupIds, defaultAudioGroupId, hasClosedCaptions, i, audioGroupId, j, audioTrack, sessionProfile
|
|
1359
|
+
var m3u8, currentVod, audioGroupIds, defaultAudioGroupId, hasClosedCaptions, i, audioGroupId, j, audioTrack, sessionProfile;
|
|
1307
1360
|
var _this = this;
|
|
1308
1361
|
return __generator(this, function (_a) {
|
|
1309
1362
|
switch (_a.label) {
|
|
@@ -1359,16 +1412,6 @@ var Session = /** @class */ (function () {
|
|
|
1359
1412
|
m3u8 += "master" + profile.bw + ".m3u8;session=" + _this._sessionId + "\n";
|
|
1360
1413
|
});
|
|
1361
1414
|
}
|
|
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
1415
|
this.produceEvent({
|
|
1373
1416
|
type: 'NOW_PLAYING',
|
|
1374
1417
|
data: {
|
|
@@ -1659,6 +1702,14 @@ var Session = /** @class */ (function () {
|
|
|
1659
1702
|
if (this.prevMediaSeqOffset.video === null) {
|
|
1660
1703
|
this.prevMediaSeqOffset.video = sessionState.mediaSeq;
|
|
1661
1704
|
}
|
|
1705
|
+
if (this.use_demuxed_audio) {
|
|
1706
|
+
if (this.prevVodMediaSeq.audio === null) {
|
|
1707
|
+
this.prevVodMediaSeq.audio = sessionState.vodMediaSeqAudio;
|
|
1708
|
+
}
|
|
1709
|
+
if (this.prevMediaSeqOffset.audio === null) {
|
|
1710
|
+
this.prevMediaSeqOffset.audio = sessionState.mediaSeqAudio;
|
|
1711
|
+
}
|
|
1712
|
+
}
|
|
1662
1713
|
if (!(sessionState.vodMediaSeqVideo < this.prevVodMediaSeq.video)) return [3 /*break*/, 30];
|
|
1663
1714
|
debug("[".concat(this._sessionId, "]: state=VOD_PLAYING, current[").concat(sessionState.vodMediaSeqVideo, "], prev[").concat(this.prevVodMediaSeq.video, "], total[").concat(currentVod.getLiveMediaSequencesCount(), "]"));
|
|
1664
1715
|
return [4 /*yield*/, this._sessionState.clearCurrentVodCache()];
|
|
@@ -1668,11 +1719,12 @@ var Session = /** @class */ (function () {
|
|
|
1668
1719
|
case 29:
|
|
1669
1720
|
currentVod = _2.sent();
|
|
1670
1721
|
this.prevVodMediaSeq.video = sessionState.vodMediaSeqVideo;
|
|
1722
|
+
this.prevVodMediaSeq.audio = sessionState.vodMediaSeqAudio;
|
|
1671
1723
|
_2.label = 30;
|
|
1672
1724
|
case 30: return [3 /*break*/, 32];
|
|
1673
1725
|
case 31:
|
|
1674
1726
|
// 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) {
|
|
1727
|
+
if ((this.prevMediaSeqOffset.video !== null) & (sessionState.mediaSeq !== this.prevMediaSeqOffset.video)) {
|
|
1676
1728
|
debug("[".concat(this._sessionId, "]: state=VOD_PLAYING, current[").concat(sessionState.vodMediaSeqVideo, "], prev[").concat(this.prevVodMediaSeq.video, "], total[").concat(currentVod.getLiveMediaSequencesCount(), "]"));
|
|
1677
1729
|
debug("[".concat(this._sessionId, "]: mediaSeq offsets -> current[").concat(sessionState.vodMediaSeqVideo, "], prev[").concat(this.prevVodMediaSeq.video, "]"));
|
|
1678
1730
|
// 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,75 @@ class Session {
|
|
|
654
648
|
if (!this._sessionState) {
|
|
655
649
|
throw new Error('Session not ready');
|
|
656
650
|
}
|
|
657
|
-
|
|
658
|
-
const sessionState = await this._sessionState.getValues(["discSeqAudio"]);
|
|
651
|
+
let currentVod = null;
|
|
652
|
+
const sessionState = await this._sessionState.getValues(["discSeqAudio", "vodMediaSeqAudio"]);
|
|
659
653
|
const playheadState = await this._playheadState.getValues(["mediaSeqAudio", "vodMediaSeqAudio"]);
|
|
660
|
-
|
|
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
|
+
}
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
// local store the prev values
|
|
673
|
+
if (this.prevVodMediaSeq.audio === null) {
|
|
674
|
+
this.prevVodMediaSeq.audio = playheadState.vodMediaSeqAudio;
|
|
675
|
+
}
|
|
676
|
+
if (this.prevMediaSeqOffset.audio === null) {
|
|
677
|
+
this.prevMediaSeqOffset.audio = playheadState.mediaSeqAudio;
|
|
678
|
+
}
|
|
679
|
+
currentVod = await this._sessionState.getCurrentVod();
|
|
661
680
|
if (currentVod) {
|
|
681
|
+
// condition suggesting that a new vod should exist
|
|
682
|
+
if (playheadState.vodMediaSeqAudio < 2 || playheadState.mediaSeqAudio !== this.prevMediaSeqOffset.audio) {
|
|
683
|
+
const AGE_THRESH = 20 * 1000;
|
|
684
|
+
let cacheAge = null;
|
|
685
|
+
if (this._sessionState.cache && this._sessionState.cache.currentVod.ts) {
|
|
686
|
+
cacheAge = Date.now() - this._sessionState.cache.currentVod.ts;
|
|
687
|
+
}
|
|
688
|
+
if (cacheAge !== null && cacheAge > AGE_THRESH) {
|
|
689
|
+
await timer(500);
|
|
690
|
+
debug(`[${this._sessionId}]: While requesting audio manifest for ${audioGroupId}-${audioLanguage}, (mseq=${playheadState.vodMediaSeqAudio})(vod cache age=${cacheAge})`);
|
|
691
|
+
await this._sessionState.clearCurrentVodCache(); // force reading up from shared store
|
|
692
|
+
currentVod = await this._sessionState.getCurrentVod();
|
|
693
|
+
}
|
|
694
|
+
}
|
|
662
695
|
try {
|
|
663
|
-
|
|
696
|
+
let manifestMseq = playheadState.mediaSeqAudio + playheadState.vodMediaSeqAudio;
|
|
697
|
+
let manifestDseq = sessionState.discSeqAudio + currentVod.discontinuitiesAudio[playheadState.vodMediaSeqAudio];
|
|
698
|
+
if (currentVod.sequenceAlwaysContainNewSegments) {
|
|
699
|
+
const mediaSequenceValue = currentVod.mediaSequenceValuesAudio[playheadState.vodMediaSeqAudio];
|
|
700
|
+
debug(`[${this._sessionId}]: {${mediaSequenceValue}}_{${currentVod.getLastSequenceMediaSequenceValueAudio()}} AUDIO`);
|
|
701
|
+
manifestMseq = playheadState.mediaSeqAudio + mediaSequenceValue;
|
|
702
|
+
}
|
|
703
|
+
debug(`[${this._sessionId}]: [${playheadState.vodMediaSeqAudio}]_[${currentVod.getLiveMediaSequencesCount("audio")}] AUDIO`);
|
|
704
|
+
const m3u8 = currentVod.getLiveMediaAudioSequences(
|
|
705
|
+
playheadState.mediaSeqAudio,
|
|
706
|
+
audioGroupId,
|
|
707
|
+
audioLanguage,
|
|
708
|
+
playheadState.vodMediaSeqAudio,
|
|
709
|
+
sessionState.discSeqAudio,
|
|
710
|
+
this.targetDurationPadding,
|
|
711
|
+
this.forceTargetDuration
|
|
712
|
+
);
|
|
664
713
|
// # Case: current VOD does not have the selected track.
|
|
665
714
|
if (!m3u8) {
|
|
666
715
|
debug(`[${this._sessionId}]: [${playheadState.mediaSeqAudio + playheadState.vodMediaSeqAudio}] Request Failed for current audio manifest for ${audioGroupId}-${audioLanguage}`);
|
|
667
716
|
}
|
|
668
|
-
debug(`[${this._sessionId}]: [${
|
|
717
|
+
debug(`[${this._sessionId}]: [${manifestMseq}][${manifestDseq}] Current audio manifest for ${audioGroupId}-${audioLanguage} requested`);
|
|
718
|
+
this.prevVodMediaSeq.audio = playheadState.vodMediaSeqAudio;
|
|
719
|
+
this.prevMediaSeqOffset.audio = playheadState.mediaSeqAudio;
|
|
669
720
|
return m3u8;
|
|
670
721
|
} catch (err) {
|
|
671
722
|
logerror(this._sessionId, err);
|
|
@@ -715,7 +766,7 @@ class Session {
|
|
|
715
766
|
}
|
|
716
767
|
this.isAllowedToClearVodCache = true;
|
|
717
768
|
}
|
|
718
|
-
} else {
|
|
769
|
+
} else {
|
|
719
770
|
sessionState.vodMediaSeqVideo = await this._sessionState.increment("vodMediaSeqVideo");
|
|
720
771
|
if (incOpts) {
|
|
721
772
|
sessionState.vodMediaSeqAudio = await this._sessionState.increment("vodMediaSeqAudio", incOpts.audio);
|
|
@@ -776,6 +827,10 @@ class Session {
|
|
|
776
827
|
// Update Value for Previous Sequence
|
|
777
828
|
this.prevVodMediaSeq.video = playheadState.vodMediaSeqVideo;
|
|
778
829
|
this.prevMediaSeqOffset.video = playheadState.mediaSeq;
|
|
830
|
+
if (this.use_demuxed_audio) {
|
|
831
|
+
this.prevVodMediaSeq.audio = playheadState.vodMediaSeqAudio;
|
|
832
|
+
this.prevMediaSeqOffset.audio = playheadState.mediaSeqAudio;
|
|
833
|
+
}
|
|
779
834
|
|
|
780
835
|
let m3u8 = currentVod.getLiveMediaSequences(playheadState.mediaSeq, 180000, playheadState.vodMediaSeqVideo, sessionState.discSeq);
|
|
781
836
|
await this._playheadState.setLastM3u8(m3u8);
|
|
@@ -941,16 +996,7 @@ class Session {
|
|
|
941
996
|
m3u8 += "master" + profile.bw + ".m3u8;session=" + this._sessionId + "\n";
|
|
942
997
|
});
|
|
943
998
|
}
|
|
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
|
-
}
|
|
999
|
+
|
|
954
1000
|
this.produceEvent({
|
|
955
1001
|
type: 'NOW_PLAYING',
|
|
956
1002
|
data: {
|
|
@@ -1145,16 +1191,25 @@ class Session {
|
|
|
1145
1191
|
if (this.prevMediaSeqOffset.video === null) {
|
|
1146
1192
|
this.prevMediaSeqOffset.video = sessionState.mediaSeq;
|
|
1147
1193
|
}
|
|
1194
|
+
if (this.use_demuxed_audio) {
|
|
1195
|
+
if (this.prevVodMediaSeq.audio === null) {
|
|
1196
|
+
this.prevVodMediaSeq.audio = sessionState.vodMediaSeqAudio;
|
|
1197
|
+
}
|
|
1198
|
+
if (this.prevMediaSeqOffset.audio === null) {
|
|
1199
|
+
this.prevMediaSeqOffset.audio = sessionState.mediaSeqAudio;
|
|
1200
|
+
}
|
|
1201
|
+
}
|
|
1148
1202
|
// Clear Cache if prev count is HIGHER than current...
|
|
1149
1203
|
if (sessionState.vodMediaSeqVideo < this.prevVodMediaSeq.video) {
|
|
1150
1204
|
debug(`[${this._sessionId}]: state=VOD_PLAYING, current[${sessionState.vodMediaSeqVideo}], prev[${this.prevVodMediaSeq.video}], total[${currentVod.getLiveMediaSequencesCount()}]`);
|
|
1151
1205
|
await this._sessionState.clearCurrentVodCache();
|
|
1152
1206
|
currentVod = await this._sessionState.getCurrentVod();
|
|
1153
1207
|
this.prevVodMediaSeq.video = sessionState.vodMediaSeqVideo;
|
|
1208
|
+
this.prevVodMediaSeq.audio = sessionState.vodMediaSeqAudio;
|
|
1154
1209
|
}
|
|
1155
1210
|
} else {
|
|
1156
1211
|
// 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) {
|
|
1212
|
+
if ((this.prevMediaSeqOffset.video !== null) & (sessionState.mediaSeq !== this.prevMediaSeqOffset.video)) {
|
|
1158
1213
|
debug(`[${this._sessionId}]: state=VOD_PLAYING, current[${sessionState.vodMediaSeqVideo}], prev[${this.prevVodMediaSeq.video}], total[${currentVod.getLiveMediaSequencesCount()}]`);
|
|
1159
1214
|
debug(`[${this._sessionId}]: mediaSeq offsets -> current[${sessionState.vodMediaSeqVideo}], prev[${this.prevVodMediaSeq.video}]`);
|
|
1160
1215
|
// 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
|
|