eyevinn-channel-engine 5.1.2 → 5.2.0
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/.github/workflows/nodejs.yml +1 -1
- package/.github/workflows/publish.yml +1 -1
- package/.github/workflows/rc.yml +1 -1
- package/CONTRIBUTING.md +40 -0
- package/Dockerfile +1 -1
- package/README.md +70 -8
- package/dist/engine/chaos_monkey.d.ts +1 -1
- package/dist/engine/chaos_monkey.js +1 -0
- package/dist/engine/event_stream.d.ts +1 -6
- package/dist/engine/event_stream.js +2 -0
- package/dist/engine/memcached_state_store.d.ts +1 -13
- package/dist/engine/memcached_state_store.js +4 -0
- package/dist/engine/memory_state_store.d.ts +1 -13
- package/dist/engine/memory_state_store.js +5 -0
- package/dist/engine/playhead_state.d.ts +0 -26
- package/dist/engine/playhead_state.js +9 -0
- package/dist/engine/preflight.d.ts +1 -1
- package/dist/engine/preflight.js +1 -0
- package/dist/engine/redis_state_store.d.ts +1 -19
- package/dist/engine/redis_state_store.js +5 -0
- package/dist/engine/server.d.ts +27 -0
- package/dist/engine/server.js +140 -6
- package/dist/engine/session.d.ts +1 -148
- package/dist/engine/session.js +398 -11
- package/dist/engine/session_live.d.ts +1 -181
- package/dist/engine/session_live.js +19 -4
- package/dist/engine/session_live_state.d.ts +0 -23
- package/dist/engine/session_live_state.js +5 -0
- package/dist/engine/session_state.d.ts +0 -45
- package/dist/engine/session_state.js +10 -0
- package/dist/engine/shared_state_store.d.ts +1 -25
- package/dist/engine/shared_state_store.js +10 -0
- package/dist/engine/state_store_types.d.ts +32 -0
- package/dist/engine/state_store_types.js +5 -0
- package/dist/engine/stream_switcher.d.ts +1 -40
- package/dist/engine/stream_switcher.js +108 -20
- package/dist/engine/subtitle_slicer.d.ts +1 -8
- package/dist/engine/subtitle_slicer.js +1 -0
- package/dist/engine/util.d.ts +1 -29
- package/dist/engine/util.js +2 -1
- package/dist/examples/adbreak.d.ts +1 -0
- package/dist/examples/adbreak.js +104 -0
- package/dist/index.d.ts +1 -1
- package/dist/package.json +20 -4
- package/docs/design/mixing-muxed-demuxed-audio.md +153 -0
- package/docs/design/subtitles-live-mix-demux.md +135 -0
- package/docs/reference.md +67 -0
- package/engine/chaos_monkey.ts +17 -0
- package/engine/{event_stream.js → event_stream.ts} +5 -3
- package/engine/{memcached_state_store.js → memcached_state_store.ts} +19 -12
- package/engine/memory_state_store.ts +71 -0
- package/engine/{playhead_state.js → playhead_state.ts} +92 -82
- package/engine/{preflight.js → preflight.ts} +1 -1
- package/engine/{redis_state_store.js → redis_state_store.ts} +216 -208
- package/engine/server.ts +210 -8
- package/engine/{session.js → session.ts} +421 -22
- package/engine/{session_live.js → session_live.ts} +54 -31
- package/engine/{session_live_state.js → session_live_state.ts} +129 -120
- package/engine/{session_state.js → session_state.ts} +269 -248
- package/engine/{shared_state_store.js → shared_state_store.ts} +31 -19
- package/engine/state_store_types.ts +35 -0
- package/engine/{stream_switcher.js → stream_switcher.ts} +133 -34
- package/engine/{subtitle_slicer.js → subtitle_slicer.ts} +10 -8
- package/engine/{util.js → util.ts} +28 -24
- package/examples/adbreak.ts +115 -0
- package/index.ts +2 -0
- package/package.json +20 -4
- package/spec/engine/custom_vod_request_params_spec.ts +99 -0
- package/spec/engine/drm_spec.ts +128 -0
- package/spec/engine/{engine_spec.js → engine_spec.ts} +44 -1
- package/spec/engine/{ha_spec.js → ha_spec.ts} +7 -4
- package/spec/engine/{init_switching_spec.js → init_switching_spec.ts} +10 -6
- package/spec/engine/{interface_spec.js → interface_spec.ts} +16 -4
- package/spec/engine/{playhead_live_spec.js → playhead_live_spec.ts} +2 -1
- package/spec/engine/{playhead_spec.js → playhead_spec.ts} +15 -8
- package/spec/engine/session_spec.ts +800 -0
- package/spec/engine/stream_switcher_audio_reconcile_spec.ts +158 -0
- package/spec/engine/{stream_switcher_spec.js → stream_switcher_spec.ts} +111 -13
- package/spec/engine/subtitle_missing_language_spec.ts +196 -0
- package/spec/engine/{subtitle_spec.js → subtitle_spec.ts} +28 -27
- package/spec/helpers/ts-resolve.js +65 -0
- package/spec/support/jasmine.json +1 -1
- package/spec/testvectors/hls_subs_no_language/config.subtitleTracks.json +12 -0
- package/spec/testvectors/hls_subs_no_language/evidence_dummy_segments_name_mismatch.m3u8 +24 -0
- package/spec/testvectors/hls_subs_no_language/evidence_real_cues_name_match.m3u8 +24 -0
- package/spec/testvectors/hls_subs_no_language/french.m3u8 +9 -0
- package/spec/testvectors/hls_subs_no_language/master.m3u8 +11 -0
- package/spec/testvectors/hls_subs_no_language/video.m3u8 +25 -0
- package/spec/testvectors/slate/master.m3u8 +3 -0
- package/spec/testvectors/slate/media.m3u8 +9 -0
- package/tsconfig.json +21 -4
- package/tsconfig.spec.json +16 -0
- package/engine/chaos_monkey.js +0 -17
- package/engine/memory_state_store.js +0 -63
- package/spec/engine/session_spec.js +0 -116
- /package/spec/engine/{session_live_spec.js → session_live_spec.ts} +0 -0
- /package/spec/engine/{util_spec.js → util_spec.ts} +0 -0
|
@@ -1,181 +1 @@
|
|
|
1
|
-
export
|
|
2
|
-
/**
|
|
3
|
-
* When we implement subtitle support in live-mix we should place it in its own file/or share it with audio
|
|
4
|
-
* we should also remove audio implementation when we implement subtitles from this file so we don't get at 4000 line long file.
|
|
5
|
-
*/
|
|
6
|
-
declare class SessionLive {
|
|
7
|
-
constructor(config: any, sessionLiveStore: any);
|
|
8
|
-
sessionId: any;
|
|
9
|
-
sessionLiveStateStore: any;
|
|
10
|
-
instanceId: any;
|
|
11
|
-
mediaSeqCountVideo: number;
|
|
12
|
-
mediaSeqCountAudio: number;
|
|
13
|
-
prevMediaSeqCountVideo: number;
|
|
14
|
-
prevMediaSeqCountAudio: number;
|
|
15
|
-
discSeqCountVideo: number;
|
|
16
|
-
discSeqCountAudio: number;
|
|
17
|
-
prevDiscSeqCountVideo: number;
|
|
18
|
-
prevDiscSeqCountAudio: number;
|
|
19
|
-
targetDuration: number;
|
|
20
|
-
masterManifestUri: string;
|
|
21
|
-
vodSegments: {};
|
|
22
|
-
vodSegmentsAudio: {};
|
|
23
|
-
mediaManifestURIs: {};
|
|
24
|
-
audioManifestURIs: {};
|
|
25
|
-
liveSegQueue: {};
|
|
26
|
-
lastRequestedMediaSeqRawVideo: any;
|
|
27
|
-
prevSeqBottomVideoSegUri: any;
|
|
28
|
-
prevSeqBottomAudioSegUri: any;
|
|
29
|
-
liveSourceM3Us: {};
|
|
30
|
-
liveSegQueueAudio: {};
|
|
31
|
-
lastRequestedMediaSeqRawAudio: any;
|
|
32
|
-
liveAudioSourceM3Us: {};
|
|
33
|
-
playheadState: 4;
|
|
34
|
-
liveSegsForFollowers: {};
|
|
35
|
-
liveSegsForFollowersAudio: {};
|
|
36
|
-
timerCompensation: boolean;
|
|
37
|
-
firstTime: boolean;
|
|
38
|
-
firstTimeAudio: boolean;
|
|
39
|
-
allowedToSet: boolean;
|
|
40
|
-
pushAmount: number;
|
|
41
|
-
restAmount: number;
|
|
42
|
-
pushAmountAudio: number;
|
|
43
|
-
restAmountAudio: number;
|
|
44
|
-
waitForPlayhead: boolean;
|
|
45
|
-
blockGenerateManifest: boolean;
|
|
46
|
-
timeOffsetVideo: number;
|
|
47
|
-
timeOffsetAudio: number;
|
|
48
|
-
v2lHasTimelinePosition: boolean;
|
|
49
|
-
useDemuxedAudio: boolean;
|
|
50
|
-
cloudWatchLogging: boolean;
|
|
51
|
-
sessionLiveProfile: any;
|
|
52
|
-
sessionAudioTracks: any;
|
|
53
|
-
initAsync(): Promise<void>;
|
|
54
|
-
sessionLiveState: any;
|
|
55
|
-
/**
|
|
56
|
-
*
|
|
57
|
-
* @param {number} resetDelay The amount of time to wait before resetting the session.
|
|
58
|
-
*
|
|
59
|
-
*/
|
|
60
|
-
resetLiveStoreAsync(resetDelay: number): Promise<void>;
|
|
61
|
-
resetSession(): Promise<void>;
|
|
62
|
-
startPlayheadAsync(): Promise<void>;
|
|
63
|
-
restartPlayheadAsync(): Promise<void>;
|
|
64
|
-
stopPlayheadAsync(): Promise<void>;
|
|
65
|
-
/**
|
|
66
|
-
* This function sets the master manifest URI in sessionLive.
|
|
67
|
-
* @param {string} masterManifestUri The master manifest URI.
|
|
68
|
-
* @returns a boolean indicating whether the master manifest URI is reachable or not.
|
|
69
|
-
*/
|
|
70
|
-
setLiveUri(masterManifestUri: string): Promise<boolean>;
|
|
71
|
-
setCurrentMediaSequenceSegments(segments: any): Promise<boolean>;
|
|
72
|
-
setCurrentAudioSequenceSegments(segments: any): Promise<boolean>;
|
|
73
|
-
setCurrentMediaAndDiscSequenceCount(mediaSeq: any, discSeq: any, audioMediaSeq: any, audioDiscSeq: any): Promise<boolean>;
|
|
74
|
-
getTransitionalSegments(): Promise<{}>;
|
|
75
|
-
getTransitionalAudioSegments(): Promise<{}>;
|
|
76
|
-
getCurrentMediaSequenceSegments(): Promise<{
|
|
77
|
-
currMseqSegs: {};
|
|
78
|
-
segCount: number;
|
|
79
|
-
}>;
|
|
80
|
-
getCurrentAudioSequenceSegments(): Promise<{
|
|
81
|
-
currMseqSegs: {};
|
|
82
|
-
segCount: number;
|
|
83
|
-
}>;
|
|
84
|
-
getCurrentMediaAndDiscSequenceCount(): Promise<{
|
|
85
|
-
mediaSeq: number;
|
|
86
|
-
discSeq: number;
|
|
87
|
-
}>;
|
|
88
|
-
getStatus(): {
|
|
89
|
-
sessionId: any;
|
|
90
|
-
playhead: {
|
|
91
|
-
state: any;
|
|
92
|
-
};
|
|
93
|
-
};
|
|
94
|
-
getCurrentMediaManifestAsync(bw: any): Promise<string>;
|
|
95
|
-
getCurrentAudioManifestAsync(audioGroupId: any, audioLanguage: any): Promise<string>;
|
|
96
|
-
getCurrentSubtitleManifestAsync(subtitleGroupId: any, subtitleLanguage: any): Promise<string>;
|
|
97
|
-
/**
|
|
98
|
-
*
|
|
99
|
-
* @param {string} masterManifestURI The master manifest URI.
|
|
100
|
-
* @returns Loads the URIs to the different media playlists from the given master playlist.
|
|
101
|
-
*
|
|
102
|
-
*/
|
|
103
|
-
_loadMasterManifest(masterManifestURI: string): Promise<any>;
|
|
104
|
-
_updateLiveSegQueue(): Promise<never>;
|
|
105
|
-
_updateLiveSegQueueAudio(): Promise<never>;
|
|
106
|
-
_collectSegmentsFromStore(): Promise<never>;
|
|
107
|
-
_fetchFromLiveSource(): Promise<{
|
|
108
|
-
success: boolean;
|
|
109
|
-
currentMseqRaw: any;
|
|
110
|
-
}>;
|
|
111
|
-
_parseFromLiveSource(current_mediasequence_raw: any): Promise<never>;
|
|
112
|
-
/**
|
|
113
|
-
* This function adds new live segments to the node from which it can
|
|
114
|
-
* generate new manifests from. Method for attaining new segments differ
|
|
115
|
-
* depending on node Rank. The Leader collects from live source and
|
|
116
|
-
* Followers collect from shared storage.
|
|
117
|
-
*/
|
|
118
|
-
_loadAllPlaylistManifests(): Promise<void>;
|
|
119
|
-
_shiftSegments(opt: any): {
|
|
120
|
-
totalDuration: number;
|
|
121
|
-
removedSegments: number;
|
|
122
|
-
removedDiscontinuities: number;
|
|
123
|
-
shiftedSegments: {};
|
|
124
|
-
};
|
|
125
|
-
_shiftVariantSegments(variantKeys: any, _name: any, _segments: any): {
|
|
126
|
-
timeToRemove: number;
|
|
127
|
-
incrementDiscSeqCount: boolean;
|
|
128
|
-
segments: any;
|
|
129
|
-
};
|
|
130
|
-
/**
|
|
131
|
-
* Shifts V2L or LIVE items if total segment duration (V2L+LIVE) are over the target duration.
|
|
132
|
-
* It will also update and increment SessionLive's mediaSeqCountVideo and DiscSeqCount based
|
|
133
|
-
* on what was shifted.
|
|
134
|
-
* @param {string} instanceName Name of instance "LEADER" | "FOLLOWER"
|
|
135
|
-
* @returns {number} The new total duration in seconds
|
|
136
|
-
*/
|
|
137
|
-
_incrementAndShift(instanceName: string): number;
|
|
138
|
-
_incrementAndShiftAudio(instanceName: any): number;
|
|
139
|
-
_loadMediaManifest(bw: any): Promise<any>;
|
|
140
|
-
_loadAudioManifest(audiotrack: any): Promise<any>;
|
|
141
|
-
_pushAmountBasedOnPreviousLastSegmentURI(m3u: any, isFirstTrack: any): number;
|
|
142
|
-
_parseMediaManifest(m3u: any, mediaManifestUri: any, liveTargetBandwidth: any, isFirstBW: any, isLeader: any): Promise<any>;
|
|
143
|
-
_parseAudioManifest(m3u: any, audioPlaylistUri: any, liveTargetAudiotrack: any, isFirstAT: any, isLeader: any): Promise<any>;
|
|
144
|
-
/**
|
|
145
|
-
* Collects 'new' PlaylistItems and converts them into custom SegmentItems,
|
|
146
|
-
* then Pushes them to the LiveSegQueue for all variants.
|
|
147
|
-
* @param {number} startIdx
|
|
148
|
-
* @param {m3u8.Item.PlaylistItem} playlistItems
|
|
149
|
-
* @param {string} baseUrl
|
|
150
|
-
* @param {string} liveTargetBandwidth
|
|
151
|
-
*/
|
|
152
|
-
_addLiveSegmentsToQueue(isFirst: any, startIdx: number, playlistItems: m3u8.Item.PlaylistItem, baseUrl: string, liveTargetVariant: any, isLeader: any, plType: any): Promise<never>;
|
|
153
|
-
_pushToQueue(seg: any, liveTargetBandwidth: any, logName: any): void;
|
|
154
|
-
_pushToQueueAudio(seg: any, liveTargetAudiotrack: any, logName: any): void;
|
|
155
|
-
_GenerateLiveManifest(bw: any): Promise<string>;
|
|
156
|
-
_GenerateLiveAudioManifest(audioGroupId: any, audioLanguage: any): Promise<string>;
|
|
157
|
-
_setVariantManifestSegmentTags(segments: any, m3u8: any, variantKey: any): any;
|
|
158
|
-
_findNearestBw(bw: any, array: any): any;
|
|
159
|
-
_getNearestBandwidth(bandwidthToMatch: any, array: any): any;
|
|
160
|
-
_getFirstBwWithSegmentsInList(allSegments: any): string;
|
|
161
|
-
_findAudioGroupsForLang(audioLanguage: any, segments: any): {
|
|
162
|
-
audioGroupId: string;
|
|
163
|
-
audioLanguage: string;
|
|
164
|
-
}[];
|
|
165
|
-
_findNearestAudiotrack(track: any, tracks: any): any;
|
|
166
|
-
_getMaxDuration(segments: any): number;
|
|
167
|
-
_filterLiveProfiles(): void;
|
|
168
|
-
_filterLiveProfilesAudio(): void;
|
|
169
|
-
_filterLiveAudioTracks(): void;
|
|
170
|
-
_getAnyFirstSegmentDurationMs(): number;
|
|
171
|
-
_isEmpty(obj: any): boolean;
|
|
172
|
-
_containsSegment(segments: any, newSegments: any): boolean;
|
|
173
|
-
_getGroupAndLangFromTrack(track: any): {
|
|
174
|
-
groupId: any;
|
|
175
|
-
language: any;
|
|
176
|
-
};
|
|
177
|
-
_getLangFromTrack(track: any): any;
|
|
178
|
-
_getGroupFromTrack(track: any): any;
|
|
179
|
-
_getTrackFromGroupAndLang(g: any, l: any): string;
|
|
180
|
-
_isBandwidth(bw: any): boolean;
|
|
181
|
-
}
|
|
1
|
+
export {};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
2
3
|
const debug = require("debug")("engine-session-live");
|
|
3
4
|
const allSettled = require("promise.allsettled");
|
|
4
5
|
const crypto = require("crypto");
|
|
@@ -226,7 +227,7 @@ class SessionLive {
|
|
|
226
227
|
}
|
|
227
228
|
catch (err) {
|
|
228
229
|
debug(`[${this.sessionId}]: SessionLive-Playhead consumer crashed`);
|
|
229
|
-
console.error(`[${this.sessionId}]: ${err.message}`);
|
|
230
|
+
console.error(`[${this.sessionId}]: ${err instanceof Error ? err.message : err}`);
|
|
230
231
|
debug(err);
|
|
231
232
|
this.playheadState = PlayheadState.CRASHED;
|
|
232
233
|
}
|
|
@@ -873,7 +874,7 @@ class SessionLive {
|
|
|
873
874
|
break;
|
|
874
875
|
}
|
|
875
876
|
const segDur = this._getAnyFirstSegmentDurationMs() || DEFAULT_PLAYHEAD_INTERVAL_MS;
|
|
876
|
-
const waitTimeMs = parseInt(segDur / 3, 10);
|
|
877
|
+
const waitTimeMs = parseInt((segDur / 3), 10);
|
|
877
878
|
debug(`[${this.sessionId}]: FOLLOWER: Leader has not put anything in store... Will check again in ${waitTimeMs}ms (Tries left=[${attempts}])`);
|
|
878
879
|
await timer(waitTimeMs);
|
|
879
880
|
this.timerCompensation = false;
|
|
@@ -895,7 +896,7 @@ class SessionLive {
|
|
|
895
896
|
break;
|
|
896
897
|
}
|
|
897
898
|
const segDur = this._getAnyFirstSegmentDurationMs() || DEFAULT_PLAYHEAD_INTERVAL_MS;
|
|
898
|
-
const waitTimeMs = parseInt(segDur / 3, 10);
|
|
899
|
+
const waitTimeMs = parseInt((segDur / 3), 10);
|
|
899
900
|
debug(`[${this.sessionId}]: FOLLOWER: Leader has not put anything audio in store... Will check again in ${waitTimeMs}ms (Tries left=[${attempts}])`);
|
|
900
901
|
await timer(waitTimeMs);
|
|
901
902
|
this.timerCompensation = false;
|
|
@@ -932,7 +933,7 @@ class SessionLive {
|
|
|
932
933
|
debug(`[${this.sessionId}]: FOLLOWER: _containsSegment=true,V[${leadersMediaSeqRaw}],[${this.lastRequestedMediaSeqRawVideo}]${hasAudio ? `,A[${leadersMediaSeqRawAudio}],[${this.lastRequestedMediaSeqRawAudio}]` : ""}`);
|
|
933
934
|
}
|
|
934
935
|
const segDur = this._getAnyFirstSegmentDurationMs() || DEFAULT_PLAYHEAD_INTERVAL_MS;
|
|
935
|
-
const waitTimeMs = parseInt(segDur / 3, 10);
|
|
936
|
+
const waitTimeMs = parseInt((segDur / 3), 10);
|
|
936
937
|
debug(`[${this.sessionId}]: FOLLOWER: Cannot find anything NEW in store... Will check again in ${waitTimeMs}ms (Tries left=[${attempts}])`);
|
|
937
938
|
await timer(waitTimeMs);
|
|
938
939
|
this.timerCompensation = false;
|
|
@@ -1094,6 +1095,9 @@ class SessionLive {
|
|
|
1094
1095
|
audiotracksToSkipOnRetry = [];
|
|
1095
1096
|
debug(`[${this.sessionId}]: Live Mseq counts=[${allStoredMediaSeqCountsVideo}]`);
|
|
1096
1097
|
// Figure out what variants's are behind.
|
|
1098
|
+
// @ts-ignore -- pre-existing behavior: `HIGHEST_MEDIA_SEQUENCE_COUNT`
|
|
1099
|
+
// is a module-level `const`; this assignment throws at runtime if ever
|
|
1100
|
+
// reached. Preserved byte-for-byte (type-only migration, #374).
|
|
1097
1101
|
HIGHEST_MEDIA_SEQUENCE_COUNT = Math.max(...allStoredMediaSeqCountsVideo);
|
|
1098
1102
|
Object.keys(this.liveSourceM3Us).map((variantKey) => {
|
|
1099
1103
|
if (this.liveSourceM3Us[variantKey].mediaSeq === HIGHEST_MEDIA_SEQUENCE_COUNT) {
|
|
@@ -2184,6 +2188,9 @@ class SessionLive {
|
|
|
2184
2188
|
}
|
|
2185
2189
|
}
|
|
2186
2190
|
if (!segAmounts.every((val, i, arr) => val === arr[0])) {
|
|
2191
|
+
// @ts-ignore -- pre-existing behavior: `console` is called as a function
|
|
2192
|
+
// here (not `console.log`), which throws at runtime if this path is hit.
|
|
2193
|
+
// Preserved byte-for-byte (type-only migration, #374).
|
|
2187
2194
|
console(`[${this.sessionId}]: Cannot Generate audio Manifest! <${this.instanceId}> Not yet collected ALL segments from Live Source...`);
|
|
2188
2195
|
return null;
|
|
2189
2196
|
}
|
|
@@ -2373,6 +2380,8 @@ class SessionLive {
|
|
|
2373
2380
|
let newItemsAudio = {};
|
|
2374
2381
|
audioTracks.forEach((audioTrack) => {
|
|
2375
2382
|
let groupAndLangToKeep = this._findAudioGroupsForLang(audioTrack.language, this.audioManifestURIs);
|
|
2383
|
+
// Cast to a 1-tuple so the (behavior-preserving) spread type-checks against
|
|
2384
|
+
// Set.add's single parameter; runtime is unchanged (extra elements ignored).
|
|
2376
2385
|
toKeep.add(...groupAndLangToKeep);
|
|
2377
2386
|
});
|
|
2378
2387
|
toKeep.forEach((trackInfo) => {
|
|
@@ -2447,6 +2456,8 @@ class SessionLive {
|
|
|
2447
2456
|
return GLItem;
|
|
2448
2457
|
}
|
|
2449
2458
|
}
|
|
2459
|
+
// @ts-ignore -- pre-existing behavior: `g`/`l` are block-scoped to the
|
|
2460
|
+
// `if (match)` block above and are not in scope here. Preserved as-is.
|
|
2450
2461
|
console.error(`Failed to extract GroupID and Language g=${g};l=${l}`);
|
|
2451
2462
|
return GLItem;
|
|
2452
2463
|
}
|
|
@@ -2459,6 +2470,8 @@ class SessionLive {
|
|
|
2459
2470
|
return l;
|
|
2460
2471
|
}
|
|
2461
2472
|
}
|
|
2473
|
+
// @ts-ignore -- pre-existing behavior: `g`/`l` are block-scoped to the
|
|
2474
|
+
// `if (match)` block above and are not in scope here. Preserved as-is.
|
|
2462
2475
|
console.error(`Failed to extract Language g=${g};l=${l}`);
|
|
2463
2476
|
return null;
|
|
2464
2477
|
}
|
|
@@ -2471,6 +2484,8 @@ class SessionLive {
|
|
|
2471
2484
|
return g;
|
|
2472
2485
|
}
|
|
2473
2486
|
}
|
|
2487
|
+
// @ts-ignore -- pre-existing behavior: `g`/`l` are block-scoped to the
|
|
2488
|
+
// `if (match)` block above and are not in scope here. Preserved as-is.
|
|
2474
2489
|
console.error(`Failed to extract Group ID g=${g};l=${l}`);
|
|
2475
2490
|
return null;
|
|
2476
2491
|
}
|
|
@@ -1,24 +1 @@
|
|
|
1
|
-
export class SessionLiveStateStore extends SharedStateStore {
|
|
2
|
-
constructor(opts: any);
|
|
3
|
-
cache: {
|
|
4
|
-
leader: {
|
|
5
|
-
ts: number;
|
|
6
|
-
value: any;
|
|
7
|
-
};
|
|
8
|
-
};
|
|
9
|
-
ping(instanceId: any): Promise<void>;
|
|
10
|
-
setLeader(instanceId: any): Promise<any>;
|
|
11
|
-
isLeader(instanceId: any): Promise<boolean>;
|
|
12
|
-
create(sessionId: any, instanceId: any): Promise<SharedSessionLiveState>;
|
|
13
|
-
}
|
|
14
|
-
import SharedStateStore = require("./shared_state_store.js");
|
|
15
|
-
declare class SharedSessionLiveState {
|
|
16
|
-
constructor(store: any, sessionId: any, instanceId: any, opts: any);
|
|
17
|
-
sessionId: any;
|
|
18
|
-
instanceId: any;
|
|
19
|
-
store: any;
|
|
20
|
-
get(key: any): Promise<any>;
|
|
21
|
-
set(key: any, value: any): Promise<any>;
|
|
22
|
-
remove(key: any): Promise<void>;
|
|
23
|
-
}
|
|
24
1
|
export {};
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
2
3
|
const SharedStateStore = require('./shared_state_store.js');
|
|
3
4
|
const debug = require("debug")("session-live-state-store");
|
|
5
|
+
// Type-only migration (#373): a faithful port of the original JS.
|
|
4
6
|
class SharedSessionLiveState {
|
|
7
|
+
sessionId;
|
|
8
|
+
instanceId;
|
|
9
|
+
store;
|
|
5
10
|
constructor(store, sessionId, instanceId, opts) {
|
|
6
11
|
this.sessionId = sessionId;
|
|
7
12
|
this.instanceId = instanceId;
|
|
@@ -1,46 +1 @@
|
|
|
1
|
-
export const SessionState: Readonly<{
|
|
2
|
-
VOD_INIT: 1;
|
|
3
|
-
VOD_PLAYING: 2;
|
|
4
|
-
VOD_NEXT_INIT: 3;
|
|
5
|
-
VOD_NEXT_INITIATING: 4;
|
|
6
|
-
VOD_RELOAD_INIT: 5;
|
|
7
|
-
VOD_RELOAD_INITIATING: 6;
|
|
8
|
-
}>;
|
|
9
|
-
export class SessionStateStore extends SharedStateStore {
|
|
10
|
-
constructor(opts: any);
|
|
11
|
-
cache: {
|
|
12
|
-
leader: {
|
|
13
|
-
ts: number;
|
|
14
|
-
value: any;
|
|
15
|
-
};
|
|
16
|
-
};
|
|
17
|
-
ping(instanceId: any): Promise<void>;
|
|
18
|
-
clearLeaderCache(): Promise<void>;
|
|
19
|
-
isLeader(instanceId: any): Promise<boolean>;
|
|
20
|
-
create(sessionId: any, instanceId: any): Promise<SharedSessionState>;
|
|
21
|
-
}
|
|
22
|
-
import SharedStateStore = require("./shared_state_store.js");
|
|
23
|
-
declare class SharedSessionState {
|
|
24
|
-
constructor(store: any, sessionId: any, instanceId: any, opts: any);
|
|
25
|
-
sessionId: any;
|
|
26
|
-
instanceId: any;
|
|
27
|
-
cache: {
|
|
28
|
-
currentVod: {
|
|
29
|
-
ts: number;
|
|
30
|
-
ttl: number;
|
|
31
|
-
value: any;
|
|
32
|
-
};
|
|
33
|
-
};
|
|
34
|
-
cacheTTL: any;
|
|
35
|
-
store: any;
|
|
36
|
-
clearCurrentVodCache(): Promise<void>;
|
|
37
|
-
getCurrentVod(): Promise<any>;
|
|
38
|
-
setCurrentVod(hlsVod: any, opts: any): Promise<any>;
|
|
39
|
-
get(key: any): Promise<any>;
|
|
40
|
-
getValues(keys: any): Promise<any>;
|
|
41
|
-
set(key: any, value: any): Promise<any>;
|
|
42
|
-
setValues(keyValues: any): Promise<any>;
|
|
43
|
-
remove(key: any): Promise<void>;
|
|
44
|
-
increment(key: any, inc: any): Promise<any>;
|
|
45
|
-
}
|
|
46
1
|
export {};
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
2
3
|
const HLSVod = require('@eyevinn/hls-vodtolive');
|
|
3
4
|
const SharedStateStore = require('./shared_state_store.js');
|
|
4
5
|
const debug = require("debug")("session-state-store");
|
|
5
6
|
const { timeLeft } = require('./util.js');
|
|
7
|
+
// Type-only migration (#373): a faithful port of the original JS.
|
|
6
8
|
const SessionState = Object.freeze({
|
|
7
9
|
VOD_INIT: 1,
|
|
8
10
|
VOD_PLAYING: 2,
|
|
@@ -13,6 +15,11 @@ const SessionState = Object.freeze({
|
|
|
13
15
|
});
|
|
14
16
|
const CURRENTVOD_CACHE_TTL = 5 * 60 * 1000; // 5 minutes
|
|
15
17
|
class SharedSessionState {
|
|
18
|
+
sessionId;
|
|
19
|
+
instanceId;
|
|
20
|
+
cache;
|
|
21
|
+
cacheTTL;
|
|
22
|
+
store;
|
|
16
23
|
constructor(store, sessionId, instanceId, opts) {
|
|
17
24
|
this.sessionId = sessionId;
|
|
18
25
|
this.instanceId = instanceId;
|
|
@@ -143,6 +150,9 @@ class SharedSessionState {
|
|
|
143
150
|
}
|
|
144
151
|
}
|
|
145
152
|
class SessionStateStore extends SharedStateStore {
|
|
153
|
+
// Referenced (as `undefined`) by clearLeaderCache in the original JS; kept
|
|
154
|
+
// as an optional field to preserve behavior without introducing a value.
|
|
155
|
+
instanceId;
|
|
146
156
|
constructor(opts) {
|
|
147
157
|
super("session", opts, {
|
|
148
158
|
mediaSeq: 0,
|
|
@@ -1,25 +1 @@
|
|
|
1
|
-
export
|
|
2
|
-
declare class SharedStateStore {
|
|
3
|
-
constructor(type: any, opts: any, initData: any);
|
|
4
|
-
initData: any;
|
|
5
|
-
type: any;
|
|
6
|
-
cache: {};
|
|
7
|
-
cacheTTL: any;
|
|
8
|
-
shared: boolean;
|
|
9
|
-
hasPipeline: boolean;
|
|
10
|
-
store: MemcachedStateStore | MemoryStateStore | RedisStateStore;
|
|
11
|
-
isShared(): boolean;
|
|
12
|
-
canPipeline(): boolean;
|
|
13
|
-
init(id: any): Promise<void>;
|
|
14
|
-
reset(id: any): Promise<void>;
|
|
15
|
-
resetAll(): Promise<void>;
|
|
16
|
-
get(id: any, key: any): Promise<any>;
|
|
17
|
-
set(id: any, key: any, value: any): Promise<any>;
|
|
18
|
-
setVolatile(id: any, key: any, value: any): Promise<any>;
|
|
19
|
-
getValues(id: any, keys: any): Promise<{}>;
|
|
20
|
-
setValues(id: any, data: any): Promise<{}>;
|
|
21
|
-
remove(id: any, key: any): Promise<void>;
|
|
22
|
-
}
|
|
23
|
-
import MemcachedStateStore = require("./memcached_state_store.js");
|
|
24
|
-
import MemoryStateStore = require("./memory_state_store.js");
|
|
25
|
-
import RedisStateStore = require("./redis_state_store.js");
|
|
1
|
+
export {};
|
|
@@ -1,9 +1,19 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
2
3
|
const debug = require("debug")("engine-state-store");
|
|
3
4
|
const RedisStateStore = require("./redis_state_store.js");
|
|
4
5
|
const MemcachedStateStore = require("./memcached_state_store.js");
|
|
5
6
|
const MemoryStateStore = require("./memory_state_store.js");
|
|
7
|
+
// Type-only migration (#373): a faithful port of the original JS. The public
|
|
8
|
+
// API (constructor + methods) and runtime behavior are unchanged.
|
|
6
9
|
class SharedStateStore {
|
|
10
|
+
initData;
|
|
11
|
+
type;
|
|
12
|
+
cache;
|
|
13
|
+
cacheTTL;
|
|
14
|
+
shared;
|
|
15
|
+
hasPipeline;
|
|
16
|
+
store;
|
|
7
17
|
constructor(type, opts, initData) {
|
|
8
18
|
this.initData = initData;
|
|
9
19
|
this.type = type;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The low-level key/value store contract implemented by the memory, memcached
|
|
3
|
+
* and redis backends and driven by `SharedStateStore`.
|
|
4
|
+
*/
|
|
5
|
+
export interface IStateStore {
|
|
6
|
+
initAsync(id: string, initData: Record<string, any>): Promise<any>;
|
|
7
|
+
resetAsync(id: string, initData: Record<string, any>): Promise<void>;
|
|
8
|
+
resetAllAsync(): Promise<void>;
|
|
9
|
+
getAsync(id: string, key: string): Promise<any>;
|
|
10
|
+
setAsync(id: string, key: string, value: any): Promise<any>;
|
|
11
|
+
setVolatileAsync(id: string, key: string, value: any): Promise<any>;
|
|
12
|
+
removeAsync(id: string, key: string): Promise<any>;
|
|
13
|
+
getValues?(id: string, keys: string[]): Promise<Record<string, any>>;
|
|
14
|
+
setValues?(id: string, data: Record<string, any>): Promise<Record<string, any>>;
|
|
15
|
+
}
|
|
16
|
+
export type SharedStates = {
|
|
17
|
+
[id: string]: {
|
|
18
|
+
[key: string]: any;
|
|
19
|
+
} | null;
|
|
20
|
+
};
|
|
21
|
+
export interface ISharedStateStoreOpts {
|
|
22
|
+
cacheTTL?: number;
|
|
23
|
+
redisUrl?: string;
|
|
24
|
+
memcachedUrl?: string;
|
|
25
|
+
version?: string;
|
|
26
|
+
volatileKeyTTL?: number;
|
|
27
|
+
[key: string]: any;
|
|
28
|
+
}
|
|
29
|
+
export interface ILeaderCache {
|
|
30
|
+
ts: number;
|
|
31
|
+
value: string | null;
|
|
32
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Shared type definitions for the engine state-store layer (#373).
|
|
3
|
+
// Type-only declarations — no runtime code is emitted for this module beyond
|
|
4
|
+
// an empty object, and nothing here changes runtime behavior.
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -1,40 +1 @@
|
|
|
1
|
-
export
|
|
2
|
-
declare class StreamSwitcher {
|
|
3
|
-
constructor(config: any);
|
|
4
|
-
sessionId: any;
|
|
5
|
-
useDemuxedAudio: boolean;
|
|
6
|
-
cloudWatchLogging: boolean;
|
|
7
|
-
streamTypeLive: boolean;
|
|
8
|
-
streamSwitchManager: any;
|
|
9
|
-
eventId: any;
|
|
10
|
-
working: boolean;
|
|
11
|
-
timeDiff: any;
|
|
12
|
-
abortTimeStamp: number;
|
|
13
|
-
prerollsCache: {};
|
|
14
|
-
getEventId(): any;
|
|
15
|
-
abortLiveFeed(session: any, sessionLive: any, message: any): Promise<boolean>;
|
|
16
|
-
/**
|
|
17
|
-
*
|
|
18
|
-
* @param {Session} session The VOD2Live Session object.
|
|
19
|
-
* @param {SessionLive} sessionLive The Live Session object.
|
|
20
|
-
* @returns A bool, true if streamSwitchManager contains current Live event to be played else false.
|
|
21
|
-
*/
|
|
22
|
-
streamSwitcher(session: Session, sessionLive: SessionLive): Promise<boolean>;
|
|
23
|
-
_initSwitching(state: any, session: any, sessionLive: any, scheduleObj: any): Promise<boolean>;
|
|
24
|
-
_isEmpty(obj: any): boolean;
|
|
25
|
-
_validURI(uri: any): Promise<boolean>;
|
|
26
|
-
_loadPreroll(uri: any): Promise<{
|
|
27
|
-
mediaSegments: {};
|
|
28
|
-
audioSegments: {};
|
|
29
|
-
}>;
|
|
30
|
-
_createCustomSimpleSegmentList(segmentList: any, manifestURI: any): {}[];
|
|
31
|
-
_getGroupAndLangIdxFromIdx(idx: any, audioObject: any): {
|
|
32
|
-
groupId: any;
|
|
33
|
-
lang: any;
|
|
34
|
-
};
|
|
35
|
-
_fetchParseM3u8(uri: any): Promise<any>;
|
|
36
|
-
_mergeSegments(fromSegments: any, toSegments: any, prepend: any): {};
|
|
37
|
-
_mergeAudioSegments(fromSegments: any, toSegments: any, prepend: any): any;
|
|
38
|
-
_insertTimedMetadata(segments: any, timedMetadata: any): void;
|
|
39
|
-
_insertTimedMetadataAudio(segments: any, timedMetadata: any): void;
|
|
40
|
-
}
|
|
1
|
+
export {};
|