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.
Files changed (97) hide show
  1. package/.github/workflows/nodejs.yml +1 -1
  2. package/.github/workflows/publish.yml +1 -1
  3. package/.github/workflows/rc.yml +1 -1
  4. package/CONTRIBUTING.md +40 -0
  5. package/Dockerfile +1 -1
  6. package/README.md +70 -8
  7. package/dist/engine/chaos_monkey.d.ts +1 -1
  8. package/dist/engine/chaos_monkey.js +1 -0
  9. package/dist/engine/event_stream.d.ts +1 -6
  10. package/dist/engine/event_stream.js +2 -0
  11. package/dist/engine/memcached_state_store.d.ts +1 -13
  12. package/dist/engine/memcached_state_store.js +4 -0
  13. package/dist/engine/memory_state_store.d.ts +1 -13
  14. package/dist/engine/memory_state_store.js +5 -0
  15. package/dist/engine/playhead_state.d.ts +0 -26
  16. package/dist/engine/playhead_state.js +9 -0
  17. package/dist/engine/preflight.d.ts +1 -1
  18. package/dist/engine/preflight.js +1 -0
  19. package/dist/engine/redis_state_store.d.ts +1 -19
  20. package/dist/engine/redis_state_store.js +5 -0
  21. package/dist/engine/server.d.ts +27 -0
  22. package/dist/engine/server.js +140 -6
  23. package/dist/engine/session.d.ts +1 -148
  24. package/dist/engine/session.js +398 -11
  25. package/dist/engine/session_live.d.ts +1 -181
  26. package/dist/engine/session_live.js +19 -4
  27. package/dist/engine/session_live_state.d.ts +0 -23
  28. package/dist/engine/session_live_state.js +5 -0
  29. package/dist/engine/session_state.d.ts +0 -45
  30. package/dist/engine/session_state.js +10 -0
  31. package/dist/engine/shared_state_store.d.ts +1 -25
  32. package/dist/engine/shared_state_store.js +10 -0
  33. package/dist/engine/state_store_types.d.ts +32 -0
  34. package/dist/engine/state_store_types.js +5 -0
  35. package/dist/engine/stream_switcher.d.ts +1 -40
  36. package/dist/engine/stream_switcher.js +108 -20
  37. package/dist/engine/subtitle_slicer.d.ts +1 -8
  38. package/dist/engine/subtitle_slicer.js +1 -0
  39. package/dist/engine/util.d.ts +1 -29
  40. package/dist/engine/util.js +2 -1
  41. package/dist/examples/adbreak.d.ts +1 -0
  42. package/dist/examples/adbreak.js +104 -0
  43. package/dist/index.d.ts +1 -1
  44. package/dist/package.json +20 -4
  45. package/docs/design/mixing-muxed-demuxed-audio.md +153 -0
  46. package/docs/design/subtitles-live-mix-demux.md +135 -0
  47. package/docs/reference.md +67 -0
  48. package/engine/chaos_monkey.ts +17 -0
  49. package/engine/{event_stream.js → event_stream.ts} +5 -3
  50. package/engine/{memcached_state_store.js → memcached_state_store.ts} +19 -12
  51. package/engine/memory_state_store.ts +71 -0
  52. package/engine/{playhead_state.js → playhead_state.ts} +92 -82
  53. package/engine/{preflight.js → preflight.ts} +1 -1
  54. package/engine/{redis_state_store.js → redis_state_store.ts} +216 -208
  55. package/engine/server.ts +210 -8
  56. package/engine/{session.js → session.ts} +421 -22
  57. package/engine/{session_live.js → session_live.ts} +54 -31
  58. package/engine/{session_live_state.js → session_live_state.ts} +129 -120
  59. package/engine/{session_state.js → session_state.ts} +269 -248
  60. package/engine/{shared_state_store.js → shared_state_store.ts} +31 -19
  61. package/engine/state_store_types.ts +35 -0
  62. package/engine/{stream_switcher.js → stream_switcher.ts} +133 -34
  63. package/engine/{subtitle_slicer.js → subtitle_slicer.ts} +10 -8
  64. package/engine/{util.js → util.ts} +28 -24
  65. package/examples/adbreak.ts +115 -0
  66. package/index.ts +2 -0
  67. package/package.json +20 -4
  68. package/spec/engine/custom_vod_request_params_spec.ts +99 -0
  69. package/spec/engine/drm_spec.ts +128 -0
  70. package/spec/engine/{engine_spec.js → engine_spec.ts} +44 -1
  71. package/spec/engine/{ha_spec.js → ha_spec.ts} +7 -4
  72. package/spec/engine/{init_switching_spec.js → init_switching_spec.ts} +10 -6
  73. package/spec/engine/{interface_spec.js → interface_spec.ts} +16 -4
  74. package/spec/engine/{playhead_live_spec.js → playhead_live_spec.ts} +2 -1
  75. package/spec/engine/{playhead_spec.js → playhead_spec.ts} +15 -8
  76. package/spec/engine/session_spec.ts +800 -0
  77. package/spec/engine/stream_switcher_audio_reconcile_spec.ts +158 -0
  78. package/spec/engine/{stream_switcher_spec.js → stream_switcher_spec.ts} +111 -13
  79. package/spec/engine/subtitle_missing_language_spec.ts +196 -0
  80. package/spec/engine/{subtitle_spec.js → subtitle_spec.ts} +28 -27
  81. package/spec/helpers/ts-resolve.js +65 -0
  82. package/spec/support/jasmine.json +1 -1
  83. package/spec/testvectors/hls_subs_no_language/config.subtitleTracks.json +12 -0
  84. package/spec/testvectors/hls_subs_no_language/evidence_dummy_segments_name_mismatch.m3u8 +24 -0
  85. package/spec/testvectors/hls_subs_no_language/evidence_real_cues_name_match.m3u8 +24 -0
  86. package/spec/testvectors/hls_subs_no_language/french.m3u8 +9 -0
  87. package/spec/testvectors/hls_subs_no_language/master.m3u8 +11 -0
  88. package/spec/testvectors/hls_subs_no_language/video.m3u8 +25 -0
  89. package/spec/testvectors/slate/master.m3u8 +3 -0
  90. package/spec/testvectors/slate/media.m3u8 +9 -0
  91. package/tsconfig.json +21 -4
  92. package/tsconfig.spec.json +16 -0
  93. package/engine/chaos_monkey.js +0 -17
  94. package/engine/memory_state_store.js +0 -63
  95. package/spec/engine/session_spec.js +0 -116
  96. /package/spec/engine/{session_live_spec.js → session_live_spec.ts} +0 -0
  97. /package/spec/engine/{util_spec.js → util_spec.ts} +0 -0
@@ -43,6 +43,7 @@ class ChannelEngine {
43
43
  alwaysMapBandwidthByNearest;
44
44
  defaultSlateUri;
45
45
  slateDuration;
46
+ adBreak;
46
47
  assetMgr;
47
48
  streamSwitchManager;
48
49
  slateRepetitions;
@@ -51,6 +52,8 @@ class ChannelEngine {
51
52
  serverStartTime;
52
53
  instanceId;
53
54
  streamSwitchTimeIntervalMs;
55
+ streamSwitchOngoingEventIntervalMs;
56
+ streamSwitchNearEndEventIntervalMs;
54
57
  sessionStore;
55
58
  sessionLiveStore;
56
59
  streamerOpts;
@@ -61,6 +64,49 @@ class ChannelEngine {
61
64
  sessionResetKey = "";
62
65
  sessionEventStream = false;
63
66
  sessionHealthKey = "";
67
+ // Allowlist of query-parameter names permitted to be forwarded to
68
+ // getNextVod() (issue #377). Config surface only — defaults to an empty list
69
+ // (no pass-through) when the option is omitted. Consumed in follow-ups
70
+ // (#378/#379/#380).
71
+ customVodRequestParams = [];
72
+ // Validate and normalize an ad-break configuration (issue #367).
73
+ // Returns a config that is always defined and disabled-by-default:
74
+ // - undefined/omitted -> { enabled: false }
75
+ // - { enabled: false, ... } -> { enabled: false } (endpoint ignored)
76
+ // - { enabled: true, adServerUri } -> validated, with the slate reference
77
+ // (if any) carried through
78
+ // Throws when an enabled break is missing a syntactically valid absolute
79
+ // http(s) ad-serving endpoint URL. `scope` is only used for error context.
80
+ static normalizeAdBreak(adBreak, scope) {
81
+ if (!adBreak || !adBreak.enabled) {
82
+ return { enabled: false };
83
+ }
84
+ if (!adBreak.adServerUri) {
85
+ throw new Error(`Ad-break configuration (${scope}) is enabled but no adServerUri was provided`);
86
+ }
87
+ let parsed;
88
+ try {
89
+ parsed = new URL(adBreak.adServerUri);
90
+ }
91
+ catch (err) {
92
+ throw new Error(`Ad-break configuration (${scope}) has an invalid adServerUri: ${adBreak.adServerUri}`);
93
+ }
94
+ if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
95
+ throw new Error(`Ad-break configuration (${scope}) adServerUri must be an http(s) URL: ${adBreak.adServerUri}`);
96
+ }
97
+ const normalized = {
98
+ enabled: true,
99
+ adServerUri: adBreak.adServerUri
100
+ };
101
+ if (adBreak.slate && adBreak.slate.uri) {
102
+ normalized.slate = {
103
+ uri: adBreak.slate.uri,
104
+ repetitions: adBreak.slate.repetitions || 10,
105
+ duration: adBreak.slate.duration || 4000
106
+ };
107
+ }
108
+ return normalized;
109
+ }
64
110
  constructor(assetMgr, options) {
65
111
  this.options = options;
66
112
  if (options && options.adCopyMgrUri) {
@@ -101,12 +147,23 @@ class ChannelEngine {
101
147
  this.slateRepetitions = options.slateRepetitions || 10;
102
148
  this.slateDuration = options.slateDuration || 4000;
103
149
  }
150
+ // Ad-break config surface (issue #367). Validate and normalize the
151
+ // engine-level default; disabled when unset. Throws on an enabled break
152
+ // that lacks a valid ad-serving endpoint URL.
153
+ this.adBreak = ChannelEngine.normalizeAdBreak(options && options.adBreak, "engine");
104
154
  if (options && options.streamSwitchManager) {
105
155
  this.streamSwitchManager = options.streamSwitchManager;
106
156
  }
107
157
  if (options && options.autoCreateSession !== undefined) {
108
158
  this.autoCreateSession = options.autoCreateSession;
109
159
  }
160
+ // Custom VOD request-parameter allowlist (issue #377). Config surface only —
161
+ // stored on the instance so follow-ups (#378/#379/#380) can consume it.
162
+ // Defaults to an empty list (no pass-through) when omitted.
163
+ this.customVodRequestParams =
164
+ options && Array.isArray(options.customVodRequestParams)
165
+ ? options.customVodRequestParams
166
+ : [];
110
167
  this.assetMgr = assetMgr;
111
168
  this.monitorTimer = {};
112
169
  this.server = fastify;
@@ -117,7 +174,27 @@ class ChannelEngine {
117
174
  this.server.options('*', preflight.handler);
118
175
  this.serverStartTime = Date.now();
119
176
  this.instanceId = uuidv4();
120
- this.streamSwitchTimeIntervalMs = 3000;
177
+ // Base stream-switch polling interval (ms). Configurable via options,
178
+ // defaults to the previously-hardcoded 3000ms. See ChannelEngineOpts.
179
+ this.streamSwitchTimeIntervalMs =
180
+ options && options.streamSwitchTimeIntervalMs !== undefined
181
+ ? options.streamSwitchTimeIntervalMs
182
+ : 3000;
183
+ // Polling interval (ms) while an event is ongoing. See "ongoing event"
184
+ // definition in ChannelEngineOpts. Defaults to the base interval (3000ms).
185
+ // Config surface only for now — not yet applied to the loop cadence (#366).
186
+ this.streamSwitchOngoingEventIntervalMs =
187
+ options && options.streamSwitchOngoingEventIntervalMs !== undefined
188
+ ? options.streamSwitchOngoingEventIntervalMs
189
+ : 3000;
190
+ // Polling interval (ms) when an event is near its end. See "near end of
191
+ // event" definition in ChannelEngineOpts, derived from the 10000ms
192
+ // end-of-event guard in stream_switcher.js. Defaults to a faster 1000ms.
193
+ // Config surface only for now — not yet applied to the loop cadence (#366).
194
+ this.streamSwitchNearEndEventIntervalMs =
195
+ options && options.streamSwitchNearEndEventIntervalMs !== undefined
196
+ ? options.streamSwitchNearEndEventIntervalMs
197
+ : 1000;
121
198
  this.sessionStore = {
122
199
  sessionStateStore: new SessionStateStore({
123
200
  redisUrl: options.redisUrl,
@@ -255,10 +332,15 @@ class ChannelEngine {
255
332
  const ts_1 = Date.now();
256
333
  await this.updateStreamSwitchAsync();
257
334
  const ts_2 = Date.now();
258
- const interval = (timeIntervalMs - (ts_2 - ts_1)) < 0 ? minIntervalMs : (timeIntervalMs - (ts_2 - ts_1));
335
+ // Adaptive cadence: back off while all active channels are mid-event and
336
+ // speed up as any channel nears its end. The poll loop is global but event
337
+ // state is per-channel, so we take the MINIMUM interval required across all
338
+ // channels — never under-polling a channel that needs responsiveness.
339
+ const desiredIntervalMs = this.computeStreamSwitchIntervalMs(timeIntervalMs);
340
+ const interval = (desiredIntervalMs - (ts_2 - ts_1)) < 0 ? minIntervalMs : (desiredIntervalMs - (ts_2 - ts_1));
259
341
  const tickInterval = await WTG.getWaitTime(interval);
260
342
  await timer(tickInterval);
261
- debug(`StreamSwitchLoop waited for all channels. Next tick in: ${tickInterval}ms`);
343
+ debug(`StreamSwitchLoop waited for all channels. Next tick in: ${tickInterval}ms (desired base=${desiredIntervalMs}ms)`);
262
344
  }
263
345
  catch (err) {
264
346
  console.error(err);
@@ -271,6 +353,42 @@ class ChannelEngine {
271
353
  StreamSwitchLoop(this.streamSwitchTimeIntervalMs);
272
354
  }
273
355
  }
356
+ // Compute the desired next poll interval for the global StreamSwitchLoop from the
357
+ // aggregated per-channel event state. Because the loop is global but event state is
358
+ // per-channel, the result is the MINIMUM interval any channel requires so we never
359
+ // under-poll a channel that needs responsiveness:
360
+ // - a channel that is near-end contributes the fast near-end interval;
361
+ // - a channel that is mid-event but not near-end contributes the slower ongoing
362
+ // interval;
363
+ // - a channel with no ongoing event contributes the base interval.
364
+ // The loop uses the minimum across all channels. When no channel reports an ongoing
365
+ // event (no schedule / no ongoing event) this falls back to the base interval,
366
+ // keeping behavior identical to today.
367
+ computeStreamSwitchIntervalMs(baseIntervalMs) {
368
+ const channels = Object.keys(sessionSwitchers);
369
+ let desiredMs = baseIntervalMs;
370
+ for (const channel of channels) {
371
+ const switcher = sessionSwitchers[channel];
372
+ if (!switcher || typeof switcher.getEventPollingState !== "function") {
373
+ continue;
374
+ }
375
+ const state = switcher.getEventPollingState();
376
+ let channelMs;
377
+ if (state.nearEnd) {
378
+ channelMs = this.streamSwitchNearEndEventIntervalMs;
379
+ }
380
+ else if (state.midEvent) {
381
+ channelMs = this.streamSwitchOngoingEventIntervalMs;
382
+ }
383
+ else {
384
+ channelMs = baseIntervalMs;
385
+ }
386
+ if (channelMs < desiredMs) {
387
+ desiredMs = channelMs;
388
+ }
389
+ }
390
+ return desiredMs;
391
+ }
274
392
  async updateStreamSwitchAsync() {
275
393
  const channels = Object.keys(sessionSwitchers);
276
394
  const getSwitchStatusAndPerformSwitch = async (channel) => {
@@ -289,7 +407,7 @@ class ChannelEngine {
289
407
  switcherStatus[channel] = status;
290
408
  }
291
409
  catch (err) {
292
- throw new Error(err);
410
+ throw err instanceof Error ? err : new Error(String(err));
293
411
  }
294
412
  }
295
413
  else {
@@ -301,7 +419,7 @@ class ChannelEngine {
301
419
  }
302
420
  catch (err) {
303
421
  debug('Problem occured when updating streamSwitchers');
304
- throw new Error(err);
422
+ throw err instanceof Error ? err : new Error(String(err));
305
423
  }
306
424
  }
307
425
  async updateChannelsAsync(channelMgr, options) {
@@ -333,9 +451,11 @@ class ChannelEngine {
333
451
  slateUri: channel.slate && channel.slate.uri ? channel.slate.uri : this.defaultSlateUri,
334
452
  slateRepetitions: channel.slate && channel.slate.repetitions ? channel.slate.repetitions : this.slateRepetitions,
335
453
  slateDuration: channel.slate && channel.slate.duration ? channel.slate.duration : this.slateDuration,
454
+ adBreak: channel.adBreak ? ChannelEngine.normalizeAdBreak(channel.adBreak, `channel ${channel.id}`) : this.adBreak,
336
455
  cloudWatchMetrics: this.logCloudWatchMetrics,
337
456
  sessionEventStream: options.sessionEventStream,
338
- rollingPDT: options.rollingPDT
457
+ rollingPDT: options.rollingPDT,
458
+ event: options.event
339
459
  }, this.sessionStore);
340
460
  sessionsLive[channel.id] = new SessionLive({
341
461
  sessionId: channel.id,
@@ -572,6 +692,20 @@ class ChannelEngine {
572
692
  if (session) {
573
693
  const eventStream = new EventStream(session);
574
694
  eventStreams[session.sessionId] = eventStream;
695
+ // Plumb allowlisted master.m3u8 query params into the session so the next
696
+ // _getNextVod() call includes them (#379). Sessions are persistent (created
697
+ // once in updateChannelsAsync and reused), so scope custom params per request:
698
+ // set them on every master-manifest request — using an empty object when the
699
+ // allowlist is unset or no allowlisted params are present — so a later request
700
+ // without them doesn't inherit a previous request's values. Non-allowlisted
701
+ // params are ignored.
702
+ const customParams = {};
703
+ for (const key of this.customVodRequestParams) {
704
+ if (request.query[key] !== undefined) {
705
+ customParams[key] = request.query[key];
706
+ }
707
+ }
708
+ session.setCustomParams(customParams);
575
709
  let filter;
576
710
  if (request.query['filter']) {
577
711
  debug(`Applying filter on master manifest ${request.query['filter']}`);
@@ -1,148 +1 @@
1
- export = Session;
2
- declare class Session {
3
- /**
4
- *
5
- * config: {
6
- * startWithId,
7
- * }
8
- *
9
- */
10
- constructor(assetManager: any, config: any, sessionStore: any);
11
- _assetManager: any;
12
- _sessionId: any;
13
- _sessionStateStore: any;
14
- _playheadStateStore: any;
15
- _instanceId: any;
16
- currentMetadata: {};
17
- _events: any[];
18
- averageSegmentDuration: any;
19
- use_demuxed_audio: boolean;
20
- use_vtt_subtitles: any;
21
- dummySubtitleEndpoint: any;
22
- subtitleSliceEndpoint: any;
23
- cloudWatchLogging: boolean;
24
- playheadDiffThreshold: any;
25
- maxTickInterval: any;
26
- maxTickIntervalIsDefault: boolean;
27
- diffCompensationRate: any;
28
- diffCompensation: any;
29
- timePositionOffset: number;
30
- prevVodMediaSeq: {
31
- video: any;
32
- audio: any;
33
- subtitle: any;
34
- };
35
- prevMediaSeqOffset: {
36
- video: any;
37
- audio: any;
38
- subtitle: any;
39
- };
40
- waitingForNextVod: boolean;
41
- leaderIsSettingNextVod: boolean;
42
- isSwitchingBackToV2L: boolean;
43
- switchDataForSession: {
44
- mediaSeq: any;
45
- discSeq: any;
46
- mediaSeqOffset: any;
47
- transitionSegments: any;
48
- audioSeq: any;
49
- discAudioSeq: any;
50
- audioSeqOffset: any;
51
- transitionAudioSegments: any;
52
- reloadBehind: any;
53
- };
54
- isAllowedToClearVodCache: boolean;
55
- alwaysNewSegments: any;
56
- alwaysMapBandwidthByNearest: any;
57
- partialStoreHLSVod: any;
58
- currentPlayheadRef: any;
59
- disableLegacyMasterManifestFormat: any;
60
- rollingPDT: any;
61
- _category: any;
62
- startWithId: any;
63
- _sessionProfile: any;
64
- _audioTracks: any;
65
- _subtitleTracks: any;
66
- _closedCaptions: any;
67
- _noSessionDataTags: any;
68
- _sessionEventStream: any;
69
- slateUri: any;
70
- slateRepetitions: any;
71
- slateDuration: any;
72
- disabledPlayhead: boolean;
73
- targetDurationPadding: any;
74
- forceTargetDuration: any;
75
- initAsync(): Promise<void>;
76
- _sessionState: any;
77
- _playheadState: any;
78
- get sessionId(): any;
79
- startPlayheadAsync(): Promise<void>;
80
- restartPlayheadAsync(): Promise<void>;
81
- stopPlayheadAsync(): Promise<void>;
82
- getStatusAsync(): Promise<{
83
- sessionId: any;
84
- playhead: {
85
- state: any;
86
- tickMs: any;
87
- mediaSeq: any;
88
- };
89
- slateInserted: any;
90
- } | {
91
- sessionId: any;
92
- }>;
93
- resetAsync(id: any): Promise<void>;
94
- getSessionState(): Promise<any>;
95
- getTruncatedVodSegments(vodUri: any, duration: any): Promise<any>;
96
- getTruncatedVodAudioSegments(vodUri: any, duration: any): Promise<any>;
97
- setCurrentMediaSequenceSegments(segments: any, mSeqOffset: any, reloadBehind: any, audioSegments: any, aSeqOffset: any): Promise<void>;
98
- getCurrentMediaSequenceSegments(opts: any): Promise<any>;
99
- getCurrentAudioSequenceSegments(opts: any): Promise<any>;
100
- setCurrentMediaAndDiscSequenceCount(_mediaSeq: any, _discSeq: any, _audioSeq: any, _discAudioSeq: any): Promise<void>;
101
- getCurrentMediaAndDiscSequenceCount(): Promise<{
102
- mediaSeq: any;
103
- discSeq: any;
104
- vodMediaSeqVideo: any;
105
- }>;
106
- getCurrentMediaManifestAsync(bw: any, playbackSessionId: any): Promise<any>;
107
- getCurrentAudioManifestAsync(audioGroupId: any, audioLanguage: any, playbackSessionId: any): Promise<any>;
108
- getCurrentSubtitleManifestAsync(subtitleGroupId: any, subtitleLanguage: any, playbackSessionId: any): Promise<any>;
109
- incrementAsync(): Promise<any>;
110
- getMediaManifestAsync(bw: any, opts: any): Promise<any>;
111
- getAudioManifestAsync(audioGroupId: any, audioLanguage: any, opts: any): Promise<any>;
112
- getMasterManifestAsync(filter: any): Promise<string>;
113
- getAudioGroupsAndLangs(): Promise<{}>;
114
- getSubtitleGroupsAndLangs(): Promise<{}>;
115
- consumeEvent(): any;
116
- produceEvent(event: any): void;
117
- hasPlayhead(): boolean;
118
- _insertSlate(currentVod: any): Promise<any>;
119
- _tickAsync(): Promise<void>;
120
- _lastTickState: {
121
- sessionState: any;
122
- isLeader: any;
123
- currentVod: any;
124
- };
125
- _getNextVod(): Promise<any>;
126
- _loadSlate(afterVod: any, reps: any, unixTs: any): Promise<any>;
127
- _truncateVod(vodResponse: any): Promise<any>;
128
- _truncateSlate(afterVod: any, requestedDuration: any, vodUri: any, unixTs: any): Promise<any>;
129
- _fillGap(afterVod: any, desiredDuration: any, unixTs: any): Promise<any>;
130
- _getNextVodById(id: any): Promise<any>;
131
- _getFirstDuration(manifest: any): Promise<any>;
132
- _getCurrentDeltaTime(): Promise<any>;
133
- _getCurrentPlayheadPosition(): Promise<any>;
134
- _getAudioPlayheadPosition(seqIdx: any): Promise<any>;
135
- _getSubtitlePlayheadPosition(seqIdx: any): Promise<any>;
136
- _getLastDuration(manifest: any): Promise<any>;
137
- _getPlayheadDiffCompensationValue(diffMs: any, thresholdMs: any): number;
138
- _isOldVod(refTs: any, vodDur: any): boolean;
139
- _determineExtraMediaIncrement(_extraType: any, _currentPosVideo: any, _extraSeqFinalIndex: any, _vodMediaSeqExtra: any, _getExtraPlayheadPositionAsyncFn: any): Promise<{
140
- increment: number;
141
- position: number;
142
- diff: string;
143
- }>;
144
- _getM3u8File(variantType: any, variantKey: any, playbackSessionId: any): Promise<any>;
145
- _getCurrentVodData(dataName: any, variantType: any, vod: any): any;
146
- _logCurrentPlayheadPositions(playheadPosVideoMs: any, playheadAudio: any, playheadSubtitle: any): void;
147
- _logAllPlayheadPositions: (sessionId: any, vod: any) => void;
148
- }
1
+ export {};