eyevinn-channel-engine 4.2.9 → 4.3.0

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.
@@ -92,7 +92,7 @@ var SharedSessionState = /** @class */ (function () {
92
92
  };
93
93
  SharedSessionState.prototype.getCurrentVod = function () {
94
94
  return __awaiter(this, void 0, void 0, function () {
95
- var currentVod, hlsVod;
95
+ var currentVod, hlsVod, strToMB;
96
96
  return __generator(this, function (_a) {
97
97
  switch (_a.label) {
98
98
  case 0:
@@ -107,16 +107,27 @@ var SharedSessionState = /** @class */ (function () {
107
107
  case 1:
108
108
  currentVod = _a.sent();
109
109
  hlsVod = null;
110
- if (currentVod) {
111
- if (this.store.isShared()) {
112
- debug("[".concat(this.sessionId, "]: reading ").concat(currentVod.length, " characters from shared store (").concat(Date.now(), " < ").concat(this.cache.currentVod.ts + this.cache.currentVod.ttl, ")"));
113
- hlsVod = new HLSVod();
114
- hlsVod.fromJSON(currentVod);
115
- }
116
- else {
117
- hlsVod = currentVod;
118
- }
119
- }
110
+ if (!currentVod) return [3 /*break*/, 5];
111
+ if (!this.store.isShared()) return [3 /*break*/, 4];
112
+ strToMB = function (str) {
113
+ var bytesPerCharacter = 2; // Assuming each character takes around 2 bytes in memory
114
+ var stringSizeBytes = str.length * bytesPerCharacter;
115
+ var sizeInMegabytes = stringSizeBytes / (1024 * 1024);
116
+ return sizeInMegabytes.toFixed(1);
117
+ };
118
+ debug("[".concat(this.sessionId, "]: reading ").concat(currentVod.length, " characters or (").concat(strToMB(currentVod), " MB) from shared store (").concat(Date.now(), " < ").concat(this.cache.currentVod.ts + this.cache.currentVod.ttl, ")"));
119
+ hlsVod = new HLSVod();
120
+ hlsVod.fromJSON(currentVod);
121
+ if (!hlsVod.skipSerializeMediaSequences) return [3 /*break*/, 3];
122
+ return [4 /*yield*/, hlsVod.generateMediaSequences()];
123
+ case 2:
124
+ _a.sent();
125
+ _a.label = 3;
126
+ case 3: return [3 /*break*/, 5];
127
+ case 4:
128
+ hlsVod = currentVod;
129
+ _a.label = 5;
130
+ case 5:
120
131
  this.cache.currentVod.ts = Date.now();
121
132
  this.cache.currentVod.value = hlsVod;
122
133
  return [2 /*return*/, hlsVod];
@@ -133,7 +144,7 @@ var SharedSessionState = /** @class */ (function () {
133
144
  if (!this.sessionId) {
134
145
  throw new Error("shared session state store has not been initialized");
135
146
  }
136
- if (!this.store.isShared()) return [3 /*break*/, 7];
147
+ if (!this.store.isShared()) return [3 /*break*/, 8];
137
148
  return [4 /*yield*/, this.store.clearLeaderCache()];
138
149
  case 1:
139
150
  _a.sent();
@@ -144,7 +155,7 @@ var SharedSessionState = /** @class */ (function () {
144
155
  return [4 /*yield*/, this.set("currentVod", hlsVod.toJSON())];
145
156
  case 3:
146
157
  _a.sent();
147
- return [3 /*break*/, 6];
158
+ return [3 /*break*/, 7];
148
159
  case 4:
149
160
  debug("[".concat(this.sessionId, "]: Not a leader. Will not overwrite. Getting currentVod in shared store"));
150
161
  return [4 /*yield*/, this.get("currentVod")];
@@ -152,13 +163,17 @@ var SharedSessionState = /** @class */ (function () {
152
163
  currentVod = _a.sent();
153
164
  hlsVod = new HLSVod();
154
165
  hlsVod.fromJSON(currentVod);
155
- _a.label = 6;
156
- case 6: return [3 /*break*/, 9];
157
- case 7: return [4 /*yield*/, this.set("currentVod", hlsVod)];
158
- case 8:
166
+ if (!hlsVod.skipSerializeMediaSequences) return [3 /*break*/, 7];
167
+ return [4 /*yield*/, hlsVod.generateMediaSequences()];
168
+ case 6:
159
169
  _a.sent();
160
- _a.label = 9;
170
+ _a.label = 7;
171
+ case 7: return [3 /*break*/, 10];
172
+ case 8: return [4 /*yield*/, this.set("currentVod", hlsVod)];
161
173
  case 9:
174
+ _a.sent();
175
+ _a.label = 10;
176
+ case 10:
162
177
  if (this.cache.currentVod) {
163
178
  this.cache.currentVod.ts = Date.now();
164
179
  this.cache.currentVod.ttl = CURRENTVOD_CACHE_TTL;
@@ -50,7 +50,8 @@ var RefAssetManager = /** @class */ (function () {
50
50
  id: vod.id,
51
51
  title: vod.title,
52
52
  uri: vod.uri,
53
- desiredDuration: 50000
53
+ desiredDuration: 50000,
54
+ startOffset: 10000,
54
55
  };
55
56
  resolve(vodResponse);
56
57
  }
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eyevinn-channel-engine",
3
- "version": "4.2.9",
3
+ "version": "4.3.0",
4
4
  "description": "OTT TV Channel Engine",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -29,8 +29,8 @@
29
29
  "license": "Apache-2.0",
30
30
  "dependencies": {
31
31
  "@eyevinn/hls-repeat": "^0.2.0",
32
- "@eyevinn/hls-truncate": "^0.2.0",
33
- "@eyevinn/hls-vodtolive": "^3.0.1",
32
+ "@eyevinn/hls-truncate": "^0.3.0",
33
+ "@eyevinn/hls-vodtolive": "^4.0.0",
34
34
  "@eyevinn/m3u8": "^0.5.3",
35
35
  "abort-controller": "^3.0.0",
36
36
  "debug": "^3.2.7",
package/engine/server.ts CHANGED
@@ -46,6 +46,8 @@ export interface ChannelEngineOpts {
46
46
  subtitleSliceEndpoint?: string;
47
47
  useVTTSubtitles?: boolean;
48
48
  alwaysNewSegments?: boolean;
49
+ partialStoreHLSVod?: boolean;
50
+ alwaysMapBandwidthByNearest?: boolean;
49
51
  diffCompensationRate?: number;
50
52
  staticDirectory?: string;
51
53
  averageSegmentDuration?: number;
@@ -100,6 +102,7 @@ export interface VodResponse {
100
102
  offset?: number;
101
103
  diffMs?: number;
102
104
  desiredDuration?: number;
105
+ startOffset?: number;
103
106
  type?: string;
104
107
  currentMetadata?: VodResponseMetadata;
105
108
  timedMetadata?: VodTimedMetadata;
@@ -181,6 +184,8 @@ export class ChannelEngine {
181
184
  private subtitleSliceEndpoint: string;
182
185
  private useVTTSubtitles: boolean;
183
186
  private alwaysNewSegments: boolean;
187
+ private partialStoreHLSVod: boolean;
188
+ private alwaysMapBandwidthByNearest: boolean;
184
189
  private defaultSlateUri?: string;
185
190
  private slateDuration?: number;
186
191
  private assetMgr: IAssetManager;
@@ -220,6 +225,14 @@ export class ChannelEngine {
220
225
  if (options && options.alwaysNewSegments) {
221
226
  this.alwaysNewSegments = true;
222
227
  }
228
+ this.partialStoreHLSVod = false;
229
+ if (options && options.partialStoreHLSVod) {
230
+ this.partialStoreHLSVod = true;
231
+ }
232
+ this.alwaysMapBandwidthByNearest = false;
233
+ if (options && options.alwaysMapBandwidthByNearest) {
234
+ this.alwaysMapBandwidthByNearest = true;
235
+ }
223
236
  if (options && options.defaultSlateUri) {
224
237
  this.defaultSlateUri = options.defaultSlateUri;
225
238
  this.slateRepetitions = options.slateRepetitions || 10;
@@ -453,6 +466,8 @@ export class ChannelEngine {
453
466
  subtitleSliceEndpoint: this.subtitleSliceEndpoint,
454
467
  useVTTSubtitles: this.useVTTSubtitles,
455
468
  alwaysNewSegments: options.alwaysNewSegments,
469
+ partialStoreHLSVod: options.partialStoreHLSVod,
470
+ alwaysMapBandwidthByNearest: options.alwaysMapBandwidthByNearest,
456
471
  noSessionDataTags: options.noSessionDataTags,
457
472
  playheadDiffThreshold: channel.options && channel.options.playheadDiffThreshold ? channel.options.playheadDiffThreshold : this.streamerOpts.defaultPlayheadDiffThreshold,
458
473
  maxTickInterval: channel.options && channel.options.maxTickInterval ? channel.options.maxTickInterval : this.streamerOpts.defaultMaxTickInterval,
package/engine/session.js CHANGED
@@ -72,11 +72,22 @@ class Session {
72
72
  }
73
73
  this.isAllowedToClearVodCache = null;
74
74
  this.alwaysNewSegments = null;
75
+ this.alwaysMapBandwidthByNearest = null;
76
+ this.partialStoreHLSVod = null;
77
+ this.currentPlayheadRef = null;
75
78
  if (config) {
76
79
  if (config.alwaysNewSegments) {
77
80
  this.alwaysNewSegments = config.alwaysNewSegments;
78
81
  }
79
82
 
83
+ if (config.partialStoreHLSVod) {
84
+ this.partialStoreHLSVod = config.partialStoreHLSVod;
85
+ }
86
+
87
+ if (config.alwaysMapBandwidthByNearest) {
88
+ this.alwaysMapBandwidthByNearest = config.alwaysMapBandwidthByNearest;
89
+ }
90
+
80
91
  if (config.sessionId) {
81
92
  this._sessionId = config.sessionId;
82
93
  }
@@ -632,7 +643,7 @@ class Session {
632
643
  }
633
644
  let currentVod = null;
634
645
  const sessionState = await this._sessionState.getValues(["discSeqAudio", "vodMediaSeqAudio"]);
635
- let playheadState = await this._playheadState.getValues(["mediaSeqAudio", "vodMediaSeqAudio"]);
646
+ let playheadState = await this._playheadState.getValues(["mediaSeqAudio", "vodMediaSeqAudio", "playheadRef"]);
636
647
 
637
648
  if (playheadState.vodMediaSeqAudio > sessionState.vodMediaSeqAudio || (playheadState.vodMediaSeqAudio < sessionState.vodMediaSeqAudio && playheadState.mediaSeqAudio === this.prevMediaSeqOffset.audio)) {
638
649
  const state = await this._sessionState.get("state");
@@ -653,14 +664,10 @@ class Session {
653
664
  if (currentVod) {
654
665
  // condition suggesting that a new vod should exist
655
666
  if (playheadState.vodMediaSeqAudio < 2 || playheadState.mediaSeqAudio !== this.prevMediaSeqOffset.audio) {
656
- const AGE_THRESH = this.averageSegmentDuration * 2;
657
- let cacheAge = null;
658
- if (this._sessionState.cache && this._sessionState.cache.currentVod.ts) {
659
- cacheAge = Date.now() - this._sessionState.cache.currentVod.ts;
660
- }
661
- if (cacheAge !== null && cacheAge > AGE_THRESH) {
667
+ if (playheadState.playheadRef > this.currentPlayheadRef) {
662
668
  await timer(500);
663
- debug(`[${this._sessionId}]: While requesting audio manifest for ${audioGroupId}-${audioLanguage}, (mseq=${playheadState.vodMediaSeqAudio})(vod cache age=${cacheAge})`);
669
+ this.currentPlayheadRef = playheadState.playheadRef;
670
+ debug(`[${this._sessionId}]: While requesting audio manifest for ${audioGroupId}-${audioLanguage}, (mseq=${playheadState.vodMediaSeqAudio})`);
664
671
  await this._sessionState.clearCurrentVodCache(); // force reading up from shared store
665
672
  currentVod = await this._sessionState.getCurrentVod();
666
673
  }
@@ -707,7 +714,7 @@ class Session {
707
714
  }
708
715
  let currentVod = null;
709
716
  const sessionState = await this._sessionState.getValues(["discSeqSubtitle", "vodMediaSeqSubtitle"]);
710
- let playheadState = await this._playheadState.getValues(["mediaSeqSubtitle", "vodMediaSeqSubtitle"]);
717
+ let playheadState = await this._playheadState.getValues(["mediaSeqSubtitle", "vodMediaSeqSubtitle", "playheadRef"]);
711
718
 
712
719
  if (playheadState.vodMediaSeqSubtitle > sessionState.vodMediaSeqSubtitle || (playheadState.vodMediaSeqSubtitle < sessionState.vodMediaSeqSubtitle && playheadState.mediaSeqSubtitle === this.prevMediaSeqOffset.subtitle)) {
713
720
  const state = await this._sessionState.get("state");
@@ -728,14 +735,10 @@ class Session {
728
735
  if (currentVod) {
729
736
  // condition suggesting that a new vod should exist
730
737
  if (playheadState.vodMediaSeqSubtitle < 2 || playheadState.mediaSeqSubtitle !== this.prevMediaSeqOffset.subtitle) {
731
- const AGE_THRESH = this.averageSegmentDuration * 2;
732
- let cacheAge = null;
733
- if (this._sessionState.cache && this._sessionState.cache.currentVod.ts) {
734
- cacheAge = Date.now() - this._sessionState.cache.currentVod.ts;
735
- }
736
- if (cacheAge !== null && cacheAge > AGE_THRESH) {
738
+ if (playheadState.playheadRef > this.currentPlayheadRef) {
737
739
  await timer(500);
738
- debug(`[${this._sessionId}]: While requesting subtitle manifest for ${subtitleGroupId}-${subtitleLanguage}, (mseq=${playheadState.vodMediaSeqSubtitle})(vod cache age=${cacheAge})`);
740
+ this.currentPlayheadRef = playheadState.playheadRef;
741
+ debug(`[${this._sessionId}]: While requesting subtitle manifest for ${subtitleGroupId}-${subtitleLanguage}, (mseq=${playheadState.vodMediaSeqSubtitle})`);
739
742
  await this._sessionState.clearCurrentVodCache(); // force reading up from shared store
740
743
  currentVod = await this._sessionState.getCurrentVod();
741
744
  }
@@ -828,7 +831,7 @@ class Session {
828
831
  let positionV = 0;
829
832
  let positionA = 0;
830
833
  const position = (await this._getCurrentPlayheadPosition()) * 1000;
831
- positionV = position / 1000;
834
+ positionV = position ? position / 1000 : 0;
832
835
  let currentVod = await this._sessionState.getCurrentVod();
833
836
  const sessionState = await this._sessionState.getValues(["vodMediaSeqAudio"]);
834
837
  let posDiff;
@@ -840,11 +843,10 @@ class Session {
840
843
  debug(`[${this._sessionId}]: About to determine audio increment`);
841
844
  do {
842
845
  const audioPosition = (await this._getAudioPlayheadPosition(sessionState.vodMediaSeqAudio + index)) * 1000;
843
- positionA = audioPosition / 1000;
844
- posDiff = (positionV-positionA).toFixed(3);
845
- debug(`[${this._sessionId}]: positionV=${positionV};positionA=${positionA};posDiff=${posDiff};(posDiff <= 0.001)=${posDiff <= 0.001}`);
846
+ positionA = audioPosition ? audioPosition / 1000 : 0;
847
+ posDiff = (positionV - positionA).toFixed(3);
848
+ debug(`[${this._sessionId}]: positionV=${positionV};positionA=${positionA};posDiff=${posDiff}`);
846
849
  if (posDiff <= maxAcceptableDiff) {
847
- debug(`[${this._sessionId}]: posDiff value (${posDiff}) is acceptable`);
848
850
  break;
849
851
  }
850
852
  if (posDiff > thresh) {
@@ -858,7 +860,7 @@ class Session {
858
860
  if (sessionState.vodMediaSeqAudio + index > audioSeqLastIdx) {
859
861
  break;
860
862
  }
861
- } while (!(-thresh < posDiff && posDiff < thresh));
863
+ } while (!(-thresh < posDiff && posDiff < thresh) && !isNaN(posDiff));
862
864
  audioIncrement = index;
863
865
  debug(`[${this._sessionId}]: Current VOD Playhead Positions are to be: [${positionV.toFixed(3)}][${positionA.toFixed(3)}] (${posDiff})`);
864
866
  }
@@ -1271,7 +1273,7 @@ class Session {
1271
1273
  await this._sessionState.set("discSeq", sessionState.discSeq + lastDiscontinuity);
1272
1274
  await this._sessionState.set("discSeqAudio", sessionState.discSeqAudio + lastDiscontinuityAudio);
1273
1275
  await this._sessionState.set("slateCount", sessionState.slateCount + 1);
1274
- await this._playheadState.set("playheadRef", Date.now(), isLeader);
1276
+ this.currentPlayheadRef = await this._playheadState.set("playheadRef", Date.now(), isLeader);
1275
1277
 
1276
1278
  cloudWatchLog(!this.cloudWatchLogging, 'engine-session', { event: 'slateInserted', channel: this._sessionId });
1277
1279
 
@@ -1326,7 +1328,9 @@ class Session {
1326
1328
  dummySubtitleEndpoint: this.dummySubtitleEndpoint,
1327
1329
  subtitleSliceEndpoint: this.subtitleSliceEndpoint,
1328
1330
  shouldContainSubtitles: this.use_vtt_subtitles,
1329
- expectedSubtitleTracks: this._subtitleTracks
1331
+ expectedSubtitleTracks: this._subtitleTracks,
1332
+ alwaysMapBandwidthByNearest: this.alwaysMapBandwidthByNearest,
1333
+ skipSerializeMediaSequences: this.partialStoreHLSVod
1330
1334
  };
1331
1335
  newVod = new HLSVod(vodResponse.uri, [], vodResponse.unixTs, vodResponse.offset * 1000, m3u8Header(this._instanceId), hlsOpts);
1332
1336
  if (vodResponse.timedMetadata) {
@@ -1370,7 +1374,6 @@ class Session {
1370
1374
  sessionState.vodMediaSeqVideo = await this._sessionState.set("vodMediaSeqVideo", 0);
1371
1375
  sessionState.vodMediaSeqAudio = await this._sessionState.set("vodMediaSeqAudio", 0);
1372
1376
  sessionState.vodMediaSeqSubtitle = await this._sessionState.set("vodMediaSeqSubtitle", 0);
1373
- await this._playheadState.set("playheadRef", Date.now(), isLeader);
1374
1377
  this.produceEvent({
1375
1378
  type: 'NOW_PLAYING',
1376
1379
  data: {
@@ -1380,6 +1383,7 @@ class Session {
1380
1383
  });
1381
1384
  sessionState.state = await this._sessionState.set("state", SessionState.VOD_PLAYING);
1382
1385
  sessionState.currentVod = await this._sessionState.setCurrentVod(currentVod, { ttl: currentVod.getDuration() * 1000 });
1386
+ this.currentPlayheadRef = await this._playheadState.set("playheadRef", Date.now(), isLeader);
1383
1387
  await this._sessionState.remove("nextVod");
1384
1388
  return;
1385
1389
  } else {
@@ -1502,7 +1506,9 @@ class Session {
1502
1506
  dummySubtitleEndpoint: this.dummySubtitleEndpoint,
1503
1507
  subtitleSliceEndpoint: this.subtitleSliceEndpoint,
1504
1508
  shouldContainSubtitles: this.use_vtt_subtitles,
1505
- expectedSubtitleTracks: this._subtitleTracks
1509
+ expectedSubtitleTracks: this._subtitleTracks,
1510
+ alwaysMapBandwidthByNearest: this.alwaysMapBandwidthByNearest,
1511
+ skipSerializeMediaSequences: this.partialStoreHLSVod
1506
1512
  };
1507
1513
  newVod = new HLSVod(vodResponse.uri, null, vodResponse.unixTs, vodResponse.offset * 1000, m3u8Header(this._instanceId), hlsOpts);
1508
1514
  if (vodResponse.timedMetadata) {
@@ -1554,7 +1560,7 @@ class Session {
1554
1560
  currentVod = newVod;
1555
1561
  debug(`[${this._sessionId}]: msequences=${currentVod.getLiveMediaSequencesCount()}; audio msequences=${currentVod.getLiveMediaSequencesCount("audio")}; subtitle msequences=${currentVod.getLiveMediaSequencesCount("subtitle")}`);
1556
1562
  sessionState.currentVod = await this._sessionState.setCurrentVod(currentVod, { ttl: currentVod.getDuration() * 1000 });
1557
- await this._playheadState.set("playheadRef", Date.now(), isLeader);
1563
+ this.currentPlayheadRef = await this._playheadState.set("playheadRef", Date.now(), isLeader);
1558
1564
  sessionState.vodMediaSeqVideo = await this._sessionState.set("vodMediaSeqVideo", 0);
1559
1565
  sessionState.vodMediaSeqAudio = await this._sessionState.set("vodMediaSeqAudio", 0);
1560
1566
  sessionState.vodMediaSeqSubtitle = await this._sessionState.set("vodMediaSeqSubtitle", 0);
@@ -1669,7 +1675,7 @@ class Session {
1669
1675
  await this._playheadState.set("vodMediaSeqVideo", 0, isLeader);
1670
1676
  await this._playheadState.set("vodMediaSeqAudio", 0, isLeader);
1671
1677
  await this._playheadState.set("vodMediaSeqSubtitle", 0, isLeader);
1672
- await this._playheadState.set("playheadRef", Date.now(), isLeader);
1678
+ this.currentPlayheadRef = await this._playheadState.set("playheadRef", Date.now(), isLeader);
1673
1679
  // 4) Log to debug and cloudwatch
1674
1680
  debug(`[${this._sessionId}]: LEADER: Set new Reloaded VOD and vodMediaSeq counts in store.`);
1675
1681
  debug(`[${this._sessionId}]: next VOD Reloaded (${currentVod.getDeltaTimes()})`);
@@ -1749,7 +1755,9 @@ class Session {
1749
1755
  dummySubtitleEndpoint: this.dummySubtitleEndpoint,
1750
1756
  subtitleSliceEndpoint: this.subtitleSliceEndpoint,
1751
1757
  shouldContainSubtitles: this.use_vtt_subtitles,
1752
- expectedSubtitleTracks: this._subtitleTracks
1758
+ expectedSubtitleTracks: this._subtitleTracks,
1759
+ alwaysMapBandwidthByNearest: this.alwaysMapBandwidthByNearest,
1760
+ skipSerializeMediaSequences: this.partialStoreHLSVod
1753
1761
  };
1754
1762
  const timestamp = Date.now();
1755
1763
  hlsVod = new HLSVod(this.slateUri, null, timestamp, null, m3u8Header(this._instanceId), hlsOpts);
@@ -1799,7 +1807,11 @@ class Session {
1799
1807
  _truncateVod(vodResponse) {
1800
1808
  return new Promise((resolve, reject) => {
1801
1809
  try {
1802
- const truncatedVod = new HLSTruncateVod(vodResponse.uri, vodResponse.desiredDuration / 1000);
1810
+ const options = {};
1811
+ if (vodResponse.startOffset) {
1812
+ options.offset = vodResponse.startOffset / 1000;
1813
+ }
1814
+ const truncatedVod = new HLSTruncateVod(vodResponse.uri, vodResponse.desiredDuration / 1000, options);
1803
1815
  truncatedVod.load()
1804
1816
  .then(() => {
1805
1817
  let audioManifestLoader;
@@ -1848,7 +1860,9 @@ class Session {
1848
1860
  dummySubtitleEndpoint: this.dummySubtitleEndpoint,
1849
1861
  subtitleSliceEndpoint: this.subtitleSliceEndpoint,
1850
1862
  shouldContainSubtitles: this.use_vtt_subtitles,
1851
- expectedSubtitleTracks: this._subtitleTracks
1863
+ expectedSubtitleTracks: this._subtitleTracks,
1864
+ alwaysMapBandwidthByNearest: this.alwaysMapBandwidthByNearest,
1865
+ skipSerializeMediaSequences: this.partialStoreHLSVod
1852
1866
  };
1853
1867
  const timestamp = Date.now();
1854
1868
  hlsVod = new HLSVod(nexVodUri, null, timestamp, null, m3u8Header(this._instanceId), hlsOpts);
@@ -57,9 +57,18 @@ class SharedSessionState {
57
57
  let hlsVod = null;
58
58
  if (currentVod) {
59
59
  if (this.store.isShared()) {
60
- debug(`[${this.sessionId}]: reading ${currentVod.length} characters from shared store (${Date.now()} < ${this.cache.currentVod.ts + this.cache.currentVod.ttl})`);
60
+ const strToMB = (str) => {
61
+ const bytesPerCharacter = 2; // Assuming each character takes around 2 bytes in memory
62
+ const stringSizeBytes = str.length * bytesPerCharacter;
63
+ const sizeInMegabytes = stringSizeBytes / (1024 * 1024);
64
+ return sizeInMegabytes.toFixed(1);
65
+ }
66
+ debug(`[${this.sessionId}]: reading ${currentVod.length} characters or (${strToMB(currentVod)} MB) from shared store (${Date.now()} < ${this.cache.currentVod.ts + this.cache.currentVod.ttl})`);
61
67
  hlsVod = new HLSVod();
62
68
  hlsVod.fromJSON(currentVod);
69
+ if (hlsVod.skipSerializeMediaSequences) {
70
+ await hlsVod.generateMediaSequences();
71
+ }
63
72
  } else {
64
73
  hlsVod = currentVod;
65
74
  }
@@ -83,6 +92,9 @@ class SharedSessionState {
83
92
  const currentVod = await this.get("currentVod");
84
93
  hlsVod = new HLSVod();
85
94
  hlsVod.fromJSON(currentVod);
95
+ if (hlsVod.skipSerializeMediaSequences) {
96
+ await hlsVod.generateMediaSequences();
97
+ }
86
98
  }
87
99
  } else {
88
100
  await this.set("currentVod", hlsVod);
@@ -57,7 +57,8 @@ class RefAssetManager implements IAssetManager {
57
57
  id: vod.id,
58
58
  title: vod.title,
59
59
  uri: vod.uri,
60
- desiredDuration: 50000
60
+ desiredDuration: 50000,
61
+ startOffset: 10000,
61
62
  };
62
63
  resolve(vodResponse);
63
64
  } else {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eyevinn-channel-engine",
3
- "version": "4.2.9",
3
+ "version": "4.3.0",
4
4
  "description": "OTT TV Channel Engine",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -29,8 +29,8 @@
29
29
  "license": "Apache-2.0",
30
30
  "dependencies": {
31
31
  "@eyevinn/hls-repeat": "^0.2.0",
32
- "@eyevinn/hls-truncate": "^0.2.0",
33
- "@eyevinn/hls-vodtolive": "^3.0.1",
32
+ "@eyevinn/hls-truncate": "^0.3.0",
33
+ "@eyevinn/hls-vodtolive": "^4.0.0",
34
34
  "@eyevinn/m3u8": "^0.5.3",
35
35
  "abort-controller": "^3.0.0",
36
36
  "debug": "^3.2.7",