eyevinn-channel-engine 4.2.3 → 4.2.5

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.
@@ -2477,26 +2477,34 @@ var Session = /** @class */ (function () {
2477
2477
  Session.prototype._truncateVod = function (vodResponse) {
2478
2478
  var _this = this;
2479
2479
  return new Promise(function (resolve, reject) {
2480
- var truncatedVod = new HLSTruncateVod(vodResponse.uri, vodResponse.desiredDuration / 1000);
2481
- truncatedVod.load()
2482
- .then(function () {
2483
- var audioManifestLoader;
2484
- var mediaManifestLoader = function (bw) {
2485
- var mediaManifestStream = new Readable();
2486
- mediaManifestStream.push(truncatedVod.getMediaManifest(bw));
2487
- mediaManifestStream.push(null);
2488
- return mediaManifestStream;
2489
- };
2490
- if (_this.use_demuxed_audio) {
2491
- audioManifestLoader = function (audioGroupId, audioLanguage) {
2480
+ try {
2481
+ var truncatedVod_1 = new HLSTruncateVod(vodResponse.uri, vodResponse.desiredDuration / 1000);
2482
+ truncatedVod_1.load()
2483
+ .then(function () {
2484
+ var audioManifestLoader;
2485
+ var mediaManifestLoader = function (bw) {
2492
2486
  var mediaManifestStream = new Readable();
2493
- mediaManifestStream.push(truncatedVod.getAudioManifest(audioGroupId, audioLanguage));
2487
+ mediaManifestStream.push(truncatedVod_1.getMediaManifest(bw));
2494
2488
  mediaManifestStream.push(null);
2495
2489
  return mediaManifestStream;
2496
2490
  };
2497
- }
2498
- resolve({ mediaManifestLoader: mediaManifestLoader, audioManifestLoader: audioManifestLoader });
2499
- });
2491
+ if (_this.use_demuxed_audio) {
2492
+ audioManifestLoader = function (audioGroupId, audioLanguage) {
2493
+ var mediaManifestStream = new Readable();
2494
+ mediaManifestStream.push(truncatedVod_1.getAudioManifest(audioGroupId, audioLanguage));
2495
+ mediaManifestStream.push(null);
2496
+ return mediaManifestStream;
2497
+ };
2498
+ }
2499
+ resolve({ mediaManifestLoader: mediaManifestLoader, audioManifestLoader: audioManifestLoader });
2500
+ }).catch(function (err) {
2501
+ debug(err);
2502
+ reject(err);
2503
+ });
2504
+ }
2505
+ catch (err) {
2506
+ reject(err);
2507
+ }
2500
2508
  });
2501
2509
  };
2502
2510
  Session.prototype._truncateSlate = function (afterVod, requestedDuration, vodUri) {
@@ -126,31 +126,34 @@ var SharedSessionState = /** @class */ (function () {
126
126
  };
127
127
  SharedSessionState.prototype.setCurrentVod = function (hlsVod, opts) {
128
128
  return __awaiter(this, void 0, void 0, function () {
129
- var newHlsVodJson, isLeader;
129
+ var isLeader;
130
130
  return __generator(this, function (_a) {
131
131
  switch (_a.label) {
132
132
  case 0:
133
133
  if (!this.sessionId) {
134
134
  throw new Error("shared session state store has not been initialized");
135
135
  }
136
- if (!this.store.isShared()) return [3 /*break*/, 3];
137
- return [4 /*yield*/, this.set("currentVod", hlsVod.toJSON())];
136
+ if (!this.store.isShared()) return [3 /*break*/, 6];
137
+ return [4 /*yield*/, this.store.clearLeaderCache()];
138
138
  case 1:
139
- newHlsVodJson = _a.sent();
139
+ _a.sent();
140
140
  return [4 /*yield*/, this.store.isLeader(this.instanceId)];
141
141
  case 2:
142
142
  isLeader = _a.sent();
143
- if (!isLeader) {
144
- debug("[".concat(this.sessionId, "]: not a leader, will not overwrite currentVod in shared store"));
145
- hlsVod = new HLSVod();
146
- hlsVod.fromJSON(newHlsVodJson);
147
- }
143
+ if (!isLeader) return [3 /*break*/, 4];
144
+ return [4 /*yield*/, this.set("currentVod", hlsVod.toJSON())];
145
+ case 3:
146
+ _a.sent();
148
147
  return [3 /*break*/, 5];
149
- case 3: return [4 /*yield*/, this.set("currentVod", hlsVod)];
150
148
  case 4:
151
- _a.sent();
149
+ debug("[".concat(this.sessionId, "]: not a leader, will not overwrite currentVod in shared store"));
152
150
  _a.label = 5;
153
- case 5:
151
+ case 5: return [3 /*break*/, 8];
152
+ case 6: return [4 /*yield*/, this.set("currentVod", hlsVod)];
153
+ case 7:
154
+ _a.sent();
155
+ _a.label = 8;
156
+ case 8:
154
157
  if (this.cache.currentVod) {
155
158
  this.cache.currentVod.ts = Date.now();
156
159
  this.cache.currentVod.ttl = CURRENTVOD_CACHE_TTL;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,92 @@
1
+ "use strict";
2
+ /*
3
+ * Reference implementation of Channel Engine library
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ var index_1 = require("../index");
7
+ var DEFAULT_ASSETS = [
8
+ {
9
+ id: 1,
10
+ title: "Tears of Steel",
11
+ uri: "https://maitv-vod.lab.eyevinn.technology/tearsofsteel_4k.mov/master.m3u8",
12
+ },
13
+ {
14
+ id: 2,
15
+ title: "VINN",
16
+ uri: "https://maitv-vod.lab.eyevinn.technology/VINN.mp4/master.m3u8",
17
+ },
18
+ ];
19
+ var RefAssetManager = /** @class */ (function () {
20
+ function RefAssetManager(opts) {
21
+ this.assets = {};
22
+ this.assets['1'] = DEFAULT_ASSETS;
23
+ this.pos = {
24
+ '1': 0,
25
+ };
26
+ }
27
+ /**
28
+ *
29
+ * @param {Object} vodRequest
30
+ * {
31
+ * sessionId,
32
+ * category,
33
+ * playlistId
34
+ * }
35
+ */
36
+ RefAssetManager.prototype.getNextVod = function (vodRequest) {
37
+ var _this = this;
38
+ return new Promise(function (resolve, reject) {
39
+ var channelId = vodRequest.playlistId;
40
+ if (_this.pos[channelId] === undefined) {
41
+ _this.pos[channelId] = 0;
42
+ _this.assets[channelId] = DEFAULT_ASSETS;
43
+ }
44
+ if (_this.assets[channelId]) {
45
+ var vod = _this.assets[channelId][_this.pos[channelId]++];
46
+ if (_this.pos[channelId] > _this.assets[channelId].length - 1) {
47
+ _this.pos[channelId] = 0;
48
+ }
49
+ var vodResponse = {
50
+ id: vod.id,
51
+ title: vod.title,
52
+ uri: vod.uri,
53
+ desiredDuration: 50000
54
+ };
55
+ resolve(vodResponse);
56
+ }
57
+ else {
58
+ reject("Invalid channelId provided");
59
+ }
60
+ });
61
+ };
62
+ return RefAssetManager;
63
+ }());
64
+ var RefChannelManager = /** @class */ (function () {
65
+ function RefChannelManager() {
66
+ this.channels = [];
67
+ this.channels.push({ id: "1", profile: this._getProfile() });
68
+ }
69
+ RefChannelManager.prototype.getChannels = function () {
70
+ return this.channels;
71
+ };
72
+ RefChannelManager.prototype._getProfile = function () {
73
+ return [
74
+ { bw: 6134000, codecs: "avc1.4d001f,mp4a.40.2", resolution: [1024, 458] },
75
+ { bw: 2323000, codecs: "avc1.4d001f,mp4a.40.2", resolution: [640, 286] },
76
+ { bw: 1313000, codecs: "avc1.4d001f,mp4a.40.2", resolution: [480, 214] },
77
+ ];
78
+ };
79
+ return RefChannelManager;
80
+ }());
81
+ var refAssetManager = new RefAssetManager();
82
+ var refChannelManager = new RefChannelManager();
83
+ var engineOptions = {
84
+ heartbeat: "/",
85
+ averageSegmentDuration: 2000,
86
+ channelManager: refChannelManager,
87
+ defaultSlateUri: "https://maitv-vod.lab.eyevinn.technology/slate-consuo.mp4/master.m3u8",
88
+ slateRepetitions: 10,
89
+ };
90
+ var engine = new index_1.ChannelEngine(refAssetManager, engineOptions);
91
+ engine.start();
92
+ engine.listen(process.env.PORT || 8000);
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eyevinn-channel-engine",
3
- "version": "4.2.3",
3
+ "version": "4.2.5",
4
4
  "description": "OTT TV Channel Engine",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -30,7 +30,7 @@
30
30
  "dependencies": {
31
31
  "@eyevinn/hls-repeat": "^0.2.0",
32
32
  "@eyevinn/hls-truncate": "^0.2.0",
33
- "@eyevinn/hls-vodtolive": "^3.0.0",
33
+ "@eyevinn/hls-vodtolive": "^3.0.1",
34
34
  "@eyevinn/m3u8": "^0.5.3",
35
35
  "abort-controller": "^3.0.0",
36
36
  "debug": "^3.2.7",
package/engine/session.js CHANGED
@@ -1794,29 +1794,34 @@ class Session {
1794
1794
 
1795
1795
  _truncateVod(vodResponse) {
1796
1796
  return new Promise((resolve, reject) => {
1797
- const truncatedVod = new HLSTruncateVod(vodResponse.uri, vodResponse.desiredDuration / 1000);
1798
- truncatedVod.load()
1799
- .then(() => {
1800
- let audioManifestLoader;
1801
- const mediaManifestLoader = (bw) => {
1802
- let mediaManifestStream = new Readable();
1803
- mediaManifestStream.push(truncatedVod.getMediaManifest(bw));
1804
- mediaManifestStream.push(null);
1805
- return mediaManifestStream;
1806
- };
1807
- if (this.use_demuxed_audio) {
1808
- audioManifestLoader = (audioGroupId, audioLanguage) => {
1797
+ try {
1798
+ const truncatedVod = new HLSTruncateVod(vodResponse.uri, vodResponse.desiredDuration / 1000);
1799
+ truncatedVod.load()
1800
+ .then(() => {
1801
+ let audioManifestLoader;
1802
+ const mediaManifestLoader = (bw) => {
1809
1803
  let mediaManifestStream = new Readable();
1810
- mediaManifestStream.push(truncatedVod.getAudioManifest(audioGroupId, audioLanguage));
1804
+ mediaManifestStream.push(truncatedVod.getMediaManifest(bw));
1811
1805
  mediaManifestStream.push(null);
1812
1806
  return mediaManifestStream;
1813
1807
  };
1814
- }
1815
- resolve({ mediaManifestLoader, audioManifestLoader });
1816
- });
1808
+ if (this.use_demuxed_audio) {
1809
+ audioManifestLoader = (audioGroupId, audioLanguage) => {
1810
+ let mediaManifestStream = new Readable();
1811
+ mediaManifestStream.push(truncatedVod.getAudioManifest(audioGroupId, audioLanguage));
1812
+ mediaManifestStream.push(null);
1813
+ return mediaManifestStream;
1814
+ };
1815
+ }
1816
+ resolve({ mediaManifestLoader, audioManifestLoader });
1817
+ }).catch(err => {
1818
+ debug(err);
1819
+ reject(err);
1820
+ });
1821
+ } catch (err) {
1822
+ reject(err);
1823
+ }
1817
1824
  });
1818
-
1819
-
1820
1825
  }
1821
1826
 
1822
1827
  _truncateSlate(afterVod, requestedDuration, vodUri) {
@@ -75,12 +75,12 @@ class SharedSessionState {
75
75
  }
76
76
 
77
77
  if (this.store.isShared()) {
78
- let newHlsVodJson = await this.set("currentVod", hlsVod.toJSON());
78
+ await this.store.clearLeaderCache();
79
79
  const isLeader = await this.store.isLeader(this.instanceId);
80
- if (!isLeader) {
80
+ if (isLeader) {
81
+ await this.set("currentVod", hlsVod.toJSON());
82
+ } else {
81
83
  debug(`[${this.sessionId}]: not a leader, will not overwrite currentVod in shared store`);
82
- hlsVod = new HLSVod();
83
- hlsVod.fromJSON(newHlsVodJson);
84
84
  }
85
85
  } else {
86
86
  await this.set("currentVod", hlsVod);
@@ -0,0 +1,104 @@
1
+ /*
2
+ * Reference implementation of Channel Engine library
3
+ */
4
+
5
+ import { ChannelEngine, ChannelEngineOpts,
6
+ IAssetManager, IChannelManager,
7
+ VodRequest, VodResponse, Channel, ChannelProfile
8
+ } from "../index";
9
+
10
+ const DEFAULT_ASSETS = [
11
+ {
12
+ id: 1,
13
+ title: "Tears of Steel",
14
+ uri: "https://maitv-vod.lab.eyevinn.technology/tearsofsteel_4k.mov/master.m3u8",
15
+ },
16
+ {
17
+ id: 2,
18
+ title: "VINN",
19
+ uri: "https://maitv-vod.lab.eyevinn.technology/VINN.mp4/master.m3u8",
20
+ },
21
+ ];
22
+
23
+ class RefAssetManager implements IAssetManager {
24
+ private assets;
25
+ private pos;
26
+
27
+ constructor(opts?) {
28
+ this.assets = {};
29
+ this.assets['1'] = DEFAULT_ASSETS;
30
+ this.pos = {
31
+ '1': 0,
32
+ };
33
+ }
34
+
35
+ /**
36
+ *
37
+ * @param {Object} vodRequest
38
+ * {
39
+ * sessionId,
40
+ * category,
41
+ * playlistId
42
+ * }
43
+ */
44
+ getNextVod(vodRequest: VodRequest): Promise<VodResponse> {
45
+ return new Promise((resolve, reject) => {
46
+ const channelId = vodRequest.playlistId;
47
+ if (this.pos[channelId] === undefined) {
48
+ this.pos[channelId] = 0;
49
+ this.assets[channelId] = DEFAULT_ASSETS;
50
+ }
51
+ if (this.assets[channelId]) {
52
+ let vod = this.assets[channelId][this.pos[channelId]++];
53
+ if (this.pos[channelId] > this.assets[channelId].length - 1) {
54
+ this.pos[channelId] = 0;
55
+ }
56
+ const vodResponse = {
57
+ id: vod.id,
58
+ title: vod.title,
59
+ uri: vod.uri,
60
+ desiredDuration: 50000
61
+ };
62
+ resolve(vodResponse);
63
+ } else {
64
+ reject("Invalid channelId provided");
65
+ }
66
+ });
67
+ }
68
+ }
69
+
70
+ class RefChannelManager implements IChannelManager {
71
+ private channels: Channel[] = [];
72
+
73
+ constructor() {
74
+ this.channels.push({ id: "1", profile: this._getProfile() });
75
+ }
76
+
77
+ getChannels(): Channel[] {
78
+ return this.channels;
79
+ }
80
+
81
+ _getProfile(): ChannelProfile[] {
82
+ return [
83
+ { bw: 6134000, codecs: "avc1.4d001f,mp4a.40.2", resolution: [1024, 458] },
84
+ { bw: 2323000, codecs: "avc1.4d001f,mp4a.40.2", resolution: [640, 286] },
85
+ { bw: 1313000, codecs: "avc1.4d001f,mp4a.40.2", resolution: [480, 214] },
86
+ ];
87
+ }
88
+ }
89
+
90
+ const refAssetManager = new RefAssetManager();
91
+ const refChannelManager = new RefChannelManager();
92
+
93
+ const engineOptions: ChannelEngineOpts = {
94
+ heartbeat: "/",
95
+ averageSegmentDuration: 2000,
96
+ channelManager: refChannelManager,
97
+ defaultSlateUri:
98
+ "https://maitv-vod.lab.eyevinn.technology/slate-consuo.mp4/master.m3u8",
99
+ slateRepetitions: 10,
100
+ };
101
+
102
+ const engine = new ChannelEngine(refAssetManager, engineOptions);
103
+ engine.start();
104
+ engine.listen(process.env.PORT || 8000);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eyevinn-channel-engine",
3
- "version": "4.2.3",
3
+ "version": "4.2.5",
4
4
  "description": "OTT TV Channel Engine",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -30,7 +30,7 @@
30
30
  "dependencies": {
31
31
  "@eyevinn/hls-repeat": "^0.2.0",
32
32
  "@eyevinn/hls-truncate": "^0.2.0",
33
- "@eyevinn/hls-vodtolive": "^3.0.0",
33
+ "@eyevinn/hls-vodtolive": "^3.0.1",
34
34
  "@eyevinn/m3u8": "^0.5.3",
35
35
  "abort-controller": "^3.0.0",
36
36
  "debug": "^3.2.7",