@vkontakte/videoplayer-core 2.0.160-dev.ff8ccb48.0 → 2.0.161-beta.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 (32) hide show
  1. package/es2015.cjs +13 -11
  2. package/es2015.esm.js +20 -18
  3. package/esnext.cjs +13 -11
  4. package/esnext.esm.js +14 -12
  5. package/evergreen.esm.js +34 -32
  6. package/package.json +2 -2
  7. package/types/providers/DashProvider/baseDashProvider.d.ts +1 -0
  8. package/types/providers/DashProvider/lib/buffer.d.ts +1 -0
  9. package/types/providers/DashProvider/lib/fetcher.d.ts +9 -1
  10. package/types/providers/DashProvider/lib/player.d.ts +4 -0
  11. package/types/providers/DashProvider/lib/processNetworkErrors.d.ts +9 -0
  12. package/types/providers/DashProvider/lib/urlsCache.d.ts +23 -0
  13. package/types/providers/DashProviderVirtual/baseDashProvider.d.ts +1 -0
  14. package/types/providers/DashProviderVirtual/lib/buffer/nativeBufferManager.d.ts +2 -1
  15. package/types/providers/DashProviderVirtual/lib/buffer/types.d.ts +2 -1
  16. package/types/providers/DashProviderVirtual/lib/buffer/virtualBuffer/baseVirtualBufferManager.d.ts +2 -2
  17. package/types/providers/DashProviderVirtual/lib/fetcher.d.ts +9 -1
  18. package/types/providers/DashProviderVirtual/lib/player/basePlayer.d.ts +5 -2
  19. package/types/providers/DashProviderVirtual/lib/player/livePlayer.d.ts +1 -1
  20. package/types/providers/DashProviderVirtual/lib/player/player.d.ts +1 -1
  21. package/types/providers/DashProviderVirtual/lib/player/types.d.ts +1 -0
  22. package/types/providers/DashProviderVirtual/lib/processNetworkErrors.d.ts +9 -0
  23. package/types/providers/DashProviderVirtual/lib/urlsCache.d.ts +22 -0
  24. package/types/providers/HlsProvider/index.d.ts +4 -2
  25. package/types/providers/MpegProvider/index.d.ts +1 -1
  26. package/types/providers/ProviderContainer/index.d.ts +5 -1
  27. package/types/providers/ProviderContainer/types.d.ts +5 -1
  28. package/types/providers/utils/Abr/rules/video/upperLimitRule.d.ts +59 -2
  29. package/types/utils/StatefulIterator/index.d.ts +3 -0
  30. package/types/utils/ThroughputEstimator.d.ts +4 -2
  31. package/types/utils/tuningConfig.d.ts +55 -1
  32. package/types/utils/videoFormat.d.ts +2 -2
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vkontakte/videoplayer-core",
3
- "version": "2.0.160-dev.ff8ccb48.0",
3
+ "version": "2.0.161-beta.0",
4
4
  "author": "vk.com",
5
5
  "description": "Videoplayer core library based on the vk.com platform",
6
6
  "homepage": "https://vk.com",
@@ -42,6 +42,6 @@
42
42
  "**/*.d.ts"
43
43
  ],
44
44
  "dependencies": {
45
- "@vkontakte/videoplayer-shared": "1.0.89-dev.ff8ccb48.0"
45
+ "@vkontakte/videoplayer-shared": "1.0.90-beta.0"
46
46
  }
47
47
  }
@@ -18,6 +18,7 @@ type IParams = IProviderParams<IDashURLSource> & {
18
18
  sourceHls?: IHLSSource;
19
19
  forceVideoCodec?: VideoCodec;
20
20
  failedVideoTrack?: Nullable<IVideoTrack>;
21
+ isOnDemand?: boolean;
21
22
  };
22
23
  export default abstract class BaseDashProvider implements IProvider {
23
24
  scene3D: Scene3D | undefined;
@@ -33,6 +33,7 @@ export declare class BufferManager {
33
33
  playingRepresentationInit$: IValueSubject<CommonInit | undefined>;
34
34
  error$: ISubject<IError>;
35
35
  gaps: Gap[];
36
+ updateEnd$: IValueSubject<void>;
36
37
  private subscription;
37
38
  private kind;
38
39
  private initData;
@@ -22,6 +22,9 @@ export interface IParams {
22
22
  compatibilityMode?: boolean;
23
23
  tracer: ITracer;
24
24
  useEnableSubtitlesParam?: boolean;
25
+ handleExtendedNetworkErrorsSet?: boolean;
26
+ useUrlCacheMechanism?: boolean;
27
+ measureNonSegmentRequests?: boolean;
25
28
  }
26
29
  export type Priority = "high" | "low" | "auto";
27
30
  export interface FetchParamsWithUrl extends FetchParams {
@@ -38,6 +41,7 @@ export interface FetchParams {
38
41
  isLowLatency?: boolean;
39
42
  bufferOptimisation?: boolean;
40
43
  ignoreNetworkErrors?: boolean;
44
+ urlCacheMechanismEnabled?: boolean;
41
45
  }
42
46
  export type RepresentationFetchResult = {
43
47
  init: CommonInit | null;
@@ -63,9 +67,13 @@ export declare class Fetcher {
63
67
  private readonly subscription;
64
68
  private compatibilityMode;
65
69
  private useEnableSubtitlesParam;
70
+ private useUrlCacheMechanism;
71
+ private measureNonSegmentRequests;
72
+ private startupPhase;
66
73
  private performanceObserver;
67
74
  private pendingConnectionMetrics;
68
- constructor({ throughputEstimator, requestQuic, tracer, compatibilityMode, useEnableSubtitlesParam }: IParams);
75
+ private handleExtendedNetworkErrorsSet;
76
+ constructor({ throughputEstimator, requestQuic, tracer, compatibilityMode, useEnableSubtitlesParam, handleExtendedNetworkErrorsSet, useUrlCacheMechanism, measureNonSegmentRequests }: IParams);
69
77
  private onHeadersReceived;
70
78
  private setupPerformanceObserver;
71
79
  private processPerformanceResourceTiming;
@@ -19,6 +19,7 @@ export interface Params {
19
19
  compatibilityMode?: boolean;
20
20
  forceVideoCodec?: VideoCodec;
21
21
  tracer: ITracer;
22
+ isOnDemand: boolean;
22
23
  }
23
24
  export declare class Player {
24
25
  private element;
@@ -81,6 +82,7 @@ export declare class Player {
81
82
  private stallWatchdogSubscription;
82
83
  private livePauseWatchdogSubscription;
83
84
  private liveWasInterrupted;
85
+ private isOnDemand;
84
86
  private destroyController;
85
87
  constructor(params: Params);
86
88
  initManifest: ReturnType<typeof abortable<[HTMLVideoElement, string, number]>>;
@@ -113,4 +115,6 @@ export declare class Player {
113
115
  * Возвращает duration в милисекундах.
114
116
  */
115
117
  calculateDurationFromSegments(): number;
118
+ private isAnyBufferUpdating;
119
+ updateSourceDurationFromSegments(): void;
116
120
  }
@@ -0,0 +1,9 @@
1
+ import type { IError, ISubject } from "@vkontakte/videoplayer-shared";
2
+ type Params = {
3
+ txtCode: string;
4
+ error$: ISubject<IError>;
5
+ recoverableError$: ISubject<IError>;
6
+ httpCode?: number | undefined;
7
+ };
8
+ export declare const processNetworkErrors: ({ txtCode, error$, recoverableError$, httpCode }: Params) => void;
9
+ export {};
@@ -0,0 +1,23 @@
1
+ export type CacheManager = {
2
+ get: () => Promise<Response | null>;
3
+ set: (response: Response) => void;
4
+ };
5
+ /**
6
+ * Пытаемся добиться кэширования вызовов.
7
+ * Сейчас есть проблема, что expires и sig меняются, хотя контент не меняется, поэтому ходим мимо кэша.
8
+ * Из за этого обрабатываем кэш вручную.
9
+ */
10
+ export declare const createCacheManager: (url: string) => Promise<CacheManager>;
11
+ export declare function canUseCacheApi(): boolean;
12
+ export declare function normalizeUrl(url: string): string;
13
+ /**
14
+ * Проверяет, не просрочен ли кэшированный ответ
15
+ */
16
+ export declare function isResponseExpired(response: Response): boolean;
17
+ export declare function cloneResponse(response: Response, url: string): Response;
18
+ /**
19
+ * Извлекает expires из оригинального URL (параметр expires1)
20
+ * Предполагается, что expires1 — timestamp в секундах
21
+ */
22
+ export declare function getExpiresFromUrl(url: string): number;
23
+ export declare const dropUrlsCache: () => Promise<void>;
@@ -18,6 +18,7 @@ type IParams = IProviderParams<IDashURLSource> & {
18
18
  sourceHls?: IHLSSource;
19
19
  forceVideoCodec?: VideoCodec;
20
20
  failedVideoTrack?: Nullable<IVideoTrack>;
21
+ isOnDemand?: boolean;
21
22
  };
22
23
  export default abstract class BaseDashProvider implements IProvider {
23
24
  scene3D: Scene3D | undefined;
@@ -1,6 +1,7 @@
1
- import type { IError, IRange, ISubject, Milliseconds } from "@vkontakte/videoplayer-shared";
1
+ import type { IError, IRange, ISubject, IValueSubject, Milliseconds } from "@vkontakte/videoplayer-shared";
2
2
  export declare class NativeBufferManager {
3
3
  error$: ISubject<IError>;
4
+ updateEnd$: IValueSubject<void>;
4
5
  private mediaSource;
5
6
  private sourceBuffer;
6
7
  private sourceBufferTaskQueue;
@@ -32,10 +32,11 @@ export interface IVirtualBufferManager<T extends Segment = Segment> {
32
32
  getForwardBufferRepresentations(currentPosition?: Milliseconds): Map<Representation["id"], T[]>;
33
33
  getForwardPlaybackBufferDuration(currentPosition?: Milliseconds): Milliseconds;
34
34
  getPlaybackBufferState(): IRange<Milliseconds> | null;
35
+ getMutexInfo(): string;
35
36
  setTarget(time: Milliseconds): void;
36
37
  setPreloadOnly(preloadOnly: boolean): void;
37
38
  findSegmentStartTime(position: Milliseconds): Milliseconds | undefined;
38
- calculateDurationFromSegments(representationId: Representation["id"]): Milliseconds;
39
+ calculateDurationFromSegments(): Milliseconds;
39
40
  destroy(): void;
40
41
  get lastDataObtainedTimestamp(): Milliseconds;
41
42
  }
@@ -59,7 +59,6 @@ export declare abstract class BaseVirtualBufferManager<T extends Segment> implem
59
59
  startWith: ReturnType<typeof abortable<[Representation["id"]]>>;
60
60
  switchTo(newRepresentationId: Representation["id"], mode?: SwithRepresentationMode): Promise<void>;
61
61
  protected getSwitchWithAbort(): ReturnType<typeof abortable<[Representation["id"], SwithRepresentationMode], void>>;
62
- switchToOld: ReturnType<typeof abortable<[Representation["id"], boolean | undefined], void>>;
63
62
  prepareSeek(): Promise<void>;
64
63
  seek(position: Milliseconds | undefined): Promise<void>;
65
64
  maintain(currentPosition?: Milliseconds | undefined): Promise<void>;
@@ -69,7 +68,8 @@ export declare abstract class BaseVirtualBufferManager<T extends Segment> implem
69
68
  abort(): Promise<void>;
70
69
  findSegmentStartTime(position: Milliseconds): Milliseconds | undefined;
71
70
  getRepresentationInitialTime(): Seconds;
72
- calculateDurationFromSegments(representationId: Representation["id"]): Milliseconds;
71
+ getMutexInfo(): string;
72
+ calculateDurationFromSegments(): Milliseconds;
73
73
  get lastDataObtainedTimestamp(): Milliseconds;
74
74
  setTarget(time: Milliseconds): void;
75
75
  setPreloadOnly(preloadOnly: boolean): void;
@@ -22,6 +22,9 @@ export interface IParams {
22
22
  compatibilityMode?: boolean;
23
23
  tracer: ITracer;
24
24
  useEnableSubtitlesParam?: boolean;
25
+ handleExtendedNetworkErrorsSet?: boolean;
26
+ useUrlCacheMechanism?: boolean;
27
+ measureNonSegmentRequests?: boolean;
25
28
  }
26
29
  export type Priority = "high" | "low" | "auto";
27
30
  export interface FetchParamsWithUrl extends FetchParams {
@@ -37,6 +40,7 @@ export interface FetchParams {
37
40
  measureThroughput?: boolean;
38
41
  isLowLatency?: boolean;
39
42
  bufferOptimisation?: boolean;
43
+ urlCacheMechanismEnabled?: boolean;
40
44
  }
41
45
  export type RepresentationFetchResult<T extends Segment> = {
42
46
  initMetadata: CommonInit | null;
@@ -62,9 +66,13 @@ export declare class Fetcher {
62
66
  private subscription;
63
67
  private compatibilityMode;
64
68
  private useEnableSubtitlesParam;
69
+ private useUrlCacheMechanism;
70
+ private measureNonSegmentRequests;
71
+ private startupPhase;
65
72
  private performanceObserver;
66
73
  private pendingConnectionMetrics;
67
- constructor({ throughputEstimator, requestQuic, tracer, compatibilityMode, useEnableSubtitlesParam }: IParams);
74
+ private handleExtendedNetworkErrorsSet;
75
+ constructor({ throughputEstimator, requestQuic, tracer, compatibilityMode, useEnableSubtitlesParam, handleExtendedNetworkErrorsSet, useUrlCacheMechanism, measureNonSegmentRequests }: IParams);
68
76
  private onHeadersReceived;
69
77
  private setupPerformanceObserver;
70
78
  private processResourceTiming;
@@ -70,9 +70,10 @@ export declare abstract class BasePlayer {
70
70
  videoLastDataObtainedTimestamp$: IValueSubject<Milliseconds>;
71
71
  fetcherRecoverableError$: Subject<IError>;
72
72
  fetcherError$: Subject<IError>;
73
+ private isOnDemand;
73
74
  protected constructor(params: Params);
74
75
  protected abstract prepareManifestUrlString(manifestBaseUrlString: string, offset: number): string;
75
- protected abstract setSourceDuration(): void;
76
+ protected abstract setSourceInitDuration(): void;
76
77
  protected abstract restoreAfterDeepStall(stallTraceAttributes: Record<string, number>): Promise<void>;
77
78
  initRepresentations: ReturnType<typeof abortable<[Representation["id"], Representation["id"] | undefined, IHLSSource | undefined]>>;
78
79
  initManifest(element: HTMLVideoElement, manifestBaseUrlString: string, offset: number): Promise<void>;
@@ -81,7 +82,6 @@ export declare abstract class BasePlayer {
81
82
  seek(requestedPosition: Milliseconds, forcePrecise?: boolean): Promise<void>;
82
83
  warmUpMediaSourceIfNeeded(position?: Milliseconds | undefined): void;
83
84
  getForwardBufferRepresentations(kind: Exclude<StreamKind, StreamKind.TEXT>): Map<Representation["id"], Segment[]> | undefined;
84
- calculateDurationFromSegments(representationId: Representation["id"]): Milliseconds;
85
85
  get isStreamEnded(): boolean;
86
86
  getStreams(): Manifest["streams"] | undefined;
87
87
  getCodecs(): Manifest["codecs"] | undefined;
@@ -89,6 +89,9 @@ export declare abstract class BasePlayer {
89
89
  setPreloadOnly(preloadOnly: boolean): void;
90
90
  stop(): void;
91
91
  destroy(): void;
92
+ updateSourceDurationFromSegments(): void;
93
+ calculateDurationFromBuffersSegments(): Milliseconds;
94
+ private isAnyBufferUpdating;
92
95
  protected get isStreamNotOpen(): boolean;
93
96
  protected reinitDecoderIfNeeded(force?: boolean): Promise<void>;
94
97
  protected stallWatchdogIntervalCallback(): Promise<void>;
@@ -18,7 +18,7 @@ export declare class LivePlayer extends BasePlayer {
18
18
  initBuffer(): void;
19
19
  protected forcePositionToRepresentationInitialTime(): Promise<void>;
20
20
  protected tick(): Promise<void>;
21
- protected setSourceDuration(): void;
21
+ protected setSourceInitDuration(): void;
22
22
  protected isStallExceeded(timeInWaiting: Milliseconds): boolean;
23
23
  protected restoreAfterDeepStall(stallTraceAttributes: Record<string, number>): Promise<void>;
24
24
  protected updateManifest(): Promise<Manifest | null>;
@@ -4,7 +4,7 @@ export declare class Player extends BasePlayer {
4
4
  constructor(params: Params);
5
5
  protected prepareManifestUrlString(manifestBaseUrlString: string, _offset: number): string;
6
6
  protected initRepresentationSubscriptions(): void;
7
- protected setSourceDuration(): void;
7
+ protected setSourceInitDuration(): void;
8
8
  protected restoreAfterDeepStall(stallTraceAttributes: Record<string, number>): Promise<void>;
9
9
  protected initDisableStallWatchdogSubscription(): void;
10
10
  protected initEndOfVideoSubscription(): void;
@@ -14,4 +14,5 @@ export interface Params {
14
14
  compatibilityMode?: boolean;
15
15
  forceVideoCodec?: VideoCodec;
16
16
  tracer: ITracer;
17
+ isOnDemand?: boolean;
17
18
  }
@@ -0,0 +1,9 @@
1
+ import type { IError, ISubject } from "@vkontakte/videoplayer-shared";
2
+ type Params = {
3
+ txtCode: string;
4
+ error$: ISubject<IError>;
5
+ recoverableError$: ISubject<IError>;
6
+ httpCode?: number | undefined;
7
+ };
8
+ export declare const processNetworkErrors: ({ txtCode, error$, recoverableError$, httpCode }: Params) => void;
9
+ export {};
@@ -0,0 +1,22 @@
1
+ export type CacheManager = {
2
+ get: () => Promise<Response | null>;
3
+ set: (response: Response) => Promise<void>;
4
+ };
5
+ /**
6
+ * Пытаемся добиться кэширования вызовов.
7
+ * Сейчас есть проблема, что expires и sig меняются, хотя контент не меняется, поэтому ходим мимо кэша.
8
+ * Из за этого обрабатываем кэш вручную.
9
+ */
10
+ export declare const createCacheManager: (url: string) => Promise<CacheManager>;
11
+ export declare function canUseCacheApi(): boolean;
12
+ export declare function normalizeUrl(url: string): string;
13
+ /**
14
+ * Проверяет, не просрочен ли кэшированный ответ
15
+ */
16
+ export declare function isResponseExpired(response: Response): boolean;
17
+ export declare function cloneResponse(response: Response, url: string): Response;
18
+ /**
19
+ * Извлекает expires из оригинального URL (параметр expires1)
20
+ * Предполагается, что expires1 — timestamp в секундах
21
+ */
22
+ export declare function getExpiresFromUrl(url: string): number;
@@ -1,6 +1,8 @@
1
1
  import type { IHLSSource } from "../../player/types";
2
2
  import type { IProvider, IProviderParams } from "../types";
3
- type Params = IProviderParams<IHLSSource>;
3
+ type Params = IProviderParams<IHLSSource> & {
4
+ isOnDemand: boolean;
5
+ };
4
6
  export default class HlsProvider implements IProvider {
5
7
  private subscription;
6
8
  private volumeSubscription;
@@ -16,7 +18,7 @@ export default class HlsProvider implements IProvider {
16
18
  private subscribe;
17
19
  destroy(): void;
18
20
  private prepare;
19
- private playIfAllowed;
21
+ protected playIfAllowed(): void;
20
22
  private seek;
21
23
  private syncPlayback;
22
24
  }
@@ -13,7 +13,7 @@ export default class MpegProvider implements IProvider {
13
13
  private subscribe;
14
14
  destroy(): void;
15
15
  private prepare;
16
- private playIfAllowed;
16
+ protected playIfAllowed(): void;
17
17
  private seek;
18
18
  private syncPlayback;
19
19
  private handleQualityLimitTransition;
@@ -19,7 +19,11 @@ interface IParams extends IProviderDependencies {
19
19
  export default class ProviderContainer implements IProviderContainer {
20
20
  current$: IValueSubject<IProviderEntry>;
21
21
  providerError$: ISubject<IError>;
22
- noAvailableProvidersError$: ISubject<VideoFormat | undefined>;
22
+ noAvailableProvidersError$: ISubject<{
23
+ forced?: VideoFormat;
24
+ input: VideoFormat[];
25
+ supported: VideoFormat[];
26
+ }>;
23
27
  volumeMultiplierError$: ISubject<IError>;
24
28
  providerOutput: IProviderOutput;
25
29
  private subscription;
@@ -4,7 +4,11 @@ import type { IProvider, IProviderOutput } from "../types";
4
4
  export interface IProviderContainer {
5
5
  current$: IValueObservable<IProviderEntry>;
6
6
  providerError$: ISubject<IError>;
7
- noAvailableProvidersError$: ISubject<VideoFormat | undefined>;
7
+ noAvailableProvidersError$: ISubject<{
8
+ forced?: VideoFormat;
9
+ input: VideoFormat[];
10
+ supported: VideoFormat[];
11
+ }>;
8
12
  volumeMultiplierError$: ISubject<IError>;
9
13
  providerOutput: IProviderOutput;
10
14
  init(): void;
@@ -3,10 +3,67 @@ 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";
5
5
  import { LimitAboveRule } from "../limitAboveRule";
6
- type UpperLimitsLogsArgs = [limitsAreInvalid: boolean, lowestAvailableQuality: Nullable<ExactVideoQuality>, highestAvailableQuality: Nullable<ExactVideoQuality>, visible: boolean, limits: QualityLimits, backgroundVideoQualityLimit: VideoQuality];
6
+ type UpperLimitsLogsArgs = [limitsAreInvalid: boolean, lowestAvailableQuality: Nullable<ExactVideoQuality>, highestAvailableQuality: Nullable<ExactVideoQuality>, visible: boolean, limits: QualityLimits, backgroundVideoQualityLimit: VideoQuality, effectiveType: string | undefined, connectionDataQualityLimit: ExactVideoQuality | undefined];
7
+ /**
8
+ * Правило верхнего ограничения качества в авто-ABR. Из списка `videoTracksDesc`
9
+ * (отсортирован от высшего к низшему) выбирает самый высокий трек, который
10
+ * одновременно удовлетворяет ВСЕМ активным лимитам сверху. Если подходящего
11
+ * нет — возвращает минимально доступный трек (graceful fallback).
12
+ *
13
+ * Источники лимитов сверху (действуют совместно, победитель — самый строгий):
14
+ *
15
+ * 1. `context.limits.max` — явный пользовательский/интеграционный лимит.
16
+ * Приходит из публичного API `Player.setAutoQualityLimits({ max, min })`
17
+ * (см. `packages/core/src/player/Player.ts`). Слой UI/интеграция пробрасывает
18
+ * его в `desiredState.autoVideoTrackLimits` → `AbrManager.updateContext({ limits })`
19
+ * → `IVideoAbrContext.limits`. `undefined` в `limits` или `limits.max` снимает
20
+ * лимит. Значение типа `ExactVideoQuality` (например, '720p'), трактуется
21
+ * включительно (`<=`). Если лимиты невалидны (min > max, либо min выше
22
+ * highestAvailable, либо max ниже lowestAvailable) — см. `areLimitsInvalid` —
23
+ * лимит игнорируется целиком, чтобы не заблокировать воспроизведение.
24
+ *
25
+ * Реальные кейсы:
26
+ * - Пользователь в настройках плеера выбрал пресет «Экономия трафика»
27
+ * (`PredefinedQualityLimits.TRAFFIC_SAVING`) — хост передаёт
28
+ * `{ max: tuning.autoTrackSelection.trafficSavingLimit }` (Q_480P).
29
+ * - Хост-приложение (мини-апп ВК, лента) ограничивает качество для
30
+ * превью/фонового воспроизведения.
31
+ * - A/B-эксперимент или бизнес-правило режет качество для конкретной
32
+ * категории видео / региона / тарифа.
33
+ *
34
+ * 2. `tuning.autoTrackSelection.backgroundVideoQualityLimit` — применяется
35
+ * только когда `context.visible === false` (плеер вне viewport, по данным
36
+ * `elementVisible$` из `observeElementVisibility`, порог — `activeVideoAreaThreshold`).
37
+ *
38
+ * Реальные кейсы: автовоспроизведение в ленте при прокрутке мимо плеера,
39
+ * PiP/мини-плеер в фоне, неактивная вкладка.
40
+ *
41
+ * 3. `effectiveType` из Network Information API (`navigator.connection`).
42
+ * Активируется `tuning.dash.useConnectionDataUpperLimit`.
43
+ * Приоритет разрешения в `connectionDataQualityLimit`:
44
+ * a. `effectiveType ∈ {'2g', 'slow-2g'}` → `tuning.dash.saveData2gQualityLimit`
45
+ * (Q_360P) — жёсткий лимит на очень слабой сети.
46
+ * b. `effectiveType === '3g'` → `tuning.dash.saveData3gQualityLimit` (Q_480P).
47
+ * c. Иначе — без ограничения.
48
+ *
49
+ * Network Information API доступен только в Chromium (Android, десктоп Chrome/Edge/
50
+ * Opera/Samsung Internet, Android WebView). В Firefox, Safari и Chrome iOS
51
+ * (WebKit) `navigator.connection === undefined` — этот источник лимита
52
+ * неактивен, правило работает только по п.1 и п.2.
53
+ *
54
+ * Реальные кейсы: пользователь в метро / зоне слабого сигнала, пользователь
55
+ * на edge/3G-тарифе.
56
+ *
57
+ * Все три источника комбинируются операцией AND: трек проходит, если
58
+ * `fitsLimits && fitsBackgroundVideoQualityLimit && fitsSaveDataLimit`. Поэтому
59
+ * итоговый потолок = минимум из активных. Нижнюю границу закрывает
60
+ * `LowerLimitRule` (поле `limits.min` здесь не используется).
61
+ */
7
62
  export declare class UpperLimitsRule extends LimitAboveRule<IVideoTrack, IVideoAbrContext, UpperLimitsLogsArgs> implements IAbrRule<IVideoTrack, IVideoAbrContext> {
8
63
  constructor(confidence: RuleConfidence);
9
64
  execute(context: IVideoAbrContext): IAbrRuleResolution<IVideoTrack>;
10
- protected createLogMessage(selectedTrack: IVideoTrack, limitsAreInvalid: boolean, lowestAvailableQuality: Nullable<ExactVideoQuality>, highestAvailableQuality: Nullable<ExactVideoQuality>, visible: boolean, limits: QualityLimits, backgroundVideoQualityLimit: VideoQuality): string;
65
+ protected createLogMessage(selectedTrack: IVideoTrack, limitsAreInvalid: boolean, lowestAvailableQuality: Nullable<ExactVideoQuality>, highestAvailableQuality: Nullable<ExactVideoQuality>, visible: boolean, limits: QualityLimits, backgroundVideoQualityLimit: VideoQuality, effectiveType: string | undefined, connectionDataQualityLimit: ExactVideoQuality | undefined): string;
66
+ private getConnection;
67
+ private resolveConnectionDataQualityLimit;
11
68
  }
12
69
  export {};
@@ -3,9 +3,11 @@ export interface IStatefulIterator<T> {
3
3
  getValue(): T;
4
4
  isCompleted(): boolean;
5
5
  isLast(): boolean;
6
+ all(): T[];
6
7
  }
7
8
  export declare class StatefulIterator<T> implements IStatefulIterator<T> {
8
9
  private readonly length;
10
+ private array;
9
11
  private index;
10
12
  private iterator;
11
13
  private current;
@@ -14,4 +16,5 @@ export declare class StatefulIterator<T> implements IStatefulIterator<T> {
14
16
  getValue(): T;
15
17
  isCompleted(): boolean;
16
18
  isLast(): boolean;
19
+ all(): T[];
17
20
  }
@@ -19,7 +19,9 @@ declare class ThroughputEstimator {
19
19
  */
20
20
  addRawThroughput(rate: Kbps): void;
21
21
  addRawRtt(time: Milliseconds): void;
22
- private static sanityCheck;
23
- private static load;
22
+ private sanityCheck;
23
+ private static loadStored;
24
+ private static writeStored;
25
+ private static validateStored;
24
26
  }
25
27
  export default ThroughputEstimator;
@@ -2,7 +2,7 @@ import type { VideoCodec, 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, Milliseconds, RecursivePartial, Seconds } from "@vkontakte/videoplayer-shared";
5
+ import type { Byte, Kbps, Milliseconds, RecursivePartial, Seconds } 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 = {
@@ -33,6 +33,9 @@ export type ITuningConfig = {
33
33
  basisTrendChangeCount: number;
34
34
  changeThreshold: number;
35
35
  useBrowserEstimation: boolean;
36
+ initialThroughput: Kbps;
37
+ measureNonSegmentRequests: boolean;
38
+ smallSampleMinDuration: Milliseconds;
36
39
  rttPenaltyRequestSize: Byte;
37
40
  streamMinSampleSize: Byte;
38
41
  streamMinSampleTime: Milliseconds;
@@ -42,6 +45,24 @@ export type ITuningConfig = {
42
45
  continuesByteSequenceInterval: Milliseconds;
43
46
  maxLastEvaluationTimeout: Milliseconds;
44
47
  };
48
+ /**
49
+ * TTL + проверка типа сети для кешированного throughput из localStorage.
50
+ * При включении: если сохранённое значение старше storedThroughputTtlMs
51
+ * или тип сети изменился (Wi-Fi→3G) — значение отбрасывается.
52
+ * Предотвращает старт в 4K при переходе с Wi-Fi на мобильную сеть.
53
+ *
54
+ * При OFF (дефолт): читаем/пишем как до фикса — plain number в legacy-ключ
55
+ * one_video_*. Это даёт безопасный rollback JS-версии без потери данных.
56
+ * При ON: новый формат (JSON с timestamp+networkType) → новый ключ vk_uvp_*.
57
+ */
58
+ useThroughputTtl: boolean;
59
+ /**
60
+ * Срок жизни кешированного throughput (мс). По умолчанию 4 часа.
61
+ * После истечения TTL значение из localStorage игнорируется —
62
+ * используется browser estimation или initialThroughput.
63
+ * Применимо только при useThroughputTtl=true.
64
+ */
65
+ storedThroughputTtlMs: Milliseconds;
45
66
  };
46
67
  autoTrackSelection: {
47
68
  bitrateFactorAtEmptyBuffer: number;
@@ -127,6 +148,8 @@ export type ITuningConfig = {
127
148
  useNewRepresentationSwitch: boolean;
128
149
  useDelayedRepresentationSwitch: boolean;
129
150
  useSmartRepresentationSwitch: boolean;
151
+ seekStallExitPolicy: boolean;
152
+ mutexStallExitPolicy: boolean;
130
153
  useFetchPriorityHints: boolean;
131
154
  useAbortMSEFix: boolean;
132
155
  enableBaseUrlSupport: boolean;
@@ -157,7 +180,11 @@ export type ITuningConfig = {
157
180
  useNewFailoverLogic: boolean;
158
181
  useFailoverHostsOnAllProviderCrash: boolean;
159
182
  videoTrackBanAfterProviderFail: Milliseconds;
183
+ saveData3gQualityLimit: ExactVideoQuality;
184
+ saveData2gQualityLimit: ExactVideoQuality;
185
+ useConnectionDataUpperLimit: boolean;
160
186
  videoStreamRepresentaionsFilter: [VideoQuality, number, VideoCodec][];
187
+ filterOnDemandQualityList: boolean;
161
188
  };
162
189
  dashCmafLive: {
163
190
  externalStopControl: boolean;
@@ -238,8 +265,10 @@ export type ITuningConfig = {
238
265
  requestQuick: boolean;
239
266
  /** @deprecated HLS.js удалён, флаг ничего не делает */
240
267
  useHlsJs: boolean;
268
+ disableHlsOnDesktop: boolean;
241
269
  useNativeHLSTextTracks: boolean;
242
270
  useNewSwitchTo: boolean;
271
+ alwaysAbortPreviousSwitch: boolean;
243
272
  useDashProviderVirtual: boolean;
244
273
  useDashProviderVirtualMobile: boolean;
245
274
  useNewAutoSelectVideoTrack: boolean;
@@ -320,6 +349,31 @@ export type ITuningConfig = {
320
349
  * (Скорее всего имеет смысл включить такой же флаг в настройках ui)
321
350
  */
322
351
  reuseOwnVideoElement?: boolean;
352
+ /**
353
+ * Обрабатываем все сетевые ошибки, которые приходят с бэка.
354
+ * на http 500 не падаем в краш.
355
+ */
356
+ handleExtendedNetworkErrorsSet?: boolean;
357
+ /**
358
+ * Кэшируем ответы от сервера руками, так как из за динамичесокй природы некоторых параметров в урле
359
+ * браузер это не может сделать.
360
+ */
361
+ useUrlCacheMechanism?: boolean;
362
+ /**
363
+ * Очищаем кэш урлов при падение провайдера.
364
+ */
365
+ dropUrlCacheWhenProviderCrashed?: boolean;
366
+ /**
367
+ * При смене/реините провайдера игнорируем результат того, смогло видео заиграть или нет.
368
+ */
369
+ ignoreForcePlayResultWhenProviderChanged?: boolean;
370
+ hls: {
371
+ filterOnDemandQualityList: boolean;
372
+ };
373
+ /**
374
+ * Устанавливаем длительность видео на основе последнего сегмента.
375
+ */
376
+ useDurationFromSegments: boolean;
323
377
  };
324
378
  export type IOptionalTuningConfig = RecursivePartial<ITuningConfig>;
325
379
  export declare const fillDefault: (partial: IOptionalTuningConfig) => ITuningConfig;
@@ -1,4 +1,4 @@
1
1
  import { type ISources, VideoFormat } from "../player/types";
2
- export declare const filterAvailableFormats: (formats: VideoFormat[]) => VideoFormat[];
2
+ export declare const filterAvailableFormats: (formats: VideoFormat[], disableHlsOnDesktop?: boolean) => VideoFormat[];
3
3
  export declare const isLiveFormat: (format: VideoFormat) => boolean;
4
- export declare const areValidLiveRecordSources: (sources: ISources) => boolean;
4
+ export declare const areValidLiveRecordSources: (sources: ISources, disableHlsOnDesktop?: boolean) => boolean;