eyevinn-channel-engine 4.3.3-rc.4 → 4.3.4

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.
package/README.md CHANGED
@@ -35,6 +35,7 @@ A live demo and example is available here: [https://vod2live.eyevinn.technology]
35
35
  - Mix VOD2Live channel with a "real" live HLS stream
36
36
  - Develop adapters to plugin with custom scheduling endpoints
37
37
  - High Availability with Redis Cache as shared state store
38
+ - Support for WebVTT subtitles
38
39
  - Support for DRM encrypted HLS VODs (in beta)
39
40
  - And much more!
40
41
 
@@ -52,8 +53,8 @@ Supported Node.js Versions
52
53
 
53
54
  | HLS Format | Muxed | Demuxed | Mix w. Live | Subtitles | DRM |
54
55
  | ---------- | ----- | ------- | ----------- | --------- | --- |
55
- | HLS + TS | Yes | Yes | Yes* | TBD | No |
56
- | HLS + CMAF | No | Yes | TBD | TBD | TBD |
56
+ | HLS + TS | Yes | Yes | Yes* | Yes | No |
57
+ | HLS + CMAF | No | Yes | TBD | Yes | TBD |
57
58
 
58
59
  *\* not supported with demuxed sources*
59
60
 
@@ -36,7 +36,13 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
36
36
  };
37
37
  var Redis = require("ioredis");
38
38
  var debug = require("debug")("redis-state-store");
39
+ var cloudWatchLog = require("./util.js").cloudWatchLog;
39
40
  var DEFAULT_VOLATILE_KEY_TTL = 5; // Timeout so it should not expire within one normal increment iteration (in seconds)
41
+ function isTrue(s) {
42
+ var regex = /^\s*(true|1)\s*$/i;
43
+ return regex.test(s);
44
+ }
45
+ var REDIS_VERBOSE_LOG = process.env.REDIS_VERBOSE_LOG ? isTrue(process.env.REDIS_VERBOSE_LOG) : false;
40
46
  var RedisStateStore = /** @class */ (function () {
41
47
  function RedisStateStore(keyPrefix, opts) {
42
48
  this.keyPrefix = keyPrefix;
@@ -135,12 +141,13 @@ var RedisStateStore = /** @class */ (function () {
135
141
  };
136
142
  RedisStateStore.prototype.getValues = function (id, keys) {
137
143
  return __awaiter(this, void 0, void 0, function () {
138
- var pipeline, data, _loop_1, this_1, _i, keys_1, key;
144
+ var pipeline, data, startMs, _loop_1, this_1, _i, keys_1, key, ops, ioTimeMs;
139
145
  return __generator(this, function (_a) {
140
146
  switch (_a.label) {
141
147
  case 0:
142
148
  pipeline = this.client.pipeline();
143
149
  data = {};
150
+ startMs = Date.now();
144
151
  _loop_1 = function (key) {
145
152
  var storeKey = "" + this_1.keyPrefix + id + key;
146
153
  pipeline.get(storeKey, function (err, reply) {
@@ -160,9 +167,12 @@ var RedisStateStore = /** @class */ (function () {
160
167
  key = keys_1[_i];
161
168
  _loop_1(key);
162
169
  }
170
+ ops = pipeline.length;
163
171
  return [4 /*yield*/, pipeline.exec()];
164
172
  case 1:
165
173
  _a.sent();
174
+ ioTimeMs = Date.now() - startMs;
175
+ cloudWatchLog(!REDIS_VERBOSE_LOG, 'redis', { event: 'getValues', operations: ops, ioTimeMs: ioTimeMs });
166
176
  return [2 /*return*/, data];
167
177
  }
168
178
  });
@@ -189,6 +199,7 @@ var RedisStateStore = /** @class */ (function () {
189
199
  catch (err) {
190
200
  console.error("REDIS get: Failed to parse ".concat(storeKey, " data: '").concat(reply, "'"));
191
201
  }
202
+ cloudWatchLog(!REDIS_VERBOSE_LOG, 'redis', { event: 'get', operations: 1, ioTimeMs: ioTimeMs });
192
203
  resolve(data_1);
193
204
  }
194
205
  else {
@@ -206,11 +217,12 @@ var RedisStateStore = /** @class */ (function () {
206
217
  };
207
218
  RedisStateStore.prototype.setValues = function (id, data) {
208
219
  return __awaiter(this, void 0, void 0, function () {
209
- var returnData, pipeline, _loop_2, this_2, _i, _a, key;
220
+ var returnData, startMs, pipeline, _loop_2, this_2, _i, _a, key, ops, ioTimeMs;
210
221
  return __generator(this, function (_b) {
211
222
  switch (_b.label) {
212
223
  case 0:
213
224
  returnData = {};
225
+ startMs = Date.now();
214
226
  pipeline = this.client.pipeline();
215
227
  _loop_2 = function (key) {
216
228
  var storeKey = "" + this_2.keyPrefix + id + key;
@@ -227,9 +239,12 @@ var RedisStateStore = /** @class */ (function () {
227
239
  key = _a[_i];
228
240
  _loop_2(key);
229
241
  }
242
+ ops = pipeline.length;
230
243
  return [4 /*yield*/, pipeline.exec()];
231
244
  case 1:
232
245
  _b.sent();
246
+ ioTimeMs = Date.now() - startMs;
247
+ cloudWatchLog(!REDIS_VERBOSE_LOG, 'redis', { event: 'setValues', operations: ops, ioTimeMs: ioTimeMs });
233
248
  return [2 /*return*/, returnData];
234
249
  }
235
250
  });
@@ -249,6 +264,7 @@ var RedisStateStore = /** @class */ (function () {
249
264
  var ioTimeMs = Date.now() - startMs;
250
265
  debug("REDIS set ".concat(storeKey, ": ").concat(res, " (").concat(ioTimeMs, "ms) ").concat(ioTimeMs > 1000 ? "REDISSLOW!" : ""));
251
266
  if (!err) {
267
+ cloudWatchLog(!REDIS_VERBOSE_LOG, 'redis', { event: 'set', operations: 1, ioTimeMs: ioTimeMs });
252
268
  resolve(value);
253
269
  }
254
270
  else {
@@ -305,6 +321,7 @@ var RedisStateStore = /** @class */ (function () {
305
321
  var ioTimeMs = Date.now() - startMs;
306
322
  debug("REDIS remove ".concat(storeKey, ": (").concat(ioTimeMs, "ms) ").concat(ioTimeMs > 1000 ? "REDISSLOW!" : ""));
307
323
  if (!err) {
324
+ cloudWatchLog(!REDIS_VERBOSE_LOG, 'redis', { event: 'remove', operations: 1, ioTimeMs: ioTimeMs });
308
325
  resolve();
309
326
  }
310
327
  else {
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eyevinn-channel-engine",
3
- "version": "4.3.3-rc.4",
3
+ "version": "4.3.4",
4
4
  "description": "OTT TV Channel Engine",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/docs/demosite.png CHANGED
Binary file
@@ -1,8 +1,16 @@
1
1
  const Redis = require("ioredis");
2
2
  const debug = require("debug")("redis-state-store");
3
+ const { cloudWatchLog } = require("./util.js");
3
4
 
4
5
  const DEFAULT_VOLATILE_KEY_TTL = 5; // Timeout so it should not expire within one normal increment iteration (in seconds)
5
6
 
7
+ function isTrue(s) {
8
+ const regex = /^\s*(true|1)\s*$/i;
9
+ return regex.test(s);
10
+ }
11
+
12
+ const REDIS_VERBOSE_LOG = process.env.REDIS_VERBOSE_LOG ? isTrue(process.env.REDIS_VERBOSE_LOG) : false;
13
+
6
14
  class RedisStateStore {
7
15
  constructor(keyPrefix, opts) {
8
16
  this.keyPrefix = keyPrefix;
@@ -59,6 +67,7 @@ class RedisStateStore {
59
67
  async getValues(id, keys) {
60
68
  const pipeline = this.client.pipeline();
61
69
  let data = {};
70
+ const startMs = Date.now();
62
71
  for (const key of keys) {
63
72
  const storeKey = "" + this.keyPrefix + id + key;
64
73
  pipeline.get(storeKey, (err, reply) => {
@@ -72,7 +81,11 @@ class RedisStateStore {
72
81
  }
73
82
  });
74
83
  }
84
+ const ops = pipeline.length;
75
85
  await pipeline.exec();
86
+ const ioTimeMs = Date.now() - startMs;
87
+ cloudWatchLog(!REDIS_VERBOSE_LOG, 'redis',
88
+ { event: 'getValues', operations: ops, ioTimeMs: ioTimeMs });
76
89
  return data;
77
90
  }
78
91
 
@@ -90,6 +103,8 @@ class RedisStateStore {
90
103
  } catch (err) {
91
104
  console.error(`REDIS get: Failed to parse ${storeKey} data: '${reply}'`);
92
105
  }
106
+ cloudWatchLog(!REDIS_VERBOSE_LOG, 'redis',
107
+ { event: 'get', operations: 1, ioTimeMs: ioTimeMs });
93
108
  resolve(data);
94
109
  } else {
95
110
  reject(err);
@@ -102,6 +117,7 @@ class RedisStateStore {
102
117
 
103
118
  async setValues(id, data) {
104
119
  const returnData = {};
120
+ const startMs = Date.now();
105
121
  const pipeline = this.client.pipeline();
106
122
  for (const key of Object.keys(data)) {
107
123
  const storeKey = "" + this.keyPrefix + id + key;
@@ -113,7 +129,11 @@ class RedisStateStore {
113
129
  }
114
130
  });
115
131
  }
132
+ const ops = pipeline.length;
116
133
  await pipeline.exec();
134
+ const ioTimeMs = Date.now() - startMs;
135
+ cloudWatchLog(!REDIS_VERBOSE_LOG, 'redis',
136
+ { event: 'setValues', operations: ops, ioTimeMs: ioTimeMs });
117
137
  return returnData;
118
138
  }
119
139
 
@@ -125,6 +145,8 @@ class RedisStateStore {
125
145
  const ioTimeMs = Date.now() - startMs;
126
146
  debug(`REDIS set ${storeKey}: ${res} (${ioTimeMs}ms) ${ioTimeMs > 1000 ? "REDISSLOW!" : ""}`);
127
147
  if (!err) {
148
+ cloudWatchLog(!REDIS_VERBOSE_LOG, 'redis',
149
+ { event: 'set', operations: 1, ioTimeMs: ioTimeMs });
128
150
  resolve(value);
129
151
  } else {
130
152
  reject(err);
@@ -159,6 +181,8 @@ class RedisStateStore {
159
181
  const ioTimeMs = Date.now() - startMs;
160
182
  debug(`REDIS remove ${storeKey}: (${ioTimeMs}ms) ${ioTimeMs > 1000 ? "REDISSLOW!" : ""}`);
161
183
  if (!err) {
184
+ cloudWatchLog(!REDIS_VERBOSE_LOG, 'redis',
185
+ { event: 'remove', operations: 1, ioTimeMs: ioTimeMs });
162
186
  resolve();
163
187
  } else {
164
188
  reject(err);
@@ -0,0 +1,25 @@
1
+ # Development env for HA
2
+
3
+ To develop and test Channel Engine in HA mode using Redis as shared state store.
4
+
5
+ Start an NGINX as Load Balancer and a Redis instance:
6
+
7
+ ```
8
+ cd ha-dev/
9
+ docker-compose -f docker-compose-lb.yml up --build
10
+ ```
11
+
12
+ The Load Balancer is then reachable on `http://localhost:8000` and will proxy (round robin) to three
13
+ instances on port 8080, 8081 and 8082.
14
+
15
+ Start one engine instance with the following parameters (at least):
16
+
17
+ ```
18
+ PORT=8080 REDIS_URL=redis://localhost:6379/ npm start
19
+ ```
20
+
21
+ and a second engine instance:
22
+
23
+ ```
24
+ PORT=8081 REDIS_URL=redis://localhost:6379/ npm start
25
+ ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eyevinn-channel-engine",
3
- "version": "4.3.3-rc.4",
3
+ "version": "4.3.4",
4
4
  "description": "OTT TV Channel Engine",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -1 +0,0 @@
1
- export {};
@@ -1,107 +0,0 @@
1
- "use strict";
2
- /*
3
- * Reference implementation of Channel Engine library using demuxed VOD assets.
4
- */
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- var index_1 = require("./index");
7
- var RefAssetManager = /** @class */ (function () {
8
- function RefAssetManager(opts) {
9
- this.assets = {
10
- 1: [
11
- {
12
- id: 1,
13
- title: "Elephants dream",
14
- uri: "https://playertest.longtailvideo.com/adaptive/elephants_dream_v4/index.m3u8",
15
- },
16
- {
17
- id: 2,
18
- title: "Test HLS Bird noises (1m10s)",
19
- uri: "https://mtoczko.github.io/hls-test-streams/test-audio-pdt/playlist.m3u8",
20
- },
21
- ],
22
- };
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.assets[channelId]) {
41
- var vod = _this.assets[channelId][_this.pos[channelId]++];
42
- if (_this.pos[channelId] > _this.assets[channelId].length - 1) {
43
- _this.pos[channelId] = 0;
44
- }
45
- resolve(vod);
46
- }
47
- else {
48
- reject("Invalid channelId provided");
49
- }
50
- });
51
- };
52
- return RefAssetManager;
53
- }());
54
- var RefChannelManager = /** @class */ (function () {
55
- function RefChannelManager() {
56
- }
57
- RefChannelManager.prototype.getChannels = function () {
58
- return [{ id: "1", profile: this._getProfile(), audioTracks: this._getAudioTracks(), subtitleTracks: this._getSubtitleTracks() }];
59
- };
60
- RefChannelManager.prototype._getProfile = function () {
61
- return [
62
- {
63
- bw: 7934000,
64
- codecs: "avc1.4d001f,mp4a.40.2",
65
- resolution: [2880, 1440],
66
- },
67
- {
68
- bw: 7514000,
69
- codecs: "avc1.4d001f,mp4a.40.2",
70
- resolution: [1920, 1080],
71
- },
72
- { bw: 7134000, codecs: "avc1.4d001f,mp4a.40.2", resolution: [1280, 720] },
73
- { bw: 6134000, codecs: "avc1.4d001f,mp4a.40.2", resolution: [1024, 458] },
74
- { bw: 2323000, codecs: "avc1.4d001f,mp4a.40.2", resolution: [640, 286] },
75
- { bw: 495894, codecs: "avc1.4d001f,mp4a.40.2", resolution: [480, 214] },
76
- ];
77
- };
78
- RefChannelManager.prototype._getAudioTracks = function () {
79
- return [
80
- { language: "en", name: "English", default: true },
81
- { language: "es", name: "Spanish", default: false },
82
- ];
83
- };
84
- RefChannelManager.prototype._getSubtitleTracks = function () {
85
- return [
86
- { language: "zh", name: "chinese", default: true },
87
- { language: "fr", name: "french", default: false }
88
- ];
89
- };
90
- return RefChannelManager;
91
- }());
92
- var refAssetManager = new RefAssetManager();
93
- var refChannelManager = new RefChannelManager();
94
- var engineOptions = {
95
- heartbeat: "/",
96
- averageSegmentDuration: 2000,
97
- channelManager: refChannelManager,
98
- defaultSlateUri: "https://mtoczko.github.io/hls-test-streams/test-audio-pdt/playlist.m3u8",
99
- slateRepetitions: 10,
100
- redisUrl: process.env.REDIS_URL,
101
- useDemuxedAudio: true,
102
- alwaysNewSegments: false,
103
- useVTTSubtitles: true
104
- };
105
- var engine = new index_1.ChannelEngine(refAssetManager, engineOptions);
106
- engine.start();
107
- engine.listen(process.env.PORT || 8000);
@@ -1 +0,0 @@
1
- export {};
@@ -1,114 +0,0 @@
1
- "use strict";
2
- /*
3
- * Reference implementation of Channel Engine library using DRM (HLS+Widevine) VOD assets.
4
- *
5
- * Playback: https://shaka-player-demo.appspot.com/demo/#audiolang=sv-SE;textlang=sv-SE;uilang=sv-SE;asset=http://localhost:8000/channels/1/master.m3u8;license=https://cwip-shaka-proxy.appspot.com/no_auth;panel=CUSTOM%20CONTENT;build=uncompiled
6
- */
7
- Object.defineProperty(exports, "__esModule", { value: true });
8
- var index_1 = require("./index");
9
- var RefAssetManager = /** @class */ (function () {
10
- function RefAssetManager(opts) {
11
- this.assets = {
12
- 1: [
13
- {
14
- id: 1,
15
- title: "VINN DRM",
16
- uri: "https://testcontent.eyevinn.technology/vinn/multidrm/index.m3u8"
17
- // License server urL: https://widevine-dash.ezdrm.com/proxy?pX=1D331C
18
- },
19
- {
20
- id: 2,
21
- title: "VINN No DRM",
22
- uri: "https://testcontent.eyevinn.technology/vinn/cmaf/index.m3u8"
23
- },
24
- {
25
- id: 3,
26
- title: "CE Promo DRM",
27
- uri: "https://testcontent.eyevinn.technology/drm/CE-promo/index.m3u8"
28
- // License server urL: https://widevine-dash.ezdrm.com/proxy?pX=1D331C
29
- },
30
- {
31
- id: 4,
32
- title: "Eyevinn Reel DRM",
33
- uri: "https://testcontent.eyevinn.technology/drm/Eyevinn-Reel/index.m3u8"
34
- // License server urL: https://widevine-dash.ezdrm.com/proxy?pX=1D331C
35
- }
36
- ],
37
- };
38
- this.pos = {
39
- 1: 0,
40
- };
41
- }
42
- /**
43
- *
44
- * @param {Object} vodRequest
45
- * {
46
- * sessionId,
47
- * category,
48
- * playlistId
49
- * }
50
- */
51
- RefAssetManager.prototype.getNextVod = function (vodRequest) {
52
- var _this = this;
53
- return new Promise(function (resolve, reject) {
54
- var channelId = vodRequest.playlistId;
55
- if (_this.assets[channelId]) {
56
- var vod = _this.assets[channelId][_this.pos[channelId]++];
57
- if (_this.pos[channelId] > _this.assets[channelId].length - 1) {
58
- _this.pos[channelId] = 0;
59
- }
60
- resolve(vod);
61
- }
62
- else {
63
- reject("Invalid channelId provided");
64
- }
65
- });
66
- };
67
- return RefAssetManager;
68
- }());
69
- var RefChannelManager = /** @class */ (function () {
70
- function RefChannelManager() {
71
- }
72
- RefChannelManager.prototype.getChannels = function () {
73
- return [{ id: "1", profile: this._getProfile(), audioTracks: this._getAudioTracks() }];
74
- };
75
- RefChannelManager.prototype._getProfile = function () {
76
- return [
77
- {
78
- bw: 7934000,
79
- codecs: "avc1.4d001f,mp4a.40.2",
80
- resolution: [2880, 1440],
81
- },
82
- {
83
- bw: 7514000,
84
- codecs: "avc1.4d001f,mp4a.40.2",
85
- resolution: [1920, 1080],
86
- },
87
- { bw: 7134000, codecs: "avc1.4d001f,mp4a.40.2", resolution: [1280, 720] },
88
- { bw: 6134000, codecs: "avc1.4d001f,mp4a.40.2", resolution: [1024, 458] },
89
- { bw: 2323000, codecs: "avc1.4d001f,mp4a.40.2", resolution: [640, 286] },
90
- { bw: 495894, codecs: "avc1.4d001f,mp4a.40.2", resolution: [480, 214] },
91
- ];
92
- };
93
- RefChannelManager.prototype._getAudioTracks = function () {
94
- return [
95
- { language: "en", name: "English" },
96
- ];
97
- };
98
- return RefChannelManager;
99
- }());
100
- var refAssetManager = new RefAssetManager();
101
- var refChannelManager = new RefChannelManager();
102
- var engineOptions = {
103
- heartbeat: "/",
104
- averageSegmentDuration: 4000,
105
- channelManager: refChannelManager,
106
- defaultSlateUri: "https://maitv-vod.lab.eyevinn.technology/slate-consuo.mp4/master.m3u8",
107
- slateRepetitions: 10,
108
- redisUrl: process.env.REDIS_URL,
109
- useDemuxedAudio: true,
110
- alwaysNewSegments: true,
111
- };
112
- var engine = new index_1.ChannelEngine(refAssetManager, engineOptions);
113
- engine.start();
114
- engine.listen(process.env.PORT || 8000);
@@ -1 +0,0 @@
1
- export {};
@@ -1,196 +0,0 @@
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 uuidv4 = require('uuid').v4;
8
- var STITCH_ENDPOINT = process.env.STITCH_ENDPOINT || "http://lambda.eyevinn.technology/stitch/master.m3u8";
9
- var RefAssetManager = /** @class */ (function () {
10
- function RefAssetManager(opts) {
11
- if (process.env.TEST_CHANNELS) {
12
- this.assets = {};
13
- this.pos = {};
14
- var testChannelsCount = parseInt(process.env.TEST_CHANNELS, 10);
15
- for (var i = 0; i < testChannelsCount; i++) {
16
- var channelId = "".concat(i + 1);
17
- this.assets[channelId] = [
18
- { id: 1, title: "Tears of Steel", uri: "https://maitv-vod.lab.eyevinn.technology/tearsofsteel_4k.mov/master.m3u8" },
19
- { id: 2, title: "Unhinged Trailer", uri: "https://maitv-vod.lab.eyevinn.technology/UNHINGED_Trailer_2020.mp4/master.m3u8" },
20
- { id: 3, title: "Morbius Trailer", uri: "https://maitv-vod.lab.eyevinn.technology/MORBIUS_Trailer_2020.mp4/master.m3u8" },
21
- { id: 4, title: "TV Plus Joachim", uri: "https://maitv-vod.lab.eyevinn.technology/tvplus-ad-joachim.mov/master.m3u8" },
22
- { id: 5, title: "The Outpost Trailer", uri: "https://maitv-vod.lab.eyevinn.technology/THE_OUTPOST_Trailer_2020.mp4/master.m3u8" },
23
- { id: 6, title: "TV Plus Megha", uri: "https://maitv-vod.lab.eyevinn.technology/tvplus-ad-megha.mov/master.m3u8" },
24
- ];
25
- this.pos[channelId] = 2;
26
- }
27
- }
28
- else {
29
- this.assets = {
30
- '1': [
31
- { id: 1, title: "Tears of Steel", uri: "https://maitv-vod.lab.eyevinn.technology/tearsofsteel_4k.mov/master.m3u8" },
32
- { id: 2, title: "Morbius Trailer", uri: "https://maitv-vod.lab.eyevinn.technology/MORBIUS_Trailer_2020.mp4/master.m3u8" },
33
- { id: 3, title: "The Outpost Trailer", uri: "https://maitv-vod.lab.eyevinn.technology/THE_OUTPOST_Trailer_2020.mp4/master.m3u8" },
34
- { id: 4, title: "Unhinged Trailer", uri: "https://maitv-vod.lab.eyevinn.technology/UNHINGED_Trailer_2020.mp4/master.m3u8" },
35
- { id: 5, title: "TV Plus Megha", uri: "https://maitv-vod.lab.eyevinn.technology/tvplus-ad-megha.mov/master.m3u8" },
36
- { id: 6, title: "TV Plus Joachim", uri: "https://maitv-vod.lab.eyevinn.technology/tvplus-ad-joachim.mov/master.m3u8" },
37
- ]
38
- };
39
- this.pos = {
40
- '1': 1
41
- };
42
- }
43
- }
44
- /* @param {Object} vodRequest
45
- * {
46
- * sessionId,
47
- * category,
48
- * playlistId
49
- * }
50
- */
51
- RefAssetManager.prototype.getNextVod = function (vodRequest) {
52
- var _this = this;
53
- return new Promise(function (resolve, reject) {
54
- var channelId = vodRequest.playlistId;
55
- if (_this.assets[channelId]) {
56
- var vod = _this.assets[channelId][_this.pos[channelId]++];
57
- if (_this.pos[channelId] > _this.assets[channelId].length - 1) {
58
- _this.pos[channelId] = 0;
59
- }
60
- var payload = {
61
- uri: vod.uri,
62
- breaks: [
63
- {
64
- pos: 0,
65
- duration: 15 * 1000,
66
- url: "https://maitv-vod.lab.eyevinn.technology/ads/apotea-15s.mp4/master.m3u8"
67
- }
68
- ]
69
- };
70
- var buff = Buffer.from(JSON.stringify(payload));
71
- var encodedPayload = buff.toString("base64");
72
- var vodResponse = {
73
- id: vod.id,
74
- title: vod.title,
75
- uri: STITCH_ENDPOINT + "?payload=" + encodedPayload
76
- };
77
- resolve(vodResponse);
78
- }
79
- else {
80
- reject("Invalid channelId provided");
81
- }
82
- });
83
- };
84
- RefAssetManager.prototype.handleError = function (err, vodResponse) {
85
- console.error(err.message);
86
- };
87
- return RefAssetManager;
88
- }());
89
- var RefChannelManager = /** @class */ (function () {
90
- function RefChannelManager(opts) {
91
- this.channels = [];
92
- if (process.env.TEST_CHANNELS) {
93
- var testChannelsCount = parseInt(process.env.TEST_CHANNELS, 10);
94
- for (var i = 0; i < testChannelsCount; i++) {
95
- this.channels.push({ id: "".concat(i + 1), profile: this._getProfile() });
96
- }
97
- }
98
- else {
99
- this.channels = [{ id: "1", profile: this._getProfile() }];
100
- }
101
- }
102
- RefChannelManager.prototype.getChannels = function () {
103
- return this.channels;
104
- };
105
- RefChannelManager.prototype._getProfile = function () {
106
- return [
107
- { bw: 8242000, codecs: 'avc1.4d001f,mp4a.40.2', resolution: [1024, 458] },
108
- { bw: 1274000, codecs: 'avc1.4d001f,mp4a.40.2', resolution: [640, 286] },
109
- { bw: 742000, codecs: 'avc1.4d001f,mp4a.40.2', resolution: [480, 214] },
110
- ];
111
- };
112
- return RefChannelManager;
113
- }());
114
- var StreamType = Object.freeze({
115
- LIVE: 1,
116
- VOD: 2,
117
- });
118
- var StreamSwitchManager = /** @class */ (function () {
119
- function StreamSwitchManager() {
120
- this.schedule = {};
121
- if (process.env.TEST_CHANNELS) {
122
- var testChannelsCount = parseInt(process.env.TEST_CHANNELS, 10);
123
- for (var i = 0; i < testChannelsCount; i++) {
124
- var channelId = "".concat(i + 1);
125
- this.schedule[channelId] = [];
126
- }
127
- }
128
- else {
129
- this.schedule = {
130
- '1': []
131
- };
132
- }
133
- }
134
- StreamSwitchManager.prototype.generateID = function () {
135
- return uuidv4();
136
- };
137
- StreamSwitchManager.prototype.getPrerollUri = function (channelId) {
138
- var defaultPrerollSlateUri = "https://maitv-vod.lab.eyevinn.technology/slate-consuo.mp4/master.m3u8";
139
- return new Promise(function (resolve, reject) { resolve(defaultPrerollSlateUri); });
140
- };
141
- StreamSwitchManager.prototype.getSchedule = function (channelId) {
142
- var _this = this;
143
- return new Promise(function (resolve, reject) {
144
- if (_this.schedule[channelId]) {
145
- var tsNow_1 = Date.now();
146
- var streamDuration = 60 * 1000;
147
- var startOffset = tsNow_1 + streamDuration;
148
- var endTime = startOffset + streamDuration;
149
- // Break in with live and scheduled VOD content after 60 seconds of VOD2Live the first time Channel Engine starts
150
- // Required: "assetId", "start_time", "end_time", "uri", "duration"
151
- // "duration" is only required for StreamType.VOD
152
- _this.schedule[channelId] = _this.schedule[channelId].filter(function (obj) { return obj.end_time >= tsNow_1; });
153
- if (_this.schedule[channelId].length === 0) {
154
- _this.schedule[channelId].push({
155
- eventId: _this.generateID(),
156
- assetId: _this.generateID(),
157
- title: "Live stream test",
158
- type: StreamType.LIVE,
159
- start_time: startOffset,
160
- end_time: endTime,
161
- uri: "https://d2fz24s2fts31b.cloudfront.net/out/v1/6484d7c664924b77893f9b4f63080e5d/manifest.m3u8",
162
- }, {
163
- eventId: _this.generateID(),
164
- assetId: _this.generateID(),
165
- title: "Scheduled VOD test",
166
- type: StreamType.VOD,
167
- start_time: (endTime + 100 * 1000),
168
- end_time: (endTime + 100 * 1000) + streamDuration,
169
- uri: "https://maitv-vod.lab.eyevinn.technology/COME_TO_DADDY_Trailer_2020.mp4/master.m3u8",
170
- duration: streamDuration,
171
- });
172
- }
173
- resolve(_this.schedule[channelId]);
174
- }
175
- else {
176
- reject("Invalid channelId provided");
177
- }
178
- });
179
- };
180
- return StreamSwitchManager;
181
- }());
182
- var refAssetManager = new RefAssetManager();
183
- var refChannelManager = new RefChannelManager();
184
- var refStreamSwitchManager = new StreamSwitchManager();
185
- var engineOptions = {
186
- heartbeat: "/",
187
- averageSegmentDuration: 2000,
188
- channelManager: refChannelManager,
189
- streamSwitchManager: refStreamSwitchManager,
190
- defaultSlateUri: "https://maitv-vod.lab.eyevinn.technology/slate-consuo.mp4/master.m3u8",
191
- slateRepetitions: 10,
192
- redisUrl: process.env.REDIS_URL,
193
- };
194
- var engine = new index_1.ChannelEngine(refAssetManager, engineOptions);
195
- engine.start();
196
- engine.listen(process.env.PORT || 8000);
@@ -1 +0,0 @@
1
- export {};