eyevinn-channel-engine 4.3.9 → 4.3.11

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.
@@ -97,7 +97,7 @@ declare class Session {
97
97
  }>;
98
98
  getCurrentMediaManifestAsync(bw: any, playbackSessionId: any): Promise<any>;
99
99
  getCurrentAudioManifestAsync(audioGroupId: any, audioLanguage: any, playbackSessionId: any): Promise<any>;
100
- getCurrentSubtitleManifestAsync(subtitleGroupId: any, subtitleLanguage: any): Promise<any>;
100
+ getCurrentSubtitleManifestAsync(subtitleGroupId: any, subtitleLanguage: any, playbackSessionId: any): Promise<any>;
101
101
  incrementAsync(): Promise<any>;
102
102
  getMediaManifestAsync(bw: any, opts: any): Promise<any>;
103
103
  getAudioManifestAsync(audioGroupId: any, audioLanguage: any, opts: any): Promise<any>;
@@ -128,4 +128,6 @@ declare class Session {
128
128
  position: number;
129
129
  diff: string;
130
130
  }>;
131
+ _getM3u8File(variantType: any, variantKey: any, playbackSessionId: any): Promise<any>;
132
+ _getCurrentVodData(dataName: any, variantType: any, vod: any): any;
131
133
  }
@@ -794,300 +794,45 @@ var Session = /** @class */ (function () {
794
794
  };
795
795
  Session.prototype.getCurrentMediaManifestAsync = function (bw, playbackSessionId) {
796
796
  return __awaiter(this, void 0, void 0, function () {
797
- var tries, sessionState, playheadState, state, DELAY_TIME_MS, ACTION, isLeader, diffMs, currentVod, manifestMseq, manifestDseq, mediaSequenceValue, m3u8_1, err_4;
797
+ var m3u8;
798
798
  return __generator(this, function (_a) {
799
- switch (_a.label) {
800
- case 0:
801
- if (!this._sessionState) {
802
- throw new Error('Session not ready');
803
- }
804
- tries = 12;
805
- _a.label = 1;
806
- case 1:
807
- if (!(tries > 0 && this.leaderIsSettingNextVod)) return [3 /*break*/, 3];
808
- debug("[".concat(this._sessionId, "]: Leader is setting the next vod. Waiting 500ms_").concat(tries));
809
- return [4 /*yield*/, timer(500)];
810
- case 2:
811
- _a.sent();
812
- tries--;
813
- return [3 /*break*/, 1];
814
- case 3: return [4 /*yield*/, this._sessionState.getValues(["vodMediaSeqVideo", "discSeq"])];
815
- case 4:
816
- sessionState = _a.sent();
817
- return [4 /*yield*/, this._playheadState.getValues(["mediaSeq", "vodMediaSeqVideo"])];
818
- case 5:
819
- playheadState = _a.sent();
820
- if (this.prevVodMediaSeq.video === null) {
821
- this.prevVodMediaSeq.video = playheadState.vodMediaSeqVideo;
822
- }
823
- if (this.prevMediaSeqOffset.video === null) {
824
- this.prevMediaSeqOffset.video = playheadState.mediaSeq;
825
- }
826
- if (!(playheadState.vodMediaSeqVideo > sessionState.vodMediaSeqVideo || (playheadState.vodMediaSeqVideo < sessionState.vodMediaSeqVideo && playheadState.mediaSeq === this.prevMediaSeqOffset.video))) return [3 /*break*/, 9];
827
- return [4 /*yield*/, this._sessionState.get("state")];
828
- case 6:
829
- state = _a.sent();
830
- DELAY_TIME_MS = 1000;
831
- ACTION = [SessionState.VOD_RELOAD_INIT, SessionState.VOD_RELOAD_INITIATING].includes(state) ? "Reloaded" : "Loaded Next";
832
- 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"));
833
- return [4 /*yield*/, timer(DELAY_TIME_MS)];
834
- case 7:
835
- _a.sent();
836
- return [4 /*yield*/, this._playheadState.getValues(["mediaSeq", "vodMediaSeqVideo"])];
837
- case 8:
838
- playheadState = _a.sent();
839
- _a.label = 9;
840
- case 9:
841
- if (!(playheadState.vodMediaSeqVideo < 2 || playheadState.mediaSeq !== this.prevMediaSeqOffset.video)) return [3 /*break*/, 14];
842
- debug("[".concat(this._sessionId, "]: current[").concat(playheadState.vodMediaSeqVideo, "]_prev[").concat(this.prevVodMediaSeq.video, "]"));
843
- debug("[".concat(this._sessionId, "]: current-offset[").concat(playheadState.mediaSeq, "]_prev-offset[").concat(this.prevMediaSeqOffset.video, "]"));
844
- // If true, then we have not updated the prev-values and not cleared the cache yet.
845
- if (playheadState.vodMediaSeqVideo < this.prevVodMediaSeq.video || playheadState.mediaSeq !== this.prevMediaSeqOffset.video) {
846
- this.isAllowedToClearVodCache = true;
847
- }
848
- return [4 /*yield*/, this._sessionStateStore.isLeader(this._instanceId)];
849
- case 10:
850
- isLeader = _a.sent();
851
- if (!(!isLeader && this.isAllowedToClearVodCache)) return [3 /*break*/, 13];
852
- 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."));
853
- return [4 /*yield*/, this._sessionState.clearCurrentVodCache()];
854
- case 11:
855
- _a.sent();
856
- this.isAllowedToClearVodCache = false;
857
- return [4 /*yield*/, this._playheadState.get("diffCompensation")];
858
- case 12:
859
- diffMs = _a.sent();
860
- if (diffMs) {
861
- this.diffCompensation = diffMs;
862
- debug("[".concat(this._sessionId, "]: Setting diffCompensation->").concat(this.diffCompensation));
863
- if (this.diffCompensation) {
864
- this.timePositionOffset = this.diffCompensation;
865
- cloudWatchLog(!this.cloudWatchLogging, 'engine-session', { event: 'timePositionOffsetUpdated', channel: this._sessionId, offsetMs: this.timePositionOffset });
866
- }
867
- else {
868
- this.timePositionOffset = 0;
869
- }
870
- }
871
- _a.label = 13;
872
- case 13: return [3 /*break*/, 15];
873
- case 14:
874
- this.isAllowedToClearVodCache = true;
875
- _a.label = 15;
876
- case 15: return [4 /*yield*/, this._sessionState.getCurrentVod()];
877
- case 16:
878
- currentVod = _a.sent();
879
- if (!currentVod) return [3 /*break*/, 21];
880
- _a.label = 17;
881
- case 17:
882
- _a.trys.push([17, 18, , 20]);
883
- manifestMseq = playheadState.mediaSeq + playheadState.vodMediaSeqVideo;
884
- manifestDseq = sessionState.discSeq + currentVod.discontinuities[playheadState.vodMediaSeqVideo];
885
- if (currentVod.sequenceAlwaysContainNewSegments) {
886
- mediaSequenceValue = currentVod.mediaSequenceValues[playheadState.vodMediaSeqVideo];
887
- debug("[".concat(this._sessionId, "]: {").concat(mediaSequenceValue, "}_{").concat(currentVod.getLastSequenceMediaSequenceValue(), "}"));
888
- manifestMseq = playheadState.mediaSeq + mediaSequenceValue;
889
- }
890
- debug("[".concat(this._sessionId, "]: [").concat(playheadState.vodMediaSeqVideo, "]_[").concat(currentVod.getLiveMediaSequencesCount(), "]"));
891
- m3u8_1 = currentVod.getLiveMediaSequences(playheadState.mediaSeq, bw, playheadState.vodMediaSeqVideo, sessionState.discSeq, this.targetDurationPadding, this.forceTargetDuration);
892
- debug("[".concat(this._sessionId, "]: [").concat(manifestMseq, "][").concat(manifestDseq, "][+").concat(this.targetDurationPadding || 0, "] Current media manifest for ").concat(bw, " requested"));
893
- this.prevVodMediaSeq.video = playheadState.vodMediaSeqVideo;
894
- this.prevMediaSeqOffset.video = playheadState.mediaSeq;
895
- return [2 /*return*/, m3u8_1];
896
- case 18:
897
- err_4 = _a.sent();
898
- logerror(this._sessionId, err_4);
899
- return [4 /*yield*/, this._sessionState.clearCurrentVodCache()];
900
- case 19:
901
- _a.sent(); // force reading up from shared store
902
- throw new Error("Failed to generate manifest: " + JSON.stringify(playheadState));
903
- case 20: return [3 /*break*/, 22];
904
- case 21: throw new Error("Engine not ready");
905
- case 22: return [2 /*return*/];
799
+ if (!this._sessionState) {
800
+ throw new Error('Session not ready');
906
801
  }
802
+ m3u8 = this._getM3u8File("video", bw, playbackSessionId);
803
+ return [2 /*return*/, m3u8];
907
804
  });
908
805
  });
909
806
  };
910
807
  Session.prototype.getCurrentAudioManifestAsync = function (audioGroupId, audioLanguage, playbackSessionId) {
911
808
  return __awaiter(this, void 0, void 0, function () {
912
- var currentVod, sessionState, playheadState, state, DELAY_TIME_MS, ACTION, manifestMseq, manifestDseq, mediaSequenceValue, m3u8_2, err_5;
809
+ var variantKey, m3u8;
913
810
  return __generator(this, function (_a) {
914
- switch (_a.label) {
915
- case 0:
916
- if (!this._sessionState) {
917
- throw new Error('Session not ready');
918
- }
919
- currentVod = null;
920
- return [4 /*yield*/, this._sessionState.getValues(["discSeqAudio", "vodMediaSeqAudio"])];
921
- case 1:
922
- sessionState = _a.sent();
923
- return [4 /*yield*/, this._playheadState.getValues(["mediaSeqAudio", "vodMediaSeqAudio", "playheadRef"])];
924
- case 2:
925
- playheadState = _a.sent();
926
- if (!(playheadState.vodMediaSeqAudio > sessionState.vodMediaSeqAudio || (playheadState.vodMediaSeqAudio < sessionState.vodMediaSeqAudio && playheadState.mediaSeqAudio === this.prevMediaSeqOffset.audio))) return [3 /*break*/, 6];
927
- return [4 /*yield*/, this._sessionState.get("state")];
928
- case 3:
929
- state = _a.sent();
930
- DELAY_TIME_MS = 1000;
931
- ACTION = [SessionState.VOD_RELOAD_INIT, SessionState.VOD_RELOAD_INITIATING].includes(state) ? "Reloaded" : "Loaded Next";
932
- 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"));
933
- return [4 /*yield*/, timer(DELAY_TIME_MS)];
934
- case 4:
935
- _a.sent();
936
- return [4 /*yield*/, this._playheadState.getValues(["mediaSeqAudio", "vodMediaSeqAudio"])];
937
- case 5:
938
- playheadState = _a.sent();
939
- _a.label = 6;
940
- case 6:
941
- // local store the prev values
942
- if (this.prevVodMediaSeq.audio === null) {
943
- this.prevVodMediaSeq.audio = playheadState.vodMediaSeqAudio;
944
- }
945
- if (this.prevMediaSeqOffset.audio === null) {
946
- this.prevMediaSeqOffset.audio = playheadState.mediaSeqAudio;
947
- }
948
- return [4 /*yield*/, this._sessionState.getCurrentVod()];
949
- case 7:
950
- currentVod = _a.sent();
951
- if (!currentVod) return [3 /*break*/, 15];
952
- if (!(playheadState.vodMediaSeqAudio < 2 || playheadState.mediaSeqAudio !== this.prevMediaSeqOffset.audio)) return [3 /*break*/, 11];
953
- if (!(playheadState.playheadRef > this.currentPlayheadRef)) return [3 /*break*/, 11];
954
- return [4 /*yield*/, timer(500)];
955
- case 8:
956
- _a.sent();
957
- this.currentPlayheadRef = playheadState.playheadRef;
958
- debug("[".concat(this._sessionId, "]: While requesting audio manifest for ").concat(audioGroupId, "-").concat(audioLanguage, ", (mseq=").concat(playheadState.vodMediaSeqAudio, ")"));
959
- return [4 /*yield*/, this._sessionState.clearCurrentVodCache()];
960
- case 9:
961
- _a.sent(); // force reading up from shared store
962
- return [4 /*yield*/, this._sessionState.getCurrentVod()];
963
- case 10:
964
- currentVod = _a.sent();
965
- _a.label = 11;
966
- case 11:
967
- _a.trys.push([11, 12, , 14]);
968
- manifestMseq = playheadState.mediaSeqAudio + playheadState.vodMediaSeqAudio;
969
- manifestDseq = sessionState.discSeqAudio + currentVod.discontinuitiesAudio[playheadState.vodMediaSeqAudio];
970
- if (currentVod.sequenceAlwaysContainNewSegments) {
971
- mediaSequenceValue = currentVod.mediaSequenceValuesAudio[playheadState.vodMediaSeqAudio];
972
- debug("[".concat(this._sessionId, "]: {").concat(mediaSequenceValue, "}_{").concat(currentVod.getLastSequenceMediaSequenceValueAudio(), "} AUDIO"));
973
- manifestMseq = playheadState.mediaSeqAudio + mediaSequenceValue;
974
- }
975
- debug("[".concat(this._sessionId, "]: [").concat(playheadState.vodMediaSeqAudio, "]_[").concat(currentVod.getLiveMediaSequencesCount("audio"), "] AUDIO (").concat(audioGroupId, ")"));
976
- m3u8_2 = currentVod.getLiveMediaAudioSequences(playheadState.mediaSeqAudio, audioGroupId, audioLanguage, playheadState.vodMediaSeqAudio, sessionState.discSeqAudio, this.targetDurationPadding, this.forceTargetDuration);
977
- // # Case: current VOD does not have the selected track.
978
- if (!m3u8_2) {
979
- debug("[".concat(this._sessionId, "]: [").concat(playheadState.mediaSeqAudio + playheadState.vodMediaSeqAudio, "] Request Failed for current audio manifest for ").concat(audioGroupId, "-").concat(audioLanguage));
980
- }
981
- debug("[".concat(this._sessionId, "]: [").concat(manifestMseq, "][").concat(manifestDseq, "] Current audio manifest for ").concat(audioGroupId, "-").concat(audioLanguage, " requested"));
982
- this.prevVodMediaSeq.audio = playheadState.vodMediaSeqAudio;
983
- this.prevMediaSeqOffset.audio = playheadState.mediaSeqAudio;
984
- return [2 /*return*/, m3u8_2];
985
- case 12:
986
- err_5 = _a.sent();
987
- logerror(this._sessionId, err_5);
988
- return [4 /*yield*/, this._sessionState.clearCurrentVodCache()];
989
- case 13:
990
- _a.sent(); // force reading up from shared store
991
- throw new Error("Failed to generate audio manifest: " + JSON.stringify(playheadState));
992
- case 14: return [3 /*break*/, 16];
993
- case 15: throw new Error("Engine not ready");
994
- case 16: return [2 /*return*/];
811
+ if (!this._sessionState) {
812
+ throw new Error('Session not ready');
995
813
  }
814
+ variantKey = JSON.stringify({ groupId: audioGroupId, lang: audioLanguage });
815
+ m3u8 = this._getM3u8File("audio", variantKey, playbackSessionId);
816
+ return [2 /*return*/, m3u8];
996
817
  });
997
818
  });
998
819
  };
999
- Session.prototype.getCurrentSubtitleManifestAsync = function (subtitleGroupId, subtitleLanguage) {
820
+ Session.prototype.getCurrentSubtitleManifestAsync = function (subtitleGroupId, subtitleLanguage, playbackSessionId) {
1000
821
  return __awaiter(this, void 0, void 0, function () {
1001
- var currentVod, sessionState, playheadState, state, DELAY_TIME_MS, ACTION, manifestMseq, manifestDseq, mediaSequenceValue, m3u8_3, err_6;
822
+ var variantKey, m3u8;
1002
823
  return __generator(this, function (_a) {
1003
- switch (_a.label) {
1004
- case 0:
1005
- if (!this._sessionState) {
1006
- throw new Error('Session not ready');
1007
- }
1008
- currentVod = null;
1009
- return [4 /*yield*/, this._sessionState.getValues(["discSeqSubtitle", "vodMediaSeqSubtitle"])];
1010
- case 1:
1011
- sessionState = _a.sent();
1012
- return [4 /*yield*/, this._playheadState.getValues(["mediaSeqSubtitle", "vodMediaSeqSubtitle", "playheadRef"])];
1013
- case 2:
1014
- playheadState = _a.sent();
1015
- if (!(playheadState.vodMediaSeqSubtitle > sessionState.vodMediaSeqSubtitle || (playheadState.vodMediaSeqSubtitle < sessionState.vodMediaSeqSubtitle && playheadState.mediaSeqSubtitle === this.prevMediaSeqOffset.subtitle))) return [3 /*break*/, 6];
1016
- return [4 /*yield*/, this._sessionState.get("state")];
1017
- case 3:
1018
- state = _a.sent();
1019
- DELAY_TIME_MS = 1000;
1020
- ACTION = [SessionState.VOD_RELOAD_INIT, SessionState.VOD_RELOAD_INITIATING].includes(state) ? "Reloaded" : "Loaded Next";
1021
- debug("[".concat(this._sessionId, "]: Recently ").concat(ACTION, " Vod. PlayheadState not up-to-date (").concat(playheadState.vodMediaSeqSubtitle, "_").concat(sessionState.vodMediaSeqSubtitle, "). Waiting ").concat(DELAY_TIME_MS, "ms before reading from store again"));
1022
- return [4 /*yield*/, timer(DELAY_TIME_MS)];
1023
- case 4:
1024
- _a.sent();
1025
- return [4 /*yield*/, this._playheadState.getValues(["mediaSeqSubtitle", "vodMediaSeqSubtitle"])];
1026
- case 5:
1027
- playheadState = _a.sent();
1028
- _a.label = 6;
1029
- case 6:
1030
- // local store the prev values
1031
- if (this.prevVodMediaSeq.subtitle === null) {
1032
- this.prevVodMediaSeq.subtitle = playheadState.vodMediaSeqSubtitle;
1033
- }
1034
- if (this.prevMediaSeqOffset.subtitle === null) {
1035
- this.prevMediaSeqOffset.subtitle = playheadState.mediaSeqSubtitle;
1036
- }
1037
- return [4 /*yield*/, this._sessionState.getCurrentVod()];
1038
- case 7:
1039
- currentVod = _a.sent();
1040
- if (!currentVod) return [3 /*break*/, 15];
1041
- if (!(playheadState.vodMediaSeqSubtitle < 2 || playheadState.mediaSeqSubtitle !== this.prevMediaSeqOffset.subtitle)) return [3 /*break*/, 11];
1042
- if (!(playheadState.playheadRef > this.currentPlayheadRef)) return [3 /*break*/, 11];
1043
- return [4 /*yield*/, timer(500)];
1044
- case 8:
1045
- _a.sent();
1046
- this.currentPlayheadRef = playheadState.playheadRef;
1047
- debug("[".concat(this._sessionId, "]: While requesting subtitle manifest for ").concat(subtitleGroupId, "-").concat(subtitleLanguage, ", (mseq=").concat(playheadState.vodMediaSeqSubtitle, ")"));
1048
- return [4 /*yield*/, this._sessionState.clearCurrentVodCache()];
1049
- case 9:
1050
- _a.sent(); // force reading up from shared store
1051
- return [4 /*yield*/, this._sessionState.getCurrentVod()];
1052
- case 10:
1053
- currentVod = _a.sent();
1054
- _a.label = 11;
1055
- case 11:
1056
- _a.trys.push([11, 12, , 14]);
1057
- manifestMseq = playheadState.mediaSeqSubtitle + playheadState.vodMediaSeqSubtitle;
1058
- manifestDseq = sessionState.discSeqSubtitle + currentVod.discontinuitiesSubtitle[playheadState.vodMediaSeqSubtitle];
1059
- if (currentVod.sequenceAlwaysContainNewSegments) {
1060
- mediaSequenceValue = currentVod.mediaSequenceValuesSubtitle[playheadState.vodMediaSeqSubtitle];
1061
- debug("[".concat(this._sessionId, "]: {").concat(mediaSequenceValue, "}_{").concat(currentVod.getLastSequenceMediaSequenceValueSubtitle(), "} SUBTITLES"));
1062
- manifestMseq = playheadState.mediaSeqSubtitle + mediaSequenceValue;
1063
- }
1064
- debug("[".concat(this._sessionId, "]: [").concat(playheadState.vodMediaSeqSubtitle, "]_[").concat(currentVod.getLiveMediaSequencesCount("subtitle"), "] SUBTITLES (").concat(subtitleGroupId, ")"));
1065
- m3u8_3 = currentVod.getLiveMediaSubtitleSequences(playheadState.mediaSeqSubtitle, subtitleGroupId, subtitleLanguage, playheadState.vodMediaSeqSubtitle, sessionState.discSeqSubtitle, this.targetDurationPadding, this.forceTargetDuration);
1066
- // # Case: current VOD does not have the selected track.
1067
- if (!m3u8_3) {
1068
- debug("[".concat(this._sessionId, "]: [").concat(playheadState.mediaSeqSubtitle + playheadState.vodMediaSeqSubtitle, "] Request Failed for current subtitle manifest for ").concat(subtitleGroupId, "-").concat(subtitleLanguage));
1069
- }
1070
- debug("[".concat(this._sessionId, "]: [").concat(manifestMseq, "][").concat(manifestDseq, "] Current subtitle manifest for ").concat(subtitleGroupId, "-").concat(subtitleLanguage, " requested"));
1071
- this.prevVodMediaSeq.subtitle = playheadState.vodMediaSeqSubtitle;
1072
- this.prevMediaSeqOffset.subtitle = playheadState.mediaSeqSubtitle;
1073
- return [2 /*return*/, m3u8_3];
1074
- case 12:
1075
- err_6 = _a.sent();
1076
- logerror(this._sessionId, err_6);
1077
- return [4 /*yield*/, this._sessionState.clearCurrentVodCache()];
1078
- case 13:
1079
- _a.sent(); // force reading up from shared store
1080
- throw new Error("Failed to generate subtitle manifest: " + JSON.stringify(playheadState));
1081
- case 14: return [3 /*break*/, 16];
1082
- case 15: throw new Error("Engine not ready");
1083
- case 16: return [2 /*return*/];
824
+ if (!this._sessionState) {
825
+ throw new Error('Session not ready');
1084
826
  }
827
+ variantKey = JSON.stringify({ groupId: subtitleGroupId, lang: subtitleLanguage });
828
+ m3u8 = this._getM3u8File("subtitle", variantKey, playbackSessionId);
829
+ return [2 /*return*/, m3u8];
1085
830
  });
1086
831
  });
1087
832
  };
1088
833
  Session.prototype.incrementAsync = function () {
1089
834
  return __awaiter(this, void 0, void 0, function () {
1090
- var isLeader, sessionState, playheadState, currentVod, _a, isOldVod, nextState, leaderAction, leaderState, _b, m3u8_4, _c, playheadPosVideoMs, playheadAudio, playheadSubtitle, audioSeqLastIdx, sessionStateObj, _d, playheadPosVideo, _e, subtitleSeqLastIdx, sessionStateObj, _f, newSessionState, updatedValues, updatedPlayhead, mediaSequenceValue, audioInfo, mediaSequenceValueAudio, subsInfo, mediaSequenceValueSubtitle, diffMs, m3u8;
835
+ var isLeader, sessionState, playheadState, currentVod, _a, isOldVod, nextState, leaderAction, leaderState, _b, m3u8_1, _c, playheadPosVideoMs, playheadAudio, playheadSubtitle, audioSeqLastIdx, sessionStateObj, _d, playheadPosVideo, _e, subtitleSeqLastIdx, sessionStateObj, _f, newSessionState, updatedValues, updatedPlayhead, mediaSequenceValue, audioInfo, mediaSequenceValueAudio, subsInfo, mediaSequenceValueSubtitle, diffMs, m3u8;
1091
836
  return __generator(this, function (_g) {
1092
837
  switch (_g.label) {
1093
838
  case 0: return [4 /*yield*/, this._tickAsync()];
@@ -1145,9 +890,9 @@ var Session = /** @class */ (function () {
1145
890
  debug("[".concat(this._sessionId, "]: Return the last generated m3u8 to give the leader some time"));
1146
891
  return [4 /*yield*/, this._playheadState.getLastM3u8()];
1147
892
  case 12:
1148
- m3u8_4 = _g.sent();
1149
- if (m3u8_4) {
1150
- return [2 /*return*/, m3u8_4];
893
+ m3u8_1 = _g.sent();
894
+ if (m3u8_1) {
895
+ return [2 /*return*/, m3u8_1];
1151
896
  }
1152
897
  else {
1153
898
  debug("[".concat(this._sessionId, "]: We don't have any previously generated m3u8"));
@@ -1695,7 +1440,7 @@ var Session = /** @class */ (function () {
1695
1440
  };
1696
1441
  Session.prototype._insertSlate = function (currentVod) {
1697
1442
  return __awaiter(this, void 0, void 0, function () {
1698
- var slateVod, sessionState, endValue, endValueAudio, lastDiscontinuity, lastDiscontinuityAudio, isLeader, updatedSessionState, _a;
1443
+ var slateVod, sessionState, endValue, endValueAudio, endValueSubtitle, lastDiscontinuity, lastDiscontinuityAudio, lastDiscontinuitySubtitle, isLeader, updatedSessionState, _a;
1699
1444
  return __generator(this, function (_b) {
1700
1445
  switch (_b.label) {
1701
1446
  case 0:
@@ -1705,24 +1450,29 @@ var Session = /** @class */ (function () {
1705
1450
  case 1:
1706
1451
  slateVod = _b.sent();
1707
1452
  debug("[".concat(this._sessionId, "]: slate loaded"));
1708
- return [4 /*yield*/, this._sessionState.getValues(["slateCount", "mediaSeq", "discSeq", "mediaSeqAudio", "discSeqAudio"])];
1453
+ return [4 /*yield*/, this._sessionState.getValues(["slateCount", "mediaSeq", "discSeq", "mediaSeqAudio", "discSeqAudio", "mediaSeqSubtitle", "discSeqSubtitle"])];
1709
1454
  case 2:
1710
1455
  sessionState = _b.sent();
1711
1456
  endValue = 0;
1712
1457
  endValueAudio = 0;
1458
+ endValueSubtitle = 0;
1713
1459
  lastDiscontinuity = 0;
1714
1460
  lastDiscontinuityAudio = 0;
1461
+ lastDiscontinuitySubtitle = 0;
1715
1462
  if (currentVod) {
1716
1463
  if (currentVod.sequenceAlwaysContainNewSegments) {
1717
1464
  endValue = currentVod.getLastSequenceMediaSequenceValue();
1718
1465
  endValueAudio = currentVod.getLastSequenceMediaSequenceValueAudio();
1466
+ endValueSubtitle = currentVod.getLastSequenceMediaSequenceValueSubtitle();
1719
1467
  }
1720
1468
  else {
1721
1469
  endValue = currentVod.getLiveMediaSequencesCount();
1722
1470
  endValueAudio = currentVod.getLiveMediaSequencesCount("audio");
1471
+ endValueSubtitle = currentVod.getLiveMediaSequencesCount("subtitle");
1723
1472
  }
1724
1473
  lastDiscontinuity = currentVod.getLastDiscontinuity();
1725
1474
  lastDiscontinuityAudio = currentVod.getLastDiscontinuityAudio();
1475
+ lastDiscontinuitySubtitle = currentVod.getLastDiscontinuitySubtitle();
1726
1476
  }
1727
1477
  return [4 /*yield*/, this._sessionStateStore.isLeader(this._instanceId)];
1728
1478
  case 3:
@@ -1730,11 +1480,14 @@ var Session = /** @class */ (function () {
1730
1480
  return [4 /*yield*/, this._sessionState.setValues({
1731
1481
  "vodMediaSeqVideo": 0,
1732
1482
  "vodMediaSeqAudio": 0,
1483
+ "vodMediaSeqSubtitle": 0,
1733
1484
  "state": SessionState.VOD_NEXT_INITIATING,
1734
1485
  "mediaSeq": sessionState.mediaSeq + endValue,
1735
1486
  "mediaSeqAudio": sessionState.mediaSeqAudio + endValueAudio,
1487
+ "mediaSeqSubtitle": sessionState.mediaSeqSubtitle + endValueAudio,
1736
1488
  "discSeq": sessionState.discSeq + lastDiscontinuity,
1737
1489
  "discSeqAudio": sessionState.discSeqAudio + lastDiscontinuityAudio,
1490
+ "discSeqSubtitle": sessionState.discSeqSubtitle + lastDiscontinuitySubtitle,
1738
1491
  "slateCount": sessionState.slateCount + 1
1739
1492
  })];
1740
1493
  case 4:
@@ -1756,7 +1509,7 @@ var Session = /** @class */ (function () {
1756
1509
  };
1757
1510
  Session.prototype._tickAsync = function () {
1758
1511
  return __awaiter(this, void 0, void 0, function () {
1759
- var newVod, sessionState, isLeader, currentVod, vodResponse, _a, nextVodPromise, nextVodStart, _b, loadPromise, hlsOpts, _c, mediaManifestLoader, audioManifestLoader, loadStart, updatedSessionState, _d, _e, _f, _g, err_7, _h, length_1, endMseqValue, endMseqValueAudio, endMseqValueSubtitle, lastDiscontinuity, lastDiscontinuityAudio, lastDiscontinuitySubtitle, _j, vodPromise, gracePeriod, nextVodStart, _k, loadPromise, hlsOpts, _l, mediaManifestLoader, audioManifestLoader, loadStart, _m, _o, updatedSessionState, _p, _q, diffMs, err_8, startTS, _r, mSeq, currentVod_1, dSeq, mSeqOffset, reloadBehind, segments, playheadState, nextMseq, _s, _t, err_9;
1512
+ var newVod, sessionState, isLeader, currentVod, vodResponse, _a, nextVodPromise, nextVodStart, _b, loadPromise, hlsOpts, _c, mediaManifestLoader, audioManifestLoader, loadStart, updatedSessionState, _d, _e, _f, _g, err_4, _h, length_1, endMseqValue, endMseqValueAudio, endMseqValueSubtitle, lastDiscontinuity, lastDiscontinuityAudio, lastDiscontinuitySubtitle, _j, vodPromise, gracePeriod, nextVodStart, _k, loadPromise, hlsOpts, _l, mediaManifestLoader, audioManifestLoader, loadStart, _m, _o, updatedSessionState, _p, _q, diffMs, err_5, startTS, _r, mSeq, currentVod_1, dSeq, mSeqOffset, reloadBehind, segments, playheadState, nextMseq, _s, _t, err_6;
1760
1513
  var _this = this;
1761
1514
  return __generator(this, function (_u) {
1762
1515
  switch (_u.label) {
@@ -1910,13 +1663,13 @@ var Session = /** @class */ (function () {
1910
1663
  return [2 /*return*/];
1911
1664
  case 22: return [3 /*break*/, 26];
1912
1665
  case 23:
1913
- err_7 = _u.sent();
1666
+ err_4 = _u.sent();
1914
1667
  console.error("[".concat(this._sessionId, "]: Failed to init first VOD"));
1915
1668
  if (this._assetManager.handleError) {
1916
1669
  this._assetManager.handleError(new Error("Failed to init first VOD"), vodResponse);
1917
1670
  }
1918
- cloudWatchLog(!this.cloudWatchLogging, 'engine-session', { event: 'error', on: 'firstvod', channel: this._sessionId, err: err_7, vod: vodResponse });
1919
- debug(err_7);
1671
+ cloudWatchLog(!this.cloudWatchLogging, 'engine-session', { event: 'error', on: 'firstvod', channel: this._sessionId, err: err_4, vod: vodResponse });
1672
+ debug(err_4);
1920
1673
  return [4 /*yield*/, this._sessionState.remove("nextVod")];
1921
1674
  case 24:
1922
1675
  _u.sent();
@@ -1925,7 +1678,7 @@ var Session = /** @class */ (function () {
1925
1678
  currentVod = _u.sent();
1926
1679
  if (!currentVod) {
1927
1680
  debug("No slate to load");
1928
- throw err_7;
1681
+ throw err_4;
1929
1682
  }
1930
1683
  return [3 /*break*/, 26];
1931
1684
  case 26:
@@ -2175,13 +1928,13 @@ var Session = /** @class */ (function () {
2175
1928
  _u.label = 56;
2176
1929
  case 56: return [3 /*break*/, 60];
2177
1930
  case 57:
2178
- err_8 = _u.sent();
1931
+ err_5 = _u.sent();
2179
1932
  console.error("[".concat(this._sessionId, "]: Failed to init next VOD"));
2180
- debug("[".concat(this._sessionId, "]: ").concat(err_8));
1933
+ debug("[".concat(this._sessionId, "]: ").concat(err_5));
2181
1934
  if (this._assetManager.handleError) {
2182
1935
  this._assetManager.handleError(new Error("Failed to init next VOD"), vodResponse);
2183
1936
  }
2184
- cloudWatchLog(!this.cloudWatchLogging, 'engine-session', { event: 'error', on: 'nextvod', channel: this._sessionId, err: err_8, vod: vodResponse });
1937
+ cloudWatchLog(!this.cloudWatchLogging, 'engine-session', { event: 'error', on: 'nextvod', channel: this._sessionId, err: err_5, vod: vodResponse });
2185
1938
  return [4 /*yield*/, this._sessionState.remove("nextVod")];
2186
1939
  case 58:
2187
1940
  _u.sent();
@@ -2190,7 +1943,7 @@ var Session = /** @class */ (function () {
2190
1943
  currentVod = _u.sent();
2191
1944
  if (!currentVod) {
2192
1945
  debug("No slate to load");
2193
- throw err_8;
1946
+ throw err_5;
2194
1947
  }
2195
1948
  // Allow Leader|Follower to clear vodCache...
2196
1949
  this.isAllowedToClearVodCache = true;
@@ -2301,9 +2054,9 @@ var Session = /** @class */ (function () {
2301
2054
  _u.label = 80;
2302
2055
  case 80: return [3 /*break*/, 82];
2303
2056
  case 81:
2304
- err_9 = _u.sent();
2057
+ err_6 = _u.sent();
2305
2058
  debug("Failed to init reload vod");
2306
- throw err_9;
2059
+ throw err_6;
2307
2060
  case 82: return [3 /*break*/, 88];
2308
2061
  case 83:
2309
2062
  debug("[".concat(this._sessionId, "]: state=VOD_RELOAD_INITIATING (").concat(sessionState.vodMediaSeqVideo, "_").concat(sessionState.vodMediaSeqAudio, "_").concat(sessionState.vodMediaSeqSubtitle, ", ").concat(currentVod.getLiveMediaSequencesCount(), "_").concat(currentVod.getLiveMediaSequencesCount("audio"), "_").concat(currentVod.getLiveMediaSequencesCount("subtitle"), ")"));
@@ -2765,6 +2518,211 @@ var Session = /** @class */ (function () {
2765
2518
  });
2766
2519
  });
2767
2520
  };
2521
+ Session.prototype._getM3u8File = function (variantType, variantKey, playbackSessionId) {
2522
+ return __awaiter(this, void 0, void 0, function () {
2523
+ var tries, delayMs, MSDKeys, currentVod, sessionState, playheadState, state, DELAY_TIME_MS, ACTION, isLeader, diffMs, manifestMseq, manifestDseq, mediaSequenceValue, m3u8_2, parsedGroupId, parsedLang, data, data, err_7;
2524
+ return __generator(this, function (_a) {
2525
+ switch (_a.label) {
2526
+ case 0:
2527
+ tries = 12;
2528
+ _a.label = 1;
2529
+ case 1:
2530
+ if (!(tries > 0 && this.leaderIsSettingNextVod)) return [3 /*break*/, 3];
2531
+ delayMs = 250;
2532
+ debug("[".concat(this._sessionId, "]: Leader is setting the next vod. Waiting ").concat(delayMs, "ms_").concat(tries));
2533
+ return [4 /*yield*/, timer(delayMs)];
2534
+ case 2:
2535
+ _a.sent();
2536
+ tries--;
2537
+ return [3 /*break*/, 1];
2538
+ case 3:
2539
+ MSDKeys = {
2540
+ mediaSeq: null,
2541
+ vodMediaSeq: null,
2542
+ discSeq: null
2543
+ };
2544
+ if (variantType === "video") {
2545
+ MSDKeys.mediaSeq = "mediaSeq";
2546
+ MSDKeys.vodMediaSeq = "vodMediaSeqVideo";
2547
+ MSDKeys.discSeq = "discSeq";
2548
+ }
2549
+ else if (variantType === "audio") {
2550
+ MSDKeys.mediaSeq = "mediaSeqAudio";
2551
+ MSDKeys.vodMediaSeq = "vodMediaSeqAudio";
2552
+ MSDKeys.discSeq = "discSeqAudio";
2553
+ }
2554
+ else if (variantType === "subtitle") {
2555
+ MSDKeys.mediaSeq = "mediaSeqSubtitle";
2556
+ MSDKeys.vodMediaSeq = "vodMediaSeqSubtitle";
2557
+ MSDKeys.discSeq = "discSeqSubtitle";
2558
+ }
2559
+ currentVod = null;
2560
+ return [4 /*yield*/, this._sessionState.getValues([MSDKeys.vodMediaSeq, MSDKeys.discSeq])];
2561
+ case 4:
2562
+ sessionState = _a.sent();
2563
+ return [4 /*yield*/, this._playheadState.getValues([MSDKeys.mediaSeq, MSDKeys.vodMediaSeq, "playheadRef"])];
2564
+ case 5:
2565
+ playheadState = _a.sent();
2566
+ if (this.prevVodMediaSeq[variantType] === null) {
2567
+ this.prevVodMediaSeq[variantType] = playheadState[MSDKeys.vodMediaSeq];
2568
+ }
2569
+ if (this.prevMediaSeqOffset[variantType] === null) {
2570
+ this.prevMediaSeqOffset[variantType] = playheadState[MSDKeys.mediaSeq];
2571
+ }
2572
+ if (!(playheadState[MSDKeys.vodMediaSeq] > sessionState[MSDKeys.vodMediaSeq] ||
2573
+ (playheadState[MSDKeys.vodMediaSeq] < sessionState[MSDKeys.vodMediaSeq] &&
2574
+ playheadState[MSDKeys.mediaSeq] === this.prevMediaSeqOffset[variantType]))) return [3 /*break*/, 9];
2575
+ return [4 /*yield*/, this._sessionState.get("state")];
2576
+ case 6:
2577
+ state = _a.sent();
2578
+ DELAY_TIME_MS = 1000;
2579
+ ACTION = [SessionState.VOD_RELOAD_INIT, SessionState.VOD_RELOAD_INITIATING].includes(state) ? "Reloaded" : "Loaded Next";
2580
+ debug("[".concat(this._sessionId, "]: Recently ").concat(ACTION, " Vod. PlayheadState not up-to-date (").concat(playheadState[MSDKeys.vodMediaSeq], "_").concat(sessionState[MSDKeys.vodMediaSeq], "). Waiting ").concat(DELAY_TIME_MS, "ms before reading from store again (").concat(variantType, ")"));
2581
+ return [4 /*yield*/, timer(DELAY_TIME_MS)];
2582
+ case 7:
2583
+ _a.sent();
2584
+ return [4 /*yield*/, this._playheadState.getValues([MSDKeys.mediaSeq, MSDKeys.vodMediaSeq])];
2585
+ case 8:
2586
+ playheadState = _a.sent();
2587
+ _a.label = 9;
2588
+ case 9:
2589
+ if (!(variantType === "video")) return [3 /*break*/, 15];
2590
+ if (!(playheadState.vodMediaSeqVideo < 2 || playheadState.mediaSeq !== this.prevMediaSeqOffset.video)) return [3 /*break*/, 14];
2591
+ debug("[".concat(this._sessionId, "]: current[").concat(playheadState.vodMediaSeqVideo, "]_prev[").concat(this.prevVodMediaSeq.video, "]"));
2592
+ debug("[".concat(this._sessionId, "]: current-offset[").concat(playheadState.mediaSeq, "]_prev-offset[").concat(this.prevMediaSeqOffset.video, "]"));
2593
+ // If true, then we have not updated the prev-values and not cleared the cache yet.
2594
+ if (playheadState.vodMediaSeqVideo < this.prevVodMediaSeq.video || playheadState.mediaSeq !== this.prevMediaSeqOffset.video) {
2595
+ this.isAllowedToClearVodCache = true;
2596
+ }
2597
+ return [4 /*yield*/, this._sessionStateStore.isLeader(this._instanceId)];
2598
+ case 10:
2599
+ isLeader = _a.sent();
2600
+ if (!(!isLeader && this.isAllowedToClearVodCache)) return [3 /*break*/, 13];
2601
+ 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."));
2602
+ return [4 /*yield*/, this._sessionState.clearCurrentVodCache()];
2603
+ case 11:
2604
+ _a.sent();
2605
+ this.isAllowedToClearVodCache = false;
2606
+ return [4 /*yield*/, this._playheadState.get("diffCompensation")];
2607
+ case 12:
2608
+ diffMs = _a.sent();
2609
+ if (diffMs) {
2610
+ this.diffCompensation = diffMs;
2611
+ debug("[".concat(this._sessionId, "]: Setting diffCompensation->").concat(this.diffCompensation));
2612
+ if (this.diffCompensation) {
2613
+ this.timePositionOffset = this.diffCompensation;
2614
+ cloudWatchLog(!this.cloudWatchLogging, "engine-session", {
2615
+ event: "timePositionOffsetUpdated",
2616
+ channel: this._sessionId,
2617
+ offsetMs: this.timePositionOffset,
2618
+ });
2619
+ }
2620
+ else {
2621
+ this.timePositionOffset = 0;
2622
+ }
2623
+ }
2624
+ _a.label = 13;
2625
+ case 13: return [3 /*break*/, 15];
2626
+ case 14:
2627
+ this.isAllowedToClearVodCache = true;
2628
+ _a.label = 15;
2629
+ case 15: return [4 /*yield*/, this._sessionState.getCurrentVod()];
2630
+ case 16:
2631
+ currentVod = _a.sent();
2632
+ if (!currentVod) return [3 /*break*/, 24];
2633
+ if (!(playheadState[MSDKeys.vodMediaSeq] < 2 || playheadState[MSDKeys.mediaSeq] !== this.prevMediaSeqOffset.video)) return [3 /*break*/, 20];
2634
+ if (!(playheadState.playheadRef > this.currentPlayheadRef)) return [3 /*break*/, 20];
2635
+ return [4 /*yield*/, timer(500)];
2636
+ case 17:
2637
+ _a.sent();
2638
+ this.currentPlayheadRef = playheadState.playheadRef;
2639
+ debug("[".concat(this._sessionId, "]: While requesting ").concat(variantType, " manifest for ").concat(variantKey, ", (mseq=").concat(playheadState[MSDKeys.vodMediaSeq], ")"));
2640
+ return [4 /*yield*/, this._sessionState.clearCurrentVodCache()];
2641
+ case 18:
2642
+ _a.sent(); // force reading up from shared store
2643
+ return [4 /*yield*/, this._sessionState.getCurrentVod()];
2644
+ case 19:
2645
+ currentVod = _a.sent();
2646
+ _a.label = 20;
2647
+ case 20:
2648
+ _a.trys.push([20, 21, , 23]);
2649
+ manifestMseq = playheadState[MSDKeys.mediaSeq] + playheadState[MSDKeys.vodMediaSeq];
2650
+ manifestDseq = sessionState[MSDKeys.discSeq] + this._getCurrentVodData("discontinuities", variantType, currentVod)[playheadState[MSDKeys.vodMediaSeq]];
2651
+ if (currentVod.sequenceAlwaysContainNewSegments) {
2652
+ mediaSequenceValue = this._getCurrentVodData("mseqValues", variantType, currentVod)[playheadState[MSDKeys.vodMediaSeq]];
2653
+ debug("[".concat(this._sessionId, "]: {").concat(mediaSequenceValue, "}_{").concat(this._getCurrentVodData("finalMseqValue", variantType, currentVod), "}"));
2654
+ manifestMseq = playheadState[MSDKeys.mediaSeq] + mediaSequenceValue;
2655
+ }
2656
+ debug("[".concat(this._sessionId, "]: [").concat(playheadState[MSDKeys.vodMediaSeq], "]_[").concat(this._getCurrentVodData("mseqCount", variantType, currentVod), "]"));
2657
+ parsedGroupId = void 0;
2658
+ parsedLang = void 0;
2659
+ if (variantType === "video") {
2660
+ m3u8_2 = currentVod.getLiveMediaSequences(playheadState[MSDKeys.mediaSeq], variantKey, playheadState[MSDKeys.vodMediaSeq], sessionState[MSDKeys.discSeq], this.targetDurationPadding, this.forceTargetDuration);
2661
+ }
2662
+ else if ((variantType === "audio")) {
2663
+ data = JSON.parse(variantKey);
2664
+ parsedGroupId = data.groupId;
2665
+ parsedLang = data.lang;
2666
+ m3u8_2 = currentVod.getLiveMediaAudioSequences(playheadState[MSDKeys.mediaSeq], parsedGroupId, parsedLang, playheadState[MSDKeys.vodMediaSeq], sessionState[MSDKeys.discSeq], this.targetDurationPadding, this.forceTargetDuration);
2667
+ }
2668
+ else if (variantType === "subtitle") {
2669
+ data = JSON.parse(variantKey);
2670
+ parsedGroupId = data.groupId;
2671
+ parsedLang = data.lang;
2672
+ m3u8_2 = currentVod.getLiveMediaSubtitleSequences(playheadState[MSDKeys.mediaSeq], parsedGroupId, parsedLang, playheadState[MSDKeys.vodMediaSeq], sessionState[MSDKeys.discSeq], this.targetDurationPadding, this.forceTargetDuration);
2673
+ }
2674
+ debug("[".concat(this._sessionId, "]:").concat(playbackSessionId ? "[".concat(playbackSessionId, "]:") : "", " [").concat(manifestMseq, "][").concat(manifestDseq, "][+").concat(this.targetDurationPadding || 0, "] Current ").concat(variantType, " manifest for ").concat(variantType === "video" ? variantKey : "".concat(parsedGroupId, "_").concat(parsedLang), " requested"));
2675
+ this.prevVodMediaSeq[variantType] = playheadState[MSDKeys.vodMediaSeq];
2676
+ this.prevMediaSeqOffset[variantType] = playheadState[MSDKeys.mediaSeq];
2677
+ return [2 /*return*/, m3u8_2];
2678
+ case 21:
2679
+ err_7 = _a.sent();
2680
+ logerror(this._sessionId, err_7);
2681
+ return [4 /*yield*/, this._sessionState.clearCurrentVodCache()];
2682
+ case 22:
2683
+ _a.sent(); // force reading up from shared store
2684
+ throw new Error("Failed to generate manifest: " + JSON.stringify(playheadState));
2685
+ case 23: return [3 /*break*/, 25];
2686
+ case 24: throw new Error("Engine not ready");
2687
+ case 25: return [2 /*return*/];
2688
+ }
2689
+ });
2690
+ });
2691
+ };
2692
+ Session.prototype._getCurrentVodData = function (dataName, variantType, vod) {
2693
+ switch (dataName) {
2694
+ case "discontinuities":
2695
+ if (variantType === "video")
2696
+ return vod.discontinuities;
2697
+ if (variantType === "audio")
2698
+ return vod.discontinuitiesAudio;
2699
+ if (variantType === "subtitle")
2700
+ return vod.discontinuitiesSubtitle;
2701
+ case "mseqValues":
2702
+ if (variantType === "video")
2703
+ return vod.mediaSequenceValues;
2704
+ if (variantType === "audio")
2705
+ return vod.mediaSequenceValuesAudio;
2706
+ if (variantType === "subtitle")
2707
+ return vod.mediaSequenceValuesSubtitle;
2708
+ case "finalMseqValue":
2709
+ if (variantType === "video")
2710
+ return vod.getLastSequenceMediaSequenceValue();
2711
+ if (variantType === "audio")
2712
+ return vod.getLastSequenceMediaSequenceValueAudio();
2713
+ if (variantType === "subtitle")
2714
+ return vod.getLastSequenceMediaSequenceValueSubtitle();
2715
+ case "mseqCount":
2716
+ if (variantType === "video")
2717
+ return vod.getLiveMediaSequencesCount();
2718
+ if (variantType === "audio")
2719
+ return vod.getLiveMediaSequencesCount("audio");
2720
+ if (variantType === "subtitle")
2721
+ return vod.getLiveMediaSequencesCount("subtitle");
2722
+ default:
2723
+ console.log("WARNING! dataName:".concat(dataName, " is not valid"));
2724
+ }
2725
+ };
2768
2726
  return Session;
2769
2727
  }());
2770
2728
  module.exports = Session;
@@ -78,7 +78,7 @@ var RefChannelManager = /** @class */ (function () {
78
78
  RefChannelManager.prototype._getAudioTracks = function () {
79
79
  return [
80
80
  { language: "en", name: "English", default: true },
81
- { language: "es", name: "Spanish", default: false },
81
+ { language: "sp", name: "Spanish", default: false },
82
82
  ];
83
83
  };
84
84
  RefChannelManager.prototype._getSubtitleTracks = function () {
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eyevinn-channel-engine",
3
- "version": "4.3.9",
3
+ "version": "4.3.11",
4
4
  "description": "OTT TV Channel Engine",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/engine/session.js CHANGED
@@ -560,231 +560,26 @@ class Session {
560
560
  if (!this._sessionState) {
561
561
  throw new Error('Session not ready');
562
562
  }
563
- // Be sure that the leader is not in the middle of setting new vod data in store.
564
- // Followers will never run this part...
565
- let tries = 12;
566
- while (tries > 0 && this.leaderIsSettingNextVod) {
567
- debug(`[${this._sessionId}]: Leader is setting the next vod. Waiting 500ms_${tries}`);
568
- await timer(500);
569
- tries--;
570
- }
571
-
572
- const sessionState = await this._sessionState.getValues(["vodMediaSeqVideo", "discSeq"]);
573
- let playheadState = await this._playheadState.getValues(["mediaSeq", "vodMediaSeqVideo"]);
574
-
575
- if (this.prevVodMediaSeq.video === null) {
576
- this.prevVodMediaSeq.video = playheadState.vodMediaSeqVideo;
577
- }
578
- if (this.prevMediaSeqOffset.video === null) {
579
- this.prevMediaSeqOffset.video = playheadState.mediaSeq;
580
- }
581
-
582
- if (playheadState.vodMediaSeqVideo > sessionState.vodMediaSeqVideo || (playheadState.vodMediaSeqVideo < sessionState.vodMediaSeqVideo && playheadState.mediaSeq === this.prevMediaSeqOffset.video)) {
583
- const state = await this._sessionState.get("state");
584
- const DELAY_TIME_MS = 1000;
585
- const ACTION = [SessionState.VOD_RELOAD_INIT, SessionState.VOD_RELOAD_INITIATING].includes(state) ? "Reloaded" : "Loaded Next";
586
- 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`);
587
- await timer(DELAY_TIME_MS);
588
- playheadState = await this._playheadState.getValues(["mediaSeq", "vodMediaSeqVideo"]);
589
- }
590
-
591
- // Force reading up from store, but only once if the condition is right
592
- if (playheadState.vodMediaSeqVideo < 2 || playheadState.mediaSeq !== this.prevMediaSeqOffset.video) {
593
- debug(`[${this._sessionId}]: current[${playheadState.vodMediaSeqVideo}]_prev[${this.prevVodMediaSeq.video}]`);
594
- debug(`[${this._sessionId}]: current-offset[${playheadState.mediaSeq}]_prev-offset[${this.prevMediaSeqOffset.video}]`);
595
- // If true, then we have not updated the prev-values and not cleared the cache yet.
596
- if (playheadState.vodMediaSeqVideo < this.prevVodMediaSeq.video || playheadState.mediaSeq !== this.prevMediaSeqOffset.video) {
597
- this.isAllowedToClearVodCache = true;
598
- }
599
- const isLeader = await this._sessionStateStore.isLeader(this._instanceId);
600
- if (!isLeader && this.isAllowedToClearVodCache) {
601
- debug(`[${this._sessionId}]: Not a leader and first|second media sequence in a VOD is requested. Invalidate cache to ensure having the correct VOD.`);
602
- await this._sessionState.clearCurrentVodCache();
603
- this.isAllowedToClearVodCache = false;
604
- const diffMs = await this._playheadState.get("diffCompensation");
605
- if (diffMs) {
606
- this.diffCompensation = diffMs;
607
- debug(`[${this._sessionId}]: Setting diffCompensation->${this.diffCompensation}`);
608
- if (this.diffCompensation) {
609
- this.timePositionOffset = this.diffCompensation;
610
- cloudWatchLog(!this.cloudWatchLogging, 'engine-session',
611
- { event: 'timePositionOffsetUpdated', channel: this._sessionId, offsetMs: this.timePositionOffset });
612
- } else {
613
- this.timePositionOffset = 0;
614
- }
615
- }
616
- }
617
- } else {
618
- this.isAllowedToClearVodCache = true;
619
- }
620
-
621
- const currentVod = await this._sessionState.getCurrentVod();
622
- if (currentVod) {
623
- try {
624
- let manifestMseq = playheadState.mediaSeq + playheadState.vodMediaSeqVideo;
625
- let manifestDseq = sessionState.discSeq + currentVod.discontinuities[playheadState.vodMediaSeqVideo];
626
- if (currentVod.sequenceAlwaysContainNewSegments) {
627
- const mediaSequenceValue = currentVod.mediaSequenceValues[playheadState.vodMediaSeqVideo];
628
- debug(`[${this._sessionId}]: {${mediaSequenceValue}}_{${currentVod.getLastSequenceMediaSequenceValue()}}`);
629
- manifestMseq = playheadState.mediaSeq + mediaSequenceValue;
630
- }
631
-
632
- debug(`[${this._sessionId}]: [${playheadState.vodMediaSeqVideo}]_[${currentVod.getLiveMediaSequencesCount()}]`);
633
- const m3u8 = currentVod.getLiveMediaSequences(playheadState.mediaSeq, bw, playheadState.vodMediaSeqVideo, sessionState.discSeq, this.targetDurationPadding, this.forceTargetDuration);
634
- debug(`[${this._sessionId}]: [${manifestMseq}][${manifestDseq}][+${this.targetDurationPadding || 0}] Current media manifest for ${bw} requested`);
635
- this.prevVodMediaSeq.video = playheadState.vodMediaSeqVideo;
636
- this.prevMediaSeqOffset.video = playheadState.mediaSeq;
637
- return m3u8;
638
- } catch (err) {
639
- logerror(this._sessionId, err);
640
- await this._sessionState.clearCurrentVodCache(); // force reading up from shared store
641
- throw new Error("Failed to generate manifest: " + JSON.stringify(playheadState));
642
- }
643
- } else {
644
- throw new Error("Engine not ready");
645
- }
563
+ const m3u8 = this._getM3u8File("video", bw, playbackSessionId);
564
+ return m3u8;
646
565
  }
647
566
 
648
567
  async getCurrentAudioManifestAsync(audioGroupId, audioLanguage, playbackSessionId) {
649
568
  if (!this._sessionState) {
650
569
  throw new Error('Session not ready');
651
570
  }
652
- let currentVod = null;
653
- const sessionState = await this._sessionState.getValues(["discSeqAudio", "vodMediaSeqAudio"]);
654
- let playheadState = await this._playheadState.getValues(["mediaSeqAudio", "vodMediaSeqAudio", "playheadRef"]);
655
-
656
- if (playheadState.vodMediaSeqAudio > sessionState.vodMediaSeqAudio || (playheadState.vodMediaSeqAudio < sessionState.vodMediaSeqAudio && playheadState.mediaSeqAudio === this.prevMediaSeqOffset.audio)) {
657
- const state = await this._sessionState.get("state");
658
- const DELAY_TIME_MS = 1000;
659
- const ACTION = [SessionState.VOD_RELOAD_INIT, SessionState.VOD_RELOAD_INITIATING].includes(state) ? "Reloaded" : "Loaded Next";
660
- 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`);
661
- await timer(DELAY_TIME_MS);
662
- playheadState = await this._playheadState.getValues(["mediaSeqAudio", "vodMediaSeqAudio"]);
663
- }
664
- // local store the prev values
665
- if (this.prevVodMediaSeq.audio === null) {
666
- this.prevVodMediaSeq.audio = playheadState.vodMediaSeqAudio;
667
- }
668
- if (this.prevMediaSeqOffset.audio === null) {
669
- this.prevMediaSeqOffset.audio = playheadState.mediaSeqAudio;
670
- }
671
- currentVod = await this._sessionState.getCurrentVod();
672
- if (currentVod) {
673
- // condition suggesting that a new vod should exist
674
- if (playheadState.vodMediaSeqAudio < 2 || playheadState.mediaSeqAudio !== this.prevMediaSeqOffset.audio) {
675
- if (playheadState.playheadRef > this.currentPlayheadRef) {
676
- await timer(500);
677
- this.currentPlayheadRef = playheadState.playheadRef;
678
- debug(`[${this._sessionId}]: While requesting audio manifest for ${audioGroupId}-${audioLanguage}, (mseq=${playheadState.vodMediaSeqAudio})`);
679
- await this._sessionState.clearCurrentVodCache(); // force reading up from shared store
680
- currentVod = await this._sessionState.getCurrentVod();
681
- }
682
- }
683
- try {
684
- let manifestMseq = playheadState.mediaSeqAudio + playheadState.vodMediaSeqAudio;
685
- let manifestDseq = sessionState.discSeqAudio + currentVod.discontinuitiesAudio[playheadState.vodMediaSeqAudio];
686
- if (currentVod.sequenceAlwaysContainNewSegments) {
687
- const mediaSequenceValue = currentVod.mediaSequenceValuesAudio[playheadState.vodMediaSeqAudio];
688
- debug(`[${this._sessionId}]: {${mediaSequenceValue}}_{${currentVod.getLastSequenceMediaSequenceValueAudio()}} AUDIO`);
689
- manifestMseq = playheadState.mediaSeqAudio + mediaSequenceValue;
690
- }
691
- debug(`[${this._sessionId}]: [${playheadState.vodMediaSeqAudio}]_[${currentVod.getLiveMediaSequencesCount("audio")}] AUDIO (${audioGroupId})`);
692
- const m3u8 = currentVod.getLiveMediaAudioSequences(
693
- playheadState.mediaSeqAudio,
694
- audioGroupId,
695
- audioLanguage,
696
- playheadState.vodMediaSeqAudio,
697
- sessionState.discSeqAudio,
698
- this.targetDurationPadding,
699
- this.forceTargetDuration
700
- );
701
- // # Case: current VOD does not have the selected track.
702
- if (!m3u8) {
703
- debug(`[${this._sessionId}]: [${playheadState.mediaSeqAudio + playheadState.vodMediaSeqAudio}] Request Failed for current audio manifest for ${audioGroupId}-${audioLanguage}`);
704
- }
705
- debug(`[${this._sessionId}]: [${manifestMseq}][${manifestDseq}] Current audio manifest for ${audioGroupId}-${audioLanguage} requested`);
706
- this.prevVodMediaSeq.audio = playheadState.vodMediaSeqAudio;
707
- this.prevMediaSeqOffset.audio = playheadState.mediaSeqAudio;
708
- return m3u8;
709
- } catch (err) {
710
- logerror(this._sessionId, err);
711
- await this._sessionState.clearCurrentVodCache(); // force reading up from shared store
712
- throw new Error("Failed to generate audio manifest: " + JSON.stringify(playheadState));
713
- }
714
- } else {
715
- throw new Error("Engine not ready");
716
- }
571
+ const variantKey = JSON.stringify({groupId: audioGroupId, lang: audioLanguage});
572
+ const m3u8 = this._getM3u8File("audio", variantKey, playbackSessionId);
573
+ return m3u8;
717
574
  }
718
575
 
719
- async getCurrentSubtitleManifestAsync(subtitleGroupId, subtitleLanguage) {
576
+ async getCurrentSubtitleManifestAsync(subtitleGroupId, subtitleLanguage, playbackSessionId) {
720
577
  if (!this._sessionState) {
721
578
  throw new Error('Session not ready');
722
579
  }
723
- let currentVod = null;
724
- const sessionState = await this._sessionState.getValues(["discSeqSubtitle", "vodMediaSeqSubtitle"]);
725
- let playheadState = await this._playheadState.getValues(["mediaSeqSubtitle", "vodMediaSeqSubtitle", "playheadRef"]);
726
-
727
- if (playheadState.vodMediaSeqSubtitle > sessionState.vodMediaSeqSubtitle || (playheadState.vodMediaSeqSubtitle < sessionState.vodMediaSeqSubtitle && playheadState.mediaSeqSubtitle === this.prevMediaSeqOffset.subtitle)) {
728
- const state = await this._sessionState.get("state");
729
- const DELAY_TIME_MS = 1000;
730
- const ACTION = [SessionState.VOD_RELOAD_INIT, SessionState.VOD_RELOAD_INITIATING].includes(state) ? "Reloaded" : "Loaded Next";
731
- debug(`[${this._sessionId}]: Recently ${ACTION} Vod. PlayheadState not up-to-date (${playheadState.vodMediaSeqSubtitle}_${sessionState.vodMediaSeqSubtitle}). Waiting ${DELAY_TIME_MS}ms before reading from store again`);
732
- await timer(DELAY_TIME_MS);
733
- playheadState = await this._playheadState.getValues(["mediaSeqSubtitle", "vodMediaSeqSubtitle"]);
734
- }
735
- // local store the prev values
736
- if (this.prevVodMediaSeq.subtitle === null) {
737
- this.prevVodMediaSeq.subtitle = playheadState.vodMediaSeqSubtitle;
738
- }
739
- if (this.prevMediaSeqOffset.subtitle === null) {
740
- this.prevMediaSeqOffset.subtitle = playheadState.mediaSeqSubtitle;
741
- }
742
- currentVod = await this._sessionState.getCurrentVod();
743
- if (currentVod) {
744
- // condition suggesting that a new vod should exist
745
- if (playheadState.vodMediaSeqSubtitle < 2 || playheadState.mediaSeqSubtitle !== this.prevMediaSeqOffset.subtitle) {
746
- if (playheadState.playheadRef > this.currentPlayheadRef) {
747
- await timer(500);
748
- this.currentPlayheadRef = playheadState.playheadRef;
749
- debug(`[${this._sessionId}]: While requesting subtitle manifest for ${subtitleGroupId}-${subtitleLanguage}, (mseq=${playheadState.vodMediaSeqSubtitle})`);
750
- await this._sessionState.clearCurrentVodCache(); // force reading up from shared store
751
- currentVod = await this._sessionState.getCurrentVod();
752
- }
753
- }
754
- try {
755
- let manifestMseq = playheadState.mediaSeqSubtitle + playheadState.vodMediaSeqSubtitle;
756
- let manifestDseq = sessionState.discSeqSubtitle + currentVod.discontinuitiesSubtitle[playheadState.vodMediaSeqSubtitle];
757
- if (currentVod.sequenceAlwaysContainNewSegments) {
758
- const mediaSequenceValue = currentVod.mediaSequenceValuesSubtitle[playheadState.vodMediaSeqSubtitle];
759
- debug(`[${this._sessionId}]: {${mediaSequenceValue}}_{${currentVod.getLastSequenceMediaSequenceValueSubtitle()}} SUBTITLES`);
760
- manifestMseq = playheadState.mediaSeqSubtitle + mediaSequenceValue;
761
- }
762
- debug(`[${this._sessionId}]: [${playheadState.vodMediaSeqSubtitle}]_[${currentVod.getLiveMediaSequencesCount("subtitle")}] SUBTITLES (${subtitleGroupId})`);
763
- const m3u8 = currentVod.getLiveMediaSubtitleSequences(
764
- playheadState.mediaSeqSubtitle,
765
- subtitleGroupId,
766
- subtitleLanguage,
767
- playheadState.vodMediaSeqSubtitle,
768
- sessionState.discSeqSubtitle,
769
- this.targetDurationPadding,
770
- this.forceTargetDuration
771
- );
772
- // # Case: current VOD does not have the selected track.
773
- if (!m3u8) {
774
- debug(`[${this._sessionId}]: [${playheadState.mediaSeqSubtitle + playheadState.vodMediaSeqSubtitle}] Request Failed for current subtitle manifest for ${subtitleGroupId}-${subtitleLanguage}`);
775
- }
776
- debug(`[${this._sessionId}]: [${manifestMseq}][${manifestDseq}] Current subtitle manifest for ${subtitleGroupId}-${subtitleLanguage} requested`);
777
- this.prevVodMediaSeq.subtitle = playheadState.vodMediaSeqSubtitle;
778
- this.prevMediaSeqOffset.subtitle = playheadState.mediaSeqSubtitle;
779
- return m3u8;
780
- } catch (err) {
781
- logerror(this._sessionId, err);
782
- await this._sessionState.clearCurrentVodCache(); // force reading up from shared store
783
- throw new Error("Failed to generate subtitle manifest: " + JSON.stringify(playheadState));
784
- }
785
- } else {
786
- throw new Error("Engine not ready");
787
- }
580
+ const variantKey = JSON.stringify({groupId: subtitleGroupId, lang: subtitleLanguage});
581
+ const m3u8 = this._getM3u8File("subtitle", variantKey, playbackSessionId);
582
+ return m3u8;
788
583
  }
789
584
 
790
585
  async incrementAsync() {
@@ -1276,32 +1071,40 @@ class Session {
1276
1071
  console.error(`[${this._sessionId}]: Will insert slate`);
1277
1072
  const slateVod = await this._loadSlate(currentVod);
1278
1073
  debug(`[${this._sessionId}]: slate loaded`);
1279
- let sessionState = await this._sessionState.getValues(["slateCount", "mediaSeq", "discSeq", "mediaSeqAudio", "discSeqAudio"]);
1074
+ let sessionState = await this._sessionState.getValues(["slateCount", "mediaSeq", "discSeq", "mediaSeqAudio", "discSeqAudio", "mediaSeqSubtitle", "discSeqSubtitle"]);
1280
1075
  let endValue = 0;
1281
1076
  let endValueAudio = 0;
1077
+ let endValueSubtitle = 0;
1282
1078
  let lastDiscontinuity = 0;
1283
1079
  let lastDiscontinuityAudio = 0;
1080
+ let lastDiscontinuitySubtitle = 0;
1284
1081
  if (currentVod) {
1285
1082
  if (currentVod.sequenceAlwaysContainNewSegments) {
1286
1083
  endValue = currentVod.getLastSequenceMediaSequenceValue();
1287
1084
  endValueAudio = currentVod.getLastSequenceMediaSequenceValueAudio();
1085
+ endValueSubtitle = currentVod.getLastSequenceMediaSequenceValueSubtitle();
1288
1086
  } else {
1289
1087
  endValue = currentVod.getLiveMediaSequencesCount();
1290
1088
  endValueAudio = currentVod.getLiveMediaSequencesCount("audio");
1089
+ endValueSubtitle = currentVod.getLiveMediaSequencesCount("subtitle");
1291
1090
  }
1292
1091
  lastDiscontinuity = currentVod.getLastDiscontinuity();
1293
1092
  lastDiscontinuityAudio = currentVod.getLastDiscontinuityAudio();
1093
+ lastDiscontinuitySubtitle = currentVod.getLastDiscontinuitySubtitle();
1294
1094
  }
1295
1095
  const isLeader = await this._sessionStateStore.isLeader(this._instanceId);
1296
1096
 
1297
1097
  const updatedSessionState = await this._sessionState.setValues({
1298
1098
  "vodMediaSeqVideo": 0,
1299
1099
  "vodMediaSeqAudio": 0,
1100
+ "vodMediaSeqSubtitle": 0,
1300
1101
  "state": SessionState.VOD_NEXT_INITIATING,
1301
1102
  "mediaSeq": sessionState.mediaSeq + endValue,
1302
1103
  "mediaSeqAudio": sessionState.mediaSeqAudio + endValueAudio,
1104
+ "mediaSeqSubtitle": sessionState.mediaSeqSubtitle + endValueAudio,
1303
1105
  "discSeq": sessionState.discSeq + lastDiscontinuity,
1304
1106
  "discSeqAudio": sessionState.discSeqAudio + lastDiscontinuityAudio,
1107
+ "discSeqSubtitle": sessionState.discSeqSubtitle + lastDiscontinuitySubtitle,
1305
1108
  "slateCount": sessionState.slateCount + 1
1306
1109
  });
1307
1110
  sessionState = { ...sessionState, ...updatedSessionState };
@@ -2134,6 +1937,204 @@ class Session {
2134
1937
  diff: posDiff
2135
1938
  };
2136
1939
  }
1940
+
1941
+ async _getM3u8File(variantType, variantKey, playbackSessionId) {
1942
+ // Be sure that the leader is not in the middle of setting new vod data in store.
1943
+ // Followers will never run this part...
1944
+ let tries = 12;
1945
+ while (tries > 0 && this.leaderIsSettingNextVod) {
1946
+ const delayMs = 250;
1947
+ debug(`[${this._sessionId}]: Leader is setting the next vod. Waiting ${delayMs}ms_${tries}`);
1948
+ await timer(delayMs);
1949
+ tries--;
1950
+ }
1951
+ // Media Sequence Data Keys
1952
+ const MSDKeys = {
1953
+ mediaSeq: null,
1954
+ vodMediaSeq: null,
1955
+ discSeq: null
1956
+ };
1957
+ if (variantType === "video") {
1958
+ MSDKeys.mediaSeq = "mediaSeq";
1959
+ MSDKeys.vodMediaSeq = "vodMediaSeqVideo";
1960
+ MSDKeys.discSeq = "discSeq";
1961
+ } else if (variantType === "audio") {
1962
+ MSDKeys.mediaSeq = "mediaSeqAudio";
1963
+ MSDKeys.vodMediaSeq = "vodMediaSeqAudio";
1964
+ MSDKeys.discSeq = "discSeqAudio";
1965
+ } else if (variantType === "subtitle") {
1966
+ MSDKeys.mediaSeq = "mediaSeqSubtitle";
1967
+ MSDKeys.vodMediaSeq = "vodMediaSeqSubtitle";
1968
+ MSDKeys.discSeq = "discSeqSubtitle";
1969
+ }
1970
+ let currentVod = null;
1971
+ const sessionState = await this._sessionState.getValues([MSDKeys.vodMediaSeq, MSDKeys.discSeq]);
1972
+ let playheadState = await this._playheadState.getValues([MSDKeys.mediaSeq, MSDKeys.vodMediaSeq, "playheadRef"]);
1973
+
1974
+ if (this.prevVodMediaSeq[variantType] === null) {
1975
+ this.prevVodMediaSeq[variantType] = playheadState[MSDKeys.vodMediaSeq];
1976
+ }
1977
+ if (this.prevMediaSeqOffset[variantType] === null) {
1978
+ this.prevMediaSeqOffset[variantType] = playheadState[MSDKeys.mediaSeq];
1979
+ }
1980
+
1981
+ if (
1982
+ playheadState[MSDKeys.vodMediaSeq] > sessionState[MSDKeys.vodMediaSeq] ||
1983
+ (playheadState[MSDKeys.vodMediaSeq] < sessionState[MSDKeys.vodMediaSeq] &&
1984
+ playheadState[MSDKeys.mediaSeq] === this.prevMediaSeqOffset[variantType])
1985
+ ) {
1986
+ const state = await this._sessionState.get("state");
1987
+ const DELAY_TIME_MS = 1000;
1988
+ const ACTION = [SessionState.VOD_RELOAD_INIT, SessionState.VOD_RELOAD_INITIATING].includes(state) ? "Reloaded" : "Loaded Next";
1989
+ debug(
1990
+ `[${this._sessionId}]: Recently ${ACTION} Vod. PlayheadState not up-to-date (${playheadState[MSDKeys.vodMediaSeq]}_${
1991
+ sessionState[MSDKeys.vodMediaSeq]
1992
+ }). Waiting ${DELAY_TIME_MS}ms before reading from store again (${variantType})`
1993
+ );
1994
+ await timer(DELAY_TIME_MS);
1995
+ playheadState = await this._playheadState.getValues([MSDKeys.mediaSeq, MSDKeys.vodMediaSeq]);
1996
+ }
1997
+
1998
+ if (variantType === "video") {
1999
+ // Force reading up from store, but only once if the condition is right.
2000
+ if (playheadState.vodMediaSeqVideo < 2 || playheadState.mediaSeq !== this.prevMediaSeqOffset.video) {
2001
+ debug(`[${this._sessionId}]: current[${playheadState.vodMediaSeqVideo}]_prev[${this.prevVodMediaSeq.video}]`);
2002
+ debug(`[${this._sessionId}]: current-offset[${playheadState.mediaSeq}]_prev-offset[${this.prevMediaSeqOffset.video}]`);
2003
+ // If true, then we have not updated the prev-values and not cleared the cache yet.
2004
+ if (playheadState.vodMediaSeqVideo < this.prevVodMediaSeq.video || playheadState.mediaSeq !== this.prevMediaSeqOffset.video) {
2005
+ this.isAllowedToClearVodCache = true;
2006
+ }
2007
+ const isLeader = await this._sessionStateStore.isLeader(this._instanceId);
2008
+ if (!isLeader && this.isAllowedToClearVodCache) {
2009
+ debug(
2010
+ `[${this._sessionId}]: Not a leader and first|second media sequence in a VOD is requested. Invalidate cache to ensure having the correct VOD.`
2011
+ );
2012
+ await this._sessionState.clearCurrentVodCache();
2013
+ this.isAllowedToClearVodCache = false;
2014
+ const diffMs = await this._playheadState.get("diffCompensation");
2015
+ if (diffMs) {
2016
+ this.diffCompensation = diffMs;
2017
+ debug(`[${this._sessionId}]: Setting diffCompensation->${this.diffCompensation}`);
2018
+ if (this.diffCompensation) {
2019
+ this.timePositionOffset = this.diffCompensation;
2020
+ cloudWatchLog(!this.cloudWatchLogging, "engine-session", {
2021
+ event: "timePositionOffsetUpdated",
2022
+ channel: this._sessionId,
2023
+ offsetMs: this.timePositionOffset,
2024
+ });
2025
+ } else {
2026
+ this.timePositionOffset = 0;
2027
+ }
2028
+ }
2029
+ }
2030
+ } else {
2031
+ this.isAllowedToClearVodCache = true;
2032
+ }
2033
+ }
2034
+
2035
+ currentVod = await this._sessionState.getCurrentVod();
2036
+ if (currentVod) {
2037
+ // condition suggesting that a new vod should exist
2038
+ if (playheadState[MSDKeys.vodMediaSeq] < 2 || playheadState[MSDKeys.mediaSeq] !== this.prevMediaSeqOffset.video) {
2039
+ if (playheadState.playheadRef > this.currentPlayheadRef) {
2040
+ await timer(500);
2041
+ this.currentPlayheadRef = playheadState.playheadRef;
2042
+ debug(`[${this._sessionId}]: While requesting ${variantType} manifest for ${variantKey}, (mseq=${playheadState[MSDKeys.vodMediaSeq]})`);
2043
+ await this._sessionState.clearCurrentVodCache(); // force reading up from shared store
2044
+ currentVod = await this._sessionState.getCurrentVod();
2045
+ }
2046
+ }
2047
+ try {
2048
+ let manifestMseq = playheadState[MSDKeys.mediaSeq] + playheadState[MSDKeys.vodMediaSeq];
2049
+ let manifestDseq =
2050
+ sessionState[MSDKeys.discSeq] + this._getCurrentVodData("discontinuities", variantType, currentVod)[playheadState[MSDKeys.vodMediaSeq]];
2051
+ if (currentVod.sequenceAlwaysContainNewSegments) {
2052
+ const mediaSequenceValue = this._getCurrentVodData("mseqValues", variantType, currentVod)[playheadState[MSDKeys.vodMediaSeq]];
2053
+ debug(`[${this._sessionId}]: {${mediaSequenceValue}}_{${this._getCurrentVodData("finalMseqValue", variantType, currentVod)}}`);
2054
+ manifestMseq = playheadState[MSDKeys.mediaSeq] + mediaSequenceValue;
2055
+ }
2056
+
2057
+ debug(`[${this._sessionId}]: [${playheadState[MSDKeys.vodMediaSeq]}]_[${this._getCurrentVodData("mseqCount", variantType, currentVod)}]`);
2058
+
2059
+ let m3u8;
2060
+ let parsedGroupId;
2061
+ let parsedLang;
2062
+ if (variantType === "video") {
2063
+ m3u8 = currentVod.getLiveMediaSequences(
2064
+ playheadState[MSDKeys.mediaSeq],
2065
+ variantKey,
2066
+ playheadState[MSDKeys.vodMediaSeq],
2067
+ sessionState[MSDKeys.discSeq],
2068
+ this.targetDurationPadding,
2069
+ this.forceTargetDuration
2070
+ );
2071
+ } else if ((variantType === "audio")) {
2072
+ const data = JSON.parse(variantKey);
2073
+ parsedGroupId = data.groupId;
2074
+ parsedLang = data.lang;
2075
+ m3u8 = currentVod.getLiveMediaAudioSequences(
2076
+ playheadState[MSDKeys.mediaSeq],
2077
+ parsedGroupId,
2078
+ parsedLang,
2079
+ playheadState[MSDKeys.vodMediaSeq],
2080
+ sessionState[MSDKeys.discSeq],
2081
+ this.targetDurationPadding,
2082
+ this.forceTargetDuration
2083
+ );
2084
+ } else if (variantType === "subtitle") {
2085
+ const data = JSON.parse(variantKey);
2086
+ parsedGroupId = data.groupId;
2087
+ parsedLang = data.lang;
2088
+ m3u8 = currentVod.getLiveMediaSubtitleSequences(
2089
+ playheadState[MSDKeys.mediaSeq],
2090
+ parsedGroupId,
2091
+ parsedLang,
2092
+ playheadState[MSDKeys.vodMediaSeq],
2093
+ sessionState[MSDKeys.discSeq],
2094
+ this.targetDurationPadding,
2095
+ this.forceTargetDuration
2096
+ );
2097
+ }
2098
+ debug(
2099
+ `[${this._sessionId}]:${playbackSessionId ? `[${playbackSessionId}]:` : ""} [${manifestMseq}][${manifestDseq}][+${this.targetDurationPadding || 0}] Current ${variantType} manifest for ${
2100
+ variantType === "video" ? variantKey : `${parsedGroupId}_${parsedLang}`
2101
+ } requested`
2102
+ );
2103
+ this.prevVodMediaSeq[variantType] = playheadState[MSDKeys.vodMediaSeq];
2104
+ this.prevMediaSeqOffset[variantType] = playheadState[MSDKeys.mediaSeq];
2105
+ return m3u8;
2106
+ } catch (err) {
2107
+ logerror(this._sessionId, err);
2108
+ await this._sessionState.clearCurrentVodCache(); // force reading up from shared store
2109
+ throw new Error("Failed to generate manifest: " + JSON.stringify(playheadState));
2110
+ }
2111
+ } else {
2112
+ throw new Error("Engine not ready");
2113
+ }
2114
+ }
2115
+
2116
+ _getCurrentVodData(dataName, variantType, vod) {
2117
+ switch (dataName) {
2118
+ case "discontinuities":
2119
+ if (variantType === "video") return vod.discontinuities;
2120
+ if (variantType === "audio") return vod.discontinuitiesAudio;
2121
+ if (variantType === "subtitle") return vod.discontinuitiesSubtitle;
2122
+ case "mseqValues":
2123
+ if (variantType === "video") return vod.mediaSequenceValues;
2124
+ if (variantType === "audio") return vod.mediaSequenceValuesAudio;
2125
+ if (variantType === "subtitle") return vod.mediaSequenceValuesSubtitle;
2126
+ case "finalMseqValue":
2127
+ if (variantType === "video") return vod.getLastSequenceMediaSequenceValue();
2128
+ if (variantType === "audio") return vod.getLastSequenceMediaSequenceValueAudio();
2129
+ if (variantType === "subtitle") return vod.getLastSequenceMediaSequenceValueSubtitle();
2130
+ case "mseqCount":
2131
+ if (variantType === "video") return vod.getLiveMediaSequencesCount();
2132
+ if (variantType === "audio") return vod.getLiveMediaSequencesCount("audio");
2133
+ if (variantType === "subtitle") return vod.getLiveMediaSequencesCount("subtitle");
2134
+ default:
2135
+ console.log(`WARNING! dataName:${dataName} is not valid`);
2136
+ }
2137
+ }
2137
2138
  }
2138
2139
 
2139
2140
  module.exports = Session;
package/examples/demux.ts CHANGED
@@ -89,7 +89,7 @@ class RefChannelManager implements IChannelManager {
89
89
  _getAudioTracks(): AudioTracks[] {
90
90
  return [
91
91
  { language: "en", name: "English", default: true },
92
- { language: "es", name: "Spanish", default: false },
92
+ { language: "sp", name: "Spanish", default: false },
93
93
  ];
94
94
  }
95
95
  _getSubtitleTracks(): SubtitleTracks[] {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eyevinn-channel-engine",
3
- "version": "4.3.9",
3
+ "version": "4.3.11",
4
4
  "description": "OTT TV Channel Engine",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",