eyevinn-channel-engine 4.0.1 → 4.0.2

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