eyevinn-channel-engine 4.2.8 → 4.2.10
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 +1 -0
- package/dist/engine/server.d.ts +3 -0
- package/dist/engine/server.js +5 -0
- package/dist/engine/session.d.ts +1 -0
- package/dist/engine/session.js +56 -45
- package/dist/examples/truncate.js +2 -1
- package/dist/package.json +3 -3
- package/engine/server.ts +8 -0
- package/engine/session.js +27 -15
- package/examples/truncate.ts +2 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -134,6 +134,7 @@ In addition there other reference implemetations that can be used:
|
|
|
134
134
|
- `examples/multicodec.ts` : example with multicodec
|
|
135
135
|
- `examples/drm.ts` : example with DRM
|
|
136
136
|
- `examples/autocreate.ts` : example to auto create channel on demand
|
|
137
|
+
- `examples/truncate.ts` : example when trimming start and end of a VOD
|
|
137
138
|
|
|
138
139
|
### Source linking hls-vodtolive library
|
|
139
140
|
|
package/dist/engine/server.d.ts
CHANGED
|
@@ -17,6 +17,7 @@ export interface ChannelEngineOpts {
|
|
|
17
17
|
subtitleSliceEndpoint?: string;
|
|
18
18
|
useVTTSubtitles?: boolean;
|
|
19
19
|
alwaysNewSegments?: boolean;
|
|
20
|
+
alwaysMapBandwidthByNearest?: boolean;
|
|
20
21
|
diffCompensationRate?: number;
|
|
21
22
|
staticDirectory?: string;
|
|
22
23
|
averageSegmentDuration?: number;
|
|
@@ -56,6 +57,7 @@ export interface VodResponse {
|
|
|
56
57
|
offset?: number;
|
|
57
58
|
diffMs?: number;
|
|
58
59
|
desiredDuration?: number;
|
|
60
|
+
startOffset?: number;
|
|
59
61
|
type?: string;
|
|
60
62
|
currentMetadata?: VodResponseMetadata;
|
|
61
63
|
timedMetadata?: VodTimedMetadata;
|
|
@@ -125,6 +127,7 @@ export declare class ChannelEngine {
|
|
|
125
127
|
private subtitleSliceEndpoint;
|
|
126
128
|
private useVTTSubtitles;
|
|
127
129
|
private alwaysNewSegments;
|
|
130
|
+
private alwaysMapBandwidthByNearest;
|
|
128
131
|
private defaultSlateUri?;
|
|
129
132
|
private slateDuration?;
|
|
130
133
|
private assetMgr;
|
package/dist/engine/server.js
CHANGED
|
@@ -89,6 +89,10 @@ var ChannelEngine = /** @class */ (function () {
|
|
|
89
89
|
if (options && options.alwaysNewSegments) {
|
|
90
90
|
this.alwaysNewSegments = true;
|
|
91
91
|
}
|
|
92
|
+
this.alwaysMapBandwidthByNearest = false;
|
|
93
|
+
if (options && options.alwaysMapBandwidthByNearest) {
|
|
94
|
+
this.alwaysMapBandwidthByNearest = true;
|
|
95
|
+
}
|
|
92
96
|
if (options && options.defaultSlateUri) {
|
|
93
97
|
this.defaultSlateUri = options.defaultSlateUri;
|
|
94
98
|
this.slateRepetitions = options.slateRepetitions || 10;
|
|
@@ -437,6 +441,7 @@ var ChannelEngine = /** @class */ (function () {
|
|
|
437
441
|
subtitleSliceEndpoint: this.subtitleSliceEndpoint,
|
|
438
442
|
useVTTSubtitles: this.useVTTSubtitles,
|
|
439
443
|
alwaysNewSegments: options.alwaysNewSegments,
|
|
444
|
+
alwaysMapBandwidthByNearest: options.alwaysMapBandwidthByNearest,
|
|
440
445
|
noSessionDataTags: options.noSessionDataTags,
|
|
441
446
|
playheadDiffThreshold: channel.options && channel.options.playheadDiffThreshold ? channel.options.playheadDiffThreshold : this.streamerOpts.defaultPlayheadDiffThreshold,
|
|
442
447
|
maxTickInterval: channel.options && channel.options.maxTickInterval ? channel.options.maxTickInterval : this.streamerOpts.defaultMaxTickInterval,
|
package/dist/engine/session.d.ts
CHANGED
package/dist/engine/session.js
CHANGED
|
@@ -101,10 +101,14 @@ var Session = /** @class */ (function () {
|
|
|
101
101
|
};
|
|
102
102
|
this.isAllowedToClearVodCache = null;
|
|
103
103
|
this.alwaysNewSegments = null;
|
|
104
|
+
this.alwaysMapBandwidthByNearest = null;
|
|
104
105
|
if (config) {
|
|
105
106
|
if (config.alwaysNewSegments) {
|
|
106
107
|
this.alwaysNewSegments = config.alwaysNewSegments;
|
|
107
108
|
}
|
|
109
|
+
if (config.alwaysMapBandwidthByNearest) {
|
|
110
|
+
this.alwaysMapBandwidthByNearest = config.alwaysMapBandwidthByNearest;
|
|
111
|
+
}
|
|
108
112
|
if (config.sessionId) {
|
|
109
113
|
this._sessionId = config.sessionId;
|
|
110
114
|
}
|
|
@@ -1142,7 +1146,7 @@ var Session = /** @class */ (function () {
|
|
|
1142
1146
|
return [4 /*yield*/, this._getCurrentPlayheadPosition()];
|
|
1143
1147
|
case 16:
|
|
1144
1148
|
position = (_s.sent()) * 1000;
|
|
1145
|
-
positionV = position / 1000;
|
|
1149
|
+
positionV = position ? position / 1000 : 0;
|
|
1146
1150
|
return [4 /*yield*/, this._sessionState.getCurrentVod()];
|
|
1147
1151
|
case 17:
|
|
1148
1152
|
currentVod_1 = _s.sent();
|
|
@@ -1160,11 +1164,10 @@ var Session = /** @class */ (function () {
|
|
|
1160
1164
|
case 19: return [4 /*yield*/, this._getAudioPlayheadPosition(sessionState_1.vodMediaSeqAudio + index)];
|
|
1161
1165
|
case 20:
|
|
1162
1166
|
audioPosition = (_s.sent()) * 1000;
|
|
1163
|
-
positionA = audioPosition / 1000;
|
|
1167
|
+
positionA = audioPosition ? audioPosition / 1000 : 0;
|
|
1164
1168
|
posDiff = (positionV - positionA).toFixed(3);
|
|
1165
|
-
debug("[".concat(this._sessionId, "]: positionV=").concat(positionV, ";positionA=").concat(positionA, ";posDiff=").concat(posDiff
|
|
1169
|
+
debug("[".concat(this._sessionId, "]: positionV=").concat(positionV, ";positionA=").concat(positionA, ";posDiff=").concat(posDiff));
|
|
1166
1170
|
if (posDiff <= maxAcceptableDiff) {
|
|
1167
|
-
debug("[".concat(this._sessionId, "]: posDiff value (").concat(posDiff, ") is acceptable"));
|
|
1168
1171
|
return [3 /*break*/, 22];
|
|
1169
1172
|
}
|
|
1170
1173
|
if (posDiff > thresh) {
|
|
@@ -1181,7 +1184,7 @@ var Session = /** @class */ (function () {
|
|
|
1181
1184
|
}
|
|
1182
1185
|
_s.label = 21;
|
|
1183
1186
|
case 21:
|
|
1184
|
-
if (!(-thresh < posDiff && posDiff < thresh)) return [3 /*break*/, 19];
|
|
1187
|
+
if (!(-thresh < posDiff && posDiff < thresh) && !isNaN(posDiff)) return [3 /*break*/, 19];
|
|
1185
1188
|
_s.label = 22;
|
|
1186
1189
|
case 22:
|
|
1187
1190
|
audioIncrement = index;
|
|
@@ -1836,7 +1839,8 @@ var Session = /** @class */ (function () {
|
|
|
1836
1839
|
dummySubtitleEndpoint: this.dummySubtitleEndpoint,
|
|
1837
1840
|
subtitleSliceEndpoint: this.subtitleSliceEndpoint,
|
|
1838
1841
|
shouldContainSubtitles: this.use_vtt_subtitles,
|
|
1839
|
-
expectedSubtitleTracks: this._subtitleTracks
|
|
1842
|
+
expectedSubtitleTracks: this._subtitleTracks,
|
|
1843
|
+
alwaysMapBandwidthByNearest: this.alwaysMapBandwidthByNearest
|
|
1840
1844
|
};
|
|
1841
1845
|
newVod = new HLSVod(vodResponse.uri, [], vodResponse.unixTs, vodResponse.offset * 1000, m3u8Header(this._instanceId), hlsOpts);
|
|
1842
1846
|
if (vodResponse.timedMetadata) {
|
|
@@ -2084,7 +2088,8 @@ var Session = /** @class */ (function () {
|
|
|
2084
2088
|
dummySubtitleEndpoint: this.dummySubtitleEndpoint,
|
|
2085
2089
|
subtitleSliceEndpoint: this.subtitleSliceEndpoint,
|
|
2086
2090
|
shouldContainSubtitles: this.use_vtt_subtitles,
|
|
2087
|
-
expectedSubtitleTracks: this._subtitleTracks
|
|
2091
|
+
expectedSubtitleTracks: this._subtitleTracks,
|
|
2092
|
+
alwaysMapBandwidthByNearest: this.alwaysMapBandwidthByNearest
|
|
2088
2093
|
};
|
|
2089
2094
|
newVod = new HLSVod(vodResponse.uri, null, vodResponse.unixTs, vodResponse.offset * 1000, m3u8Header(this._instanceId), hlsOpts);
|
|
2090
2095
|
if (vodResponse.timedMetadata) {
|
|
@@ -2143,53 +2148,53 @@ var Session = /** @class */ (function () {
|
|
|
2143
2148
|
currentVod = newVod;
|
|
2144
2149
|
debug("[".concat(this._sessionId, "]: msequences=").concat(currentVod.getLiveMediaSequencesCount(), "; audio msequences=").concat(currentVod.getLiveMediaSequencesCount("audio"), "; subtitle msequences=").concat(currentVod.getLiveMediaSequencesCount("subtitle")));
|
|
2145
2150
|
_w = sessionState;
|
|
2146
|
-
return [4 /*yield*/, this._sessionState.
|
|
2151
|
+
return [4 /*yield*/, this._sessionState.setCurrentVod(currentVod, { ttl: currentVod.getDuration() * 1000 })];
|
|
2147
2152
|
case 56:
|
|
2148
|
-
_w.
|
|
2149
|
-
|
|
2150
|
-
return [4 /*yield*/, this._sessionState.set("vodMediaSeqAudio", 0)];
|
|
2153
|
+
_w.currentVod = _10.sent();
|
|
2154
|
+
return [4 /*yield*/, this._playheadState.set("playheadRef", Date.now(), isLeader)];
|
|
2151
2155
|
case 57:
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
return [4 /*yield*/, this._sessionState.set("
|
|
2156
|
+
_10.sent();
|
|
2157
|
+
_x = sessionState;
|
|
2158
|
+
return [4 /*yield*/, this._sessionState.set("vodMediaSeqVideo", 0)];
|
|
2155
2159
|
case 58:
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
return [4 /*yield*/, this._sessionState.set("
|
|
2160
|
+
_x.vodMediaSeqVideo = _10.sent();
|
|
2161
|
+
_y = sessionState;
|
|
2162
|
+
return [4 /*yield*/, this._sessionState.set("vodMediaSeqAudio", 0)];
|
|
2159
2163
|
case 59:
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
return [4 /*yield*/, this._sessionState.set("
|
|
2164
|
+
_y.vodMediaSeqAudio = _10.sent();
|
|
2165
|
+
_z = sessionState;
|
|
2166
|
+
return [4 /*yield*/, this._sessionState.set("vodMediaSeqSubtitle", 0)];
|
|
2163
2167
|
case 60:
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
return [4 /*yield*/, this._sessionState.set("
|
|
2168
|
+
_z.vodMediaSeqSubtitle = _10.sent();
|
|
2169
|
+
_0 = sessionState;
|
|
2170
|
+
return [4 /*yield*/, this._sessionState.set("mediaSeq", sessionState.mediaSeq + endMseqValue)];
|
|
2167
2171
|
case 61:
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
return [4 /*yield*/, this._sessionState.set("
|
|
2172
|
+
_0.mediaSeq = _10.sent();
|
|
2173
|
+
_1 = sessionState;
|
|
2174
|
+
return [4 /*yield*/, this._sessionState.set("mediaSeqAudio", sessionState.mediaSeqAudio + endMseqValueAudio)];
|
|
2171
2175
|
case 62:
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
return [4 /*yield*/, this._sessionState.set("
|
|
2176
|
+
_1.mediaSeqAudio = _10.sent();
|
|
2177
|
+
_2 = sessionState;
|
|
2178
|
+
return [4 /*yield*/, this._sessionState.set("mediaSeqSubtitle", sessionState.mediaSeqSubtitle + endMseqValueSubtitle)];
|
|
2175
2179
|
case 63:
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
return [4 /*yield*/, this._sessionState.set("
|
|
2180
|
+
_2.mediaSeqSubtitle = _10.sent();
|
|
2181
|
+
_3 = sessionState;
|
|
2182
|
+
return [4 /*yield*/, this._sessionState.set("discSeq", sessionState.discSeq + lastDiscontinuity)];
|
|
2179
2183
|
case 64:
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
return [4 /*yield*/, this._sessionState.
|
|
2184
|
+
_3.discSeq = _10.sent();
|
|
2185
|
+
_4 = sessionState;
|
|
2186
|
+
return [4 /*yield*/, this._sessionState.set("discSeqAudio", sessionState.discSeqAudio + lastDiscontinuityAudio)];
|
|
2183
2187
|
case 65:
|
|
2184
|
-
_10.sent();
|
|
2188
|
+
_4.discSeqAudio = _10.sent();
|
|
2185
2189
|
_5 = sessionState;
|
|
2186
|
-
return [4 /*yield*/, this._sessionState.
|
|
2190
|
+
return [4 /*yield*/, this._sessionState.set("discSeqSubtitle", sessionState.discSeqSubtitle + lastDiscontinuitySubtitle)];
|
|
2187
2191
|
case 66:
|
|
2188
|
-
_5.
|
|
2189
|
-
this.
|
|
2190
|
-
return [4 /*yield*/, this.
|
|
2192
|
+
_5.discSeqSubtitle = _10.sent();
|
|
2193
|
+
debug("[".concat(this._sessionId, "]: new sequence data set in store V[").concat(sessionState.mediaSeq, "][").concat(sessionState.discSeq, "]_A[").concat(sessionState.mediaSeqAudio, "][").concat(sessionState.discSeqAudio, "]_S[").concat(sessionState.mediaSeqSubtitle, "][").concat(sessionState.discSeqSubtitle, "]"));
|
|
2194
|
+
return [4 /*yield*/, this._sessionState.remove("nextVod")];
|
|
2191
2195
|
case 67:
|
|
2192
2196
|
_10.sent();
|
|
2197
|
+
this.leaderIsSettingNextVod = false;
|
|
2193
2198
|
return [4 /*yield*/, this._playheadState.set("diffCompensation", this.diffCompensation, isLeader)];
|
|
2194
2199
|
case 68:
|
|
2195
2200
|
_10.sent();
|
|
@@ -2429,7 +2434,8 @@ var Session = /** @class */ (function () {
|
|
|
2429
2434
|
dummySubtitleEndpoint: _this.dummySubtitleEndpoint,
|
|
2430
2435
|
subtitleSliceEndpoint: _this.subtitleSliceEndpoint,
|
|
2431
2436
|
shouldContainSubtitles: _this.use_vtt_subtitles,
|
|
2432
|
-
expectedSubtitleTracks: _this._subtitleTracks
|
|
2437
|
+
expectedSubtitleTracks: _this._subtitleTracks,
|
|
2438
|
+
alwaysMapBandwidthByNearest: _this.alwaysMapBandwidthByNearest
|
|
2433
2439
|
};
|
|
2434
2440
|
var timestamp = Date.now();
|
|
2435
2441
|
hlsVod_1 = new HLSVod(_this.slateUri, null, timestamp, null, m3u8Header(_this._instanceId), hlsOpts);
|
|
@@ -2482,7 +2488,11 @@ var Session = /** @class */ (function () {
|
|
|
2482
2488
|
var _this = this;
|
|
2483
2489
|
return new Promise(function (resolve, reject) {
|
|
2484
2490
|
try {
|
|
2485
|
-
var
|
|
2491
|
+
var options = {};
|
|
2492
|
+
if (vodResponse.startOffset) {
|
|
2493
|
+
options.offset = vodResponse.startOffset / 1000;
|
|
2494
|
+
}
|
|
2495
|
+
var truncatedVod_1 = new HLSTruncateVod(vodResponse.uri, vodResponse.desiredDuration / 1000, options);
|
|
2486
2496
|
truncatedVod_1.load()
|
|
2487
2497
|
.then(function () {
|
|
2488
2498
|
var audioManifestLoader;
|
|
@@ -2532,7 +2542,8 @@ var Session = /** @class */ (function () {
|
|
|
2532
2542
|
dummySubtitleEndpoint: _this.dummySubtitleEndpoint,
|
|
2533
2543
|
subtitleSliceEndpoint: _this.subtitleSliceEndpoint,
|
|
2534
2544
|
shouldContainSubtitles: _this.use_vtt_subtitles,
|
|
2535
|
-
expectedSubtitleTracks: _this._subtitleTracks
|
|
2545
|
+
expectedSubtitleTracks: _this._subtitleTracks,
|
|
2546
|
+
alwaysMapBandwidthByNearest: _this.alwaysMapBandwidthByNearest
|
|
2536
2547
|
};
|
|
2537
2548
|
var timestamp = Date.now();
|
|
2538
2549
|
hlsVod_2 = new HLSVod(nexVodUri, null, timestamp, null, m3u8Header(_this._instanceId), hlsOpts);
|
|
@@ -2761,9 +2772,9 @@ var Session = /** @class */ (function () {
|
|
|
2761
2772
|
}
|
|
2762
2773
|
};
|
|
2763
2774
|
Session.prototype._isOldVod = function (refTs, vodDur) {
|
|
2764
|
-
var TIME_PADDING_MS = 20 * 1000; // 20secs
|
|
2765
2775
|
var VOD_DURATION_MS = vodDur * 1000;
|
|
2766
|
-
var
|
|
2776
|
+
var TIME_PADDING_MS = VOD_DURATION_MS * 0.05; //5 percent of content duration
|
|
2777
|
+
var TIME_SINCE_VOD_STARTED_MS = Date.now() - refTs + TIME_PADDING_MS;
|
|
2767
2778
|
if (TIME_SINCE_VOD_STARTED_MS > VOD_DURATION_MS) {
|
|
2768
2779
|
return true;
|
|
2769
2780
|
}
|
package/dist/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eyevinn-channel-engine",
|
|
3
|
-
"version": "4.2.
|
|
3
|
+
"version": "4.2.10",
|
|
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.
|
|
33
|
-
"@eyevinn/hls-vodtolive": "^3.
|
|
32
|
+
"@eyevinn/hls-truncate": "^0.3.0",
|
|
33
|
+
"@eyevinn/hls-vodtolive": "^3.1.1",
|
|
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,7 @@ export interface ChannelEngineOpts {
|
|
|
46
46
|
subtitleSliceEndpoint?: string;
|
|
47
47
|
useVTTSubtitles?: boolean;
|
|
48
48
|
alwaysNewSegments?: boolean;
|
|
49
|
+
alwaysMapBandwidthByNearest?: boolean;
|
|
49
50
|
diffCompensationRate?: number;
|
|
50
51
|
staticDirectory?: string;
|
|
51
52
|
averageSegmentDuration?: number;
|
|
@@ -100,6 +101,7 @@ export interface VodResponse {
|
|
|
100
101
|
offset?: number;
|
|
101
102
|
diffMs?: number;
|
|
102
103
|
desiredDuration?: number;
|
|
104
|
+
startOffset?: number;
|
|
103
105
|
type?: string;
|
|
104
106
|
currentMetadata?: VodResponseMetadata;
|
|
105
107
|
timedMetadata?: VodTimedMetadata;
|
|
@@ -181,6 +183,7 @@ export class ChannelEngine {
|
|
|
181
183
|
private subtitleSliceEndpoint: string;
|
|
182
184
|
private useVTTSubtitles: boolean;
|
|
183
185
|
private alwaysNewSegments: boolean;
|
|
186
|
+
private alwaysMapBandwidthByNearest: boolean;
|
|
184
187
|
private defaultSlateUri?: string;
|
|
185
188
|
private slateDuration?: number;
|
|
186
189
|
private assetMgr: IAssetManager;
|
|
@@ -220,6 +223,10 @@ export class ChannelEngine {
|
|
|
220
223
|
if (options && options.alwaysNewSegments) {
|
|
221
224
|
this.alwaysNewSegments = true;
|
|
222
225
|
}
|
|
226
|
+
this.alwaysMapBandwidthByNearest = false;
|
|
227
|
+
if (options && options.alwaysMapBandwidthByNearest) {
|
|
228
|
+
this.alwaysMapBandwidthByNearest = true;
|
|
229
|
+
}
|
|
223
230
|
if (options && options.defaultSlateUri) {
|
|
224
231
|
this.defaultSlateUri = options.defaultSlateUri;
|
|
225
232
|
this.slateRepetitions = options.slateRepetitions || 10;
|
|
@@ -453,6 +460,7 @@ export class ChannelEngine {
|
|
|
453
460
|
subtitleSliceEndpoint: this.subtitleSliceEndpoint,
|
|
454
461
|
useVTTSubtitles: this.useVTTSubtitles,
|
|
455
462
|
alwaysNewSegments: options.alwaysNewSegments,
|
|
463
|
+
alwaysMapBandwidthByNearest: options.alwaysMapBandwidthByNearest,
|
|
456
464
|
noSessionDataTags: options.noSessionDataTags,
|
|
457
465
|
playheadDiffThreshold: channel.options && channel.options.playheadDiffThreshold ? channel.options.playheadDiffThreshold : this.streamerOpts.defaultPlayheadDiffThreshold,
|
|
458
466
|
maxTickInterval: channel.options && channel.options.maxTickInterval ? channel.options.maxTickInterval : this.streamerOpts.defaultMaxTickInterval,
|
package/engine/session.js
CHANGED
|
@@ -72,11 +72,16 @@ class Session {
|
|
|
72
72
|
}
|
|
73
73
|
this.isAllowedToClearVodCache = null;
|
|
74
74
|
this.alwaysNewSegments = null;
|
|
75
|
+
this.alwaysMapBandwidthByNearest = null;
|
|
75
76
|
if (config) {
|
|
76
77
|
if (config.alwaysNewSegments) {
|
|
77
78
|
this.alwaysNewSegments = config.alwaysNewSegments;
|
|
78
79
|
}
|
|
79
80
|
|
|
81
|
+
if (config.alwaysMapBandwidthByNearest) {
|
|
82
|
+
this.alwaysMapBandwidthByNearest = config.alwaysMapBandwidthByNearest;
|
|
83
|
+
}
|
|
84
|
+
|
|
80
85
|
if (config.sessionId) {
|
|
81
86
|
this._sessionId = config.sessionId;
|
|
82
87
|
}
|
|
@@ -828,7 +833,7 @@ class Session {
|
|
|
828
833
|
let positionV = 0;
|
|
829
834
|
let positionA = 0;
|
|
830
835
|
const position = (await this._getCurrentPlayheadPosition()) * 1000;
|
|
831
|
-
positionV = position / 1000;
|
|
836
|
+
positionV = position ? position / 1000 : 0;
|
|
832
837
|
let currentVod = await this._sessionState.getCurrentVod();
|
|
833
838
|
const sessionState = await this._sessionState.getValues(["vodMediaSeqAudio"]);
|
|
834
839
|
let posDiff;
|
|
@@ -840,11 +845,10 @@ class Session {
|
|
|
840
845
|
debug(`[${this._sessionId}]: About to determine audio increment`);
|
|
841
846
|
do {
|
|
842
847
|
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}
|
|
848
|
+
positionA = audioPosition ? audioPosition / 1000 : 0;
|
|
849
|
+
posDiff = (positionV - positionA).toFixed(3);
|
|
850
|
+
debug(`[${this._sessionId}]: positionV=${positionV};positionA=${positionA};posDiff=${posDiff}`);
|
|
846
851
|
if (posDiff <= maxAcceptableDiff) {
|
|
847
|
-
debug(`[${this._sessionId}]: posDiff value (${posDiff}) is acceptable`);
|
|
848
852
|
break;
|
|
849
853
|
}
|
|
850
854
|
if (posDiff > thresh) {
|
|
@@ -858,7 +862,7 @@ class Session {
|
|
|
858
862
|
if (sessionState.vodMediaSeqAudio + index > audioSeqLastIdx) {
|
|
859
863
|
break;
|
|
860
864
|
}
|
|
861
|
-
} while (!(-thresh < posDiff && posDiff < thresh));
|
|
865
|
+
} while (!(-thresh < posDiff && posDiff < thresh) && !isNaN(posDiff));
|
|
862
866
|
audioIncrement = index;
|
|
863
867
|
debug(`[${this._sessionId}]: Current VOD Playhead Positions are to be: [${positionV.toFixed(3)}][${positionA.toFixed(3)}] (${posDiff})`);
|
|
864
868
|
}
|
|
@@ -1326,7 +1330,8 @@ class Session {
|
|
|
1326
1330
|
dummySubtitleEndpoint: this.dummySubtitleEndpoint,
|
|
1327
1331
|
subtitleSliceEndpoint: this.subtitleSliceEndpoint,
|
|
1328
1332
|
shouldContainSubtitles: this.use_vtt_subtitles,
|
|
1329
|
-
expectedSubtitleTracks: this._subtitleTracks
|
|
1333
|
+
expectedSubtitleTracks: this._subtitleTracks,
|
|
1334
|
+
alwaysMapBandwidthByNearest: this.alwaysMapBandwidthByNearest
|
|
1330
1335
|
};
|
|
1331
1336
|
newVod = new HLSVod(vodResponse.uri, [], vodResponse.unixTs, vodResponse.offset * 1000, m3u8Header(this._instanceId), hlsOpts);
|
|
1332
1337
|
if (vodResponse.timedMetadata) {
|
|
@@ -1502,7 +1507,8 @@ class Session {
|
|
|
1502
1507
|
dummySubtitleEndpoint: this.dummySubtitleEndpoint,
|
|
1503
1508
|
subtitleSliceEndpoint: this.subtitleSliceEndpoint,
|
|
1504
1509
|
shouldContainSubtitles: this.use_vtt_subtitles,
|
|
1505
|
-
expectedSubtitleTracks: this._subtitleTracks
|
|
1510
|
+
expectedSubtitleTracks: this._subtitleTracks,
|
|
1511
|
+
alwaysMapBandwidthByNearest: this.alwaysMapBandwidthByNearest
|
|
1506
1512
|
};
|
|
1507
1513
|
newVod = new HLSVod(vodResponse.uri, null, vodResponse.unixTs, vodResponse.offset * 1000, m3u8Header(this._instanceId), hlsOpts);
|
|
1508
1514
|
if (vodResponse.timedMetadata) {
|
|
@@ -1553,6 +1559,8 @@ class Session {
|
|
|
1553
1559
|
debug(`[${this._sessionId}]: playhead positions [A]=${newVod.getPlayheadPositions("audio")}`);
|
|
1554
1560
|
currentVod = newVod;
|
|
1555
1561
|
debug(`[${this._sessionId}]: msequences=${currentVod.getLiveMediaSequencesCount()}; audio msequences=${currentVod.getLiveMediaSequencesCount("audio")}; subtitle msequences=${currentVod.getLiveMediaSequencesCount("subtitle")}`);
|
|
1562
|
+
sessionState.currentVod = await this._sessionState.setCurrentVod(currentVod, { ttl: currentVod.getDuration() * 1000 });
|
|
1563
|
+
await this._playheadState.set("playheadRef", Date.now(), isLeader);
|
|
1556
1564
|
sessionState.vodMediaSeqVideo = await this._sessionState.set("vodMediaSeqVideo", 0);
|
|
1557
1565
|
sessionState.vodMediaSeqAudio = await this._sessionState.set("vodMediaSeqAudio", 0);
|
|
1558
1566
|
sessionState.vodMediaSeqSubtitle = await this._sessionState.set("vodMediaSeqSubtitle", 0);
|
|
@@ -1564,9 +1572,7 @@ class Session {
|
|
|
1564
1572
|
sessionState.discSeqSubtitle = await this._sessionState.set("discSeqSubtitle", sessionState.discSeqSubtitle + lastDiscontinuitySubtitle);
|
|
1565
1573
|
debug(`[${this._sessionId}]: new sequence data set in store V[${sessionState.mediaSeq}][${sessionState.discSeq}]_A[${sessionState.mediaSeqAudio}][${sessionState.discSeqAudio}]_S[${sessionState.mediaSeqSubtitle}][${sessionState.discSeqSubtitle}]`);
|
|
1566
1574
|
await this._sessionState.remove("nextVod");
|
|
1567
|
-
sessionState.currentVod = await this._sessionState.setCurrentVod(currentVod, { ttl: currentVod.getDuration() * 1000 });
|
|
1568
1575
|
this.leaderIsSettingNextVod = false;
|
|
1569
|
-
await this._playheadState.set("playheadRef", Date.now(), isLeader);
|
|
1570
1576
|
await this._playheadState.set("diffCompensation", this.diffCompensation, isLeader);
|
|
1571
1577
|
debug(`[${this._sessionId}]: sharing durrent vods diffCompensation=${this.diffCompensation}`);
|
|
1572
1578
|
this.produceEvent({
|
|
@@ -1749,7 +1755,8 @@ 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
|
|
1753
1760
|
};
|
|
1754
1761
|
const timestamp = Date.now();
|
|
1755
1762
|
hlsVod = new HLSVod(this.slateUri, null, timestamp, null, m3u8Header(this._instanceId), hlsOpts);
|
|
@@ -1799,7 +1806,11 @@ class Session {
|
|
|
1799
1806
|
_truncateVod(vodResponse) {
|
|
1800
1807
|
return new Promise((resolve, reject) => {
|
|
1801
1808
|
try {
|
|
1802
|
-
const
|
|
1809
|
+
const options = {};
|
|
1810
|
+
if (vodResponse.startOffset) {
|
|
1811
|
+
options.offset = vodResponse.startOffset / 1000;
|
|
1812
|
+
}
|
|
1813
|
+
const truncatedVod = new HLSTruncateVod(vodResponse.uri, vodResponse.desiredDuration / 1000, options);
|
|
1803
1814
|
truncatedVod.load()
|
|
1804
1815
|
.then(() => {
|
|
1805
1816
|
let audioManifestLoader;
|
|
@@ -1848,7 +1859,8 @@ class Session {
|
|
|
1848
1859
|
dummySubtitleEndpoint: this.dummySubtitleEndpoint,
|
|
1849
1860
|
subtitleSliceEndpoint: this.subtitleSliceEndpoint,
|
|
1850
1861
|
shouldContainSubtitles: this.use_vtt_subtitles,
|
|
1851
|
-
expectedSubtitleTracks: this._subtitleTracks
|
|
1862
|
+
expectedSubtitleTracks: this._subtitleTracks,
|
|
1863
|
+
alwaysMapBandwidthByNearest: this.alwaysMapBandwidthByNearest
|
|
1852
1864
|
};
|
|
1853
1865
|
const timestamp = Date.now();
|
|
1854
1866
|
hlsVod = new HLSVod(nexVodUri, null, timestamp, null, m3u8Header(this._instanceId), hlsOpts);
|
|
@@ -2037,9 +2049,9 @@ class Session {
|
|
|
2037
2049
|
}
|
|
2038
2050
|
|
|
2039
2051
|
_isOldVod(refTs, vodDur) {
|
|
2040
|
-
const TIME_PADDING_MS = 20 * 1000 // 20secs
|
|
2041
2052
|
const VOD_DURATION_MS = vodDur * 1000;
|
|
2042
|
-
const
|
|
2053
|
+
const TIME_PADDING_MS = VOD_DURATION_MS * 0.05; //5 percent of content duration
|
|
2054
|
+
const TIME_SINCE_VOD_STARTED_MS = Date.now() - refTs + TIME_PADDING_MS;
|
|
2043
2055
|
if (TIME_SINCE_VOD_STARTED_MS > VOD_DURATION_MS) {
|
|
2044
2056
|
return true;
|
|
2045
2057
|
}
|
package/examples/truncate.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eyevinn-channel-engine",
|
|
3
|
-
"version": "4.2.
|
|
3
|
+
"version": "4.2.10",
|
|
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.
|
|
33
|
-
"@eyevinn/hls-vodtolive": "^3.
|
|
32
|
+
"@eyevinn/hls-truncate": "^0.3.0",
|
|
33
|
+
"@eyevinn/hls-vodtolive": "^3.1.1",
|
|
34
34
|
"@eyevinn/m3u8": "^0.5.3",
|
|
35
35
|
"abort-controller": "^3.0.0",
|
|
36
36
|
"debug": "^3.2.7",
|