eyevinn-channel-engine 4.2.1 → 4.2.3
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 +6 -5
- package/dist/engine/server.d.ts +11 -1
- package/dist/engine/server.js +56 -51
- package/dist/engine/session.d.ts +2 -0
- package/dist/engine/session.js +352 -293
- package/dist/engine/stream_switcher.d.ts +1 -0
- package/dist/engine/stream_switcher.js +16 -0
- package/dist/examples/autocreate.js +99 -0
- package/dist/{server.js → examples/default.js} +1 -1
- package/dist/{server-demux.js → examples/demux.js} +1 -1
- package/dist/{server-drm.js → examples/drm.js} +1 -1
- package/dist/{server-livemix.js → examples/livemix.js} +1 -1
- package/dist/examples/multicodec.d.ts +1 -0
- package/dist/{server-multicodec.js → examples/multicodec.js} +1 -1
- package/dist/package.json +4 -4
- package/engine/server.ts +36 -34
- package/engine/session.js +60 -7
- package/engine/stream_switcher.js +18 -0
- package/examples/autocreate.ts +112 -0
- package/{server.ts → examples/default.ts} +1 -1
- package/{server-demux.ts → examples/demux.ts} +1 -1
- package/{server-drm.ts → examples/drm.ts} +1 -1
- package/{server-livemix.ts → examples/livemix.ts} +1 -1
- package/{server-multicodec.ts → examples/multicodec.ts} +1 -1
- package/package.json +4 -4
- package/tsconfig.json +1 -5
- /package/dist/{server-demux.d.ts → examples/autocreate.d.ts} +0 -0
- /package/dist/{server-drm.d.ts → examples/default.d.ts} +0 -0
- /package/dist/{server-livemix.d.ts → examples/demux.d.ts} +0 -0
- /package/dist/{server-multicodec.d.ts → examples/drm.d.ts} +0 -0
- /package/dist/{server.d.ts → examples/livemix.d.ts} +0 -0
package/README.md
CHANGED
|
@@ -110,7 +110,7 @@ Build the app:
|
|
|
110
110
|
npm run build
|
|
111
111
|
```
|
|
112
112
|
|
|
113
|
-
To start the reference implementation in `
|
|
113
|
+
To start the reference implementation in `examples/default.ts` run:
|
|
114
114
|
|
|
115
115
|
```
|
|
116
116
|
npm start
|
|
@@ -129,10 +129,11 @@ DEBUG=engine-* npm start
|
|
|
129
129
|
```
|
|
130
130
|
|
|
131
131
|
In addition there other reference implemetations that can be used:
|
|
132
|
-
- `
|
|
133
|
-
- `
|
|
134
|
-
- `
|
|
135
|
-
- `
|
|
132
|
+
- `examples/demux.ts` : example with demuxed audio
|
|
133
|
+
- `examples/livemix.ts` : example with live mimxing
|
|
134
|
+
- `examples/multicodec.ts` : example with multicodec
|
|
135
|
+
- `examples/drm.ts` : example with DRM
|
|
136
|
+
- `examples/autocreate.ts` : example to auto create channel on demand
|
|
136
137
|
|
|
137
138
|
### Source linking hls-vodtolive library
|
|
138
139
|
|
package/dist/engine/server.d.ts
CHANGED
|
@@ -26,6 +26,7 @@ export interface ChannelEngineOpts {
|
|
|
26
26
|
adXchangeUri?: string;
|
|
27
27
|
noSessionDataTags?: boolean;
|
|
28
28
|
volatileKeyTTL?: number;
|
|
29
|
+
autoCreateSession?: boolean;
|
|
29
30
|
}
|
|
30
31
|
export interface VodRequest {
|
|
31
32
|
sessionId: string;
|
|
@@ -43,13 +44,18 @@ export interface VodTimedMetadata {
|
|
|
43
44
|
'x-channelid'?: string;
|
|
44
45
|
'class': string;
|
|
45
46
|
}
|
|
47
|
+
export interface LiveTimedMetadata {
|
|
48
|
+
'id': string;
|
|
49
|
+
'start-date': string;
|
|
50
|
+
'x-title'?: string;
|
|
51
|
+
}
|
|
46
52
|
export interface VodResponse {
|
|
47
53
|
title: any;
|
|
48
54
|
id: string;
|
|
49
55
|
uri: string;
|
|
50
56
|
offset?: number;
|
|
51
57
|
diffMs?: number;
|
|
52
|
-
|
|
58
|
+
desiredDuration?: number;
|
|
53
59
|
type?: string;
|
|
54
60
|
currentMetadata?: VodResponseMetadata;
|
|
55
61
|
timedMetadata?: VodTimedMetadata;
|
|
@@ -92,6 +98,7 @@ export interface SubtitleTracks {
|
|
|
92
98
|
}
|
|
93
99
|
export interface IChannelManager {
|
|
94
100
|
getChannels: () => Channel[];
|
|
101
|
+
autoCreateChannel?: (channelId: string) => void;
|
|
95
102
|
}
|
|
96
103
|
export declare enum ScheduleStreamType {
|
|
97
104
|
LIVE = 1,
|
|
@@ -106,6 +113,7 @@ export interface Schedule {
|
|
|
106
113
|
end_time: number;
|
|
107
114
|
uri: string;
|
|
108
115
|
duration?: number;
|
|
116
|
+
timedMetadata?: LiveTimedMetadata;
|
|
109
117
|
}
|
|
110
118
|
export interface IStreamSwitchManager {
|
|
111
119
|
getSchedule: (channelId: string) => Promise<Schedule[]>;
|
|
@@ -133,6 +141,7 @@ export declare class ChannelEngine {
|
|
|
133
141
|
private logCloudWatchMetrics;
|
|
134
142
|
private adCopyMgrUri?;
|
|
135
143
|
private adXchangeUri?;
|
|
144
|
+
private autoCreateSession;
|
|
136
145
|
constructor(assetMgr: IAssetManager, options?: ChannelEngineOpts);
|
|
137
146
|
updateStreamSwitchAsync(): Promise<void>;
|
|
138
147
|
updateChannelsAsync(channelMgr: any, options: any): Promise<void>;
|
|
@@ -142,6 +151,7 @@ export declare class ChannelEngine {
|
|
|
142
151
|
getSessionCount(): number;
|
|
143
152
|
getPlayheadCount(): number;
|
|
144
153
|
_monitorAsync(session: any, sessionLive: any): Promise<void>;
|
|
154
|
+
createChannel(channelId: any): Promise<void>;
|
|
145
155
|
getMasterManifest(channelId: any): Promise<any>;
|
|
146
156
|
getMediaManifests(channelId: any): Promise<{}>;
|
|
147
157
|
getAudioManifests(channelId: any): Promise<{}>;
|
package/dist/engine/server.js
CHANGED
|
@@ -47,12 +47,13 @@ var SessionLive = require('./session_live.js');
|
|
|
47
47
|
var StreamSwitcher = require('./stream_switcher.js');
|
|
48
48
|
var EventStream = require('./event_stream.js');
|
|
49
49
|
var SubtitleSlicer = require('./subtitle_slicer.js');
|
|
50
|
+
var timer = require('./util.js').timer;
|
|
50
51
|
var SessionStateStore = require('./session_state.js').SessionStateStore;
|
|
51
52
|
var SessionLiveStateStore = require('./session_live_state.js').SessionLiveStateStore;
|
|
52
53
|
var PlayheadStateStore = require('./playhead_state.js').PlayheadStateStore;
|
|
53
54
|
var _a = require('./util.js'), filterQueryParser = _a.filterQueryParser, toHHMMSS = _a.toHHMMSS, WaitTimeGenerator = _a.WaitTimeGenerator;
|
|
54
55
|
var version = require('../package.json').version;
|
|
55
|
-
var
|
|
56
|
+
var AUTO_CREATE_CHANNEL_TIMEOUT = 3000;
|
|
56
57
|
var sessions = {}; // Should be a persistent store...
|
|
57
58
|
var sessionsLive = {}; // Should be a persistent store...
|
|
58
59
|
var sessionSwitchers = {}; // Should be a persistent store...
|
|
@@ -69,6 +70,7 @@ var ScheduleStreamType;
|
|
|
69
70
|
var ChannelEngine = /** @class */ (function () {
|
|
70
71
|
function ChannelEngine(assetMgr, options) {
|
|
71
72
|
var _this = this;
|
|
73
|
+
this.autoCreateSession = false;
|
|
72
74
|
this.options = options;
|
|
73
75
|
if (options && options.adCopyMgrUri) {
|
|
74
76
|
this.adCopyMgrUri = options.adCopyMgrUri;
|
|
@@ -95,6 +97,9 @@ var ChannelEngine = /** @class */ (function () {
|
|
|
95
97
|
if (options && options.streamSwitchManager) {
|
|
96
98
|
this.streamSwitchManager = options.streamSwitchManager;
|
|
97
99
|
}
|
|
100
|
+
if (options && options.autoCreateSession !== undefined) {
|
|
101
|
+
this.autoCreateSession = options.autoCreateSession;
|
|
102
|
+
}
|
|
98
103
|
this.assetMgr = assetMgr;
|
|
99
104
|
this.monitorTimer = {};
|
|
100
105
|
this.server = restify.createServer();
|
|
@@ -417,6 +422,7 @@ var ChannelEngine = /** @class */ (function () {
|
|
|
417
422
|
case 0:
|
|
418
423
|
debug("Do we have any new channels?");
|
|
419
424
|
newChannels = channelMgr.getChannels().filter(function (channel) { return !sessions[channel.id]; });
|
|
425
|
+
debug(newChannels);
|
|
420
426
|
addAsync = function (channel) { return __awaiter(_this, void 0, void 0, function () {
|
|
421
427
|
var _this = this;
|
|
422
428
|
return __generator(this, function (_a) {
|
|
@@ -486,7 +492,7 @@ var ChannelEngine = /** @class */ (function () {
|
|
|
486
492
|
return __generator(this, function (_a) {
|
|
487
493
|
switch (_a.label) {
|
|
488
494
|
case 0:
|
|
489
|
-
debug("Adding channel with ID ".concat(channel.id));
|
|
495
|
+
debug("Adding live channel with ID ".concat(channel.id));
|
|
490
496
|
return [4 /*yield*/, sessionsLive[channel.id].initAsync()];
|
|
491
497
|
case 1:
|
|
492
498
|
_a.sent();
|
|
@@ -652,6 +658,32 @@ var ChannelEngine = /** @class */ (function () {
|
|
|
652
658
|
});
|
|
653
659
|
});
|
|
654
660
|
};
|
|
661
|
+
ChannelEngine.prototype.createChannel = function (channelId) {
|
|
662
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
663
|
+
var _this = this;
|
|
664
|
+
return __generator(this, function (_a) {
|
|
665
|
+
switch (_a.label) {
|
|
666
|
+
case 0:
|
|
667
|
+
if (!!sessions[channelId]) return [3 /*break*/, 2];
|
|
668
|
+
if (!this.options.channelManager.autoCreateChannel) return [3 /*break*/, 2];
|
|
669
|
+
this.options.channelManager.autoCreateChannel(channelId);
|
|
670
|
+
setTimeout(function () { return __awaiter(_this, void 0, void 0, function () { return __generator(this, function (_a) {
|
|
671
|
+
switch (_a.label) {
|
|
672
|
+
case 0: return [4 /*yield*/, this.updateChannelsAsync(this.options.channelManager, this.options)];
|
|
673
|
+
case 1:
|
|
674
|
+
_a.sent();
|
|
675
|
+
return [2 /*return*/];
|
|
676
|
+
}
|
|
677
|
+
}); }); });
|
|
678
|
+
return [4 /*yield*/, timer(AUTO_CREATE_CHANNEL_TIMEOUT)];
|
|
679
|
+
case 1:
|
|
680
|
+
_a.sent();
|
|
681
|
+
_a.label = 2;
|
|
682
|
+
case 2: return [2 /*return*/];
|
|
683
|
+
}
|
|
684
|
+
});
|
|
685
|
+
});
|
|
686
|
+
};
|
|
655
687
|
ChannelEngine.prototype.getMasterManifest = function (channelId) {
|
|
656
688
|
return __awaiter(this, void 0, void 0, function () {
|
|
657
689
|
var session, masterM3U8, err;
|
|
@@ -835,52 +867,25 @@ var ChannelEngine = /** @class */ (function () {
|
|
|
835
867
|
if (req.query['category']) {
|
|
836
868
|
options.category = req.query['category'];
|
|
837
869
|
}
|
|
838
|
-
if (!(
|
|
839
|
-
|
|
840
|
-
return [
|
|
870
|
+
if (!(this.autoCreateSession && req.query['channel'])) return [3 /*break*/, 2];
|
|
871
|
+
debug("Attempting to create channel with id ".concat(req.query['channel']));
|
|
872
|
+
return [4 /*yield*/, this.createChannel(req.query['channel'])];
|
|
841
873
|
case 1:
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
874
|
+
_a.sent();
|
|
875
|
+
debug("Automatically created channel with id ".concat(req.query['channel']));
|
|
876
|
+
_a.label = 2;
|
|
845
877
|
case 2:
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
options.averageSegmentDuration = this.streamerOpts.defaultAverageSegmentDuration;
|
|
849
|
-
options.useDemuxedAudio = this.useDemuxedAudio;
|
|
850
|
-
options.dummySubtitleEndpoint = this.dummySubtitleEndpoint;
|
|
851
|
-
options.subtitleSliceEndpoint = this.subtitleSliceEndpoint;
|
|
852
|
-
options.useVTTSubtitles = this.useVTTSubtitles;
|
|
853
|
-
options.alwaysNewSegments = this.alwaysNewSegments;
|
|
854
|
-
options.playheadDiffThreshold = this.streamerOpts.defaultPlayheadDiffThreshold;
|
|
855
|
-
options.maxTickInterval = this.streamerOpts.defaultMaxTickInterval;
|
|
856
|
-
options.targetDurationPadding = this.streamerOpts.targetDurationPadding;
|
|
857
|
-
options.forceTargetDuration = this.streamerOpts.forceTargetDuration;
|
|
858
|
-
options.diffCompensationRate = this.streamerOpts.diffCompensationRate;
|
|
859
|
-
// if we are initiating a master manifest
|
|
860
|
-
// outside of specific Channel context,
|
|
861
|
-
// if slate options are set at the ChannelEngine level, then set these here
|
|
862
|
-
if (this.defaultSlateUri) {
|
|
863
|
-
options.slateUri = this.defaultSlateUri;
|
|
878
|
+
if (req.query['channel'] && sessions[req.query['channel']]) {
|
|
879
|
+
session = sessions[req.query['channel']];
|
|
864
880
|
}
|
|
865
|
-
if (
|
|
866
|
-
|
|
881
|
+
else if (req.query['session'] && sessions[req.query['session']]) {
|
|
882
|
+
session = sessions[req.query['session']];
|
|
867
883
|
}
|
|
868
|
-
if (this.slateDuration) {
|
|
869
|
-
options.slateDuration = this.slateDuration;
|
|
870
|
-
}
|
|
871
|
-
options.disabledPlayhead = true; // disable playhead for personalized streams
|
|
872
|
-
session = new Session(this.assetMgr, options, this.sessionStore);
|
|
873
|
-
return [4 /*yield*/, session.initAsync()];
|
|
874
|
-
case 3:
|
|
875
|
-
_a.sent();
|
|
876
|
-
sessions[session.sessionId] = session;
|
|
877
|
-
_a.label = 4;
|
|
878
|
-
case 4:
|
|
879
884
|
if (req.query['startWithId']) {
|
|
880
885
|
options.startWithId = req.query['startWithId'];
|
|
881
886
|
debug("New session to start with assetId=".concat(options.startWithId));
|
|
882
887
|
}
|
|
883
|
-
if (!session) return [3 /*break*/,
|
|
888
|
+
if (!session) return [3 /*break*/, 7];
|
|
884
889
|
eventStream = new EventStream(session);
|
|
885
890
|
eventStreams[session.sessionId] = eventStream;
|
|
886
891
|
filter = void 0;
|
|
@@ -888,11 +893,11 @@ var ChannelEngine = /** @class */ (function () {
|
|
|
888
893
|
debug("Applying filter on master manifest ".concat(req.query['filter']));
|
|
889
894
|
filter = filterQueryParser(req.query['filter']);
|
|
890
895
|
}
|
|
891
|
-
_a.label =
|
|
892
|
-
case
|
|
893
|
-
_a.trys.push([
|
|
896
|
+
_a.label = 3;
|
|
897
|
+
case 3:
|
|
898
|
+
_a.trys.push([3, 5, , 6]);
|
|
894
899
|
return [4 /*yield*/, session.getMasterManifestAsync(filter)];
|
|
895
|
-
case
|
|
900
|
+
case 4:
|
|
896
901
|
body = _a.sent();
|
|
897
902
|
res.sendRaw(200, Buffer.from(body, 'utf8'), {
|
|
898
903
|
"Content-Type": "application/vnd.apple.mpegurl",
|
|
@@ -904,16 +909,16 @@ var ChannelEngine = /** @class */ (function () {
|
|
|
904
909
|
"X-Instance-Id": this.instanceId + "<".concat(version, ">"),
|
|
905
910
|
});
|
|
906
911
|
next();
|
|
907
|
-
return [3 /*break*/,
|
|
908
|
-
case
|
|
912
|
+
return [3 /*break*/, 6];
|
|
913
|
+
case 5:
|
|
909
914
|
err_4 = _a.sent();
|
|
910
915
|
next(this._errorHandler(err_4));
|
|
911
|
-
return [3 /*break*/,
|
|
912
|
-
case
|
|
913
|
-
case
|
|
916
|
+
return [3 /*break*/, 6];
|
|
917
|
+
case 6: return [3 /*break*/, 8];
|
|
918
|
+
case 7:
|
|
914
919
|
next(this._gracefulErrorHandler("Could not find a valid session"));
|
|
915
|
-
_a.label =
|
|
916
|
-
case
|
|
920
|
+
_a.label = 8;
|
|
921
|
+
case 8: return [2 /*return*/];
|
|
917
922
|
}
|
|
918
923
|
});
|
|
919
924
|
});
|
package/dist/engine/session.d.ts
CHANGED
|
@@ -107,6 +107,7 @@ declare class Session {
|
|
|
107
107
|
_tickAsync(): Promise<void>;
|
|
108
108
|
_getNextVod(): Promise<any>;
|
|
109
109
|
_loadSlate(afterVod: any, reps: any): Promise<any>;
|
|
110
|
+
_truncateVod(vodResponse: any): Promise<any>;
|
|
110
111
|
_truncateSlate(afterVod: any, requestedDuration: any, vodUri: any): Promise<any>;
|
|
111
112
|
_fillGap(afterVod: any, desiredDuration: any): Promise<any>;
|
|
112
113
|
_getNextVodById(id: any): Promise<any>;
|
|
@@ -117,4 +118,5 @@ declare class Session {
|
|
|
117
118
|
_getSubtitlePlayheadPosition(seqIdx: any): Promise<any>;
|
|
118
119
|
_getLastDuration(manifest: any): Promise<any>;
|
|
119
120
|
_getPlayheadDiffCompensationValue(diffMs: any, thresholdMs: any): number;
|
|
121
|
+
_isOldVod(refTs: any, vodDur: any): boolean;
|
|
120
122
|
}
|