@vkontakte/videoplayer-core 2.0.179-dev.4cee6bcff.0 → 2.0.179-dev.62f578567.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 +17 -17
- package/es2015.esm.js +16 -16
- package/esnext.cjs +16 -16
- package/esnext.esm.js +15 -15
- package/evergreen.esm.js +16 -16
- package/package.json +2 -2
- package/types/player/Player.d.ts +1 -1
- package/types/player/types.d.ts +2 -0
- package/types/providers/DashProvider/lib/buffer.d.ts +2 -0
- package/types/providers/DashProvider/lib/fetcher.d.ts +9 -4
- package/types/providers/DashProvider/lib/player.d.ts +1 -0
- package/types/providers/DashProviderVirtual/lib/buffer/types.d.ts +2 -0
- package/types/providers/DashProviderVirtual/lib/buffer/virtualBuffer/baseVirtualBufferManager.d.ts +3 -1
- package/types/providers/DashProviderVirtual/lib/buffer/virtualBuffer/byteRangeVirtualBufferManager.d.ts +1 -0
- package/types/providers/DashProviderVirtual/lib/fetcher.d.ts +9 -4
- package/types/providers/DashProviderVirtual/lib/player/basePlayer.d.ts +5 -2
- package/types/providers/ProviderContainer/index.d.ts +3 -0
- package/types/providers/types.d.ts +2 -2
- package/types/providers/utils/Abr/abrController.d.ts +7 -4
- package/types/providers/utils/Abr/controllers/historyController.d.ts +67 -0
- package/types/providers/utils/Abr/controllers/oscillationController.d.ts +83 -0
- package/types/providers/utils/Abr/controllers/trackOutcomeController.d.ts +53 -0
- package/types/providers/utils/Abr/rules/video/banBasedOnHistoryRule.d.ts +17 -0
- package/types/providers/utils/Abr/types.d.ts +6 -3
- package/types/providers/utils/Abr/utils.d.ts +1 -0
- package/types/providers/utils/segmentCache/IndexedDbSegmentCacheStorage.d.ts +54 -0
- package/types/providers/utils/segmentCache/MediaSegmentBatchCache.d.ts +59 -0
- package/types/providers/utils/segmentCache/constants.d.ts +20 -0
- package/types/providers/utils/segmentCache/index.d.ts +8 -0
- package/types/providers/utils/segmentCache/segmentCacheDb.d.ts +25 -0
- package/types/providers/utils/segmentCache/segmentCacheUtils.d.ts +25 -0
- package/types/providers/utils/segmentCache/types.d.ts +85 -0
- package/types/utils/tuningConfig.d.ts +8 -9
- package/types/providers/DashProvider/lib/urlsCache.d.ts +0 -23
- package/types/providers/DashProviderVirtual/lib/urlsCache.d.ts +0 -22
- package/types/providers/utils/Abr/trackHistory.d.ts +0 -9
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vkontakte/videoplayer-core",
|
|
3
|
-
"version": "2.0.179-dev.
|
|
3
|
+
"version": "2.0.179-dev.62f578567.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.108-dev.
|
|
45
|
+
"@vkontakte/videoplayer-shared": "1.0.108-dev.62f578567.0"
|
|
46
46
|
}
|
|
47
47
|
}
|
package/types/player/Player.d.ts
CHANGED
|
@@ -30,7 +30,7 @@ export default class Player implements IPlayer {
|
|
|
30
30
|
experimental: PlayerExperimentalImpl;
|
|
31
31
|
private devNullLog;
|
|
32
32
|
private collectDecodingInfoDestroyCb;
|
|
33
|
-
private
|
|
33
|
+
private releaseTimers;
|
|
34
34
|
constructor(tuning?: IOptionalTuningConfig, tracer?: ITracer, playerOptions?: IPlayerOptions);
|
|
35
35
|
private readonly doInit;
|
|
36
36
|
/**
|
package/types/player/types.d.ts
CHANGED
|
@@ -315,12 +315,14 @@ export interface PlayerInfoValues {
|
|
|
315
315
|
*
|
|
316
316
|
* default value: `undefined`
|
|
317
317
|
*/
|
|
318
|
+
currentVirtualVideoBuffer$: StartEnd<Seconds> | undefined;
|
|
318
319
|
currentVideoBuffer$: StartEnd<Seconds> | undefined;
|
|
319
320
|
/**
|
|
320
321
|
* Текущий аудио-буффер плеера (тот; который содержит текущую позицию воспроизведения)
|
|
321
322
|
*
|
|
322
323
|
* default value: `undefined`
|
|
323
324
|
*/
|
|
325
|
+
currentVirtualAudioBuffer$: StartEnd<Seconds> | undefined;
|
|
324
326
|
currentAudioBuffer$: StartEnd<Seconds> | undefined;
|
|
325
327
|
/**
|
|
326
328
|
* Текущий браузерный видео-буффер (тот; который содержит текущую позицию воспроизведения)
|
|
@@ -42,6 +42,7 @@ export declare class BufferManager {
|
|
|
42
42
|
private parsedInitData;
|
|
43
43
|
private representations;
|
|
44
44
|
private segments;
|
|
45
|
+
private segmentIndexMap;
|
|
45
46
|
private allInitsLoaded;
|
|
46
47
|
private activeSegments;
|
|
47
48
|
private forwardBufferRepresentations;
|
|
@@ -110,6 +111,7 @@ export declare class BufferManager {
|
|
|
110
111
|
private feedPreDownloadedFirstSegment;
|
|
111
112
|
private loadByteRangeSegments;
|
|
112
113
|
private prepareByteRangeFetchSegmentParams;
|
|
114
|
+
private buildCacheMetadata;
|
|
113
115
|
private prepareTemplateFetchSegmentParams;
|
|
114
116
|
private abortActiveSegments;
|
|
115
117
|
private onSomeTemplateDataLoaded;
|
|
@@ -4,6 +4,7 @@ import type { Byte, IValueSubject, ISubject, Milliseconds, IRange, ITracer, IErr
|
|
|
4
4
|
import { abortable } from "@vkontakte/videoplayer-shared";
|
|
5
5
|
import type { ExactVideoQuality } from "@vkontakte/videoplayer-shared";
|
|
6
6
|
import type { CommonInit, GenericContainerParser, Segment, SegmentReference } from "../../utils/parsers/types";
|
|
7
|
+
import type { ISegmentCacheStorage, CacheMetadata, SegmentCacheMode } from "../../utils/segmentCache";
|
|
7
8
|
declare global {
|
|
8
9
|
interface Navigator {
|
|
9
10
|
connection: {
|
|
@@ -24,12 +25,13 @@ export interface IParams {
|
|
|
24
25
|
tracer: ITracer;
|
|
25
26
|
useEnableSubtitlesParam?: boolean;
|
|
26
27
|
handleExtendedNetworkErrorsSet?: boolean;
|
|
27
|
-
useUrlCacheMechanism?: boolean;
|
|
28
28
|
measureNonSegmentRequests?: boolean;
|
|
29
29
|
measureFastSamples?: boolean;
|
|
30
30
|
cacheHitTtfbMaxMs?: Milliseconds;
|
|
31
31
|
preloadFirstSegment?: boolean;
|
|
32
32
|
maxQualityForFirstSegmentPreload?: ExactVideoQuality;
|
|
33
|
+
segmentCacheService?: ISegmentCacheStorage;
|
|
34
|
+
segmentCacheMode?: SegmentCacheMode;
|
|
33
35
|
}
|
|
34
36
|
export type Priority = "high" | "low" | "auto";
|
|
35
37
|
export interface FetchParamsWithUrl extends FetchParams {
|
|
@@ -46,8 +48,8 @@ export interface FetchParams {
|
|
|
46
48
|
isLowLatency?: boolean;
|
|
47
49
|
bufferOptimisation?: boolean;
|
|
48
50
|
ignoreNetworkErrors?: boolean;
|
|
49
|
-
urlCacheMechanismEnabled?: boolean;
|
|
50
51
|
representationHeight?: number;
|
|
52
|
+
cacheMetadata?: CacheMetadata;
|
|
51
53
|
}
|
|
52
54
|
export type RepresentationFetchResult = {
|
|
53
55
|
init: CommonInit | null;
|
|
@@ -74,17 +76,18 @@ export declare class Fetcher {
|
|
|
74
76
|
private readonly subscription;
|
|
75
77
|
private compatibilityMode;
|
|
76
78
|
private useEnableSubtitlesParam;
|
|
77
|
-
private useUrlCacheMechanism;
|
|
78
79
|
private measureNonSegmentRequests;
|
|
79
80
|
private measureFastSamples;
|
|
80
81
|
private cacheHitTtfbMaxMs;
|
|
81
82
|
private preloadFirstSegment;
|
|
82
83
|
private maxQualityForFirstSegmentPreload;
|
|
84
|
+
private segmentCacheService;
|
|
85
|
+
private mediaBatchCache;
|
|
83
86
|
private startupPhase;
|
|
84
87
|
private performanceObserver;
|
|
85
88
|
private pendingConnectionMetrics;
|
|
86
89
|
private handleExtendedNetworkErrorsSet;
|
|
87
|
-
constructor({ throughputEstimator, requestQuic, tracer, compatibilityMode, useEnableSubtitlesParam, handleExtendedNetworkErrorsSet,
|
|
90
|
+
constructor({ throughputEstimator, requestQuic, tracer, compatibilityMode, useEnableSubtitlesParam, handleExtendedNetworkErrorsSet, measureNonSegmentRequests, measureFastSamples, cacheHitTtfbMaxMs, preloadFirstSegment, maxQualityForFirstSegmentPreload, segmentCacheService, segmentCacheMode }: IParams);
|
|
88
91
|
private onHeadersReceived;
|
|
89
92
|
private setupPerformanceObserver;
|
|
90
93
|
private processPerformanceResourceTiming;
|
|
@@ -95,6 +98,8 @@ export declare class Fetcher {
|
|
|
95
98
|
fetchManifest: ReturnType<typeof abortable<[string], string | null>>;
|
|
96
99
|
fetch: ReturnType<typeof abortable<[string, FetchParams], ArrayBuffer | null>>;
|
|
97
100
|
fetchRepresentation(segmentReference: SegmentReference, parser: GenericContainerParser<unknown>, fetchParams: FetchParams): Promise<RepresentationFetchResult | null>;
|
|
101
|
+
/** Скипнутые сегменты не записаны в кэш — при следующем запросе региона докачаются как miss. */
|
|
102
|
+
private traceSkippedCacheSegments;
|
|
98
103
|
destroy(): void;
|
|
99
104
|
private fetchByteRangeRepresentation;
|
|
100
105
|
private fetchTemplateRepresentation;
|
|
@@ -40,6 +40,7 @@ export declare class Player {
|
|
|
40
40
|
private subscriptionRemovable;
|
|
41
41
|
private representationSubscription;
|
|
42
42
|
private fetcher;
|
|
43
|
+
private segmentCacheService;
|
|
43
44
|
state$: StateMachine<State>;
|
|
44
45
|
currentVideoRepresentation$: IValueSubject<Representation["id"] | undefined>;
|
|
45
46
|
currentVideoRepresentationInit$: IValueSubject<CommonInit | undefined>;
|
|
@@ -3,6 +3,7 @@ import type { CommonInit, Manifest, Representation, Segment } from "../../../uti
|
|
|
3
3
|
import type { Fetcher } from "../fetcher";
|
|
4
4
|
import type { ITuningConfig } from "../../../../utils/tuningConfig";
|
|
5
5
|
import type { VideoSegmentLoadProgress } from "../../../utils/Abr/types";
|
|
6
|
+
import type { ISegmentCacheStorage } from "../../../utils/segmentCache";
|
|
6
7
|
export type TRepresentationSwitchMode = "lazy" | "force";
|
|
7
8
|
export declare enum SwithRepresentationMode {
|
|
8
9
|
Lazy = "lazy",
|
|
@@ -15,6 +16,7 @@ export interface Dependencies {
|
|
|
15
16
|
tuning: ITuningConfig;
|
|
16
17
|
compatibilityMode?: boolean;
|
|
17
18
|
manifest: Manifest | null;
|
|
19
|
+
segmentCacheService?: ISegmentCacheStorage;
|
|
18
20
|
getCurrentPosition(): Milliseconds | undefined;
|
|
19
21
|
getCurrentStallDuration(): Milliseconds;
|
|
20
22
|
isActiveLowLatency(): boolean;
|
package/types/providers/DashProviderVirtual/lib/buffer/virtualBuffer/baseVirtualBufferManager.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { Fetcher, FetchParamsWithUrl, Priority, RepresentationFetchResult }
|
|
|
2
2
|
import type { CommonInit, ContainerParser, Representation, Segment } from "../../../../utils/parsers/types";
|
|
3
3
|
import { StreamKind } from "../../../../utils/parsers/types";
|
|
4
4
|
import type { ITuningConfig } from "../../../../../utils/tuningConfig";
|
|
5
|
+
import type { ISegmentCacheStorage } from "../../../../utils/segmentCache";
|
|
5
6
|
import type { Byte, IError, IRange, ISubject, ITracer, IValueSubject, Milliseconds, Seconds } from "@vkontakte/videoplayer-shared";
|
|
6
7
|
import { abortable, Subscription } from "@vkontakte/videoplayer-shared";
|
|
7
8
|
import type { NativeBufferManager } from "../nativeBufferManager";
|
|
@@ -19,6 +20,7 @@ export declare abstract class BaseVirtualBufferManager<T extends Segment> implem
|
|
|
19
20
|
protected readonly fetcher: Fetcher;
|
|
20
21
|
protected readonly tracer: ITracer;
|
|
21
22
|
protected readonly tuning: ITuningConfig;
|
|
23
|
+
protected readonly segmentCacheService: ISegmentCacheStorage | undefined;
|
|
22
24
|
protected representations: Map<Representation["id"], Representation>;
|
|
23
25
|
protected playingRepresentationId: Representation["id"] | undefined;
|
|
24
26
|
protected downloadingRepresentationId: Representation["id"] | undefined;
|
|
@@ -54,7 +56,7 @@ export declare abstract class BaseVirtualBufferManager<T extends Segment> implem
|
|
|
54
56
|
protected readonly getCurrentPosition: () => Milliseconds | undefined;
|
|
55
57
|
protected readonly getCurrentStallDuration: () => Milliseconds | undefined;
|
|
56
58
|
protected brokenSegmentAppendDetected: boolean;
|
|
57
|
-
protected constructor(kind: StreamKind, nativeBufferManager: NativeBufferManager, representations: Representation[], { fetcher, tracer, tuning, getCurrentPosition, getCurrentStallDuration, manifest }: Dependencies);
|
|
59
|
+
protected constructor(kind: StreamKind, nativeBufferManager: NativeBufferManager, representations: Representation[], { fetcher, tracer, tuning, getCurrentPosition, getCurrentStallDuration, manifest, segmentCacheService }: Dependencies);
|
|
58
60
|
protected abstract loadItems(itemsToLoad: IBufferPlaybackQueueItem<T>[], representation: Representation, priority?: Priority): Promise<void>;
|
|
59
61
|
protected abstract selectItemsToLoad(): IBufferPlaybackQueueItem<T>[];
|
|
60
62
|
protected abstract prepareFetchParams(items: IBufferPlaybackQueueItem<T>[], representation: Representation): FetchParamsWithUrl;
|
|
@@ -8,6 +8,7 @@ export declare class ByteRangeVirtualBufferManager extends BaseVirtualBufferMana
|
|
|
8
8
|
protected override loadItems(itemsToLoad: IBufferPlaybackQueueItem<ByteRangeSegment>[], representation: Representation, priority?: Priority): Promise<void>;
|
|
9
9
|
protected override selectItemsToLoad(): IBufferPlaybackQueueItem<ByteRangeSegment>[];
|
|
10
10
|
protected override prepareFetchParams(items: IBufferPlaybackQueueItem<ByteRangeSegment>[], representation: Representation): FetchParamsWithUrl;
|
|
11
|
+
private buildCacheMetadata;
|
|
11
12
|
/**
|
|
12
13
|
* Закидываем в буфер сегменты атомарнее чем сегмент целиком. Например, по боксам в мпеге и по блокам в вебме.
|
|
13
14
|
* Таким образом не ждём его полной загрузки и готовы играть его намного быстрее
|
|
@@ -4,6 +4,7 @@ import type { Byte, IError, IRange, ISubject, ITracer, IValueSubject, Millisecon
|
|
|
4
4
|
import { abortable } from "@vkontakte/videoplayer-shared";
|
|
5
5
|
import type { ExactVideoQuality } from "@vkontakte/videoplayer-shared";
|
|
6
6
|
import type { CommonInit, GenericContainerParser, Segment, SegmentReference, StreamKind } from "../../utils/parsers/types";
|
|
7
|
+
import type { ISegmentCacheStorage, CacheMetadata, SegmentCacheMode } from "../../utils/segmentCache";
|
|
7
8
|
declare global {
|
|
8
9
|
interface Navigator {
|
|
9
10
|
connection: {
|
|
@@ -24,12 +25,13 @@ export interface IParams {
|
|
|
24
25
|
tracer: ITracer;
|
|
25
26
|
useEnableSubtitlesParam?: boolean;
|
|
26
27
|
handleExtendedNetworkErrorsSet?: boolean;
|
|
27
|
-
useUrlCacheMechanism?: boolean;
|
|
28
28
|
measureNonSegmentRequests?: boolean;
|
|
29
29
|
measureFastSamples?: boolean;
|
|
30
30
|
cacheHitTtfbMaxMs?: Milliseconds;
|
|
31
31
|
preloadFirstSegment?: boolean;
|
|
32
32
|
maxQualityForFirstSegmentPreload?: ExactVideoQuality;
|
|
33
|
+
segmentCacheService?: ISegmentCacheStorage;
|
|
34
|
+
segmentCacheMode?: SegmentCacheMode;
|
|
33
35
|
}
|
|
34
36
|
export type Priority = "high" | "low" | "auto";
|
|
35
37
|
export interface FetchParamsWithUrl extends FetchParams {
|
|
@@ -45,8 +47,8 @@ export interface FetchParams {
|
|
|
45
47
|
measureThroughput?: boolean;
|
|
46
48
|
isLowLatency?: boolean;
|
|
47
49
|
bufferOptimisation?: boolean;
|
|
48
|
-
urlCacheMechanismEnabled?: boolean;
|
|
49
50
|
kind: StreamKind;
|
|
51
|
+
cacheMetadata?: CacheMetadata;
|
|
50
52
|
}
|
|
51
53
|
export type RepresentationFetchResult<T extends Segment> = {
|
|
52
54
|
initMetadata: CommonInit | null;
|
|
@@ -73,17 +75,18 @@ export declare class Fetcher {
|
|
|
73
75
|
private subscription;
|
|
74
76
|
private compatibilityMode;
|
|
75
77
|
private useEnableSubtitlesParam;
|
|
76
|
-
private useUrlCacheMechanism;
|
|
77
78
|
private measureNonSegmentRequests;
|
|
78
79
|
private measureFastSamples;
|
|
79
80
|
private cacheHitTtfbMaxMs;
|
|
80
81
|
private preloadFirstSegment;
|
|
81
82
|
private maxQualityForFirstSegmentPreload;
|
|
83
|
+
private segmentCacheService;
|
|
84
|
+
private mediaBatchCache;
|
|
82
85
|
private startupPhase;
|
|
83
86
|
private performanceObserver;
|
|
84
87
|
private pendingConnectionMetrics;
|
|
85
88
|
private handleExtendedNetworkErrorsSet;
|
|
86
|
-
constructor({ throughputEstimator, requestQuic, tracer, compatibilityMode, useEnableSubtitlesParam, handleExtendedNetworkErrorsSet,
|
|
89
|
+
constructor({ throughputEstimator, requestQuic, tracer, compatibilityMode, useEnableSubtitlesParam, handleExtendedNetworkErrorsSet, measureNonSegmentRequests, measureFastSamples, cacheHitTtfbMaxMs, preloadFirstSegment, maxQualityForFirstSegmentPreload, segmentCacheService, segmentCacheMode }: IParams);
|
|
87
90
|
private onHeadersReceived;
|
|
88
91
|
private setupPerformanceObserver;
|
|
89
92
|
private processResourceTiming;
|
|
@@ -94,6 +97,8 @@ export declare class Fetcher {
|
|
|
94
97
|
fetchManifest: ReturnType<typeof abortable<[string], string | null>>;
|
|
95
98
|
fetch: ReturnType<typeof abortable<[string, FetchParams], ArrayBuffer | null>>;
|
|
96
99
|
fetchRepresentation<T extends Segment>(segmentReference: SegmentReference, parser: GenericContainerParser<unknown>, dowbloadAbortSignal: AbortSignal, priority?: Priority, representationHeight?: number, kind?: StreamKind): Promise<RepresentationFetchResult<T> | null | undefined>;
|
|
100
|
+
/** Скипнутые сегменты не записаны в кэш — при следующем запросе региона докачаются как miss. */
|
|
101
|
+
private traceSkippedCacheSegments;
|
|
97
102
|
destroy(): void;
|
|
98
103
|
private fetchByteRangeRepresentation;
|
|
99
104
|
private fetchTemplateRepresentation;
|
|
@@ -9,6 +9,7 @@ import type { IError, IRange, ISubject, ISubscription, ITracer, IValueSubject, M
|
|
|
9
9
|
import { abortable, Subject, Subscription, SubscriptionRemovable } from "@vkontakte/videoplayer-shared";
|
|
10
10
|
import type { VideoSegmentLoadProgress } from "../../../utils/Abr/types";
|
|
11
11
|
import { Fetcher } from "../fetcher";
|
|
12
|
+
import type { ISegmentCacheStorage } from "../../../utils/segmentCache";
|
|
12
13
|
import type { Dependencies, IVirtualBufferManager, SwithRepresentationMode } from "../buffer/types";
|
|
13
14
|
import type { Params } from "./types";
|
|
14
15
|
import { State } from "./types";
|
|
@@ -34,6 +35,7 @@ export declare abstract class BasePlayer {
|
|
|
34
35
|
protected subscriptionRemovable: SubscriptionRemovable;
|
|
35
36
|
protected representationSubscription: Subscription;
|
|
36
37
|
protected fetcher: Fetcher;
|
|
38
|
+
protected segmentCacheService: ISegmentCacheStorage | undefined;
|
|
37
39
|
protected forceEnded$: ISubject<void>;
|
|
38
40
|
protected stallWatchdogSubscription: ISubscription | undefined;
|
|
39
41
|
protected destroyController: AbortController;
|
|
@@ -62,10 +64,11 @@ export declare abstract class BasePlayer {
|
|
|
62
64
|
liveSeekableDuration$: IValueSubject<Milliseconds>;
|
|
63
65
|
liveAvailabilityStartTime$: IValueSubject<Milliseconds>;
|
|
64
66
|
liveStreamStatus$: IValueSubject<LiveStreamStatus | undefined>;
|
|
65
|
-
|
|
66
|
-
|
|
67
|
+
currentVirtualVideoBuffer$: IValueSubject<IRange<Seconds>>;
|
|
68
|
+
currentVirtualAudioBuffer$: IValueSubject<IRange<Seconds>>;
|
|
67
69
|
bufferLength$: IValueSubject<Milliseconds>;
|
|
68
70
|
nativeBufferLength$: IValueSubject<Milliseconds>;
|
|
71
|
+
nativeVideoBufferLength$: IValueSubject<IRange<Seconds>>;
|
|
69
72
|
nativeAudioBufferLength$: IValueSubject<IRange<Seconds>>;
|
|
70
73
|
liveLatency$: IValueSubject<Milliseconds | undefined>;
|
|
71
74
|
liveLoadBufferLength$: IValueSubject<Milliseconds>;
|
|
@@ -37,6 +37,7 @@ export default class ProviderContainer implements IProviderContainer {
|
|
|
37
37
|
private currentProviderStarted;
|
|
38
38
|
private volumeMultiplierManager;
|
|
39
39
|
private dashMaxTvVideoQuality;
|
|
40
|
+
private segmentCacheCleared;
|
|
40
41
|
private mayday;
|
|
41
42
|
private maydayStatistics;
|
|
42
43
|
constructor(params: IParams);
|
|
@@ -50,6 +51,8 @@ export default class ProviderContainer implements IProviderContainer {
|
|
|
50
51
|
private destroyProvider;
|
|
51
52
|
private handleMaydayRecommendation;
|
|
52
53
|
private applyErrorSideEffects;
|
|
54
|
+
/** Битые данные в кэше могут вызывать повторные ошибки после реинита — очищаем кэш целиком. */
|
|
55
|
+
private clearSegmentCacheOnError;
|
|
53
56
|
private createProvider;
|
|
54
57
|
private createScreenProvider;
|
|
55
58
|
private createChromecastProvider;
|
|
@@ -81,8 +81,8 @@ export interface IProviderOutput {
|
|
|
81
81
|
autoVideoTrackLimits$: IValueSubject<QualityLimits | undefined>;
|
|
82
82
|
autoVideoTrackLimitingAvailable$: IValueSubject<boolean>;
|
|
83
83
|
canChangePlaybackSpeed$: IValueSubject<boolean | undefined>;
|
|
84
|
-
|
|
85
|
-
|
|
84
|
+
currentVirtualVideoBuffer$: IValueSubject<IRange<Seconds> | undefined>;
|
|
85
|
+
currentVirtualAudioBuffer$: IValueSubject<IRange<Seconds> | undefined>;
|
|
86
86
|
currentNativeVideoBuffer$: IValueSubject<IRange<Seconds> | undefined>;
|
|
87
87
|
currentNativeAudioBuffer$: IValueSubject<IRange<Seconds> | undefined>;
|
|
88
88
|
totalBufferDuration$: IValueSubject<Milliseconds | undefined>;
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import type { AbrLimitSources, IAbrController, IAbrRule, IBaseAbrControllerContext, IRuleInitContext, RuleLogData } from "./types";
|
|
2
2
|
import type { IBaseTrack } from "../../../player/types";
|
|
3
|
+
import { HistoryController } from "./controllers/historyController";
|
|
3
4
|
export declare const formatRuleLog: ({ name, ...logData }: RuleLogData) => string;
|
|
4
5
|
export default class AbrController<
|
|
5
6
|
T extends IBaseTrack,
|
|
6
7
|
C extends IBaseAbrControllerContext
|
|
7
8
|
> implements IAbrController<T> {
|
|
8
|
-
private
|
|
9
|
+
private historyController;
|
|
9
10
|
private rules;
|
|
10
11
|
private _context;
|
|
11
12
|
private _limitSources;
|
|
13
|
+
constructor(historyController?: HistoryController<T>);
|
|
12
14
|
get context(): C;
|
|
13
15
|
get limitSources(): AbrLimitSources;
|
|
14
16
|
init(rules: IAbrRule<T, C>[], initContext: IRuleInitContext): void;
|
|
@@ -17,7 +19,8 @@ export default class AbrController<
|
|
|
17
19
|
autoSelectTrack(rules?: IAbrRule<T, C>[]): T;
|
|
18
20
|
private traceQualitySwitch;
|
|
19
21
|
private isLowQuality;
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
22
|
+
/** Полный сброс истории: cooldown, осцилляции и баны. */
|
|
23
|
+
resetHistory(): void;
|
|
24
|
+
resetOscillation(): void;
|
|
25
|
+
resetTrackOutcome(): void;
|
|
23
26
|
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { IBaseTrack } from "../../../../player/types";
|
|
2
|
+
import type { IObservable } from "@vkontakte/videoplayer-shared";
|
|
3
|
+
import type { ITuningConfig } from "../../../../utils/tuningConfig";
|
|
4
|
+
import type { IBaseAbrControllerContext } from "../types";
|
|
5
|
+
import type { TrackBans } from "./trackOutcomeController";
|
|
6
|
+
import type { OscillationReturnStats } from "./oscillationController";
|
|
7
|
+
import type { TrackOutcomeStats } from "./trackOutcomeController";
|
|
8
|
+
/** Телеметрия истории переключений: разрезы осцилляции и исходов (баны, испытательный срок). */
|
|
9
|
+
export type HistoryStats = {
|
|
10
|
+
oscillation: OscillationReturnStats;
|
|
11
|
+
outcome: TrackOutcomeStats | undefined;
|
|
12
|
+
};
|
|
13
|
+
type SelectBasedOnHistoryParams<T extends IBaseTrack> = {
|
|
14
|
+
candidate: T;
|
|
15
|
+
context: IBaseAbrControllerContext;
|
|
16
|
+
};
|
|
17
|
+
type ConstructorParams = {
|
|
18
|
+
/**
|
|
19
|
+
* Конфиг автоподбора качества; при отсутствии — только cooldown включается.
|
|
20
|
+
* oscillationCooldownEnabled включает влияние осцилляционного замка на выбор,
|
|
21
|
+
* trackOutcomeEnabled — применение банов; сбор журнала и исходов идёт всегда.
|
|
22
|
+
*/
|
|
23
|
+
autoTrackSelection?: ITuningConfig["autoTrackSelection"];
|
|
24
|
+
severeStallOccurred$?: IObservable<boolean>;
|
|
25
|
+
isSeeked$?: IObservable<boolean>;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Решает, допускается ли переключение дорожки: трековый cooldown и доказанная осцилляция.
|
|
29
|
+
* Владеет историей выборов дорожек, детекцией осцилляции (OscillationController)
|
|
30
|
+
* и исходами переключений (TrackOutcomeController) — в исходы попадают только выполненные
|
|
31
|
+
* переключения. Состояние ведётся по id дорожек одного вида (видео или аудио) —
|
|
32
|
+
* общий инстанс для разных видов смешал бы осцилляции и баны.
|
|
33
|
+
*/
|
|
34
|
+
export declare class HistoryController<T extends IBaseTrack = IBaseTrack> {
|
|
35
|
+
private lastApprovedTrack;
|
|
36
|
+
private lastSelectedAtById;
|
|
37
|
+
private readonly oscillationController;
|
|
38
|
+
private readonly outcomeController;
|
|
39
|
+
private readonly oscillationLockEnabled;
|
|
40
|
+
private readonly trackOutcomeEnabled;
|
|
41
|
+
private readonly subscription;
|
|
42
|
+
constructor({ autoTrackSelection, severeStallOccurred$, isSeeked$ }?: ConstructorParams);
|
|
43
|
+
get last(): T | undefined;
|
|
44
|
+
/**
|
|
45
|
+
* Полный сценарий гейтирования против истории переключений: решение по кандидату
|
|
46
|
+
* (cooldown / осцилляция), обновление всей истории (выборы, журнал, исходы)
|
|
47
|
+
* и телеметрия при блоке. Возвращает трек, который следует выбрать.
|
|
48
|
+
*/
|
|
49
|
+
selectBasedOnHistory({ candidate, context }: SelectBasedOnHistoryParams<T>): T;
|
|
50
|
+
private decide;
|
|
51
|
+
private isUpgrade;
|
|
52
|
+
private isTrackOnCooldown;
|
|
53
|
+
/** Полный сброс: cooldown, журнал осцилляций и исходы переключений. */
|
|
54
|
+
clear(): void;
|
|
55
|
+
/** Журнал фиксирует отклонённое намерение, исходы не трогаются: испытательный срок не начинался. */
|
|
56
|
+
private rejectSwitch;
|
|
57
|
+
private commitSwitch;
|
|
58
|
+
getActiveBans(): TrackBans | undefined;
|
|
59
|
+
/** Телеметрия истории: статистика осцилляций и исходов переключений (у аудио outcome-контроллера нет). */
|
|
60
|
+
getStats(): HistoryStats;
|
|
61
|
+
/** Телеметрия и лог заблокированного переключения; снапшот контекста — для состояния сети/буфера. */
|
|
62
|
+
private reportBlockedSwitch;
|
|
63
|
+
resetOscillation(): void;
|
|
64
|
+
resetOutcome(): void;
|
|
65
|
+
destroy(): void;
|
|
66
|
+
}
|
|
67
|
+
export {};
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import type { IBaseTrack } from "../../../../player/types";
|
|
2
|
+
import type { Milliseconds } from "@vkontakte/videoplayer-shared";
|
|
3
|
+
export declare const OSCILLATION_WINDOW_MS = 6e4;
|
|
4
|
+
export declare const OSCILLATION_MIN_RETURNS = 2;
|
|
5
|
+
export declare enum BlockReason {
|
|
6
|
+
TrackCooldown = "track-cooldown",
|
|
7
|
+
OscillationCooldown = "oscillation-cooldown"
|
|
8
|
+
}
|
|
9
|
+
export type SwitchDirection = "up" | "down";
|
|
10
|
+
export type SwitchEvent = {
|
|
11
|
+
kind: "switch";
|
|
12
|
+
fromId: IBaseTrack["id"];
|
|
13
|
+
toId: IBaseTrack["id"];
|
|
14
|
+
direction: SwitchDirection;
|
|
15
|
+
/** true — отклонённое намерение; отсутствие флага — выполненное переключение */
|
|
16
|
+
rejected?: boolean;
|
|
17
|
+
timestamp: Milliseconds;
|
|
18
|
+
};
|
|
19
|
+
export type SwitchJournalEntry = SwitchEvent | {
|
|
20
|
+
kind: "stallStart" | "stallEnd";
|
|
21
|
+
timestamp: Milliseconds;
|
|
22
|
+
};
|
|
23
|
+
export type SwitchRecordParams = {
|
|
24
|
+
fromId: IBaseTrack["id"];
|
|
25
|
+
toId: IBaseTrack["id"];
|
|
26
|
+
direction: SwitchDirection;
|
|
27
|
+
rejected?: boolean;
|
|
28
|
+
};
|
|
29
|
+
export type OscillationReturnStats = {
|
|
30
|
+
maxTrackReturns: number;
|
|
31
|
+
sumTrackReturns: number;
|
|
32
|
+
maxPairReturns: number;
|
|
33
|
+
sumPairReturns: number;
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Осцилляция — метание качества туда-сюда (флаппинг): ABR гоняет качество
|
|
37
|
+
* 720p → 480p → 720p → 480p, обычно потому что оценка канала скачет вокруг границы
|
|
38
|
+
* двух качеств: чуть выросла — поднялись, чуть просела — упали. Вреден тем, что каждое
|
|
39
|
+
* переключение — это сброс загружаемых сегментов и риск буферизации, а зритель видит
|
|
40
|
+
* «пилящую» картинку.
|
|
41
|
+
*
|
|
42
|
+
* Владеет журналом последних событий ABR: переключения дорожек (выполненные и отклонённые
|
|
43
|
+
* cooldown намерения) и stall start/end. Журнал хранит порядок событий (в отличие от истории
|
|
44
|
+
* выборов с таймстампами) — только по порядку можно отличить флаппинг от разовых событий.
|
|
45
|
+
* Детектор isOscillationProven отвечает на вопрос «доказана ли осцилляция» — по нему
|
|
46
|
+
* AbrController решает, применять ли трековый cooldown. События stall/seek раздаёт
|
|
47
|
+
* HistoryController. Подробно: docs/architecture/abr/switch-journal.md
|
|
48
|
+
*/
|
|
49
|
+
export declare class OscillationController {
|
|
50
|
+
private buffer;
|
|
51
|
+
private lastEntry;
|
|
52
|
+
recordStall(isOccurred: boolean): void;
|
|
53
|
+
recordSwitch({ fromId, toId, direction, rejected }: SwitchRecordParams): void;
|
|
54
|
+
entries(): readonly SwitchJournalEntry[];
|
|
55
|
+
reset(): void;
|
|
56
|
+
isOscillationProven(): boolean;
|
|
57
|
+
/**
|
|
58
|
+
* Телеметрия near-miss к доказательству осцилляции: немедленные откаты в окне журнала,
|
|
59
|
+
* просуммированные тремя способами — по возвращённой дорожке, по неупорядоченной паре
|
|
60
|
+
* дорожек пинг-понга и итогово (max/сумма). Показывает форму пилообразной серии там,
|
|
61
|
+
* где порог OSCILLATION_MIN_RETURNS ещё не взят или взят с запасом: одиночный ramp
|
|
62
|
+
* размазывает откаты по разным дорожкам и парам (max 1 при сумме 2), пила через разные
|
|
63
|
+
* вершины концентрирует откаты на одной дорожке, но на разных парах (maxTrack 2 при
|
|
64
|
+
* maxPair 1), пинг-понг на двух дорожках — и там и там (maxPair ≥ maxTrack).
|
|
65
|
+
* Решение о расширении критерия детекции принимается по этим счётчикам в A/B,
|
|
66
|
+
* а не по boolean isOscillationProven.
|
|
67
|
+
*/
|
|
68
|
+
getStats(): OscillationReturnStats;
|
|
69
|
+
/**
|
|
70
|
+
* Считает немедленные откаты в окне осцилляции (OSCILLATION_WINDOW_MS от текущего момента).
|
|
71
|
+
* «Возврат» — переключение на дорожку, с которой ушли предыдущей записью, в противоположном
|
|
72
|
+
* направлении (A → B → A): одиночный ramp вниз-вверх (congestion без stall) не считается
|
|
73
|
+
* осцилляцией, а повторные откаты на ту же дорожку — считаются. Отклонённые cooldown
|
|
74
|
+
* намерения не считаются. Stall-запись обнуляет счётчики и разрывает смежность переключений:
|
|
75
|
+
* каскад до просадки и восстановление после неё — не осцилляция.
|
|
76
|
+
*
|
|
77
|
+
* Возвращает два разреза одних и тех же откатов: по дорожке и по паре (см. ImmediateReturnCounts).
|
|
78
|
+
*/
|
|
79
|
+
private countImmediateReturns;
|
|
80
|
+
private push;
|
|
81
|
+
private isConsecutiveDuplicateRejectedIntent;
|
|
82
|
+
private dropEntriesOlderThanWindow;
|
|
83
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { IBaseTrack } from "../../../../player/types";
|
|
2
|
+
import type { Milliseconds } from "@vkontakte/videoplayer-shared";
|
|
3
|
+
import type { ITuningConfig } from "../../../../utils/tuningConfig";
|
|
4
|
+
export type TrackBans = Record<IBaseTrack["id"], Milliseconds>;
|
|
5
|
+
/** Телеметрия исходов переключений: испытательный срок, недавние фейлы и активные баны. */
|
|
6
|
+
export type TrackOutcomeStats = {
|
|
7
|
+
/** Текущая дорожка на испытательном сроке (или просто последняя выбранная). */
|
|
8
|
+
currentTrackId: IBaseTrack["id"] | undefined;
|
|
9
|
+
/** Сколько мс текущая дорожка уже выбрана — прогресс испытательного срока. */
|
|
10
|
+
currentProbationMs: Milliseconds;
|
|
11
|
+
/** Провален ли испытательный срок текущей дорожки (stall или слишком ранний уход). */
|
|
12
|
+
probationFailed: boolean;
|
|
13
|
+
/** Число недавних фейлов в окне trackBanWindowMs по каждой дорожке. */
|
|
14
|
+
failsByTrack: Record<IBaseTrack["id"], number>;
|
|
15
|
+
/** Активные баны: id -> до какого времени. */
|
|
16
|
+
activeBans: TrackBans;
|
|
17
|
+
};
|
|
18
|
+
export type TrackSwitchOutcomeParams = {
|
|
19
|
+
fromId: IBaseTrack["id"];
|
|
20
|
+
toId: IBaseTrack["id"];
|
|
21
|
+
isUpgrade: boolean;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Владелец исходов переключений: испытательный срок trackProbationMs и баны за неудачные подъёмы.
|
|
25
|
+
* Питается ТОЛЬКО выполненными переключениями (после всех гейтов контроллера) и severe stall —
|
|
26
|
+
* отклонённые cooldown намерения не являются попыткой испытательного срока.
|
|
27
|
+
* См. docs/superpowers/specs/2026-08-30-anchor-ban-abr-design.md.
|
|
28
|
+
*/
|
|
29
|
+
export declare class TrackOutcomeController {
|
|
30
|
+
private readonly autoTrackSelection;
|
|
31
|
+
private currentId;
|
|
32
|
+
private currentTrackSelectedAt;
|
|
33
|
+
private probationFailed;
|
|
34
|
+
private fails;
|
|
35
|
+
private bans;
|
|
36
|
+
constructor({ autoTrackSelection }: {
|
|
37
|
+
autoTrackSelection: ITuningConfig["autoTrackSelection"];
|
|
38
|
+
});
|
|
39
|
+
/**
|
|
40
|
+
* Первый трек сессии не приходит переключением (уходить не с чего), поэтому без явной
|
|
41
|
+
* регистрации его испытательный срок не начинается: severe stall на стартовом качестве
|
|
42
|
+
* и спуск с него не дают неудачи, хотя это самый частый сценарий «взяли высоко — не потянули».
|
|
43
|
+
*/
|
|
44
|
+
recordInitialTrack(trackId: IBaseTrack["id"]): void;
|
|
45
|
+
recordSwitch({ fromId, toId, isUpgrade }: TrackSwitchOutcomeParams): void;
|
|
46
|
+
/** Отдаёт только ещё активные баны и подчищает истёкшие. */
|
|
47
|
+
getActiveBans(): TrackBans;
|
|
48
|
+
getStats(): TrackOutcomeStats;
|
|
49
|
+
reset(): void;
|
|
50
|
+
private finishProbation;
|
|
51
|
+
recordSevereStallHappened(): void;
|
|
52
|
+
private pushFail;
|
|
53
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { IAbrRule, IAbrRuleResolution, IVideoAbrContext, RuleLogData } from "../../types";
|
|
2
|
+
import type { IVideoTrack } from "../../../../../player/types";
|
|
3
|
+
import { LimitAboveRule } from "../limitAboveRule";
|
|
4
|
+
import type { RulePhaseConfig } from "../../controllers/abrPhaseController";
|
|
5
|
+
type BanLogsArgs = [bannedIds: string[]];
|
|
6
|
+
/**
|
|
7
|
+
* Правило банов по истории переключений: активный banUntil (TrackOutcomeController, см. спеку
|
|
8
|
+
* anchor-ban) отсекает дорожку и всё выше неё — не потянули 720, не потянут и 1080. Потолок —
|
|
9
|
+
* старший незабаненный ниже самого низкого забаненного, поэтому всё не выше потолка (и победитель
|
|
10
|
+
* слияния лимитов в том числе) гарантированно незабаненное.
|
|
11
|
+
*/
|
|
12
|
+
export declare class BanBasedOnHistoryRule extends LimitAboveRule<IVideoTrack, IVideoAbrContext, BanLogsArgs> implements IAbrRule<IVideoTrack, IVideoAbrContext> {
|
|
13
|
+
constructor(phaseConfig: RulePhaseConfig);
|
|
14
|
+
execute(context: IVideoAbrContext): IAbrRuleResolution<IVideoTrack>;
|
|
15
|
+
protected createLogData(selectedTrack: IVideoTrack, bannedIds: string[]): RuleLogData;
|
|
16
|
+
}
|
|
17
|
+
export {};
|
|
@@ -5,6 +5,7 @@ import type { Representation, Segment } from "../parsers/types";
|
|
|
5
5
|
import type { ElementSizeManager } from "../HTMLVideoElement/ElementSizeManager";
|
|
6
6
|
import type { IObservableMediaElement } from "../HTMLVideoElement/observable";
|
|
7
7
|
import type { AbrPhase } from "./controllers/abrPhaseController";
|
|
8
|
+
import type { TrackBans } from "./controllers/trackOutcomeController";
|
|
8
9
|
export type AbrLimitSources = {
|
|
9
10
|
readonly above: string | undefined;
|
|
10
11
|
readonly below: string | undefined;
|
|
@@ -25,7 +26,8 @@ export declare enum VideoRuleName {
|
|
|
25
26
|
UpperLimit = "upper_limit_rule",
|
|
26
27
|
Throughput = "throughput_rule",
|
|
27
28
|
AbandonRequest = "abandon_request_rule",
|
|
28
|
-
InsufficientBuffer = "insufficient_buffer_rule"
|
|
29
|
+
InsufficientBuffer = "insufficient_buffer_rule",
|
|
30
|
+
Ban = "ban_rule"
|
|
29
31
|
}
|
|
30
32
|
export declare enum AudioRuleName {
|
|
31
33
|
MinAudioForVideo = "min_audio_for_video_rule",
|
|
@@ -92,12 +94,12 @@ export interface IAbrRule<
|
|
|
92
94
|
C extends IBaseAbrControllerContext
|
|
93
95
|
> {
|
|
94
96
|
readonly activePhases: ReadonlySet<AbrPhase>;
|
|
95
|
-
init(
|
|
97
|
+
init(ruleContext: IRuleInitContext): void;
|
|
96
98
|
destroy(): void;
|
|
97
99
|
execute(context: C): IAbrRuleResolution<T>;
|
|
98
100
|
}
|
|
99
101
|
export interface IAbrController<T extends IBaseTrack> {
|
|
100
|
-
init(rules: IAbrRule<T, IBaseAbrControllerContext>[],
|
|
102
|
+
init(rules: IAbrRule<T, IBaseAbrControllerContext>[], ruleContext: IRuleInitContext): void;
|
|
101
103
|
destroy(): void;
|
|
102
104
|
updateContext(context: IBaseAbrControllerContext): void;
|
|
103
105
|
autoSelectTrack(rules?: IAbrRule<T, IBaseAbrControllerContext>[]): T;
|
|
@@ -115,6 +117,7 @@ export interface IBaseAbrControllerContext extends IVideoTracksContext {
|
|
|
115
117
|
forwardBufferDuration: Milliseconds | undefined;
|
|
116
118
|
playbackRate: number;
|
|
117
119
|
throughputVariance: number;
|
|
120
|
+
bannedUntil?: TrackBans;
|
|
118
121
|
}
|
|
119
122
|
export type VideoSegmentLoadProgress = {
|
|
120
123
|
startedAtMs: Milliseconds;
|
|
@@ -7,6 +7,7 @@ export declare enum CompareTrack {
|
|
|
7
7
|
Ascending = 1
|
|
8
8
|
}
|
|
9
9
|
export declare const isVideoTrack: (track: IBaseTrack) => track is IVideoTrack;
|
|
10
|
+
export declare const describeTrack: (track: Nullable<IBaseTrack>) => string | number | undefined;
|
|
10
11
|
export declare const getAudioTrackComparator: (type: CompareTrack) => (track1: IAudioTrack, track2: IAudioTrack) => number;
|
|
11
12
|
export declare const getVideoTrackComparator: (type: CompareTrack) => (track1: IVideoTrack, track2: IVideoTrack) => number;
|
|
12
13
|
export declare const getTrackComparator: <T extends IBaseTrack>(compareTrack: CompareTrack) => (track1: T, track2: T) => number;
|