@vkontakte/videoplayer-core 2.0.171-dev.c1327f3bc.0 → 2.0.171-dev.ed76c949d.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/es2015.cjs +30 -138
- package/es2015.esm.js +32 -140
- package/esnext.cjs +24 -132
- package/esnext.esm.js +24 -132
- package/evergreen.esm.js +26 -134
- package/package.json +2 -2
- package/types/player/Player.d.ts +1 -0
- package/types/providers/DashLiveProvider/utils/LiveDashPlayer.d.ts +2 -0
- package/types/providers/DashProvider/baseDashProvider.d.ts +1 -2
- package/types/providers/DashProviderVirtual/baseDashProvider.d.ts +1 -2
- package/types/providers/ProviderContainer/Mayday/GraceTimeout.d.ts +17 -0
- package/types/providers/ProviderContainer/Mayday/heuristics/StartupHangupHeuristic.d.ts +46 -0
- package/types/providers/ProviderContainer/Mayday/heuristics/TvFetcherErrorHeuristic.d.ts +10 -0
- package/types/providers/ProviderContainer/Mayday/index.d.ts +2 -1
- package/types/providers/ProviderContainer/Mayday/types.d.ts +1 -0
- package/types/providers/ProviderContainer/utils/formatsSupport.d.ts +0 -1
- package/types/providers/ProviderContainer/utils/playbackHangup.d.ts +6 -2
- package/types/providers/utils/Abr/abrController.d.ts +4 -1
- package/types/providers/utils/Abr/abrManager.d.ts +1 -0
- package/types/providers/utils/Abr/controllers/stallsController.d.ts +8 -1
- package/types/providers/utils/Abr/rules/audio/audioThroughputRule.d.ts +2 -2
- package/types/providers/utils/Abr/rules/audio/minAudioForVideoRule.d.ts +2 -2
- package/types/providers/utils/Abr/rules/baseRule.d.ts +2 -2
- package/types/providers/utils/Abr/rules/video/abandonRequestRule.d.ts +2 -2
- package/types/providers/utils/Abr/rules/video/bolaRule.d.ts +2 -2
- package/types/providers/utils/Abr/rules/video/bufferRule.d.ts +2 -2
- package/types/providers/utils/Abr/rules/video/fitsContainerRule.d.ts +2 -2
- package/types/providers/utils/Abr/rules/video/insufficientBufferRule.d.ts +2 -2
- package/types/providers/utils/Abr/rules/video/lowerLimitRule.d.ts +2 -2
- package/types/providers/utils/Abr/rules/video/stallsRule.d.ts +6 -2
- package/types/providers/utils/Abr/rules/video/throughputRule.d.ts +2 -2
- package/types/providers/utils/Abr/rules/video/tvDisabledVideoTrackRule.d.ts +2 -2
- package/types/providers/utils/Abr/rules/video/upperLimitRule.d.ts +2 -2
- package/types/providers/utils/Abr/types.d.ts +6 -6
- package/types/providers/utils/Abr/utils.d.ts +1 -3
- package/types/utils/timers.d.ts +2 -0
- package/types/utils/tuningConfig.d.ts +16 -17
- package/types/providers/ProviderContainer/Mayday/heuristics/HangupHeuristic.d.ts +0 -22
- package/types/providers/utils/Abr/rules/video/downloadTimeRule.d.ts +0 -15
- package/types/utils/buffer/dynamicBufferTarget.d.ts +0 -10
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vkontakte/videoplayer-core",
|
|
3
|
-
"version": "2.0.171-dev.
|
|
3
|
+
"version": "2.0.171-dev.ed76c949d.0",
|
|
4
4
|
"author": "vk.ru",
|
|
5
5
|
"description": "Videoplayer core library based on the vk.ru platform",
|
|
6
6
|
"homepage": "https://vk.ru",
|
|
@@ -42,6 +42,6 @@
|
|
|
42
42
|
"**/*.d.ts"
|
|
43
43
|
],
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@vkontakte/videoplayer-shared": "1.0.100-dev.
|
|
45
|
+
"@vkontakte/videoplayer-shared": "1.0.100-dev.ed76c949d.0"
|
|
46
46
|
}
|
|
47
47
|
}
|
package/types/player/Player.d.ts
CHANGED
|
@@ -30,6 +30,7 @@ export default class Player implements IPlayer {
|
|
|
30
30
|
experimental: PlayerExperimentalImpl;
|
|
31
31
|
private devNullLog;
|
|
32
32
|
private collectDecodingInfoDestroyCb;
|
|
33
|
+
private hasReleasedTimers;
|
|
33
34
|
constructor(tuning?: IOptionalTuningConfig, tracer?: ITracer, playerOptions?: IPlayerOptions);
|
|
34
35
|
private readonly doInit;
|
|
35
36
|
/**
|
|
@@ -54,9 +54,8 @@ export default abstract class BaseDashProvider implements IProvider {
|
|
|
54
54
|
protected getProviderSubscriptionInfo(): IProviderSubscriptionInfo;
|
|
55
55
|
protected subscribe(): void;
|
|
56
56
|
private syncBufferTarget;
|
|
57
|
-
private resolveAudioBufferTargetMs;
|
|
58
57
|
private resolveBufferTargetMs;
|
|
59
|
-
private
|
|
58
|
+
private resolveAudioBufferTargetMs;
|
|
60
59
|
protected selectVideoAudioRepresentations(): [Representation, Representation | undefined] | undefined;
|
|
61
60
|
protected prepare(manifestOffset?: number): void;
|
|
62
61
|
protected syncPlayback: () => void;
|
|
@@ -55,9 +55,8 @@ export default abstract class BaseDashProvider implements IProvider {
|
|
|
55
55
|
protected getProviderSubscriptionInfo(): IProviderSubscriptionInfo;
|
|
56
56
|
protected subscribe(): void;
|
|
57
57
|
private syncBufferTarget;
|
|
58
|
-
private resolveAudioBufferTargetMs;
|
|
59
58
|
private resolveBufferTargetMs;
|
|
60
|
-
private
|
|
59
|
+
private resolveAudioBufferTargetMs;
|
|
61
60
|
protected selectVideoAudioRepresentations(): [Representation, Representation | undefined] | undefined;
|
|
62
61
|
protected prepare(manifestOffset?: number): void;
|
|
63
62
|
protected syncPlayback: () => void;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Milliseconds } from "@vkontakte/videoplayer-shared";
|
|
2
|
+
/**
|
|
3
|
+
* Декрементный grace-таймаут: каждый вызов `decay()` уменьшает оставшееся время.
|
|
4
|
+
*
|
|
5
|
+
* После создания `current` возвращает начальное значение.
|
|
6
|
+
* Каждый вызов `decay()` умножает `remaining` на `decayFactor`, но не меньше `minTimeout`.
|
|
7
|
+
* Когда `remaining` достигает `minTimeout` — следующий `decay()` возвращает 0 (expire).
|
|
8
|
+
*/
|
|
9
|
+
export declare class GraceTimeout {
|
|
10
|
+
private remaining;
|
|
11
|
+
private readonly decayFactor;
|
|
12
|
+
private readonly minTimeout;
|
|
13
|
+
constructor(initialTimeout: Milliseconds, decayFactor: number, minTimeout: Milliseconds);
|
|
14
|
+
get current(): Milliseconds;
|
|
15
|
+
decay(): Milliseconds;
|
|
16
|
+
reset(initialTimeout: Milliseconds): void;
|
|
17
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { Subject } from "@vkontakte/videoplayer-shared";
|
|
2
|
+
import type { IError } from "@vkontakte/videoplayer-shared";
|
|
3
|
+
import type { IHeuristicDeps, IMaydayEvent } from "../types";
|
|
4
|
+
import type { IAsyncHeuristic, HeuristicResult } from "./IHeuristic";
|
|
5
|
+
/**
|
|
6
|
+
* Эвристика зависания перехода stopped-*.
|
|
7
|
+
*
|
|
8
|
+
* В зависимости от видимости вкладки и наличия звука выбирает стратегию
|
|
9
|
+
* и эмитит одну из рекомендаций:
|
|
10
|
+
*
|
|
11
|
+
* Visible-вкладка: grace-таймаут с уменьшением таймаута на поступление данных.
|
|
12
|
+
* — данные поступают → таймер продлевается.
|
|
13
|
+
* — grace истёк без прогресса → emit switch_codec (или switch_provider).
|
|
14
|
+
*
|
|
15
|
+
* Hidden-вкладка (audible): та же grace-модель с таймаутом (таймеры в воркере не тротлятся).
|
|
16
|
+
* — данные поступают → таймер продлевается.
|
|
17
|
+
* — grace истёк без прогресса → emit switch_codec.
|
|
18
|
+
*
|
|
19
|
+
* Hidden-вкладка (muted/deferred): молча ждём возврата на visible, desired state не трогаем.
|
|
20
|
+
* — вкладка стала visible → emit reinit (полный реинит сам восстановит воспроизведение).
|
|
21
|
+
* — переход всё-таки завершился в фоне (видео заиграло) → отмена, reinit не нужен.
|
|
22
|
+
*/
|
|
23
|
+
export declare class StartupHangupHeuristic implements IAsyncHeuristic {
|
|
24
|
+
private deps;
|
|
25
|
+
static readonly heuristicName = "StartupHangupHeuristic";
|
|
26
|
+
readonly type = "async";
|
|
27
|
+
readonly recommendation$: Subject<IMaydayEvent>;
|
|
28
|
+
private timerId;
|
|
29
|
+
private subscription;
|
|
30
|
+
private error;
|
|
31
|
+
private grace;
|
|
32
|
+
private hangupStartedAt;
|
|
33
|
+
private dataArrivals;
|
|
34
|
+
private hiddenWaitActive;
|
|
35
|
+
constructor(deps: IHeuristicDeps);
|
|
36
|
+
analyze(error: IError): HeuristicResult;
|
|
37
|
+
private startMonitoring;
|
|
38
|
+
private waitForVisible;
|
|
39
|
+
private restartTimer;
|
|
40
|
+
private recommendSwitch;
|
|
41
|
+
private isTabHidden;
|
|
42
|
+
private logOutcome;
|
|
43
|
+
private cancel;
|
|
44
|
+
reset(): void;
|
|
45
|
+
destroy(): void;
|
|
46
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { IError } from "@vkontakte/videoplayer-shared";
|
|
2
|
+
import type { IHeuristicDeps } from "../types";
|
|
3
|
+
import type { ISyncHeuristic, HeuristicResult } from "./IHeuristic";
|
|
4
|
+
export declare class TvFetcherErrorHeuristic implements ISyncHeuristic {
|
|
5
|
+
private _deps;
|
|
6
|
+
static readonly heuristicName = "TvFetcherErrorHeuristic";
|
|
7
|
+
readonly type = "sync";
|
|
8
|
+
constructor(_deps: IHeuristicDeps);
|
|
9
|
+
analyze(error: IError): HeuristicResult;
|
|
10
|
+
}
|
|
@@ -3,5 +3,6 @@ export type { IMaydayDeps, IFallbackContext, IRecommendation, RecoveryAction, IM
|
|
|
3
3
|
export type { ISyncHeuristic, IAsyncHeuristic, HeuristicResult } from "./heuristics/IHeuristic";
|
|
4
4
|
export { MediaErrorHeuristic } from "./heuristics/MediaErrorHeuristic";
|
|
5
5
|
export { FetcherErrorHeuristic } from "./heuristics/FetcherErrorHeuristic";
|
|
6
|
-
export {
|
|
6
|
+
export { TvFetcherErrorHeuristic } from "./heuristics/TvFetcherErrorHeuristic";
|
|
7
|
+
export { StartupHangupHeuristic } from "./heuristics/StartupHangupHeuristic";
|
|
7
8
|
export { MaydayStatistics } from "./MaydayStatistics";
|
|
@@ -54,6 +54,7 @@ export interface IHeuristicDeps {
|
|
|
54
54
|
getVisibilityState: () => DocumentVisibilityState | undefined;
|
|
55
55
|
getReadyState: () => number | undefined;
|
|
56
56
|
getVideoPaused: () => boolean | undefined;
|
|
57
|
+
getIsMuted: () => boolean;
|
|
57
58
|
currentNativeBuffer$: IValueSubject<IRange<Seconds> | undefined>;
|
|
58
59
|
videoLastDataObtainedTimestamp$: IValueSubject<Milliseconds | undefined>;
|
|
59
60
|
desiredPlaybackState$: IStateMachine<PlaybackState>;
|
|
@@ -15,7 +15,6 @@ type LiveFormat = VideoFormat.WEB_RTC_LIVE | VideoFormat.HLS_LIVE | VideoFormat.
|
|
|
15
15
|
type AllLiveFormats = [LiveFormat, LiveFormat, LiveFormat, LiveFormat, LiveFormat];
|
|
16
16
|
export declare const getLiveFormatsPriority: ({ androidPreferredFormat, preferCMAF, preferWebRTC }: Constraints) => AllLiveFormats;
|
|
17
17
|
export declare const getChromeCastFormatsPriority: (live: boolean) => VideoFormat[];
|
|
18
|
-
export declare const selectCodec: (codecs: Set<string>) => string | undefined;
|
|
19
18
|
type CodecStream = {
|
|
20
19
|
codecs: string;
|
|
21
20
|
hdr?: boolean;
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { IProviderEntry } from "../types";
|
|
2
2
|
import type { IObservable, Milliseconds } from "@vkontakte/videoplayer-shared";
|
|
3
|
-
import { Observable } from "@vkontakte/videoplayer-shared";
|
|
4
3
|
import type { IStateMachine } from "../../../utils/StateMachine/types";
|
|
5
4
|
import { PlaybackState } from "../../../player/types";
|
|
6
5
|
interface IParams {
|
|
@@ -12,5 +11,10 @@ interface IParams {
|
|
|
12
11
|
playbackHangupNoDataThreshold: Milliseconds;
|
|
13
12
|
useDelayedPlaybackHangupWithData: boolean;
|
|
14
13
|
}
|
|
15
|
-
|
|
14
|
+
export interface IPlaybackHangupInfo {
|
|
15
|
+
from: PlaybackState;
|
|
16
|
+
to: PlaybackState;
|
|
17
|
+
label: string;
|
|
18
|
+
}
|
|
19
|
+
declare const _default: (params: IParams) => IObservable<IPlaybackHangupInfo>;
|
|
16
20
|
export default _default;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import type { IAbrController, IAbrRule, IBaseAbrControllerContext, IRuleInitContext } from "./types";
|
|
1
|
+
import type { IAbrController, IAbrRule, IBaseAbrControllerContext, IRuleInitContext, RuleLogData } from "./types";
|
|
2
2
|
import type { IBaseTrack } from "../../../player/types";
|
|
3
|
+
export declare const formatRuleLog: ({ name, ...logData }: RuleLogData) => string;
|
|
3
4
|
export default class AbrController<
|
|
4
5
|
T extends IBaseTrack,
|
|
5
6
|
C extends IBaseAbrControllerContext
|
|
@@ -12,6 +13,8 @@ export default class AbrController<
|
|
|
12
13
|
destroy(): void;
|
|
13
14
|
updateContext(context: C): void;
|
|
14
15
|
autoSelectTrack(rules?: IAbrRule<T, C>[]): T;
|
|
16
|
+
private traceQualitySwitch;
|
|
17
|
+
private isLowQuality;
|
|
15
18
|
private selectTrackBasedOnHistory;
|
|
16
19
|
/** при переключении аудио стрима очищаем историю для предотвращения залипания в `onCooldown` */
|
|
17
20
|
historyReset(): void;
|
|
@@ -10,6 +10,7 @@ export declare class AbrManager {
|
|
|
10
10
|
private context;
|
|
11
11
|
private phaseController;
|
|
12
12
|
private allVideoRules;
|
|
13
|
+
private tracer;
|
|
13
14
|
init(context: IInitAbrManagerContext): void;
|
|
14
15
|
updateContext(updateContext: IUpdatableAbrManagerContext): void;
|
|
15
16
|
autoSelectTrack<T extends IVideoTrack | IAudioTrack>(kind: Exclude<StreamKind, StreamKind.TEXT>): T;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { IObservable, IValueSubject, Milliseconds } from "@vkontakte/videoplayer-shared";
|
|
1
|
+
import type { IObservable, ITracer, IValueSubject, Milliseconds } from "@vkontakte/videoplayer-shared";
|
|
2
2
|
import type { ITuningConfig } from "../../../../utils/tuningConfig";
|
|
3
3
|
import type { IVideoTrack } from "../../../../player/types";
|
|
4
4
|
import type { IObservableVideo } from "../../HTMLVideoElement/observable";
|
|
@@ -10,6 +10,7 @@ interface IConnectData {
|
|
|
10
10
|
observableVideo: IObservableVideo;
|
|
11
11
|
currentStallDuration$: IValueSubject<Milliseconds>;
|
|
12
12
|
tuning: ITuningConfig["stallsManager"];
|
|
13
|
+
tracer: ITracer;
|
|
13
14
|
}
|
|
14
15
|
export declare class StallsController {
|
|
15
16
|
private currentStallDuration$;
|
|
@@ -20,6 +21,9 @@ export declare class StallsController {
|
|
|
20
21
|
private lastUniqueVideoTrackSelectedTimestamp;
|
|
21
22
|
private lastUniqueVideoTrackSelected;
|
|
22
23
|
private providerStartWatchingTimestamp;
|
|
24
|
+
private tracer;
|
|
25
|
+
private severeStallTracer;
|
|
26
|
+
private severeStallStartedAt;
|
|
23
27
|
private subscription;
|
|
24
28
|
severeStallOccurred$: IValueSubject<boolean>;
|
|
25
29
|
totalStallsCount$: IValueSubject<number>;
|
|
@@ -28,6 +32,9 @@ export declare class StallsController {
|
|
|
28
32
|
lastStallDuration$: IValueSubject<Milliseconds>;
|
|
29
33
|
init(data: IConnectData): void;
|
|
30
34
|
destroy(): void;
|
|
35
|
+
private startSevereStallTracer;
|
|
36
|
+
private endSevereStallTracer;
|
|
37
|
+
private traceUpdateStallData;
|
|
31
38
|
private updateStallData;
|
|
32
39
|
}
|
|
33
40
|
export {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { IAbrRule, IAbrRuleResolution, IAudioAbrContext } from "../../types";
|
|
1
|
+
import type { IAbrRule, IAbrRuleResolution, IAudioAbrContext, RuleLogData } from "../../types";
|
|
2
2
|
import type { IAudioTrack, IVideoTrack } from "../../../../../player/types";
|
|
3
3
|
import { LimitAboveRule } from "../limitAboveRule";
|
|
4
4
|
import type { Kbps, Nullable } from "@vkontakte/videoplayer-shared";
|
|
@@ -8,6 +8,6 @@ type AudioThroughputLogsArgs = [forwardBufferHealth: Nullable<number>, playbackR
|
|
|
8
8
|
export declare class AudioThroughputRule extends LimitAboveRule<IAudioTrack, IAudioAbrContext, AudioThroughputLogsArgs> implements IAbrRule<IAudioTrack, IAudioAbrContext> {
|
|
9
9
|
constructor(phaseConfig: RulePhaseConfig);
|
|
10
10
|
execute(context: IAudioAbrContext): IAbrRuleResolution<IAudioTrack>;
|
|
11
|
-
protected
|
|
11
|
+
protected createLogData(selectedTrack: IVideoTrack, forwardBufferHealth: number | undefined, playbackRate: number, reserve: Kbps, playbackRateFactor: number, bitrateFactor: number, estimatedThroughput: Kbps, tuning: ITuningConfig): RuleLogData;
|
|
12
12
|
}
|
|
13
13
|
export {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { IAbrRule, IAbrRuleResolution, IAudioAbrContext } from "../../types";
|
|
1
|
+
import type { IAbrRule, IAbrRuleResolution, IAudioAbrContext, RuleLogData } from "../../types";
|
|
2
2
|
import type { IAudioTrack, IVideoTrack } from "../../../../../player/types";
|
|
3
3
|
import { LimitBelowRule } from "../limitBelowRule";
|
|
4
4
|
import type { ITuningConfig } from "../../../../../utils/tuningConfig";
|
|
@@ -8,6 +8,6 @@ type MinAudioForVideoLogsArgs = [lastVideoTrackSelected: Nullable<IVideoTrack>,
|
|
|
8
8
|
export declare class MinAudioForVideoRule extends LimitBelowRule<IAudioTrack, IAudioAbrContext, MinAudioForVideoLogsArgs> implements IAbrRule<IAudioTrack, IAudioAbrContext> {
|
|
9
9
|
constructor(phaseConfig: RulePhaseConfig);
|
|
10
10
|
execute(context: IAudioAbrContext): IAbrRuleResolution<IAudioTrack>;
|
|
11
|
-
protected
|
|
11
|
+
protected createLogData(selectedTrack: IVideoTrack, lastVideoTrackSelected: Nullable<IVideoTrack>, tuning: ITuningConfig): RuleLogData;
|
|
12
12
|
}
|
|
13
13
|
export {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { IAbrRule, IAbrRuleResolution, IBaseAbrControllerContext, IRuleInitContext, RuleConfidence, RuleType } from "../types";
|
|
1
|
+
import type { IAbrRule, IAbrRuleResolution, IBaseAbrControllerContext, IRuleInitContext, RuleConfidence, RuleLogData, RuleType } from "../types";
|
|
2
2
|
import type { IBaseTrack } from "../../../../player/types";
|
|
3
3
|
import { Subscription } from "@vkontakte/videoplayer-shared";
|
|
4
4
|
import type { AbrPhase } from "../controllers/abrPhaseController";
|
|
@@ -19,5 +19,5 @@ export declare abstract class BaseRule<
|
|
|
19
19
|
destroy(): void;
|
|
20
20
|
abstract execute(context: C): IAbrRuleResolution<T>;
|
|
21
21
|
protected createResolution(context: C, selectedTrack: T, ...params: LogsArgs): IAbrRuleResolution<T>;
|
|
22
|
-
protected abstract
|
|
22
|
+
protected abstract createLogData(selectedTrack: T, ...params: LogsArgs): RuleLogData;
|
|
23
23
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { IAbrRule, IAbrRuleResolution, IVideoAbrContext } from "../../types";
|
|
1
|
+
import type { IAbrRule, IAbrRuleResolution, IVideoAbrContext, RuleLogData } from "../../types";
|
|
2
2
|
import type { IVideoTrack } from "../../../../../player/types";
|
|
3
3
|
import type { Milliseconds } from "@vkontakte/videoplayer-shared";
|
|
4
4
|
import { LimitAboveRule } from "../limitAboveRule";
|
|
@@ -7,6 +7,6 @@ type LogsArgs = [elapsedMs: Milliseconds, loadedFraction: number, estimatedRemai
|
|
|
7
7
|
export declare class AbandonRequestRule extends LimitAboveRule<IVideoTrack, IVideoAbrContext, LogsArgs> implements IAbrRule<IVideoTrack, IVideoAbrContext> {
|
|
8
8
|
constructor(phaseConfig: RulePhaseConfig);
|
|
9
9
|
execute(context: IVideoAbrContext): IAbrRuleResolution<IVideoTrack>;
|
|
10
|
-
protected
|
|
10
|
+
protected createLogData(selectedTrack: IVideoTrack, elapsedMs: Milliseconds, loadedFraction: number, estimatedRemainingMs: Milliseconds, bufferLimitMs: Milliseconds, triggered: boolean): RuleLogData;
|
|
11
11
|
}
|
|
12
12
|
export {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { IAbrRule, IAbrRuleResolution, IRuleInitContext, IVideoAbrContext } from "../../types";
|
|
1
|
+
import type { IAbrRule, IAbrRuleResolution, IRuleInitContext, IVideoAbrContext, RuleLogData } from "../../types";
|
|
2
2
|
import type { IVideoTrack } from "../../../../../player/types";
|
|
3
3
|
import type { Kbps, Seconds } from "@vkontakte/videoplayer-shared";
|
|
4
4
|
import { LimitAboveRule } from "../limitAboveRule";
|
|
@@ -26,6 +26,6 @@ export declare class BolaRule extends LimitAboveRule<IVideoTrack, IVideoAbrConte
|
|
|
26
26
|
private resolveSegmentDurationS;
|
|
27
27
|
private applyBolaOSafeguard;
|
|
28
28
|
private resetPlaceholder;
|
|
29
|
-
protected
|
|
29
|
+
protected createLogData(selectedTrack: IVideoTrack, bufferLevelS: Seconds, placeholderBufferS: Seconds, segmentDurationS: Seconds, Vp: number, gp: number, validBitrates: Kbps[], selectedIndex: number, phase: AbrPhase | undefined): RuleLogData;
|
|
30
30
|
}
|
|
31
31
|
export {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { IAbrRule, IAbrRuleResolution, IVideoAbrContext } from "../../types";
|
|
1
|
+
import type { IAbrRule, IAbrRuleResolution, IVideoAbrContext, RuleLogData } from "../../types";
|
|
2
2
|
import type { IVideoTrack } from "../../../../../player/types";
|
|
3
3
|
import type { Nullable } from "@vkontakte/videoplayer-shared";
|
|
4
4
|
import { LimitAboveRule } from "../limitAboveRule";
|
|
@@ -12,6 +12,6 @@ type BufferRuleLogsArgs = [currentVideoTrack: Nullable<IVideoTrack>, lastVideoTr
|
|
|
12
12
|
export declare class BufferRule extends LimitAboveRule<IVideoTrack, IVideoAbrContext, BufferRuleLogsArgs> implements IAbrRule<IVideoTrack, IVideoAbrContext> {
|
|
13
13
|
constructor(phaseConfig: RulePhaseConfig);
|
|
14
14
|
execute(context: IVideoAbrContext): IAbrRuleResolution<IVideoTrack>;
|
|
15
|
-
protected
|
|
15
|
+
protected createLogData(selectedTrack: IVideoTrack, currentVideoTrack: Nullable<IVideoTrack>, lastVideoTrackSelected: Nullable<IVideoTrack>, forwardBufferHealth: Nullable<number>, abrTuning: ITuningConfig["autoTrackSelection"]): RuleLogData;
|
|
16
16
|
}
|
|
17
17
|
export {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { IAbrRule, IAbrRuleResolution, IVideoAbrContext } from "../../types";
|
|
1
|
+
import type { IAbrRule, IAbrRuleResolution, IVideoAbrContext, RuleLogData } from "../../types";
|
|
2
2
|
import type { IVideoTrack } from "../../../../../player/types";
|
|
3
3
|
import type { IRectangle, Nullable } from "@vkontakte/videoplayer-shared";
|
|
4
4
|
import { LimitAboveRule } from "../limitAboveRule";
|
|
@@ -9,7 +9,7 @@ type FitsContainerLogsArgs = [containerSizeLimit: Nullable<IContainerSizeLimit>,
|
|
|
9
9
|
export declare class FitsContainerRule extends LimitAboveRule<IVideoTrack, IVideoAbrContext, FitsContainerLogsArgs> implements IAbrRule<IVideoTrack, IVideoAbrContext> {
|
|
10
10
|
constructor(phaseConfig: RulePhaseConfig);
|
|
11
11
|
execute(context: IVideoAbrContext): IAbrRuleResolution<IVideoTrack>;
|
|
12
|
-
protected
|
|
12
|
+
protected createLogData(selectedTrack: IVideoTrack, containerSizeLimit: Nullable<IContainerSizeLimit>, containerSizeFactor: number, abrTuning: ITuningConfig["autoTrackSelection"]): RuleLogData;
|
|
13
13
|
private getContainerSizeLimit;
|
|
14
14
|
}
|
|
15
15
|
export {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { IAbrRule, IAbrRuleResolution, IRuleInitContext, IVideoAbrContext } from "../../types";
|
|
1
|
+
import type { IAbrRule, IAbrRuleResolution, IRuleInitContext, IVideoAbrContext, RuleLogData } from "../../types";
|
|
2
2
|
import type { IVideoTrack } from "../../../../../player/types";
|
|
3
3
|
import type { Milliseconds } from "@vkontakte/videoplayer-shared";
|
|
4
4
|
import { LimitAboveRule } from "../limitAboveRule";
|
|
@@ -10,6 +10,6 @@ export declare class InsufficientBufferRule extends LimitAboveRule<IVideoTrack,
|
|
|
10
10
|
override init(initContext: IRuleInitContext): void;
|
|
11
11
|
execute(context: IVideoAbrContext): IAbrRuleResolution<IVideoTrack>;
|
|
12
12
|
private selectThroughputAwareFallback;
|
|
13
|
-
protected
|
|
13
|
+
protected createLogData(selectedTrack: IVideoTrack, forwardBufferDuration: Milliseconds | undefined, thresholdMs: Milliseconds, triggered: boolean, suppressedByGrace: boolean): RuleLogData;
|
|
14
14
|
}
|
|
15
15
|
export {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { IAbrRule, IAbrRuleResolution, IVideoAbrContext } from "../../types";
|
|
1
|
+
import type { IAbrRule, IAbrRuleResolution, IVideoAbrContext, RuleLogData } from "../../types";
|
|
2
2
|
import type { IVideoTrack } from "../../../../../player/types";
|
|
3
3
|
import type { Nullable, QualityLimits } from "@vkontakte/videoplayer-shared";
|
|
4
4
|
import { type ExactVideoQuality } from "@vkontakte/videoplayer-shared";
|
|
@@ -8,6 +8,6 @@ type LowerLimitLogsArgs = [limitsAreInvalid: boolean, lowestAvailableQuality: Nu
|
|
|
8
8
|
export declare class LowerLimitRule extends LimitBelowRule<IVideoTrack, IVideoAbrContext, LowerLimitLogsArgs> implements IAbrRule<IVideoTrack, IVideoAbrContext> {
|
|
9
9
|
constructor(phaseConfig: RulePhaseConfig);
|
|
10
10
|
execute(context: IVideoAbrContext): IAbrRuleResolution<IVideoTrack>;
|
|
11
|
-
protected
|
|
11
|
+
protected createLogData(selectedTrack: IVideoTrack, limitsAreInvalid: boolean, lowestAvailableQuality: Nullable<ExactVideoQuality>, highestAvailableQuality: Nullable<ExactVideoQuality>, limits: QualityLimits): RuleLogData;
|
|
12
12
|
}
|
|
13
13
|
export {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { IAbrRule, IAbrRuleResolution, IVideoAbrContext } from "../../types";
|
|
1
|
+
import type { IAbrRule, IAbrRuleResolution, IVideoAbrContext, RuleLogData } from "../../types";
|
|
2
2
|
import type { IVideoTrack } from "../../../../../player/types";
|
|
3
3
|
import type { Kbps, Nullable } from "@vkontakte/videoplayer-shared";
|
|
4
4
|
import { LimitAboveRule } from "../limitAboveRule";
|
|
@@ -11,9 +11,13 @@ export declare class StallsRule extends LimitAboveRule<IVideoTrack, IVideoAbrCon
|
|
|
11
11
|
private lastStallDurationRestriction;
|
|
12
12
|
private maxQualityLimitOnStall;
|
|
13
13
|
private predictedThroughputWithoutData;
|
|
14
|
+
private restrictionTracer;
|
|
15
|
+
private restrictionStartedAt;
|
|
14
16
|
constructor(phaseConfig: RulePhaseConfig);
|
|
15
17
|
execute(context: IVideoAbrContext): IAbrRuleResolution<IVideoTrack>;
|
|
16
|
-
protected
|
|
18
|
+
protected createLogData(selectedTrack: IVideoTrack, forwardBufferHealth: Nullable<number>, playbackRate: number, reserve: Kbps, playbackRateFactor: number, bitrateFactor: number, tuning: ITuningConfig): RuleLogData;
|
|
19
|
+
private traceRestrictionSet;
|
|
20
|
+
private traceRestrictionReset;
|
|
17
21
|
private updateStallQualityLimits;
|
|
18
22
|
}
|
|
19
23
|
export {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { IAbrRule, IAbrRuleResolution, IVideoAbrContext } from "../../types";
|
|
1
|
+
import type { IAbrRule, IAbrRuleResolution, IVideoAbrContext, RuleLogData } from "../../types";
|
|
2
2
|
import type { IVideoTrack } from "../../../../../player/types";
|
|
3
3
|
import type { Kbps, Nullable } from "@vkontakte/videoplayer-shared";
|
|
4
4
|
import { LimitAboveRule } from "../limitAboveRule";
|
|
@@ -8,6 +8,6 @@ type ThroughputLogsArgs = [forwardBufferHealth: Nullable<number>, playbackRate:
|
|
|
8
8
|
export declare class ThroughputRule extends LimitAboveRule<IVideoTrack, IVideoAbrContext, ThroughputLogsArgs> implements IAbrRule<IVideoTrack, IVideoAbrContext> {
|
|
9
9
|
constructor(phaseConfig: RulePhaseConfig);
|
|
10
10
|
execute(context: IVideoAbrContext): IAbrRuleResolution<IVideoTrack>;
|
|
11
|
-
protected
|
|
11
|
+
protected createLogData(selectedTrack: IVideoTrack, forwardBufferHealth: Nullable<number>, playbackRate: number, reserve: Kbps, playbackRateFactor: number, bitrateFactor: number, estimatedThroughput: Kbps, phase: AbrPhase | undefined, tuning: ITuningConfig): RuleLogData;
|
|
12
12
|
}
|
|
13
13
|
export {};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import type { IAbrRule, IAbrRuleResolution, IVideoAbrContext } from "../../types";
|
|
1
|
+
import type { IAbrRule, IAbrRuleResolution, IVideoAbrContext, RuleLogData } from "../../types";
|
|
2
2
|
import type { IVideoTrack } from "../../../../../player/types";
|
|
3
3
|
import { LimitAboveRule } from "../limitAboveRule";
|
|
4
4
|
import type { RulePhaseConfig } from "../../controllers/abrPhaseController";
|
|
5
5
|
export declare class TvDisabledVideoTrackRule extends LimitAboveRule<IVideoTrack, IVideoAbrContext> implements IAbrRule<IVideoTrack, IVideoAbrContext> {
|
|
6
6
|
constructor(phaseConfig: RulePhaseConfig);
|
|
7
7
|
execute(context: IVideoAbrContext): IAbrRuleResolution<IVideoTrack>;
|
|
8
|
-
protected
|
|
8
|
+
protected createLogData(selectedTrack: IVideoTrack): RuleLogData;
|
|
9
9
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { IAbrRule, IAbrRuleResolution, IVideoAbrContext } from "../../types";
|
|
1
|
+
import type { IAbrRule, IAbrRuleResolution, IVideoAbrContext, RuleLogData } from "../../types";
|
|
2
2
|
import type { IVideoTrack } from "../../../../../player/types";
|
|
3
3
|
import type { Nullable, QualityLimits, VideoQuality } from "@vkontakte/videoplayer-shared";
|
|
4
4
|
import { type ExactVideoQuality } from "@vkontakte/videoplayer-shared";
|
|
@@ -63,7 +63,7 @@ type UpperLimitsLogsArgs = [limitsAreInvalid: boolean, lowestAvailableQuality: N
|
|
|
63
63
|
export declare class UpperLimitsRule extends LimitAboveRule<IVideoTrack, IVideoAbrContext, UpperLimitsLogsArgs> implements IAbrRule<IVideoTrack, IVideoAbrContext> {
|
|
64
64
|
constructor(phaseConfig: RulePhaseConfig);
|
|
65
65
|
execute(context: IVideoAbrContext): IAbrRuleResolution<IVideoTrack>;
|
|
66
|
-
protected
|
|
66
|
+
protected createLogData(selectedTrack: IVideoTrack, limitsAreInvalid: boolean, lowestAvailableQuality: Nullable<ExactVideoQuality>, highestAvailableQuality: Nullable<ExactVideoQuality>, visible: boolean, limits: QualityLimits, backgroundVideoQualityLimit: VideoQuality, effectiveType: string | undefined, connectionDataQualityLimit: ExactVideoQuality | undefined): RuleLogData;
|
|
67
67
|
private getConnection;
|
|
68
68
|
private resolveConnectionDataQualityLimit;
|
|
69
69
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { IAudioTrack, IBaseTrack, IVideoTrack } from "../../../player/types";
|
|
2
|
-
import type { Byte, IComponentLogger, IObservable, IRectangle, IValueSubject, Kbps, Milliseconds, Nullable, QualityLimits } from "@vkontakte/videoplayer-shared";
|
|
2
|
+
import type { Byte, IComponentLogger, IObservable, IRectangle, ITracer, IValueSubject, Kbps, Milliseconds, Nullable, QualityLimits } from "@vkontakte/videoplayer-shared";
|
|
3
3
|
import type { ITuningConfig } from "../../../utils/tuningConfig";
|
|
4
4
|
import type { Representation, Segment } from "../parsers/types";
|
|
5
5
|
import type { ElementSizeManager } from "../HTMLVideoElement/ElementSizeManager";
|
|
@@ -21,8 +21,7 @@ export declare enum VideoRuleName {
|
|
|
21
21
|
UpperLimit = "upper_limit_rule",
|
|
22
22
|
Throughput = "throughput_rule",
|
|
23
23
|
AbandonRequest = "abandon_request_rule",
|
|
24
|
-
InsufficientBuffer = "insufficient_buffer_rule"
|
|
25
|
-
DownloadTime = "download_time_rule"
|
|
24
|
+
InsufficientBuffer = "insufficient_buffer_rule"
|
|
26
25
|
}
|
|
27
26
|
export declare enum AudioRuleName {
|
|
28
27
|
MinAudioForVideo = "min_audio_for_video_rule",
|
|
@@ -40,7 +39,6 @@ export interface IUpdatableAbrManagerContext {
|
|
|
40
39
|
desiredVideoTrack: Nullable<IVideoTrack>;
|
|
41
40
|
limits: QualityLimits;
|
|
42
41
|
forwardBufferHealth?: number;
|
|
43
|
-
forwardBufferTarget: Milliseconds;
|
|
44
42
|
forwardVideoBufferRepresentations: Nullable<Map<Representation["id"], Segment[]>>;
|
|
45
43
|
forwardAudioBufferRepresentations: Nullable<Map<Representation["id"], Segment[]>>;
|
|
46
44
|
forwardBufferDuration?: Milliseconds;
|
|
@@ -59,6 +57,7 @@ export interface IInitAbrManagerContext {
|
|
|
59
57
|
throughputVariance$?: IValueSubject<number>;
|
|
60
58
|
element: HTMLMediaElement;
|
|
61
59
|
abrLogger: IComponentLogger;
|
|
60
|
+
tracer: ITracer;
|
|
62
61
|
panelSize?: IRectangle;
|
|
63
62
|
}
|
|
64
63
|
export interface IVideoElementAbrManagerContext {
|
|
@@ -75,12 +74,13 @@ export interface IAudioTracksContext {
|
|
|
75
74
|
audioTracksDesc: IAudioTrack[];
|
|
76
75
|
}
|
|
77
76
|
export type IAbrManagerContext = Omit<IUpdatableAbrManagerContext, "videoTracks" | "audioTracks"> & IVideoElementAbrManagerContext & IInitAbrManagerContext & IVideoTracksContext & IAudioTracksContext;
|
|
77
|
+
export type RuleLogData = Record<string, string | number | boolean | undefined>;
|
|
78
78
|
export interface IAbrRuleResolution<T extends IBaseTrack> {
|
|
79
79
|
track: T;
|
|
80
80
|
confidence: number;
|
|
81
81
|
type: RuleType;
|
|
82
82
|
name: string;
|
|
83
|
-
|
|
83
|
+
logData: RuleLogData;
|
|
84
84
|
}
|
|
85
85
|
export interface IRuleInitContext extends IInitAbrManagerContext {}
|
|
86
86
|
export interface IAbrRule<
|
|
@@ -103,6 +103,7 @@ export interface IBaseAbrControllerContext extends IVideoTracksContext {
|
|
|
103
103
|
lastVideoTrackSelected: Nullable<IVideoTrack>;
|
|
104
104
|
tuning: ITuningConfig;
|
|
105
105
|
abrLogger: IComponentLogger;
|
|
106
|
+
tracer: ITracer;
|
|
106
107
|
estimatedThroughput: Kbps;
|
|
107
108
|
reserve: Kbps;
|
|
108
109
|
forwardBufferHealth: Nullable<number>;
|
|
@@ -120,7 +121,6 @@ export interface IVideoAbrContext extends IBaseAbrControllerContext {
|
|
|
120
121
|
container: Nullable<IRectangle>;
|
|
121
122
|
panelSize: Nullable<IRectangle>;
|
|
122
123
|
forwardBufferRepresentations: Nullable<Map<Representation["id"], Segment[]>>;
|
|
123
|
-
forwardBufferTarget: Milliseconds;
|
|
124
124
|
limits: QualityLimits;
|
|
125
125
|
visible: boolean;
|
|
126
126
|
severeStallOccurred: boolean;
|
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { Milliseconds, Nullable } from "@vkontakte/videoplayer-shared";
|
|
2
2
|
import type { IAudioTrack, IBaseTrack, IVideoTrack } from "../../../player/types";
|
|
3
|
-
import type { Segment } from "../parsers/types";
|
|
4
|
-
export declare const computeForwardBitrate: (segments: Nullable<Segment[]>) => Kbps;
|
|
5
3
|
export declare const bufferToPlaybackMs: (contentMs: Milliseconds | undefined, playbackRate: number) => Milliseconds;
|
|
6
4
|
export declare enum CompareTrack {
|
|
7
5
|
Descending = -1,
|
|
@@ -2,7 +2,7 @@ import type { VideoCodecName, VideoFormat } from "../player/types";
|
|
|
2
2
|
import { WebmCodecStrategy } from "../enums/WebmCodecStrategy";
|
|
3
3
|
import { AndroidPreferredFormat } from "../enums/AndroidPreferredFormat";
|
|
4
4
|
import { IOSPreferredFormat } from "../enums/IOSPreferredFormat";
|
|
5
|
-
import type { Byte, Kbps, Milliseconds, RecursivePartial, Seconds } from "@vkontakte/videoplayer-shared";
|
|
5
|
+
import type { Byte, Kbps, Milliseconds, RecursivePartial, Seconds, TimerModule } from "@vkontakte/videoplayer-shared";
|
|
6
6
|
import { type ExactVideoQuality, VideoQuality } from "@vkontakte/videoplayer-shared";
|
|
7
7
|
import { AudioRuleName, VideoRuleName } from "../providers/utils/Abr/types";
|
|
8
8
|
export type ITuningConfig = {
|
|
@@ -13,11 +13,23 @@ export type ITuningConfig = {
|
|
|
13
13
|
playingUnstableThresholdMs: Milliseconds;
|
|
14
14
|
/** Список имён включённых эвристик. Пустой массив = все эвристики выключены */
|
|
15
15
|
heuristics: string[];
|
|
16
|
+
/** Множитель уменьшения grace-таймаута при каждом поступлении данных в StartupHangupHeuristic */
|
|
17
|
+
hangupGraceDecayFactor: number;
|
|
18
|
+
/** Минимальный grace-таймаут (мс). При достижении — следующий decay возвращает 0 (немедленный expire) */
|
|
19
|
+
hangupGraceMinTimeoutMs: Milliseconds;
|
|
20
|
+
/**
|
|
21
|
+
* Если true — audible (не muted) хэнгап в hidden-вкладке откладывается до возврата на visible (reinit),
|
|
22
|
+
* desired state при этом не меняется.
|
|
23
|
+
* Если false — audible хэнгап в hidden-вкладке мониторится: данные перезапускают decay-таймер,
|
|
24
|
+
* при ≥3 поступлениях данных без завершения перехода — эскалация в switch_codec/switch_provider.
|
|
25
|
+
*/
|
|
26
|
+
deferAudibleHangupOnHiddenTab: boolean;
|
|
16
27
|
};
|
|
17
28
|
/**
|
|
18
29
|
* Включает очистку состояния плеера при вызове метода stop()
|
|
19
30
|
*/
|
|
20
31
|
allowPlayerReuse: boolean;
|
|
32
|
+
useWorkerTimers: TimerModule[];
|
|
21
33
|
throughputEstimator: {
|
|
22
34
|
type: "TwoEma" | "EmaAndMa";
|
|
23
35
|
emaAlphaSlow: number;
|
|
@@ -106,6 +118,7 @@ export type ITuningConfig = {
|
|
|
106
118
|
activeVideoAreaThreshold: number;
|
|
107
119
|
trafficSavingLimit: ExactVideoQuality;
|
|
108
120
|
highQualityLimit: ExactVideoQuality;
|
|
121
|
+
lowQualityTelemetryLimit: ExactVideoQuality;
|
|
109
122
|
};
|
|
110
123
|
stallsManager: {
|
|
111
124
|
enabled: boolean;
|
|
@@ -146,7 +159,6 @@ export type ITuningConfig = {
|
|
|
146
159
|
forwardBufferTargetManual: Milliseconds;
|
|
147
160
|
forwardBufferTargetPreload: Milliseconds;
|
|
148
161
|
audioBufferAheadOfVideoMs: Milliseconds;
|
|
149
|
-
useDynamicBufferTarget: boolean;
|
|
150
162
|
seekBiasInTheEnd: Milliseconds;
|
|
151
163
|
maxSegmentDurationLeftToSelectNextSegment: Milliseconds;
|
|
152
164
|
minSafeBufferThreshold: number;
|
|
@@ -175,7 +187,6 @@ export type ITuningConfig = {
|
|
|
175
187
|
vktvAbrThrottle: number;
|
|
176
188
|
timeupdateEventTickThrottle: number;
|
|
177
189
|
fetcherBufferOptimisation: boolean;
|
|
178
|
-
codecsPrioritizeEnabled: boolean;
|
|
179
190
|
usePersistentGaps: boolean;
|
|
180
191
|
abrThrottle: number;
|
|
181
192
|
useVideoElementWaitingCurrentTimeReassign: boolean;
|
|
@@ -222,26 +233,14 @@ export type ITuningConfig = {
|
|
|
222
233
|
budgetFactor: number;
|
|
223
234
|
fallbackSegmentDurationMs: Milliseconds;
|
|
224
235
|
};
|
|
225
|
-
dynamicBufferTarget: {
|
|
226
|
-
maxMs: Milliseconds;
|
|
227
|
-
optimisticHeadroomLow: number;
|
|
228
|
-
optimisticHeadroomHigh: number;
|
|
229
|
-
weakThroughputLowKbps: Kbps;
|
|
230
|
-
weakThroughputHighKbps: Kbps;
|
|
231
|
-
maxFactor: number;
|
|
232
|
-
};
|
|
233
236
|
videoStreamRepresentaionsFilter: [VideoQuality, number, VideoCodecName][];
|
|
234
237
|
filterOnDemandQualityList: boolean;
|
|
235
238
|
dashMaxTvVideoQuality: boolean;
|
|
236
239
|
checkRepresentationCanPlayType: Extract<CanPlayTypeResult, "maybe" | "probably"> | false;
|
|
237
240
|
preloadFirstSegment: boolean;
|
|
238
241
|
maxQualityForFirstSegmentPreload: ExactVideoQuality;
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
safetyFactor: number;
|
|
242
|
-
bootstrapBufferMs: Milliseconds;
|
|
243
|
-
demandTolerance: number;
|
|
244
|
-
};
|
|
242
|
+
/** Включает отправку телеметрии трейсера (resume) при превышении stall watchdog */
|
|
243
|
+
tracerResumeOnUnexpectedStall: boolean;
|
|
245
244
|
};
|
|
246
245
|
dashCmafLive: {
|
|
247
246
|
externalStopControl: boolean;
|