eyevinn-channel-engine 4.0.16 → 4.0.18
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/CONTRIBUTING.md +62 -0
- package/README.md +62 -0
- package/dist/engine/server.d.ts +1 -0
- package/dist/engine/session.js +10 -5
- package/dist/package.json +5 -2
- package/engine/server.ts +3 -0
- package/engine/session.js +9 -4
- package/package.json +5 -2
- package/spec/engine/init_switching_spec.js +12 -10
package/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Submitting Issues
|
|
2
|
+
|
|
3
|
+
We use GitHub issues to track public bugs. If you are submitting a bug, please provide
|
|
4
|
+
as much info as possible to make it easier to reproduce the issue and update unit tests.
|
|
5
|
+
|
|
6
|
+
# Contributing Code
|
|
7
|
+
|
|
8
|
+
This project uses [conventional commits](https://www.conventionalcommits.org/en/v1.0.0/#summary).
|
|
9
|
+
|
|
10
|
+
We follow the [GitHub Flow](https://guides.github.com/introduction/flow/index.html) so all contributions happen through pull requests. We actively welcome your pull requests:
|
|
11
|
+
|
|
12
|
+
1. Fork the repo and create your branch from master.
|
|
13
|
+
2. If you've added code that should be tested, add tests.
|
|
14
|
+
3. If you've changed APIs, update the documentation.
|
|
15
|
+
4. Ensure the test suite passes.
|
|
16
|
+
5. Issue that pull request!
|
|
17
|
+
|
|
18
|
+
When submitting code changes your submissions are understood to be under the same MIT License that covers the project. Feel free to contact Eyevinn Technology if that's a concern.
|
|
19
|
+
|
|
20
|
+
# Code of Conduct
|
|
21
|
+
|
|
22
|
+
## Our Pledge
|
|
23
|
+
|
|
24
|
+
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
|
|
25
|
+
|
|
26
|
+
## Our Standards
|
|
27
|
+
|
|
28
|
+
Examples of behavior that contributes to creating a positive environment include:
|
|
29
|
+
|
|
30
|
+
- Using welcoming and inclusive language
|
|
31
|
+
- Being respectful of differing viewpoints and experiences
|
|
32
|
+
- Gracefully accepting constructive criticism
|
|
33
|
+
- Focusing on what is best for the community
|
|
34
|
+
- Showing empathy towards other community members
|
|
35
|
+
|
|
36
|
+
Examples of unacceptable behavior by participants include:
|
|
37
|
+
|
|
38
|
+
- The use of sexualized language or imagery and unwelcome sexual attention or advances
|
|
39
|
+
- Trolling, insulting/derogatory comments, and personal or political attacks
|
|
40
|
+
- Public or private harassment
|
|
41
|
+
- Publishing others' private information, such as a physical or electronic address, without explicit permission
|
|
42
|
+
- Other conduct which could reasonably be considered inappropriate in a professional setting
|
|
43
|
+
|
|
44
|
+
## Our Responsibilities
|
|
45
|
+
|
|
46
|
+
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
|
|
47
|
+
|
|
48
|
+
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
|
|
49
|
+
|
|
50
|
+
## Scope
|
|
51
|
+
|
|
52
|
+
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
|
|
53
|
+
|
|
54
|
+
## Enforcement
|
|
55
|
+
|
|
56
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
|
|
57
|
+
|
|
58
|
+
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
|
|
59
|
+
|
|
60
|
+
## Attribution
|
|
61
|
+
|
|
62
|
+
This Code of Conduct is adapted from the Contributor Covenant, version 1.4, available at http://contributor-covenant.org/version/1/4
|
package/README.md
CHANGED
|
@@ -91,6 +91,68 @@ and this means that it is not possible to mix muxed TS with demuxed CMAF.
|
|
|
91
91
|
|
|
92
92
|
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')`;
|
|
93
93
|
|
|
94
|
+
## Contributing
|
|
95
|
+
|
|
96
|
+
Read [CONTRIBUTING](CONTRIBUTING.md) first and then follow the instructions below to get started with the devolpment environment.
|
|
97
|
+
|
|
98
|
+
### Development
|
|
99
|
+
|
|
100
|
+
Ensure that you are running node version 16 as version 18 is not supported yet.
|
|
101
|
+
|
|
102
|
+
```
|
|
103
|
+
node --version
|
|
104
|
+
v16.17.0
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Then install the dependencies:
|
|
108
|
+
|
|
109
|
+
```
|
|
110
|
+
npm install
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Build the app:
|
|
114
|
+
|
|
115
|
+
```
|
|
116
|
+
npm run build
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
To start the reference implementation in `server.ts` run:
|
|
120
|
+
|
|
121
|
+
```
|
|
122
|
+
npm start
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
For full debug mode you set the environment variable `DEBUG`.
|
|
126
|
+
|
|
127
|
+
```
|
|
128
|
+
DEBUG=* npm start
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
or if you want be more specific for example:
|
|
132
|
+
|
|
133
|
+
```
|
|
134
|
+
DEBUG=engine-* npm start
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
In addition there other reference implemetations that can be used:
|
|
138
|
+
- `server-demux.ts` : example with demuxed audio
|
|
139
|
+
- `server-livemix.ts` : example with live mimxing
|
|
140
|
+
- `server-multicodec.ts` : example with multicodec
|
|
141
|
+
|
|
142
|
+
### Source linking hls-vodtolive library
|
|
143
|
+
|
|
144
|
+
It is not uncommon that you need to test an local branch of the hls-vodtolive library and in order to do that you can use `npm link`.
|
|
145
|
+
|
|
146
|
+
1. Go to the directory where you have the source code for the hls-vodtolive library and run `npm link`
|
|
147
|
+
2. Then go to the channel engine source code directory and run `npm link @eyevinn/hls-vodtolive`
|
|
148
|
+
|
|
149
|
+
To restore and use the npm published version run the following in the channel engine source code directory:
|
|
150
|
+
|
|
151
|
+
```
|
|
152
|
+
npm uninstall --no-save @eyevinn/hls-vodtolive
|
|
153
|
+
npm install
|
|
154
|
+
```
|
|
155
|
+
|
|
94
156
|
## Support
|
|
95
157
|
|
|
96
158
|
Join our [community on Slack](http://slack.streamingtech.se) where you can post any questions regarding any of our open source projects. Eyevinn's consulting business can also offer you:
|
package/dist/engine/server.d.ts
CHANGED
package/dist/engine/session.js
CHANGED
|
@@ -952,7 +952,7 @@ var Session = /** @class */ (function () {
|
|
|
952
952
|
};
|
|
953
953
|
Session.prototype.incrementAsync = function () {
|
|
954
954
|
return __awaiter(this, void 0, void 0, function () {
|
|
955
|
-
var isLeader, sessionState, playheadState, currentVod, _a, leaderAction, _b, m3u8_3, _c, audioIncrement, position, currentVod_1, sessionState_1, posDiff, incrementValue, index, audioSeqLastIdx, thresh, audioPosition, _d, _e, _f, _g, _h, _j, _k, _l, _m, mediaSequenceValue, diffMs, m3u8;
|
|
955
|
+
var isLeader, sessionState, playheadState, currentVod, _a, leaderAction, _b, m3u8_3, _c, audioIncrement, positionV, positionA, position, currentVod_1, sessionState_1, posDiff, incrementValue, index, audioSeqLastIdx, thresh, audioPosition, _d, _e, _f, _g, _h, _j, _k, _l, _m, mediaSequenceValue, diffMs, m3u8;
|
|
956
956
|
return __generator(this, function (_o) {
|
|
957
957
|
switch (_o.label) {
|
|
958
958
|
case 0: return [4 /*yield*/, this._tickAsync()];
|
|
@@ -1020,9 +1020,12 @@ var Session = /** @class */ (function () {
|
|
|
1020
1020
|
_c.vodMediaSeqVideo = _o.sent();
|
|
1021
1021
|
audioIncrement = void 0;
|
|
1022
1022
|
if (!this.use_demuxed_audio) return [3 /*break*/, 23];
|
|
1023
|
+
positionV = 0;
|
|
1024
|
+
positionA = 0;
|
|
1023
1025
|
return [4 /*yield*/, this._getCurrentPlayheadPosition()];
|
|
1024
1026
|
case 16:
|
|
1025
1027
|
position = (_o.sent()) * 1000;
|
|
1028
|
+
positionV = position / 1000;
|
|
1026
1029
|
return [4 /*yield*/, this._sessionState.getCurrentVod()];
|
|
1027
1030
|
case 17:
|
|
1028
1031
|
currentVod_1 = _o.sent();
|
|
@@ -1039,6 +1042,7 @@ var Session = /** @class */ (function () {
|
|
|
1039
1042
|
case 19: return [4 /*yield*/, this._getAudioPlayheadPosition(sessionState_1.vodMediaSeqAudio + index)];
|
|
1040
1043
|
case 20:
|
|
1041
1044
|
audioPosition = (_o.sent()) * 1000;
|
|
1045
|
+
positionA = audioPosition / 1000;
|
|
1042
1046
|
posDiff = position - audioPosition;
|
|
1043
1047
|
if (posDiff <= 0) {
|
|
1044
1048
|
return [3 /*break*/, 22];
|
|
@@ -1060,6 +1064,7 @@ var Session = /** @class */ (function () {
|
|
|
1060
1064
|
_o.label = 22;
|
|
1061
1065
|
case 22:
|
|
1062
1066
|
audioIncrement = index;
|
|
1067
|
+
debug("[".concat(this._sessionId, "]: Current VOD Playhead Positions are to be: [").concat(positionV.toFixed(3), "][").concat(positionA.toFixed(3), "] (").concat((positionA - positionV).toFixed(3), ")"));
|
|
1063
1068
|
_o.label = 23;
|
|
1064
1069
|
case 23:
|
|
1065
1070
|
debug("[".concat(this._sessionId, "]: Will increment audio with ").concat(audioIncrement));
|
|
@@ -1628,7 +1633,7 @@ var Session = /** @class */ (function () {
|
|
|
1628
1633
|
if (!vodResponse.type) {
|
|
1629
1634
|
debug("[".concat(this._sessionId, "]: got first VOD uri=").concat(vodResponse.uri, ":").concat(vodResponse.offset || 0));
|
|
1630
1635
|
hlsOpts = { sequenceAlwaysContainNewSegments: this.alwaysNewSegments, forcedDemuxMode: this.use_demuxed_audio };
|
|
1631
|
-
newVod = new HLSVod(vodResponse.uri, [],
|
|
1636
|
+
newVod = new HLSVod(vodResponse.uri, [], vodResponse.unixTs, vodResponse.offset * 1000, m3u8Header(this._instanceId), hlsOpts);
|
|
1632
1637
|
if (vodResponse.timedMetadata) {
|
|
1633
1638
|
Object.keys(vodResponse.timedMetadata).map(function (k) {
|
|
1634
1639
|
newVod.addMetadata(k, vodResponse.timedMetadata[k]);
|
|
@@ -1836,7 +1841,7 @@ var Session = /** @class */ (function () {
|
|
|
1836
1841
|
if (!vodResponse.type) {
|
|
1837
1842
|
debug("[".concat(this._sessionId, "]: got next VOD uri=").concat(vodResponse.uri, ":").concat(vodResponse.offset));
|
|
1838
1843
|
hlsOpts = { sequenceAlwaysContainNewSegments: this.alwaysNewSegments, forcedDemuxMode: this.use_demuxed_audio };
|
|
1839
|
-
newVod = new HLSVod(vodResponse.uri, null,
|
|
1844
|
+
newVod = new HLSVod(vodResponse.uri, null, vodResponse.unixTs, vodResponse.offset * 1000, m3u8Header(this._instanceId), hlsOpts);
|
|
1840
1845
|
if (vodResponse.timedMetadata) {
|
|
1841
1846
|
Object.keys(vodResponse.timedMetadata).map(function (k) {
|
|
1842
1847
|
newVod.addMetadata(k, vodResponse.timedMetadata[k]);
|
|
@@ -2147,8 +2152,8 @@ var Session = /** @class */ (function () {
|
|
|
2147
2152
|
slateVod_1.load()
|
|
2148
2153
|
.then(function () {
|
|
2149
2154
|
var hlsOpts = { sequenceAlwaysContainNewSegments: _this.alwaysNewSegments, forcedDemuxMode: _this.use_demuxed_audio };
|
|
2150
|
-
hlsVod_1 = new HLSVod(_this.slateUri, null, null, null, m3u8Header(_this._instanceId), hlsOpts);
|
|
2151
2155
|
var timestamp = Date.now();
|
|
2156
|
+
hlsVod_1 = new HLSVod(_this.slateUri, null, timestamp, null, m3u8Header(_this._instanceId), hlsOpts);
|
|
2152
2157
|
hlsVod_1.addMetadata('id', "slate-".concat(timestamp));
|
|
2153
2158
|
hlsVod_1.addMetadata('start-date', new Date(timestamp).toISOString());
|
|
2154
2159
|
hlsVod_1.addMetadata('planned-duration', ((reps || _this.slateRepetitions) * _this.slateDuration) / 1000);
|
|
@@ -2210,8 +2215,8 @@ var Session = /** @class */ (function () {
|
|
|
2210
2215
|
slateVod_2.load()
|
|
2211
2216
|
.then(function () {
|
|
2212
2217
|
var hlsOpts = { sequenceAlwaysContainNewSegments: _this.alwaysNewSegments, forcedDemuxMode: _this.use_demuxed_audio };
|
|
2213
|
-
hlsVod_2 = new HLSVod(nexVodUri, null, null, null, m3u8Header(_this._instanceId), hlsOpts);
|
|
2214
2218
|
var timestamp = Date.now();
|
|
2219
|
+
hlsVod_2 = new HLSVod(nexVodUri, null, timestamp, null, m3u8Header(_this._instanceId), hlsOpts);
|
|
2215
2220
|
hlsVod_2.addMetadata('id', "slate-".concat(timestamp));
|
|
2216
2221
|
hlsVod_2.addMetadata('start-date', new Date(timestamp).toISOString());
|
|
2217
2222
|
hlsVod_2.addMetadata('planned-duration', requestedDuration);
|
package/dist/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eyevinn-channel-engine",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.18",
|
|
4
4
|
"description": "OTT TV Channel Engine",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -13,6 +13,9 @@
|
|
|
13
13
|
"start-demux": "node dist/server-demux.js",
|
|
14
14
|
"start-livemix": "node dist/server-livemix.js"
|
|
15
15
|
},
|
|
16
|
+
"engines": {
|
|
17
|
+
"node": "<18"
|
|
18
|
+
},
|
|
16
19
|
"author": "Eyevinn Technology AB <work@eyevinn.se>",
|
|
17
20
|
"contributors": [
|
|
18
21
|
"Jonas Birmé <jonas.birme@eyevinn.se> (Eyevinn Technology AB)",
|
|
@@ -26,7 +29,7 @@
|
|
|
26
29
|
"dependencies": {
|
|
27
30
|
"@eyevinn/hls-repeat": "^0.2.0",
|
|
28
31
|
"@eyevinn/hls-truncate": "^0.2.0",
|
|
29
|
-
"@eyevinn/hls-vodtolive": "^2.3.
|
|
32
|
+
"@eyevinn/hls-vodtolive": "^2.3.8",
|
|
30
33
|
"@eyevinn/m3u8": "^0.5.3",
|
|
31
34
|
"abort-controller": "^3.0.0",
|
|
32
35
|
"debug": "^3.2.7",
|
package/engine/server.ts
CHANGED
|
@@ -89,6 +89,9 @@ export interface VodResponse {
|
|
|
89
89
|
type?: string;
|
|
90
90
|
currentMetadata?: VodResponseMetadata;
|
|
91
91
|
timedMetadata?: VodTimedMetadata;
|
|
92
|
+
// Wall-clock start time of the VOD as unix ts. If set
|
|
93
|
+
// the program-date-time will be added to each segment
|
|
94
|
+
unixTs?: number;
|
|
92
95
|
}
|
|
93
96
|
|
|
94
97
|
export interface IAssetManager {
|
package/engine/session.js
CHANGED
|
@@ -726,7 +726,10 @@ class Session {
|
|
|
726
726
|
sessionState.vodMediaSeqVideo = await this._sessionState.increment("vodMediaSeqVideo");
|
|
727
727
|
let audioIncrement;
|
|
728
728
|
if (this.use_demuxed_audio) {
|
|
729
|
+
let positionV = 0;
|
|
730
|
+
let positionA = 0;
|
|
729
731
|
const position = (await this._getCurrentPlayheadPosition()) * 1000;
|
|
732
|
+
positionV = position / 1000;
|
|
730
733
|
let currentVod = await this._sessionState.getCurrentVod();
|
|
731
734
|
const sessionState = await this._sessionState.getValues(["vodMediaSeqAudio"]);
|
|
732
735
|
let posDiff;
|
|
@@ -737,6 +740,7 @@ class Session {
|
|
|
737
740
|
debug(`[${this._sessionId}]: About to determine audio increment`);
|
|
738
741
|
do {
|
|
739
742
|
const audioPosition = (await this._getAudioPlayheadPosition(sessionState.vodMediaSeqAudio + index)) * 1000;
|
|
743
|
+
positionA = audioPosition / 1000;
|
|
740
744
|
posDiff = position - audioPosition;
|
|
741
745
|
if (posDiff <= 0) {
|
|
742
746
|
break;
|
|
@@ -753,6 +757,7 @@ class Session {
|
|
|
753
757
|
}
|
|
754
758
|
} while (!(-thresh < posDiff && posDiff < thresh));
|
|
755
759
|
audioIncrement = index;
|
|
760
|
+
debug(`[${this._sessionId}]: Current VOD Playhead Positions are to be: [${positionV.toFixed(3)}][${positionA.toFixed(3)}] (${(positionA-positionV).toFixed(3)})`);
|
|
756
761
|
}
|
|
757
762
|
debug(`[${this._sessionId}]: Will increment audio with ${audioIncrement}`);
|
|
758
763
|
sessionState.vodMediaSeqAudio = await this._sessionState.increment("vodMediaSeqAudio", audioIncrement);
|
|
@@ -1152,7 +1157,7 @@ class Session {
|
|
|
1152
1157
|
if (!vodResponse.type) {
|
|
1153
1158
|
debug(`[${this._sessionId}]: got first VOD uri=${vodResponse.uri}:${vodResponse.offset || 0}`);
|
|
1154
1159
|
const hlsOpts = { sequenceAlwaysContainNewSegments: this.alwaysNewSegments, forcedDemuxMode: this.use_demuxed_audio };
|
|
1155
|
-
newVod = new HLSVod(vodResponse.uri, [],
|
|
1160
|
+
newVod = new HLSVod(vodResponse.uri, [], vodResponse.unixTs, vodResponse.offset * 1000, m3u8Header(this._instanceId), hlsOpts);
|
|
1156
1161
|
if (vodResponse.timedMetadata) {
|
|
1157
1162
|
Object.keys(vodResponse.timedMetadata).map(k => {
|
|
1158
1163
|
newVod.addMetadata(k, vodResponse.timedMetadata[k]);
|
|
@@ -1301,7 +1306,7 @@ class Session {
|
|
|
1301
1306
|
if (!vodResponse.type) {
|
|
1302
1307
|
debug(`[${this._sessionId}]: got next VOD uri=${vodResponse.uri}:${vodResponse.offset}`);
|
|
1303
1308
|
const hlsOpts = { sequenceAlwaysContainNewSegments: this.alwaysNewSegments, forcedDemuxMode: this.use_demuxed_audio };
|
|
1304
|
-
newVod = new HLSVod(vodResponse.uri, null,
|
|
1309
|
+
newVod = new HLSVod(vodResponse.uri, null, vodResponse.unixTs, vodResponse.offset * 1000, m3u8Header(this._instanceId), hlsOpts);
|
|
1305
1310
|
if (vodResponse.timedMetadata) {
|
|
1306
1311
|
Object.keys(vodResponse.timedMetadata).map(k => {
|
|
1307
1312
|
newVod.addMetadata(k, vodResponse.timedMetadata[k]);
|
|
@@ -1532,8 +1537,8 @@ class Session {
|
|
|
1532
1537
|
slateVod.load()
|
|
1533
1538
|
.then(() => {
|
|
1534
1539
|
const hlsOpts = { sequenceAlwaysContainNewSegments: this.alwaysNewSegments, forcedDemuxMode: this.use_demuxed_audio };
|
|
1535
|
-
hlsVod = new HLSVod(this.slateUri, null, null, null, m3u8Header(this._instanceId), hlsOpts);
|
|
1536
1540
|
const timestamp = Date.now();
|
|
1541
|
+
hlsVod = new HLSVod(this.slateUri, null, timestamp, null, m3u8Header(this._instanceId), hlsOpts);
|
|
1537
1542
|
hlsVod.addMetadata('id', `slate-${timestamp}`);
|
|
1538
1543
|
hlsVod.addMetadata('start-date', new Date(timestamp).toISOString());
|
|
1539
1544
|
hlsVod.addMetadata('planned-duration', ((reps || this.slateRepetitions) * this.slateDuration) / 1000);
|
|
@@ -1592,8 +1597,8 @@ class Session {
|
|
|
1592
1597
|
slateVod.load()
|
|
1593
1598
|
.then(() => {
|
|
1594
1599
|
const hlsOpts = { sequenceAlwaysContainNewSegments: this.alwaysNewSegments, forcedDemuxMode: this.use_demuxed_audio };
|
|
1595
|
-
hlsVod = new HLSVod(nexVodUri, null, null, null, m3u8Header(this._instanceId), hlsOpts);
|
|
1596
1600
|
const timestamp = Date.now();
|
|
1601
|
+
hlsVod = new HLSVod(nexVodUri, null, timestamp, null, m3u8Header(this._instanceId), hlsOpts);
|
|
1597
1602
|
hlsVod.addMetadata('id', `slate-${timestamp}`);
|
|
1598
1603
|
hlsVod.addMetadata('start-date', new Date(timestamp).toISOString());
|
|
1599
1604
|
hlsVod.addMetadata('planned-duration', requestedDuration);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eyevinn-channel-engine",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.18",
|
|
4
4
|
"description": "OTT TV Channel Engine",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -13,6 +13,9 @@
|
|
|
13
13
|
"start-demux": "node dist/server-demux.js",
|
|
14
14
|
"start-livemix": "node dist/server-livemix.js"
|
|
15
15
|
},
|
|
16
|
+
"engines": {
|
|
17
|
+
"node": "<18"
|
|
18
|
+
},
|
|
16
19
|
"author": "Eyevinn Technology AB <work@eyevinn.se>",
|
|
17
20
|
"contributors": [
|
|
18
21
|
"Jonas Birmé <jonas.birme@eyevinn.se> (Eyevinn Technology AB)",
|
|
@@ -26,7 +29,7 @@
|
|
|
26
29
|
"dependencies": {
|
|
27
30
|
"@eyevinn/hls-repeat": "^0.2.0",
|
|
28
31
|
"@eyevinn/hls-truncate": "^0.2.0",
|
|
29
|
-
"@eyevinn/hls-vodtolive": "^2.3.
|
|
32
|
+
"@eyevinn/hls-vodtolive": "^2.3.8",
|
|
30
33
|
"@eyevinn/m3u8": "^0.5.3",
|
|
31
34
|
"abort-controller": "^3.0.0",
|
|
32
35
|
"debug": "^3.2.7",
|
|
@@ -468,6 +468,7 @@ describe("The initialize switching", () => {
|
|
|
468
468
|
if (m) {
|
|
469
469
|
mseqNo = Number(m[1]);
|
|
470
470
|
}
|
|
471
|
+
|
|
471
472
|
expect(mseqNo).toBe(10);
|
|
472
473
|
const size = sessionCurrentSegs["1313000"].length;
|
|
473
474
|
expect(sessionCurrentSegs["1313000"][0]).toEqual({
|
|
@@ -484,7 +485,7 @@ describe("The initialize switching", () => {
|
|
|
484
485
|
const borderSegment = sessionCurrentSegs["1313000"][size - 1 - 3];
|
|
485
486
|
expect(borderSegment.duration).toBe(10.880);
|
|
486
487
|
expect(borderSegment.cue).toBe(null);
|
|
487
|
-
expect(borderSegment.timelinePosition).toBe(null);
|
|
488
|
+
expect(borderSegment.timelinePosition).not.toBe(null);
|
|
488
489
|
expect(borderSegment.uri).toBe("https://maitv-vod.lab.eyevinn.technology/MORBIUS_Trailer_2020.mp4/1000/1000-00000.ts");
|
|
489
490
|
expect(borderSegment.daterange["id"]).not.toBe(null);
|
|
490
491
|
expect(borderSegment.daterange["start-date"]).not.toBe(null);
|
|
@@ -750,7 +751,8 @@ describe("The initialize switching", () => {
|
|
|
750
751
|
|
|
751
752
|
const expectedLastVODSegItem = {
|
|
752
753
|
discontinuity: true,
|
|
753
|
-
daterange: null
|
|
754
|
+
daterange: null,
|
|
755
|
+
vodTransition: true
|
|
754
756
|
}
|
|
755
757
|
const expectedFirstV2LSegItem = {
|
|
756
758
|
duration: 7.2,
|
|
@@ -768,13 +770,11 @@ describe("The initialize switching", () => {
|
|
|
768
770
|
}
|
|
769
771
|
|
|
770
772
|
expect(newVodSegments["1313000"][0]).toEqual(expectedLastVODSegItem);
|
|
771
|
-
expect(newVodSegments["1313000"][1]).toEqual(
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
byteRange: undefined,
|
|
777
|
-
});
|
|
773
|
+
expect(newVodSegments["1313000"][1].duration).toEqual(10.846444);
|
|
774
|
+
expect(newVodSegments["1313000"][1].cue).toBeNull();
|
|
775
|
+
expect(newVodSegments["1313000"][1].uri).toEqual('https://maitv-vod.lab.eyevinn.technology/VINN.mp4/600/600-00000.ts');
|
|
776
|
+
|
|
777
|
+
newVodSegments["1313000"][2].timelinePosition = null; // disregard timeline position
|
|
778
778
|
expect(newVodSegments["1313000"][2]).toEqual(expectedFirstV2LSegItem);
|
|
779
779
|
// expect(newVodSegments["1313000"][5]).toEqual({
|
|
780
780
|
// discontinuity: true,
|
|
@@ -784,9 +784,11 @@ describe("The initialize switching", () => {
|
|
|
784
784
|
expect("start-date" in borderSegment.daterange).toBe(true);
|
|
785
785
|
expect("id" in borderSegment.daterange).toBe(true);
|
|
786
786
|
expect(borderSegment.duration).toEqual(11.3447);
|
|
787
|
-
expect(borderSegment.timelinePosition).toEqual(null);
|
|
787
|
+
expect(borderSegment.timelinePosition).not.toEqual(null);
|
|
788
788
|
expect(borderSegment.cue).toEqual(null);
|
|
789
789
|
expect(borderSegment.uri).toEqual("https://maitv-vod.lab.eyevinn.technology/BECKY_Trailer_2020.mp4/1000/1000-00000.ts");
|
|
790
|
+
|
|
791
|
+
newVodSegments["1313000"][7].timelinePosition = null; // disregard timeline position
|
|
790
792
|
expect(newVodSegments["1313000"][7]).toEqual(expectedSecondVODSegItem);
|
|
791
793
|
});
|
|
792
794
|
|