eyevinn-channel-engine 4.0.1 → 4.0.3

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