@vkontakte/videoplayer-core 2.0.181-dev.111b83b80.0 → 2.0.181-dev.132333d53.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 (52) hide show
  1. package/es2015.cjs +16 -16
  2. package/es2015.esm.js +8 -8
  3. package/esnext.cjs +8 -8
  4. package/esnext.esm.js +15 -15
  5. package/evergreen.esm.js +8 -8
  6. package/package.json +2 -2
  7. package/types/index.d.ts +3 -1
  8. package/types/player/Player.d.ts +2 -0
  9. package/types/player/types.d.ts +20 -3
  10. package/types/providers/DashProvider/baseDashProvider.d.ts +3 -0
  11. package/types/providers/DashProvider/lib/buffer.d.ts +49 -5
  12. package/types/providers/DashProvider/lib/fetcher.d.ts +31 -6
  13. package/types/providers/DashProvider/lib/player.d.ts +5 -0
  14. package/types/providers/DashProviderVirtual/baseDashProvider.d.ts +3 -0
  15. package/types/providers/DashProviderVirtual/lib/buffer/types.d.ts +3 -0
  16. package/types/providers/DashProviderVirtual/lib/buffer/virtualBuffer/baseVirtualBufferManager.d.ts +21 -4
  17. package/types/providers/DashProviderVirtual/lib/fetcher.d.ts +30 -6
  18. package/types/providers/DashProviderVirtual/lib/player/basePlayer.d.ts +2 -0
  19. package/types/providers/DashProviderVirtual/lib/player/types.d.ts +4 -1
  20. package/types/providers/ProviderContainer/index.d.ts +2 -0
  21. package/types/providers/types.d.ts +2 -1
  22. package/types/providers/utils/Abr/abrManager.d.ts +2 -0
  23. package/types/providers/utils/Abr/mlAbr/chunkDownloadHistory.d.ts +34 -0
  24. package/types/providers/utils/Abr/mlAbr/modelInput.d.ts +47 -0
  25. package/types/providers/utils/Abr/mlAbr/workerClient.d.ts +57 -0
  26. package/types/providers/utils/Abr/mlAbr/workerProtocol.d.ts +67 -0
  27. package/types/providers/utils/Abr/rules/baseRule.d.ts +2 -1
  28. package/types/providers/utils/Abr/rules/video/mlAbrRule.d.ts +52 -0
  29. package/types/providers/utils/Abr/rules/video/stallsRule.d.ts +9 -11
  30. package/types/providers/utils/Abr/types.d.ts +10 -1
  31. package/types/providers/utils/StallsManager.d.ts +1 -8
  32. package/types/utils/ClientChecker/services/DeviceChecker.d.ts +4 -0
  33. package/types/utils/ClientChecker/types/userAgentData.d.ts +4 -2
  34. package/types/utils/ThroughputEstimator.d.ts +20 -4
  35. package/types/utils/UserHappinessController.d.ts +8 -0
  36. package/types/utils/UserHappinessObserver/constants.d.ts +12 -0
  37. package/types/utils/UserHappinessObserver/index.d.ts +15 -0
  38. package/types/utils/UserHappinessObserver/metrics/hasFatalError.d.ts +3 -0
  39. package/types/utils/UserHappinessObserver/metrics/highStallRatio.d.ts +3 -0
  40. package/types/utils/UserHappinessObserver/metrics/lowQuality/constants.d.ts +5 -0
  41. package/types/utils/UserHappinessObserver/metrics/lowQuality/createLowQuality.d.ts +4 -0
  42. package/types/utils/UserHappinessObserver/metrics/lowQuality/index.d.ts +1 -0
  43. package/types/utils/UserHappinessObserver/metrics/lowQuality/types.d.ts +13 -0
  44. package/types/utils/UserHappinessObserver/metrics/lowQuality/utils.d.ts +26 -0
  45. package/types/utils/UserHappinessObserver/metrics/slowFirstFrame.d.ts +3 -0
  46. package/types/utils/UserHappinessObserver/types.d.ts +8 -0
  47. package/types/utils/UserHappinessObserver/utils/qualityPlatform.d.ts +2 -0
  48. package/types/utils/UserHappinessObserver/utils/thresholds.d.ts +2 -0
  49. package/types/utils/UserHappinessObserver/utils/watchedTimeSeconds.d.ts +3 -0
  50. package/types/utils/tuningConfig.d.ts +71 -20
  51. package/types/utils/userHappinessTriggers.d.ts +4 -0
  52. package/types/utils/buffer/getBackwardBufferDuration.d.ts +0 -3
@@ -0,0 +1,47 @@
1
+ import type { Byte } from "@vkontakte/videoplayer-shared";
2
+ import { VideoQuality } from "@vkontakte/videoplayer-shared";
3
+ import type { IChunkDownloadRecord } from "./chunkDownloadHistory";
4
+ /**
5
+ * Контракт модели PPO ABR, версия артефакта 22.10 (карточка модели — Confluence
6
+ * pageId=2177405140). Константы зашиты в .tflite и конфигурироваться не могут.
7
+ */
8
+ export declare const ML_ABR_ACTIONS = 8;
9
+ export declare const ML_ABR_HISTORY = 24;
10
+ /** Горизонт размеров будущих чанков (v22.10): 4 чанка вперёд на качество. */
11
+ export declare const ML_ABR_FOREHORON = 4;
12
+ /** Лестница модели: индекс массива — индекс действия артефакта. */
13
+ export declare const ML_ABR_LADDER: readonly VideoQuality[];
14
+ export declare const ladderIndexOfQuality: (quality: VideoQuality) => number;
15
+ export interface IMlAbrInputSource {
16
+ /** История загрузок, от старых к новым; длиннее H — берутся последние H. */
17
+ history: readonly IChunkDownloadRecord[];
18
+ /** Размеры будущих чанков по качествам лестницы (F=4, от следующего); оценка в байтах уже подставлена правилом. */
19
+ nextChunkSizes: ReadonlyMap<VideoQuality, readonly Byte[]>;
20
+ /** Доступные качества: лестница ∩ внешние лимиты. Вход маски модели. */
21
+ availableQualities: ReadonlySet<VideoQuality>;
22
+ /** Заполненность буфера в секундах, до преобразования speed. */
23
+ bufferSeconds: number;
24
+ /** Флаг размера буфера: 0 → 70 с, 1 → 120 с. */
25
+ bufferFlag: 0 | 1;
26
+ /** Доля оставшегося видео: remaining / total. */
27
+ remainingRatio: number;
28
+ /** playbackRate: v22.10 поддерживает ≠1 двумя преобразованиями (buffer/speed, download×speed). */
29
+ playbackRate: number;
30
+ }
31
+ export interface IMlAbrModelInput {
32
+ /** [H] измеренная полоса чанка, Mbps/10. */
33
+ readonly throughput: Float32Array;
34
+ /** [H] время загрузки чанка, с/10 (уже ×speed). */
35
+ readonly download: Float32Array;
36
+ /** [A×H] one-hot история выборов. */
37
+ readonly actionHistory: Float32Array;
38
+ /** [A×F] размеры будущих чанков, байт/1e6. */
39
+ readonly chunkSizes: Float32Array;
40
+ /** [A×H] размеры скачанных чанков, байт/1e6. */
41
+ readonly prevChunkSizes: Float32Array;
42
+ /** [A] маска доступности, строго 0/1. */
43
+ readonly actionMask: Float32Array;
44
+ /** [3] buffer_s (÷speed), buffer_flag, remaining/total. */
45
+ readonly actorScalars: Float32Array;
46
+ }
47
+ export declare const buildMlAbrModelInput: (source: IMlAbrInputSource) => IMlAbrModelInput;
@@ -0,0 +1,57 @@
1
+ import type { IMlAbrModelInput } from "./modelInput";
2
+ import type { TMlAbrWorkerResponse } from "./workerProtocol";
3
+ export declare enum MlAbrRuntimeStatus {
4
+ NotStarted = "not_started",
5
+ InProgress = "in_progress",
6
+ Completed = "completed",
7
+ Failed = "failed"
8
+ }
9
+ export interface IMlAbrDecision {
10
+ /** Индекс качества в лестнице модели. */
11
+ qualityIndex: number;
12
+ /** Вероятности по действиям; для телеметрии (top-3). */
13
+ probs: Float32Array;
14
+ }
15
+ interface IMinimalWorker {
16
+ onmessage: ((event: MessageEvent<TMlAbrWorkerResponse>) => void) | null;
17
+ postMessage(message: unknown, transfer?: Transferable[]): void;
18
+ terminate(): void;
19
+ }
20
+ export interface IMlAbrWorkerClientDeps {
21
+ /** Точка подмены в тестах; в проде — глобальный fetch. */
22
+ fetch?: typeof fetch;
23
+ /** Точка подмены в тестах; в проде — глобальный Worker. */
24
+ Worker?: new (workerUrl: string) => IMinimalWorker;
25
+ }
26
+ export interface IMlAbrWorkerClientOptions {
27
+ /** URL артефакта worker.js на CDN (версионируемый путь — ручка экспериментов). */
28
+ workerJsUrl: string;
29
+ /** Байты модели: instance-провайдер или fetch гостевого URL; null — источника нет. */
30
+ model: Promise<ArrayBuffer | null>;
31
+ /** Каталог litert-артефакта; оттуда параллельно префетчатся iife и wasm. */
32
+ litertWasmUrl?: string;
33
+ /** Таймаут от создания до init-result; превышение гасит воркер. */
34
+ initTimeoutMs?: number;
35
+ deps?: IMlAbrWorkerClientDeps;
36
+ }
37
+ export interface IMlAbrWorkerClient {
38
+ readonly status: MlAbrRuntimeStatus;
39
+ readonly failureReason: string | undefined;
40
+ /** Резолвится после init-result; отказ — исключением с причиной. */
41
+ readonly ready: Promise<void>;
42
+ predict(input: IMlAbrModelInput): Promise<IMlAbrDecision>;
43
+ destroy(): void;
44
+ }
45
+ /**
46
+ * Клиент воркера: все сетевые заходы стартуют ПАРАЛЛЕЛЬНО с момента
47
+ * создания — код воркера, litert iife, wasm-бинарь (10+ МБ — главный
48
+ * полюс, вариант выбирается той же пробой relaxedSimd, что у loadLiteRt)
49
+ * и модель. Воркер собирается из уже скачанного кода через blob, получает
50
+ * всё предзагруженное первым сообщением и не ходит в сеть сам.
51
+ *
52
+ * Статусная машина вместо исключений: конвейер ABR синхронен, любую
53
+ * неготовность превращает в воздержание правила; причина отказа — строкой
54
+ * в debug-лог. Артефакты кросс-доменные — fetch требует CORS на CDN-ресурсе.
55
+ */
56
+ export declare const createMlAbrWorkerClient: (options: IMlAbrWorkerClientOptions) => IMlAbrWorkerClient;
57
+ export {};
@@ -0,0 +1,67 @@
1
+ import type { IMlAbrModelInput } from "./modelInput";
2
+ /**
3
+ * Протокол воркера ML ABR (артефакт uvp-deps на CDN, репозиторий
4
+ * uvp-deps — источник правды схемы). Контракт зеркалируется типами сюда:
5
+ * SDK не зависит от пакета воркера, расхождение ловится интеграционным
6
+ * прогоном, а не типами.
7
+ *
8
+ * Один init (модель transferable), затем поток predict. Ответы несут id
9
+ * запроса: порядок predict'ов не гарантирован, потребитель сверяется по id.
10
+ * Массивы входа передаются transferable — после отправки буферы
11
+ * отсоединены, пересозданием занимается отправитель (построитель входов
12
+ * собирает свежие массивы на каждый цикл).
13
+ */
14
+ export declare const ML_ABR_WORKER_PROTOCOL_VERSION = 1;
15
+ export interface IMlAbrInitMessage {
16
+ type: "init";
17
+ id: number;
18
+ /** Байты .tflite-артефакта; воркер забирает буфер transferable. */
19
+ model: ArrayBuffer;
20
+ /** Код iife-сборки litert, предзагруженный клиентом параллельно; без него — litertJsUrl. */
21
+ litertJsCode?: string;
22
+ /** Байты wasm-бинаря; воркер резолвит их через blob и locateFile. */
23
+ litertWasmBytes?: ArrayBuffer;
24
+ /** Fallback: URL iife-сборки LiteRT, если код не предзагружен. */
25
+ litertJsUrl?: string;
26
+ /** Каталог wasm-бинарёй: оттуда loadLiteRt берёт .js-лоадер (кэш прогрет префетчем клиента). */
27
+ litertWasmUrl?: string;
28
+ }
29
+ export interface IMlAbrPredictMessage {
30
+ type: "predict";
31
+ id: number;
32
+ input: IMlAbrModelInput;
33
+ }
34
+ export interface IMlAbrDestroyMessage {
35
+ type: "destroy";
36
+ }
37
+ export type TMlAbrWorkerRequest = IMlAbrInitMessage | IMlAbrPredictMessage | IMlAbrDestroyMessage;
38
+ export interface IMlAbrInitOk {
39
+ type: "init-result";
40
+ id: number;
41
+ ok: true;
42
+ protocolVersion: typeof ML_ABR_WORKER_PROTOCOL_VERSION;
43
+ /** Фактические имена входов артефакта (args_N или семантические). */
44
+ inputNames: string[];
45
+ }
46
+ export interface IMlAbrInitFail {
47
+ type: "init-result";
48
+ id: number;
49
+ ok: false;
50
+ reason: string;
51
+ }
52
+ export interface IMlAbrPredictOk {
53
+ type: "predict-result";
54
+ id: number;
55
+ ok: true;
56
+ /** Индекс качества в лестнице модели. */
57
+ qualityIndex: number;
58
+ /** Вероятности по действиям; transferable обратно. */
59
+ probs: Float32Array;
60
+ }
61
+ export interface IMlAbrPredictFail {
62
+ type: "predict-result";
63
+ id: number;
64
+ ok: false;
65
+ reason: string;
66
+ }
67
+ export type TMlAbrWorkerResponse = IMlAbrInitOk | IMlAbrInitFail | IMlAbrPredictOk | IMlAbrPredictFail;
@@ -12,7 +12,8 @@ export declare abstract class BaseRule<
12
12
  readonly activePhases: ReadonlySet<AbrPhase>;
13
13
  protected subscription: Subscription;
14
14
  protected type: RuleType;
15
- protected name: string;
15
+ /** Имя правила: публично — AbrManager фильтрует набор по именам в ML-режиме. */
16
+ name: string;
16
17
  protected confidence: RuleConfidence;
17
18
  constructor(phaseConfig: RulePhaseConfig);
18
19
  init(_initContext: IRuleInitContext): void;
@@ -0,0 +1,52 @@
1
+ import type { IAbrRule, IAbrRuleResolution, IRuleInitContext, IVideoAbrContext, RuleLogData } from "../../types";
2
+ import type { IVideoTrack } from "../../../../../player/types";
3
+ import { LimitAboveRule } from "../limitAboveRule";
4
+ import type { RulePhaseConfig } from "../../controllers/abrPhaseController";
5
+ import { type IMlAbrDecision } from "../../mlAbr/workerClient";
6
+ export type MlAbrModelSource = "getModels" | "guest";
7
+ /**
8
+ * Голос модели в конвейере. Синхронный контракт execute сохранён: инференс
9
+ * асинхронный, результат живёт в кэше с dirty-флагом, пересчёт запускается
10
+ * мимо execute. До готовности и при любом отказе правило голосует воздержанием —
11
+ * конвейер работает на классическом наборе.
12
+ */
13
+ export declare class MlAbrRule extends LimitAboveRule<IVideoTrack, IVideoAbrContext> implements IAbrRule<IVideoTrack, IVideoAbrContext> {
14
+ private initContext;
15
+ private history;
16
+ private modelResolver;
17
+ private modelSource;
18
+ private runtime;
19
+ private decision;
20
+ private decisionDirty;
21
+ private predictInFlight;
22
+ private lastLoggedStatus;
23
+ private decisionOwner;
24
+ constructor(phaseConfig: RulePhaseConfig);
25
+ /** Владелец решения: конвейер гасит Throughput/Bola, пока модель реально голосует. */
26
+ isDecisionOwner(): boolean;
27
+ init(initContext: IRuleInitContext): void;
28
+ destroy(): void;
29
+ execute(context: IVideoAbrContext): IAbrRuleResolution<IVideoTrack>;
30
+ protected createLogData(selectedTrack: IVideoTrack, decision: IMlAbrDecision | undefined, sizesEstimated: boolean | undefined, warmup: number, abstainReason: string | undefined): RuleLogData;
31
+ private lastSizesEstimated;
32
+ private modelSourceOf;
33
+ private warmupOf;
34
+ private warmupFallback;
35
+ /** Гейты входа в ML-режим (PRD «Steady модели»); undefined — можно голосовать. */
36
+ private abstainReason;
37
+ /**
38
+ * «Сначала байты, потом чанк»: рантайм (и его dynamic import) не трогается,
39
+ * пока байты модели не в руках. Провайдер → null и нет guestUrl → вообще
40
+ * ничего не грузим, правило навсегда воздерживается.
41
+ */
42
+ private ensureModelLoaded;
43
+ private maybePredict;
44
+ private buildInputSource;
45
+ private nextSizesOf;
46
+ private isWithinLimits;
47
+ private trackOfQuality;
48
+ /** remaining/total требует позиции плейхеда; ближайшая оценка — левый край окна сегментов. */
49
+ private approxPlayedMs;
50
+ /** Наблюдаемость (требование тикета): переходы состояний — в debug-лог, дубли не пишем. */
51
+ private logState;
52
+ }
@@ -1,23 +1,21 @@
1
1
  import type { IAbrRule, IAbrRuleResolution, IVideoAbrContext, RuleLogData } from "../../types";
2
2
  import type { IVideoTrack } from "../../../../../player/types";
3
- import type { Kbps, Nullable } from "@vkontakte/videoplayer-shared";
4
3
  import { LimitAboveRule } from "../limitAboveRule";
5
- import type { ITuningConfig } from "../../../../../utils/tuningConfig";
6
4
  import type { RulePhaseConfig } from "../../controllers/abrPhaseController";
7
- type StallLogsArgs = [forwardBufferHealth: Nullable<number>, playbackRate: number, reserve: Kbps, playbackRateFactor: number, bitrateFactor: number, tuning: ITuningConfig];
8
- export declare class StallsRule extends LimitAboveRule<IVideoTrack, IVideoAbrContext, StallLogsArgs> implements IAbrRule<IVideoTrack, IVideoAbrContext> {
9
- private severeStallOccurred;
10
- private qualityRestrictionTimer;
11
- private lastStallDurationRestriction;
5
+ export declare class StallsRule extends LimitAboveRule<IVideoTrack, IVideoAbrContext, []> implements IAbrRule<IVideoTrack, IVideoAbrContext> {
6
+ private wasSevereStall;
7
+ private restrictedInCurrentStall;
8
+ private stalledQuality;
9
+ private stallsByQuality;
10
+ private recoveryStartedAt;
12
11
  private maxQualityLimitOnStall;
13
- private predictedThroughputWithoutData;
14
12
  private restrictionTracer;
15
13
  private restrictionStartedAt;
16
14
  constructor(phaseConfig: RulePhaseConfig);
17
15
  execute(context: IVideoAbrContext): IAbrRuleResolution<IVideoTrack>;
18
- protected createLogData(selectedTrack: IVideoTrack, forwardBufferHealth: Nullable<number>, playbackRate: number, reserve: Kbps, playbackRateFactor: number, bitrateFactor: number, tuning: ITuningConfig): RuleLogData;
16
+ protected createLogData(selectedTrack: IVideoTrack): RuleLogData;
17
+ private trackStallEpisode;
18
+ private resolveQualityLimit;
19
19
  private traceRestrictionSet;
20
20
  private traceRestrictionReset;
21
- private updateStallQualityLimits;
22
21
  }
23
- export {};
@@ -1,7 +1,9 @@
1
1
  import type { IAudioTrack, IBaseTrack, IVideoTrack } from "../../../player/types";
2
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
+ import type { MlModelResolver } from "../../../player/types";
4
5
  import type { Representation, Segment } from "../parsers/types";
6
+ import type { IChunkDownloadHistory } from "./mlAbr/chunkDownloadHistory";
5
7
  import type { ElementSizeManager } from "../HTMLVideoElement/ElementSizeManager";
6
8
  import type { IObservableMediaElement } from "../HTMLVideoElement/observable";
7
9
  import type { AbrPhase } from "./controllers/abrPhaseController";
@@ -25,7 +27,8 @@ export declare enum VideoRuleName {
25
27
  UpperLimit = "upper_limit_rule",
26
28
  Throughput = "throughput_rule",
27
29
  AbandonRequest = "abandon_request_rule",
28
- InsufficientBuffer = "insufficient_buffer_rule"
30
+ InsufficientBuffer = "insufficient_buffer_rule",
31
+ MlAbr = "ml_abr_rule"
29
32
  }
30
33
  export declare enum AudioRuleName {
31
34
  MinAudioForVideo = "min_audio_for_video_rule",
@@ -59,6 +62,10 @@ export interface IInitAbrManagerContext {
59
62
  throughput$: IValueSubject<Kbps>;
60
63
  rtt$: IValueSubject<Milliseconds>;
61
64
  throughputVariance$?: IValueSubject<number>;
65
+ /** История загрузок видеочанков для MlAbr; не передан — фича деградирует в воздержание. */
66
+ chunkDownloadHistory?: IChunkDownloadHistory;
67
+ /** Провайдер байтов модели из инстанс-данных приложения; гейт загрузки рантайма. */
68
+ mlAbrModelResolver?: MlModelResolver;
62
69
  element: HTMLMediaElement;
63
70
  abrLogger: IComponentLogger;
64
71
  tracer: ITracer;
@@ -92,6 +99,8 @@ export interface IAbrRule<
92
99
  C extends IBaseAbrControllerContext
93
100
  > {
94
101
  readonly activePhases: ReadonlySet<AbrPhase>;
102
+ /** Имя правила из VideoRuleName/AudioRuleName; AbrManager фильтрует набор по именам. */
103
+ readonly name: string;
95
104
  init(initContext: IRuleInitContext): void;
96
105
  destroy(): void;
97
106
  execute(context: C): IAbrRuleResolution<T>;
@@ -1,9 +1,8 @@
1
- import type { ExactVideoQuality, IObservable, IValueSubject, Milliseconds, Kbps, Seconds } from "@vkontakte/videoplayer-shared";
1
+ import type { IObservable, IValueSubject, Milliseconds, Seconds } from "@vkontakte/videoplayer-shared";
2
2
  import type { IVideoTrack } from "../../player/types";
3
3
  import type { ITuningConfig } from "../../utils/tuningConfig";
4
4
  interface IConnectData {
5
5
  videoLastDataObtainedTimestamp$: IValueSubject<Milliseconds>;
6
- throughput$: IValueSubject<number>;
7
6
  rtt$: IValueSubject<Milliseconds>;
8
7
  isBuffering$: IObservable<boolean>;
9
8
  isSeeked$: IObservable<boolean>;
@@ -18,7 +17,6 @@ interface IConnectData {
18
17
  declare class StallsManager {
19
18
  private currentStallDuration$;
20
19
  private videoLastDataObtainedTimestamp$;
21
- private throughput$;
22
20
  private rtt$;
23
21
  private tuning;
24
22
  private abrParams;
@@ -26,20 +24,15 @@ declare class StallsManager {
26
24
  private isSeeked$;
27
25
  private isBuffering$;
28
26
  private isPaused;
29
- private maxQualityLimit;
30
27
  private lastUniqueVideoTrackSelected;
31
28
  private currentStallsCount;
32
29
  private sumStallsDuration;
33
30
  private lastStallDuration;
34
31
  private providerStartWatchingTimestamp;
35
32
  private lastUniqueVideoTrackSelectedTimestamp;
36
- private predictedThroughputWithoutData;
37
- private qualityRestrictionTimer;
38
33
  private subscription;
39
34
  severeStallOccurred$: IValueSubject<boolean>;
40
35
  init(data: IConnectData): void;
41
- get videoMaxQualityLimit(): ExactVideoQuality | undefined;
42
- get predictedThroughput(): Kbps;
43
36
  get abrTuningParams(): ITuningConfig["autoTrackSelection"];
44
37
  set lastVideoTrackSelected(lastUniqueVideoTrackSelected: IVideoTrack);
45
38
  destroy(): void;
@@ -20,6 +20,7 @@ export interface DeviceHardware {
20
20
  export declare class DeviceChecker implements Checker {
21
21
  private _displayChecker;
22
22
  private _isMobile;
23
+ private _isSmartTV;
23
24
  private _current;
24
25
  private _iosVersion;
25
26
  private _highEntropyValues;
@@ -31,6 +32,7 @@ export declare class DeviceChecker implements Checker {
31
32
  get current(): CurrentClientDevice;
32
33
  get os(): OS;
33
34
  get details(): DeviceDetails;
35
+ get isSmartTV(): boolean;
34
36
  get hardware(): DeviceHardware;
35
37
  get highEntropyValues(): HighEntropyValues;
36
38
  get isIOS(): boolean;
@@ -42,12 +44,14 @@ export declare class DeviceChecker implements Checker {
42
44
  get isWindows(): boolean;
43
45
  get isLinux(): boolean;
44
46
  get isMobile(): boolean;
47
+ get isTablet(): boolean;
45
48
  get iOSVersion(): number | undefined;
46
49
  detect(): void;
47
50
  private detectHardware;
48
51
  detectGpu(): Promise<void>;
49
52
  private requestGpuInfo;
50
53
  private detectHighEntropyValues;
54
+ private detectSmartTv;
51
55
  private detectDevice;
52
56
  private detectOS;
53
57
  private normalizeOSName;
@@ -19,6 +19,7 @@ export declare enum UADataPlatform {
19
19
  }
20
20
  export interface HighEntropyValues {
21
21
  mobile?: boolean;
22
+ formFactors?: string[];
22
23
  model?: string;
23
24
  platform?: UADataPlatform;
24
25
  platformVersion?: string;
@@ -27,7 +28,8 @@ export interface HighEntropyValues {
27
28
  brands?: UADataBrandItem[];
28
29
  }
29
30
  export type NavigatorWithUserAgentData = Navigator & {
30
- userAgentData: {
31
- getHighEntropyValues: (values: Array<string>) => HighEntropyValues;
31
+ userAgentData?: {
32
+ mobile?: boolean;
33
+ getHighEntropyValues?: (values: Array<string>) => Promise<HighEntropyValues>;
32
34
  };
33
35
  };
@@ -1,15 +1,30 @@
1
- import type { Byte, Kbps, Milliseconds, IValueSubject } from "@vkontakte/videoplayer-shared";
1
+ import type { Byte, Kbps, Milliseconds, IValueSubject, IComponentLogger } from "@vkontakte/videoplayer-shared";
2
2
  import type { ITuningConfig } from "./tuningConfig";
3
3
  declare class ThroughputEstimator {
4
4
  private throughput;
5
5
  private rtt;
6
6
  private subscription;
7
+ private wiring;
8
+ private readonly throughputVarianceProxy$;
9
+ private currentHost;
10
+ private hasThroughputSamples;
11
+ private hasRttSamples;
12
+ private storageReadDone;
7
13
  private tuningConfig;
14
+ private readonly logger?;
15
+ private initialThroughputSource;
16
+ private initialRttSource;
8
17
  private concurrentDownloads;
9
18
  throughput$: IValueSubject<Kbps>;
10
19
  rtt$: IValueSubject<Milliseconds>;
11
20
  rttAdjustedThroughput$: IValueSubject<Kbps>;
12
- constructor(tuning: ITuningConfig["throughputEstimator"]);
21
+ constructor(tuning: ITuningConfig["throughputEstimator"], hostname$?: IValueSubject<string | undefined>, logger?: IComponentLogger);
22
+ private static readLegacyNumber;
23
+ private static resolveInitialThroughput;
24
+ private static resolveInitialRtt;
25
+ private tryAdopt;
26
+ private recreateSmoothed;
27
+ private wireSmoothed;
13
28
  destroy(): void;
14
29
  trackXHR(xhr: XMLHttpRequest): void;
15
30
  trackStream(stream: ReadableStream, isLowLatency?: boolean): void;
@@ -21,10 +36,11 @@ declare class ThroughputEstimator {
21
36
  */
22
37
  addRawThroughput(rate: Kbps): void;
23
38
  addRawRtt(time: Milliseconds): void;
39
+ private markSample;
24
40
  private sanityCheck;
25
41
  get throughputVariance$(): IValueSubject<number>;
26
- private static loadStored;
27
- private static writeStored;
42
+ private static readHostRecord;
43
+ private writeStored;
28
44
  private static validateStored;
29
45
  }
30
46
  export default ThroughputEstimator;
@@ -0,0 +1,8 @@
1
+ import type { ITracer } from "@vkontakte/videoplayer-shared";
2
+ import type { IPlayerEvents, IPlayerExperimental, IPlayerInfo } from "../player/types";
3
+ export declare class UserHappinessController {
4
+ private readonly subscription;
5
+ private readonly observer?;
6
+ constructor(info: IPlayerInfo, events: IPlayerEvents, experimental: IPlayerExperimental, tracer: ITracer, configuredTriggers: unknown);
7
+ destroy(): void;
8
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Пороги метрик довольности пользователя. Источник формул и значений:
3
+ * UVP-11892 и документация метрики:
4
+ * https://confluence.vk.team/pages/viewpage.action?pageId=2056272767
5
+ */
6
+ export declare const MIN_SESSION_TVT_SECONDS = 30;
7
+ export declare const MAX_STALL_RATIO = 1.5;
8
+ export declare const MAX_MOBILE_STALL_RATIO = 3;
9
+ export declare const MAX_FIRST_FRAME_TIME_MS = 2e3;
10
+ export declare const MAX_MOBILE_FIRST_FRAME_TIME_MS = 1300;
11
+ export declare const MIN_QUALITY_SCORE = .8;
12
+ export declare const ALLOWED_DEFICIT_RANK = .2;
@@ -0,0 +1,15 @@
1
+ import type { IValueSubject } from "@vkontakte/videoplayer-shared";
2
+ import type { IPlayerEvents, IPlayerExperimental, IPlayerInfo } from "../../player/types";
3
+ import type { UserHappinessTrigger } from "../userHappinessTriggers";
4
+ import type { UserHappinessQualityPlatform, UserHappinessThresholds } from "./types";
5
+ export declare class UserHappinessObserver {
6
+ private readonly subscription;
7
+ private readonly sessionFinalized$;
8
+ readonly lowQuality$: IValueSubject<boolean>;
9
+ readonly highStallRatio$: IValueSubject<boolean>;
10
+ readonly hasFatalError$: IValueSubject<boolean>;
11
+ readonly slowFirstFrame$: IValueSubject<boolean>;
12
+ constructor(info: IPlayerInfo, events: IPlayerEvents, experimental: IPlayerExperimental, triggers: readonly UserHappinessTrigger[], thresholds: UserHappinessThresholds, qualityPlatform: UserHappinessQualityPlatform);
13
+ destroy(): void;
14
+ finalizeSession(): void;
15
+ }
@@ -0,0 +1,3 @@
1
+ import type { IValueSubject, Subscription } from "@vkontakte/videoplayer-shared";
2
+ import type { IPlayerEvents } from "../../../player/types";
3
+ export declare const createHasFatalError: (events: IPlayerEvents, subscription: Subscription) => IValueSubject<boolean>;
@@ -0,0 +1,3 @@
1
+ import type { IValueObservable, IValueSubject, Milliseconds, Seconds, Subscription } from "@vkontakte/videoplayer-shared";
2
+ import type { IPlayerEvents, IPlayerInfo } from "../../../player/types";
3
+ export declare const createHighStallRatio: (info: IPlayerInfo, events: IPlayerEvents, watchedTimeSeconds$: IValueObservable<Seconds>, sessionFinalized$: IValueObservable<boolean>, subscription: Subscription, maxStallRatio: number, nowInt: () => Milliseconds) => IValueSubject<boolean>;
@@ -0,0 +1,5 @@
1
+ import { VideoQuality } from "@vkontakte/videoplayer-shared";
2
+ export declare const QUALITY_RANKS: Partial<Record<VideoQuality, number>>;
3
+ export declare const DEFAULT_NETWORK_QUALITY_THRESHOLDS: readonly [281, 452, 967, 2300, 2551, 4483, 8965];
4
+ export declare const WEBM_NETWORK_QUALITY_THRESHOLDS: readonly [196.4, 357.7, 595.6, 1108, 2100, 7850, 16770];
5
+ export declare const AV1_NETWORK_QUALITY_THRESHOLDS: readonly [245, 424, 641, 1140, 2048, 3935, 7469];
@@ -0,0 +1,4 @@
1
+ import { type IValueObservable, type IValueSubject, type Seconds, type Subscription } from "@vkontakte/videoplayer-shared";
2
+ import type { IPlayerExperimental, IPlayerInfo } from "../../../../player/types";
3
+ import type { UserHappinessQualityPlatform, UserHappinessThresholds } from "../../types";
4
+ export declare const createLowQuality: (info: IPlayerInfo, experimental: IPlayerExperimental, totalViewTimeSeconds$: IValueObservable<Seconds>, sessionFinalized$: IValueObservable<boolean>, subscription: Subscription, thresholds: Pick<UserHappinessThresholds, "minQualityScore" | "allowedDeficitRank">, qualityPlatform: UserHappinessQualityPlatform) => IValueSubject<boolean>;
@@ -0,0 +1 @@
1
+ export { createLowQuality } from "./createLowQuality";
@@ -0,0 +1,13 @@
1
+ export interface QualityScoreFineStats {
2
+ requiredQualityTotalSeconds: number;
3
+ qualityScoreFineSeconds: number;
4
+ }
5
+ export interface QualityStats {
6
+ totalSeconds: number;
7
+ rankSeconds: number;
8
+ unknownSeconds: number;
9
+ }
10
+ export interface ModeStats {
11
+ totalSeconds: number;
12
+ rankSeconds: number;
13
+ }
@@ -0,0 +1,26 @@
1
+ import type { VideoQuality } from "@vkontakte/videoplayer-shared";
2
+ import { Surface, VideoFormat } from "../../../../player/types";
3
+ import type { UserHappinessQualityPlatform } from "../../types";
4
+ import type { ModeStats, QualityScoreFineStats, QualityStats } from "./types";
5
+ export declare const getQualityRank: (quality: VideoQuality | undefined) => number | undefined;
6
+ /** Ранг цели для fallback по mode_stats, без viewport и сетевых ограничений. */
7
+ export declare const getFallbackModeQualityRank: (surface: Surface, isLive: boolean, availableQualities: VideoQuality[]) => number | undefined;
8
+ /**
9
+ * Восстанавливает required_quality для текущего runtime-интервала по правилам SQL:
10
+ * mode/surface → viewport → max_quality → network_quality_rank.
11
+ */
12
+ export declare const getRequiredQualityRank: (surface: Surface, availableQualities: VideoQuality[], options: {
13
+ viewportSize?: {
14
+ width: number;
15
+ height: number;
16
+ };
17
+ throughputKbps?: number;
18
+ format?: VideoFormat;
19
+ platform: UserHappinessQualityPlatform;
20
+ }) => number | undefined;
21
+ /** Добавляет одну пару actual|required в потоковые агрегаты quality_score_fine сессии. */
22
+ export declare const addRequiredQualityPair: (stats: QualityScoreFineStats, actualQualityRank: number | undefined, requiredQualityRank: number, watchTimeSeconds: number) => void;
23
+ /** Реализация quality_score_fine для агрегированных пар actual|required одной сессии. */
24
+ export declare const getQualityScoreFine: (stats: QualityScoreFineStats) => number | undefined;
25
+ /** Точная проверка finalize_quality из fallback-ветки PDF/SQL. */
26
+ export declare const finalizeQualityFallback: (qualityStats: QualityStats, modeStats: ModeStats, allowedDeficitRank: number) => boolean | undefined;
@@ -0,0 +1,3 @@
1
+ import type { IValueSubject, Milliseconds, Subscription } from "@vkontakte/videoplayer-shared";
2
+ import type { IPlayerEvents } from "../../../player/types";
3
+ export declare const createSlowFirstFrame: (events: IPlayerEvents, subscription: Subscription, maxFirstFrameTimeMs: Milliseconds) => IValueSubject<boolean>;
@@ -0,0 +1,8 @@
1
+ import type { Milliseconds } from "@vkontakte/videoplayer-shared";
2
+ export type UserHappinessQualityPlatform = "web2" | "mvk" | "smart_tv";
3
+ export interface UserHappinessThresholds {
4
+ maxFirstFrameTimeMs: Milliseconds;
5
+ maxStallRatio: number;
6
+ minQualityScore: number;
7
+ allowedDeficitRank: number;
8
+ }
@@ -0,0 +1,2 @@
1
+ import type { UserHappinessQualityPlatform } from "../types";
2
+ export declare const getUserHappinessQualityPlatform: (isMobile: boolean, isSmartTV: boolean) => UserHappinessQualityPlatform;
@@ -0,0 +1,2 @@
1
+ import type { UserHappinessThresholds } from "../types";
2
+ export declare const getUserHappinessThresholds: (isMobile: boolean) => UserHappinessThresholds;
@@ -0,0 +1,3 @@
1
+ import type { IValueSubject, Milliseconds, Seconds, Subscription } from "@vkontakte/videoplayer-shared";
2
+ import type { IPlayerEvents, IPlayerInfo } from "../../../player/types";
3
+ export declare const createWatchedTimeSeconds: (info: IPlayerInfo, events: IPlayerEvents, subscription: Subscription, nowInt: () => Milliseconds) => IValueSubject<Seconds>;