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.
Files changed (31) hide show
  1. package/README.md +6 -5
  2. package/dist/engine/server.d.ts +11 -1
  3. package/dist/engine/server.js +56 -51
  4. package/dist/engine/session.d.ts +2 -0
  5. package/dist/engine/session.js +352 -293
  6. package/dist/engine/stream_switcher.d.ts +1 -0
  7. package/dist/engine/stream_switcher.js +16 -0
  8. package/dist/examples/autocreate.js +99 -0
  9. package/dist/{server.js → examples/default.js} +1 -1
  10. package/dist/{server-demux.js → examples/demux.js} +1 -1
  11. package/dist/{server-drm.js → examples/drm.js} +1 -1
  12. package/dist/{server-livemix.js → examples/livemix.js} +1 -1
  13. package/dist/examples/multicodec.d.ts +1 -0
  14. package/dist/{server-multicodec.js → examples/multicodec.js} +1 -1
  15. package/dist/package.json +4 -4
  16. package/engine/server.ts +36 -34
  17. package/engine/session.js +60 -7
  18. package/engine/stream_switcher.js +18 -0
  19. package/examples/autocreate.ts +112 -0
  20. package/{server.ts → examples/default.ts} +1 -1
  21. package/{server-demux.ts → examples/demux.ts} +1 -1
  22. package/{server-drm.ts → examples/drm.ts} +1 -1
  23. package/{server-livemix.ts → examples/livemix.ts} +1 -1
  24. package/{server-multicodec.ts → examples/multicodec.ts} +1 -1
  25. package/package.json +4 -4
  26. package/tsconfig.json +1 -5
  27. /package/dist/{server-demux.d.ts → examples/autocreate.d.ts} +0 -0
  28. /package/dist/{server-drm.d.ts → examples/default.d.ts} +0 -0
  29. /package/dist/{server-livemix.d.ts → examples/demux.d.ts} +0 -0
  30. /package/dist/{server-multicodec.d.ts → examples/drm.d.ts} +0 -0
  31. /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 `server.ts` run:
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
- - `server-demux.ts` : example with demuxed audio
133
- - `server-livemix.ts` : example with live mimxing
134
- - `server-multicodec.ts` : example with multicodec
135
- - `server-drm.ts` : example with DRM
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
 
@@ -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
- desiredDuraiton?: number;
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<{}>;
@@ -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 timer = function (ms) { return new Promise(function (res) { return setTimeout(res, ms); }); };
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 (!(req.query['channel'] && sessions[req.query['channel']])) return [3 /*break*/, 1];
839
- session = sessions[req.query['channel']];
840
- return [3 /*break*/, 4];
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
- if (!(req.query['session'] && sessions[req.query['session']])) return [3 /*break*/, 2];
843
- session = sessions[req.query['session']];
844
- return [3 /*break*/, 4];
874
+ _a.sent();
875
+ debug("Automatically created channel with id ".concat(req.query['channel']));
876
+ _a.label = 2;
845
877
  case 2:
846
- options.adCopyMgrUri = this.adCopyMgrUri;
847
- options.adXchangeUri = this.adXchangeUri;
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 (this.slateRepetitions) {
866
- options.slateRepetitions = this.slateRepetitions;
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*/, 9];
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 = 5;
892
- case 5:
893
- _a.trys.push([5, 7, , 8]);
896
+ _a.label = 3;
897
+ case 3:
898
+ _a.trys.push([3, 5, , 6]);
894
899
  return [4 /*yield*/, session.getMasterManifestAsync(filter)];
895
- case 6:
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*/, 8];
908
- case 7:
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*/, 8];
912
- case 8: return [3 /*break*/, 10];
913
- case 9:
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 = 10;
916
- case 10: return [2 /*return*/];
920
+ _a.label = 8;
921
+ case 8: return [2 /*return*/];
917
922
  }
918
923
  });
919
924
  });
@@ -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
  }