eyevinn-channel-engine 4.0.0-rc.1 → 4.0.1

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
@@ -1,5 +1,5 @@
1
1
  # Eyevinn Channel Engine
2
- > *Open Source FAST Channel Engine based on VOD2Live technology*
2
+ > *Open Source FAST Channel Engine library based on VOD2Live technology*
3
3
 
4
4
  [![Slack](http://slack.streamingtech.se/badge.svg)](http://slack.streamingtech.se)
5
5
 
@@ -29,12 +29,36 @@ Supported Node.js Versions
29
29
  | 16.x | Yes |
30
30
  | 18.x | No |
31
31
 
32
+ ## Supported Source Formats
33
+
34
+ | HLS Format | Muxed | Demuxed | Mix w. Live | Subtitles | DRM |
35
+ | ---------- | ----- | ------- | ----------- | --------- | --- |
36
+ | HLS + TS | Yes | Yes | Yes* | TBD | No |
37
+ | HLS + CMAF | No | Yes | TBD | TBD | TBD |
38
+
39
+ *\* not supported with demuxed sources*
40
+
32
41
  ## Usage
33
42
 
34
43
  Follow [this tutorial](https://vod2live.docs.eyevinn.technology/getting-started.html) to get started building your own FAST channel engine.
35
44
 
45
+ You can also use prebuilt [Eyevinn FAST Engine Docker Container](https://github.com/Eyevinn/docker-fast) based on this library. To try it out you can start an instance with 50 demo channels by running this command:
46
+
47
+ ```
48
+ docker run -d -p 8000:8000 -p 8001:8001 \
49
+ -e DEMO_NUM_CHANNELS=50 \
50
+ eyevinntechnology/fast-engine
51
+ ```
52
+
53
+ Open the URL http://localhost:8001/ in your browser for a multiview of all 50 channels, and to playback one of the 50 channels point your HLS video player to the URL: http://localhost:8000/channels/<N>/master.m3u8 where <N> is a number between 1 and 50.
54
+
36
55
  ## Migration
37
56
 
57
+ ### Upgrading from 3.4.x to >= 4.0.0
58
+
59
+ Support for HLS-CMAF and handling audio and video segments of different durations was added to v4
60
+ and this means that it is not possible to mix muxed TS with demuxed CMAF.
61
+
38
62
  ### Upgrading from 3.3.x to >= 3.4.x
39
63
 
40
64
  A breaking change was introduced in v3.4.0 when Typescript types were introduced. The library no longer exports a default. This means that you need to change `const ChannelEngine = require('eyevinn-channel-engine')` to `const { ChannelEngine } = require('eyevinn-channel-engine')`;
@@ -106,5 +106,5 @@ declare class Session {
106
106
  _getCurrentPlayheadPosition(): Promise<any>;
107
107
  _getAudioPlayheadPosition(seqIdx: any): Promise<any>;
108
108
  _getLastDuration(manifest: any): Promise<any>;
109
- _getPlayheadDiffCompesationValue(diffMs: any, thresholdMs: any): number;
109
+ _getPlayheadDiffCompensationValue(diffMs: any, thresholdMs: any): number;
110
110
  }
@@ -327,12 +327,12 @@ var Session = /** @class */ (function () {
327
327
  if (this.alwaysNewSegments) {
328
328
  // Apply Playhead diff compensation, only after external diff compensation has concluded.
329
329
  if (this.diffCompensation <= 0) {
330
- timeToAdd = this._getPlayheadDiffCompesationValue(diff, this.playheadDiffThreshold);
330
+ timeToAdd = this._getPlayheadDiffCompensationValue(diff, this.playheadDiffThreshold);
331
331
  tickInterval += timeToAdd;
332
332
  }
333
333
  }
334
334
  else {
335
- timeToAdd = this._getPlayheadDiffCompesationValue(diff, this.playheadDiffThreshold);
335
+ timeToAdd = this._getPlayheadDiffCompensationValue(diff, this.playheadDiffThreshold);
336
336
  tickInterval += timeToAdd;
337
337
  }
338
338
  // Apply external diff compensation if available.
@@ -2303,7 +2303,7 @@ var Session = /** @class */ (function () {
2303
2303
  }
2304
2304
  });
2305
2305
  };
2306
- Session.prototype._getPlayheadDiffCompesationValue = function (diffMs, thresholdMs) {
2306
+ Session.prototype._getPlayheadDiffCompensationValue = function (diffMs, thresholdMs) {
2307
2307
  var compensationSec = 0;
2308
2308
  if (diffMs > thresholdMs) {
2309
2309
  compensationSec = (diffMs / 1000) - (thresholdMs / 1000);
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eyevinn-channel-engine",
3
- "version": "4.0.0-rc.1",
3
+ "version": "4.0.1",
4
4
  "description": "OTT TV Channel Engine",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -18,14 +18,15 @@
18
18
  "Jonas Birmé <jonas.birme@eyevinn.se> (Eyevinn Technology AB)",
19
19
  "Alan Allard <alan.allard@eyevinn.se> (Eyevinn Technology AB)",
20
20
  "Craig McEldowney <craig@ottera.tv>",
21
- "Nicholas Frederiksen <nicholas.frederiksen@eyevinn.se> (Eyevinn Technology AB)"
21
+ "Nicholas Frederiksen <nicholas.frederiksen@eyevinn.se> (Eyevinn Technology AB)",
22
+ "Johan Lautakoski <johan.lautakoski@eyevinn.se> (Eyevinn Technology AB)"
22
23
  ],
23
24
  "repository": "https://github.com/Eyevinn/channel-engine",
24
25
  "license": "Apache-2.0",
25
26
  "dependencies": {
26
27
  "@eyevinn/hls-repeat": "^0.2.0",
27
28
  "@eyevinn/hls-truncate": "^0.2.0",
28
- "@eyevinn/hls-vodtolive": "^2.1.1",
29
+ "@eyevinn/hls-vodtolive": "^2.2.1",
29
30
  "@eyevinn/m3u8": "^0.5.3",
30
31
  "abort-controller": "^3.0.0",
31
32
  "debug": "^3.2.7",
@@ -4,37 +4,19 @@
4
4
  */
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  var index_1 = require("./index");
7
- var STITCH_ENDPOINT = "http://localhost:8000/stitch/master.m3u8";
8
7
  var RefAssetManager = /** @class */ (function () {
9
8
  function RefAssetManager(opts) {
10
9
  this.assets = {
11
10
  1: [
12
- /* #TS+DEMUX HLS VODS */
13
- // {
14
- // id: 1,
15
- // title: "Elephants Dream",
16
- // uri: "https://playertest.longtailvideo.com/adaptive/elephants_dream_v4/index.m3u8",
17
- // },
18
- // {
19
- // id: 2,
20
- // title: "Test HLS Bird noises (1m10s)",
21
- // uri: "https://mtoczko.github.io/hls-test-streams/test-audio-pdt/playlist.m3u8",
22
- // },
23
- /* #CMAF+DEMUX HLS VODS */
24
11
  {
25
12
  id: 1,
26
- title: "Nymo Bloopers",
27
- uri: "https://vod.streaming.a2d.tv/a07ff4eb-6770-4805-a0ad-a4d1b127880d/4fef8b00-6d0b-11ed-89b6-2b1a288899a0_20356478.ism/.m3u8"
13
+ title: "Elephants Dream",
14
+ uri: "https://playertest.longtailvideo.com/adaptive/elephants_dream_v4/index.m3u8",
28
15
  },
29
16
  {
30
17
  id: 2,
31
- title: "Benjamin Sjunger",
32
- uri: "https://vod.streaming.a2d.tv/3f389c48-03e3-48a2-8e98-a02c55185a68/4c792a30-89ad-11ed-95d9-1b374c4e2f9f_20411056.ism/.m3u8"
33
- },
34
- {
35
- id: 3,
36
- title: "Idol Vinnarlåten",
37
- uri: "https://vod.streaming.a2d.tv/369f8dd6-bc62-40a3-b734-4bc1cb50c00b/e9ef93d0-6d10-11ed-83d0-17c0db863fe0_20356484.ism/.m3u8"
18
+ title: "Test HLS Bird noises (1m10s)",
19
+ uri: "https://mtoczko.github.io/hls-test-streams/test-audio-pdt/playlist.m3u8",
38
20
  },
39
21
  ],
40
22
  };
@@ -61,32 +43,8 @@ var RefAssetManager = /** @class */ (function () {
61
43
  _this.pos[channelId] = 0;
62
44
  }
63
45
  vod.timedMetadata = {
64
- "start-date": new Date().toISOString(),
65
- class: "se.eyevinn.demo",
66
- };
67
- var payload = {
68
- uri: vod.uri,
69
- breaks: [
70
- /* #TS+DEMUX HLS BREAK VOD */
71
- // {
72
- // pos: 0,
73
- // duration: 60 * 1000,
74
- // url: "https://lab-live.cdn.eyevinn.technology/DEMUX_002/master_demux_aac-en-fr.m3u8",
75
- // },
76
- /* #CMAF+DEMUX HLS BREAK VOD */
77
- {
78
- pos: 0,
79
- duration: 20 * 1000,
80
- url: "https://ovpuspvod.a2d-stage.tv/trailers/63ef9c36e3ffa90028603374/output.ism/.m3u8",
81
- },
82
- ],
83
- };
84
- var buff = Buffer.from(JSON.stringify(payload));
85
- var encodedPayload = buff.toString("base64");
86
- vod = {
87
- id: vod.id,
88
- title: vod.title,
89
- uri: STITCH_ENDPOINT + "?payload=" + encodedPayload,
46
+ 'start-date': new Date().toISOString(),
47
+ 'class': 'se.eyevinn.demo'
90
48
  };
91
49
  resolve(vod);
92
50
  }
@@ -132,10 +90,7 @@ var engineOptions = {
132
90
  heartbeat: "/",
133
91
  averageSegmentDuration: 2000,
134
92
  channelManager: refChannelManager,
135
- /* #TS+DEMUX SLATE VOD */
136
- defaultSlateUri: "https://ovpuspvod.a2d-stage.tv/trailers/bumpers/tv4_spring/output.ism/.m3u8",
137
- /* #CMAF+DEMUX SLATE VOD */
138
- //defaultSlateUri: "https://ovpuspvod.a2d-stage.tv/trailers/bumpers/tv4_spring/output.ism/.m3u8",
93
+ defaultSlateUri: "https://maitv-vod.lab.eyevinn.technology/slate-consuo.mp4/master.m3u8",
139
94
  slateRepetitions: 10,
140
95
  redisUrl: process.env.REDIS_URL,
141
96
  useDemuxedAudio: true,
package/engine/session.js CHANGED
@@ -245,12 +245,12 @@ class Session {
245
245
  if (this.alwaysNewSegments) {
246
246
  // Apply Playhead diff compensation, only after external diff compensation has concluded.
247
247
  if (this.diffCompensation <= 0) {
248
- const timeToAdd = this._getPlayheadDiffCompesationValue(diff, this.playheadDiffThreshold);
248
+ const timeToAdd = this._getPlayheadDiffCompensationValue(diff, this.playheadDiffThreshold);
249
249
  tickInterval += timeToAdd;
250
250
  }
251
251
  } else {
252
252
  // Apply Playhead diff compensation, always.
253
- const timeToAdd = this._getPlayheadDiffCompesationValue(diff, this.playheadDiffThreshold);
253
+ const timeToAdd = this._getPlayheadDiffCompensationValue(diff, this.playheadDiffThreshold);
254
254
  tickInterval += timeToAdd;
255
255
  }
256
256
  // Apply external diff compensation if available.
@@ -1657,7 +1657,7 @@ class Session {
1657
1657
  });
1658
1658
  }
1659
1659
 
1660
- _getPlayheadDiffCompesationValue(diffMs, thresholdMs) {
1660
+ _getPlayheadDiffCompensationValue(diffMs, thresholdMs) {
1661
1661
  let compensationSec = 0;
1662
1662
  if (diffMs > thresholdMs) {
1663
1663
  compensationSec = (diffMs / 1000) - (thresholdMs / 1000);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eyevinn-channel-engine",
3
- "version": "4.0.0-rc.1",
3
+ "version": "4.0.1",
4
4
  "description": "OTT TV Channel Engine",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -18,14 +18,15 @@
18
18
  "Jonas Birmé <jonas.birme@eyevinn.se> (Eyevinn Technology AB)",
19
19
  "Alan Allard <alan.allard@eyevinn.se> (Eyevinn Technology AB)",
20
20
  "Craig McEldowney <craig@ottera.tv>",
21
- "Nicholas Frederiksen <nicholas.frederiksen@eyevinn.se> (Eyevinn Technology AB)"
21
+ "Nicholas Frederiksen <nicholas.frederiksen@eyevinn.se> (Eyevinn Technology AB)",
22
+ "Johan Lautakoski <johan.lautakoski@eyevinn.se> (Eyevinn Technology AB)"
22
23
  ],
23
24
  "repository": "https://github.com/Eyevinn/channel-engine",
24
25
  "license": "Apache-2.0",
25
26
  "dependencies": {
26
27
  "@eyevinn/hls-repeat": "^0.2.0",
27
28
  "@eyevinn/hls-truncate": "^0.2.0",
28
- "@eyevinn/hls-vodtolive": "^2.1.1",
29
+ "@eyevinn/hls-vodtolive": "^2.2.1",
29
30
  "@eyevinn/m3u8": "^0.5.3",
30
31
  "abort-controller": "^3.0.0",
31
32
  "debug": "^3.2.7",
package/server-demux.ts CHANGED
@@ -14,40 +14,21 @@ import {
14
14
  AudioTracks,
15
15
  } from "./index";
16
16
 
17
- const STITCH_ENDPOINT = "http://localhost:8000/stitch/master.m3u8";
18
-
19
17
  class RefAssetManager implements IAssetManager {
20
18
  private assets;
21
19
  private pos;
22
20
  constructor(opts?) {
23
21
  this.assets = {
24
22
  1: [
25
- /* #TS+DEMUX HLS VODS */
26
- // {
27
- // id: 1,
28
- // title: "Elephants Dream",
29
- // uri: "https://playertest.longtailvideo.com/adaptive/elephants_dream_v4/index.m3u8",
30
- // },
31
- // {
32
- // id: 2,
33
- // title: "Test HLS Bird noises (1m10s)",
34
- // uri: "https://mtoczko.github.io/hls-test-streams/test-audio-pdt/playlist.m3u8",
35
- // },
36
- /* #CMAF+DEMUX HLS VODS */
37
23
  {
38
24
  id: 1,
39
- title: "Nymo Bloopers",
40
- uri: "https://vod.streaming.a2d.tv/a07ff4eb-6770-4805-a0ad-a4d1b127880d/4fef8b00-6d0b-11ed-89b6-2b1a288899a0_20356478.ism/.m3u8"
25
+ title: "Elephants Dream",
26
+ uri: "https://playertest.longtailvideo.com/adaptive/elephants_dream_v4/index.m3u8",
41
27
  },
42
28
  {
43
29
  id: 2,
44
- title: "Benjamin Sjunger",
45
- uri: "https://vod.streaming.a2d.tv/3f389c48-03e3-48a2-8e98-a02c55185a68/4c792a30-89ad-11ed-95d9-1b374c4e2f9f_20411056.ism/.m3u8"
46
- },
47
- {
48
- id: 3,
49
- title: "Idol Vinnarlåten",
50
- uri: "https://vod.streaming.a2d.tv/369f8dd6-bc62-40a3-b734-4bc1cb50c00b/e9ef93d0-6d10-11ed-83d0-17c0db863fe0_20356484.ism/.m3u8"
30
+ title: "Test HLS Bird noises (1m10s)",
31
+ uri: "https://mtoczko.github.io/hls-test-streams/test-audio-pdt/playlist.m3u8",
51
32
  },
52
33
  ],
53
34
  };
@@ -74,32 +55,8 @@ class RefAssetManager implements IAssetManager {
74
55
  this.pos[channelId] = 0;
75
56
  }
76
57
  vod.timedMetadata = {
77
- "start-date": new Date().toISOString(),
78
- class: "se.eyevinn.demo",
79
- };
80
- const payload = {
81
- uri: vod.uri,
82
- breaks: [
83
- /* #TS+DEMUX HLS BREAK VOD */
84
- // {
85
- // pos: 0,
86
- // duration: 60 * 1000,
87
- // url: "https://lab-live.cdn.eyevinn.technology/DEMUX_002/master_demux_aac-en-fr.m3u8",
88
- // },
89
- /* #CMAF+DEMUX HLS BREAK VOD */
90
- {
91
- pos: 0,
92
- duration: 20 * 1000,
93
- url: "https://ovpuspvod.a2d-stage.tv/trailers/63ef9c36e3ffa90028603374/output.ism/.m3u8",
94
- },
95
- ],
96
- };
97
- const buff = Buffer.from(JSON.stringify(payload));
98
- const encodedPayload = buff.toString("base64");
99
- vod = {
100
- id: vod.id,
101
- title: vod.title,
102
- uri: STITCH_ENDPOINT + "?payload=" + encodedPayload,
58
+ 'start-date': new Date().toISOString(),
59
+ 'class': 'se.eyevinn.demo'
103
60
  };
104
61
  resolve(vod);
105
62
  } else {
@@ -144,10 +101,7 @@ const engineOptions: ChannelEngineOpts = {
144
101
  heartbeat: "/",
145
102
  averageSegmentDuration: 2000,
146
103
  channelManager: refChannelManager,
147
- /* #TS+DEMUX SLATE VOD */
148
- defaultSlateUri: "https://ovpuspvod.a2d-stage.tv/trailers/bumpers/tv4_spring/output.ism/.m3u8",
149
- /* #CMAF+DEMUX SLATE VOD */
150
- //defaultSlateUri: "https://ovpuspvod.a2d-stage.tv/trailers/bumpers/tv4_spring/output.ism/.m3u8",
104
+ defaultSlateUri: "https://maitv-vod.lab.eyevinn.technology/slate-consuo.mp4/master.m3u8",
151
105
  slateRepetitions: 10,
152
106
  redisUrl: process.env.REDIS_URL,
153
107
  useDemuxedAudio: true,
@@ -331,12 +331,14 @@ describe("The initialize switching", () => {
331
331
  uri: "https://maitv-vod.lab.eyevinn.technology/tearsofsteel_4k.mov/600/600-00002.ts",
332
332
  timelinePosition: null,
333
333
  cue: null,
334
+ byteRange: undefined,
334
335
  });
335
336
  expect(currVodSegments[1313000][currVodSegments[1313000].length - 1]).toEqual({
336
337
  duration: 7.5,
337
338
  uri: "https://maitv-vod.lab.eyevinn.technology/tearsofsteel_4k.mov/600/600-00008.ts",
338
339
  timelinePosition: null,
339
340
  cue: null,
341
+ byteRange: undefined,
340
342
  });
341
343
 
342
344
  await sessionLive.setCurrentMediaAndDiscSequenceCount(currVodCounts.mediaSeq, currVodCounts.discSeq);
@@ -421,6 +423,7 @@ describe("The initialize switching", () => {
421
423
  uri: "https://maitv-vod.lab.eyevinn.technology/tearsofsteel_4k.mov/600/600-00015.ts",
422
424
  timelinePosition: null,
423
425
  cue: null,
426
+ byteRange: undefined,
424
427
  });
425
428
  nock.cleanAll();
426
429
  });
@@ -472,6 +475,7 @@ describe("The initialize switching", () => {
472
475
  uri: "https://maitv-vod.lab.eyevinn.technology/tearsofsteel_4k.mov/600/600-00012.ts",
473
476
  timelinePosition: null,
474
477
  cue: null,
478
+ byteRange: undefined,
475
479
  });
476
480
  expect(sessionCurrentSegs["1313000"][size - 1 - 4]).toEqual({
477
481
  discontinuity: true,
@@ -752,13 +756,15 @@ describe("The initialize switching", () => {
752
756
  duration: 7.2,
753
757
  timelinePosition: null,
754
758
  cue: null,
755
- uri: 'https://maitv-vod.lab.eyevinn.technology/VINN.mp4/600/600-00001.ts'
759
+ uri: 'https://maitv-vod.lab.eyevinn.technology/VINN.mp4/600/600-00001.ts',
760
+ byteRange: undefined,
756
761
  }
757
762
  const expectedSecondVODSegItem = {
758
763
  duration: 7.5075,
759
764
  uri: "https://maitv-vod.lab.eyevinn.technology/BECKY_Trailer_2020.mp4/1000/1000-00001.ts",
760
765
  timelinePosition: null,
761
766
  cue: null,
767
+ byteRange: undefined,
762
768
  }
763
769
 
764
770
  expect(newVodSegments["1313000"][0]).toEqual(expectedLastVODSegItem);
@@ -766,7 +772,8 @@ describe("The initialize switching", () => {
766
772
  duration: 10.846444,
767
773
  timelinePosition: null,
768
774
  cue: null,
769
- uri: 'https://maitv-vod.lab.eyevinn.technology/VINN.mp4/600/600-00000.ts'
775
+ uri: 'https://maitv-vod.lab.eyevinn.technology/VINN.mp4/600/600-00000.ts',
776
+ byteRange: undefined,
770
777
  });
771
778
  expect(newVodSegments["1313000"][2]).toEqual(expectedFirstV2LSegItem);
772
779
  // expect(newVodSegments["1313000"][5]).toEqual({