@vkontakte/videoplayer-core 2.0.171-dev.881304e5f.0 → 2.0.171-dev.a5a2d3fc3.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 +38 -140
- package/es2015.esm.js +23 -125
- package/esnext.cjs +26 -128
- package/esnext.esm.js +24 -126
- package/evergreen.esm.js +24 -126
- package/package.json +2 -2
- package/types/player/types.d.ts +16 -4
- package/types/providers/DashLiveProvider/utils/LiveDashPlayer.d.ts +2 -1
- package/types/providers/DashProvider/lib/buffer.d.ts +4 -0
- package/types/providers/DashProvider/lib/fetcher.d.ts +6 -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.versionA.d.ts +5 -1
- package/types/providers/DashProviderVirtual/lib/buffer/virtualBuffer/byteRangeVirtualBufferManager.versionA.d.ts +1 -0
- package/types/providers/DashProviderVirtual/lib/fetcher.d.ts +6 -4
- package/types/providers/DashProviderVirtual/lib/player/basePlayer.d.ts +5 -1
- package/types/providers/ProviderContainer/Mayday/GraceTimeout.d.ts +17 -0
- package/types/providers/ProviderContainer/Mayday/heuristics/SegmentAppendHeuristic.d.ts +10 -0
- package/types/providers/ProviderContainer/Mayday/heuristics/StartupHangupHeuristic.d.ts +46 -0
- package/types/providers/ProviderContainer/Mayday/index.d.ts +1 -1
- package/types/providers/ProviderContainer/Mayday/types.d.ts +2 -1
- package/types/providers/ProviderContainer/index.d.ts +3 -0
- package/types/providers/ProviderContainer/utils/playbackHangup.d.ts +6 -2
- package/types/providers/types.d.ts +4 -2
- package/types/providers/utils/Abr/abrController.d.ts +4 -1
- package/types/providers/utils/Abr/abrManager.d.ts +1 -0
- package/types/providers/utils/Abr/controllers/stallsController.d.ts +8 -1
- package/types/providers/utils/Abr/rules/audio/audioThroughputRule.d.ts +2 -2
- package/types/providers/utils/Abr/rules/audio/minAudioForVideoRule.d.ts +2 -2
- package/types/providers/utils/Abr/rules/baseRule.d.ts +2 -2
- package/types/providers/utils/Abr/rules/video/abandonRequestRule.d.ts +2 -2
- package/types/providers/utils/Abr/rules/video/bolaRule.d.ts +2 -2
- package/types/providers/utils/Abr/rules/video/bufferRule.d.ts +2 -2
- package/types/providers/utils/Abr/rules/video/fitsContainerRule.d.ts +2 -2
- package/types/providers/utils/Abr/rules/video/insufficientBufferRule.d.ts +2 -2
- package/types/providers/utils/Abr/rules/video/lowerLimitRule.d.ts +2 -2
- package/types/providers/utils/Abr/rules/video/stallsRule.d.ts +6 -2
- package/types/providers/utils/Abr/rules/video/throughputRule.d.ts +2 -2
- package/types/providers/utils/Abr/rules/video/tvDisabledVideoTrackRule.d.ts +2 -2
- package/types/providers/utils/Abr/rules/video/upperLimitRule.d.ts +2 -2
- package/types/providers/utils/Abr/types.d.ts +5 -2
- package/types/providers/utils/HTMLVideoElement/observable.d.ts +1 -1
- package/types/providers/utils/segmentCache/IndexedDbSegmentCacheStorage.d.ts +52 -0
- package/types/providers/utils/segmentCache/SegmentCache.d.ts +40 -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 +74 -0
- package/types/utils/buffer/isBrokenSegmentAppend.d.ts +3 -0
- package/types/utils/buffer/timeRangesToIntervals.d.ts +3 -0
- package/types/utils/tuningConfig.d.ts +16 -9
- package/types/providers/DashProvider/lib/urlsCache.d.ts +0 -23
- package/types/providers/DashProviderVirtual/lib/urlsCache.d.ts +0 -22
- package/types/providers/ProviderContainer/Mayday/heuristics/HangupHeuristic.d.ts +0 -22
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { IAbrRule, IAbrRuleResolution, IVideoAbrContext } from "../../types";
|
|
1
|
+
import type { IAbrRule, IAbrRuleResolution, IVideoAbrContext, RuleLogData } from "../../types";
|
|
2
2
|
import type { IVideoTrack } from "../../../../../player/types";
|
|
3
3
|
import type { Nullable, QualityLimits } from "@vkontakte/videoplayer-shared";
|
|
4
4
|
import { type ExactVideoQuality } from "@vkontakte/videoplayer-shared";
|
|
@@ -8,6 +8,6 @@ type LowerLimitLogsArgs = [limitsAreInvalid: boolean, lowestAvailableQuality: Nu
|
|
|
8
8
|
export declare class LowerLimitRule extends LimitBelowRule<IVideoTrack, IVideoAbrContext, LowerLimitLogsArgs> implements IAbrRule<IVideoTrack, IVideoAbrContext> {
|
|
9
9
|
constructor(phaseConfig: RulePhaseConfig);
|
|
10
10
|
execute(context: IVideoAbrContext): IAbrRuleResolution<IVideoTrack>;
|
|
11
|
-
protected
|
|
11
|
+
protected createLogData(selectedTrack: IVideoTrack, limitsAreInvalid: boolean, lowestAvailableQuality: Nullable<ExactVideoQuality>, highestAvailableQuality: Nullable<ExactVideoQuality>, limits: QualityLimits): RuleLogData;
|
|
12
12
|
}
|
|
13
13
|
export {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { IAbrRule, IAbrRuleResolution, IVideoAbrContext } from "../../types";
|
|
1
|
+
import type { IAbrRule, IAbrRuleResolution, IVideoAbrContext, RuleLogData } from "../../types";
|
|
2
2
|
import type { IVideoTrack } from "../../../../../player/types";
|
|
3
3
|
import type { Kbps, Nullable } from "@vkontakte/videoplayer-shared";
|
|
4
4
|
import { LimitAboveRule } from "../limitAboveRule";
|
|
@@ -11,9 +11,13 @@ export declare class StallsRule extends LimitAboveRule<IVideoTrack, IVideoAbrCon
|
|
|
11
11
|
private lastStallDurationRestriction;
|
|
12
12
|
private maxQualityLimitOnStall;
|
|
13
13
|
private predictedThroughputWithoutData;
|
|
14
|
+
private restrictionTracer;
|
|
15
|
+
private restrictionStartedAt;
|
|
14
16
|
constructor(phaseConfig: RulePhaseConfig);
|
|
15
17
|
execute(context: IVideoAbrContext): IAbrRuleResolution<IVideoTrack>;
|
|
16
|
-
protected
|
|
18
|
+
protected createLogData(selectedTrack: IVideoTrack, forwardBufferHealth: Nullable<number>, playbackRate: number, reserve: Kbps, playbackRateFactor: number, bitrateFactor: number, tuning: ITuningConfig): RuleLogData;
|
|
19
|
+
private traceRestrictionSet;
|
|
20
|
+
private traceRestrictionReset;
|
|
17
21
|
private updateStallQualityLimits;
|
|
18
22
|
}
|
|
19
23
|
export {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { IAbrRule, IAbrRuleResolution, IVideoAbrContext } from "../../types";
|
|
1
|
+
import type { IAbrRule, IAbrRuleResolution, IVideoAbrContext, RuleLogData } from "../../types";
|
|
2
2
|
import type { IVideoTrack } from "../../../../../player/types";
|
|
3
3
|
import type { Kbps, Nullable } from "@vkontakte/videoplayer-shared";
|
|
4
4
|
import { LimitAboveRule } from "../limitAboveRule";
|
|
@@ -8,6 +8,6 @@ type ThroughputLogsArgs = [forwardBufferHealth: Nullable<number>, playbackRate:
|
|
|
8
8
|
export declare class ThroughputRule extends LimitAboveRule<IVideoTrack, IVideoAbrContext, ThroughputLogsArgs> implements IAbrRule<IVideoTrack, IVideoAbrContext> {
|
|
9
9
|
constructor(phaseConfig: RulePhaseConfig);
|
|
10
10
|
execute(context: IVideoAbrContext): IAbrRuleResolution<IVideoTrack>;
|
|
11
|
-
protected
|
|
11
|
+
protected createLogData(selectedTrack: IVideoTrack, forwardBufferHealth: Nullable<number>, playbackRate: number, reserve: Kbps, playbackRateFactor: number, bitrateFactor: number, estimatedThroughput: Kbps, phase: AbrPhase | undefined, tuning: ITuningConfig): RuleLogData;
|
|
12
12
|
}
|
|
13
13
|
export {};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import type { IAbrRule, IAbrRuleResolution, IVideoAbrContext } from "../../types";
|
|
1
|
+
import type { IAbrRule, IAbrRuleResolution, IVideoAbrContext, RuleLogData } from "../../types";
|
|
2
2
|
import type { IVideoTrack } from "../../../../../player/types";
|
|
3
3
|
import { LimitAboveRule } from "../limitAboveRule";
|
|
4
4
|
import type { RulePhaseConfig } from "../../controllers/abrPhaseController";
|
|
5
5
|
export declare class TvDisabledVideoTrackRule extends LimitAboveRule<IVideoTrack, IVideoAbrContext> implements IAbrRule<IVideoTrack, IVideoAbrContext> {
|
|
6
6
|
constructor(phaseConfig: RulePhaseConfig);
|
|
7
7
|
execute(context: IVideoAbrContext): IAbrRuleResolution<IVideoTrack>;
|
|
8
|
-
protected
|
|
8
|
+
protected createLogData(selectedTrack: IVideoTrack): RuleLogData;
|
|
9
9
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { IAbrRule, IAbrRuleResolution, IVideoAbrContext } from "../../types";
|
|
1
|
+
import type { IAbrRule, IAbrRuleResolution, IVideoAbrContext, RuleLogData } from "../../types";
|
|
2
2
|
import type { IVideoTrack } from "../../../../../player/types";
|
|
3
3
|
import type { Nullable, QualityLimits, VideoQuality } from "@vkontakte/videoplayer-shared";
|
|
4
4
|
import { type ExactVideoQuality } from "@vkontakte/videoplayer-shared";
|
|
@@ -63,7 +63,7 @@ type UpperLimitsLogsArgs = [limitsAreInvalid: boolean, lowestAvailableQuality: N
|
|
|
63
63
|
export declare class UpperLimitsRule extends LimitAboveRule<IVideoTrack, IVideoAbrContext, UpperLimitsLogsArgs> implements IAbrRule<IVideoTrack, IVideoAbrContext> {
|
|
64
64
|
constructor(phaseConfig: RulePhaseConfig);
|
|
65
65
|
execute(context: IVideoAbrContext): IAbrRuleResolution<IVideoTrack>;
|
|
66
|
-
protected
|
|
66
|
+
protected createLogData(selectedTrack: IVideoTrack, limitsAreInvalid: boolean, lowestAvailableQuality: Nullable<ExactVideoQuality>, highestAvailableQuality: Nullable<ExactVideoQuality>, visible: boolean, limits: QualityLimits, backgroundVideoQualityLimit: VideoQuality, effectiveType: string | undefined, connectionDataQualityLimit: ExactVideoQuality | undefined): RuleLogData;
|
|
67
67
|
private getConnection;
|
|
68
68
|
private resolveConnectionDataQualityLimit;
|
|
69
69
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { IAudioTrack, IBaseTrack, IVideoTrack } from "../../../player/types";
|
|
2
|
-
import type { Byte, IComponentLogger, IObservable, IRectangle, IValueSubject, Kbps, Milliseconds, Nullable, QualityLimits } from "@vkontakte/videoplayer-shared";
|
|
2
|
+
import type { Byte, IComponentLogger, IObservable, IRectangle, ITracer, IValueSubject, Kbps, Milliseconds, Nullable, QualityLimits } from "@vkontakte/videoplayer-shared";
|
|
3
3
|
import type { ITuningConfig } from "../../../utils/tuningConfig";
|
|
4
4
|
import type { Representation, Segment } from "../parsers/types";
|
|
5
5
|
import type { ElementSizeManager } from "../HTMLVideoElement/ElementSizeManager";
|
|
@@ -57,6 +57,7 @@ export interface IInitAbrManagerContext {
|
|
|
57
57
|
throughputVariance$?: IValueSubject<number>;
|
|
58
58
|
element: HTMLMediaElement;
|
|
59
59
|
abrLogger: IComponentLogger;
|
|
60
|
+
tracer: ITracer;
|
|
60
61
|
panelSize?: IRectangle;
|
|
61
62
|
}
|
|
62
63
|
export interface IVideoElementAbrManagerContext {
|
|
@@ -73,12 +74,13 @@ export interface IAudioTracksContext {
|
|
|
73
74
|
audioTracksDesc: IAudioTrack[];
|
|
74
75
|
}
|
|
75
76
|
export type IAbrManagerContext = Omit<IUpdatableAbrManagerContext, "videoTracks" | "audioTracks"> & IVideoElementAbrManagerContext & IInitAbrManagerContext & IVideoTracksContext & IAudioTracksContext;
|
|
77
|
+
export type RuleLogData = Record<string, string | number | boolean | undefined>;
|
|
76
78
|
export interface IAbrRuleResolution<T extends IBaseTrack> {
|
|
77
79
|
track: T;
|
|
78
80
|
confidence: number;
|
|
79
81
|
type: RuleType;
|
|
80
82
|
name: string;
|
|
81
|
-
|
|
83
|
+
logData: RuleLogData;
|
|
82
84
|
}
|
|
83
85
|
export interface IRuleInitContext extends IInitAbrManagerContext {}
|
|
84
86
|
export interface IAbrRule<
|
|
@@ -101,6 +103,7 @@ export interface IBaseAbrControllerContext extends IVideoTracksContext {
|
|
|
101
103
|
lastVideoTrackSelected: Nullable<IVideoTrack>;
|
|
102
104
|
tuning: ITuningConfig;
|
|
103
105
|
abrLogger: IComponentLogger;
|
|
106
|
+
tracer: ITracer;
|
|
104
107
|
estimatedThroughput: Kbps;
|
|
105
108
|
reserve: Kbps;
|
|
106
109
|
forwardBufferHealth: Nullable<number>;
|
|
@@ -17,7 +17,7 @@ export interface IObservableVideo {
|
|
|
17
17
|
loadedMetadata$: IObservable<undefined>;
|
|
18
18
|
loadedData$: IObservable<undefined>;
|
|
19
19
|
isBuffering$: IObservable<boolean>;
|
|
20
|
-
|
|
20
|
+
currentVideoBuffer$: IObservable<IRange<Seconds>>;
|
|
21
21
|
totalBufferDuration$: IObservable<Milliseconds>;
|
|
22
22
|
bufferRangeCount$: IObservable<number>;
|
|
23
23
|
volumeState$: IObservable<IVolumeState>;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { InitSegmentParams, ISegmentCacheStorage, SegmentCacheConfig, SetSegmentParams } from "./types";
|
|
2
|
+
export declare class IndexedDbSegmentCacheStorage implements ISegmentCacheStorage {
|
|
3
|
+
private config;
|
|
4
|
+
private dbPromise;
|
|
5
|
+
private destroyed;
|
|
6
|
+
private evictionTimerId;
|
|
7
|
+
private globalTotalBytes;
|
|
8
|
+
private maxTotalStoredBytes;
|
|
9
|
+
private quotaExceeded;
|
|
10
|
+
private cacheEventsChannel;
|
|
11
|
+
constructor(config: SegmentCacheConfig);
|
|
12
|
+
private getDb;
|
|
13
|
+
private isFresh;
|
|
14
|
+
/**
|
|
15
|
+
* Читает записи по массиву ключей в одной транзакции.
|
|
16
|
+
* Свежие по TTL — возвращает данные и обновляет lastAccessAt (не чаще чем раз в TOUCH_INTERVAL_MS,
|
|
17
|
+
* чтобы избежать write amplification: каждый cache hit не должен делать store.put с полным ArrayBuffer).
|
|
18
|
+
* Протухшие — удаляет, декрементирует globalTotalBytes.
|
|
19
|
+
*/
|
|
20
|
+
private readFreshRecord;
|
|
21
|
+
/**
|
|
22
|
+
* При открытии БД пересчитывает globalTotalBytes: проходит по всем записям,
|
|
23
|
+
* суммирует размер живых (не протухших по TTL) и удаляет протухшие.
|
|
24
|
+
* TTL различается: media — ttlMs, init/index — initTtlMs.
|
|
25
|
+
*/
|
|
26
|
+
private handleDbOpened;
|
|
27
|
+
/** Возвращает TTL в зависимости от типа записи по первичному ключу. */
|
|
28
|
+
private ttlForEntry;
|
|
29
|
+
getSegments(normalizedUrl: string, indices: number[]): Promise<Map<number, ArrayBuffer>>;
|
|
30
|
+
setSegment(params: SetSegmentParams): Promise<void>;
|
|
31
|
+
getInitSegment({ normalizedUrl, rangeType, range }: InitSegmentParams): Promise<ArrayBuffer | null>;
|
|
32
|
+
/** Универсальная запись с подсчётом delta, QuotaExceededError-обработкой и eviction. */
|
|
33
|
+
private putRecord;
|
|
34
|
+
private handleQuotaExceededError;
|
|
35
|
+
/** Полная очистка кэша с рассылкой события остальным инстансам (вкладки, другие плееры). */
|
|
36
|
+
clear(): Promise<void>;
|
|
37
|
+
destroy(): void;
|
|
38
|
+
private scheduleEviction;
|
|
39
|
+
/**
|
|
40
|
+
* LRU-eviction: запускается по дебаунсу после каждой записи.
|
|
41
|
+
* Без квоты — триггерит при достижении maxTotalStoredBytes.
|
|
42
|
+
* После QuotaExceededError — раньше, на maxTotalStoredBytes * evictionThreshold,
|
|
43
|
+
* чтобы не упереться в квоту повторно.
|
|
44
|
+
* Очищает с запасом — до maxTotalStoredBytes * evictionTargetPercent.
|
|
45
|
+
*/
|
|
46
|
+
private runEviction;
|
|
47
|
+
/**
|
|
48
|
+
* Удаляет самые старые по lastAccessAt записи, пока не освободит хотя бы bytesToFree.
|
|
49
|
+
* maxBytesPerBatch ограничивает длительность одной транзакции; без лимита — при QuotaExceededError.
|
|
50
|
+
*/
|
|
51
|
+
private evictOldest;
|
|
52
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { ISegmentCacheStorage, CacheMetadata, CacheMetadataEntry } from "./types";
|
|
2
|
+
import type { SubRange } from "./segmentCacheUtils";
|
|
3
|
+
export declare enum CacheCheckResultType {
|
|
4
|
+
FullHit = "full_hit",
|
|
5
|
+
FullMiss = "full_miss",
|
|
6
|
+
Partial = "partial"
|
|
7
|
+
}
|
|
8
|
+
export type CacheCheckResult = {
|
|
9
|
+
type: CacheCheckResultType.FullHit;
|
|
10
|
+
data: ArrayBuffer;
|
|
11
|
+
} | {
|
|
12
|
+
type: CacheCheckResultType.FullMiss;
|
|
13
|
+
} | {
|
|
14
|
+
type: CacheCheckResultType.Partial;
|
|
15
|
+
cached: Map<number, ArrayBuffer>;
|
|
16
|
+
missingRange: SubRange;
|
|
17
|
+
startBuffer: {
|
|
18
|
+
buffer: ArrayBuffer;
|
|
19
|
+
loaded: number;
|
|
20
|
+
} | null;
|
|
21
|
+
};
|
|
22
|
+
export declare class SegmentCache {
|
|
23
|
+
private cacheService;
|
|
24
|
+
constructor(cacheService: ISegmentCacheStorage);
|
|
25
|
+
getCached(url: string, metadata: CacheMetadata): Promise<CacheCheckResult>;
|
|
26
|
+
storeDownloadedSegments({ url, buffer, segments, networkDataOffset }: {
|
|
27
|
+
url: string;
|
|
28
|
+
buffer: ArrayBuffer;
|
|
29
|
+
segments: CacheMetadataEntry[];
|
|
30
|
+
networkDataOffset?: number;
|
|
31
|
+
}): void;
|
|
32
|
+
private assembleStartBuffer;
|
|
33
|
+
private buildPartialFromCacheStart;
|
|
34
|
+
storeMissing({ url, missingRange, networkData, networkDataOffset }: {
|
|
35
|
+
url: string;
|
|
36
|
+
missingRange: SubRange;
|
|
37
|
+
networkData: ArrayBuffer;
|
|
38
|
+
networkDataOffset?: number;
|
|
39
|
+
}): void;
|
|
40
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export declare const DB_NAME = "vk_player_segment_cache";
|
|
2
|
+
export declare const DB_VERSION = 1;
|
|
3
|
+
export declare const STORE = "cache";
|
|
4
|
+
export declare const EVICTION_DEBOUNCE_MS = 5e3;
|
|
5
|
+
/** Канал синхронизации инстансов storage (вкладки, несколько плееров на странице) */
|
|
6
|
+
export declare const CACHE_EVENTS_CHANNEL = "vk_player_segment_cache_events";
|
|
7
|
+
/** Событие полной очистки кэша: получатель сбрасывает in-memory счётчик байт, база уже пуста */
|
|
8
|
+
export declare const CACHE_CLEARED_EVENT = "cleared";
|
|
9
|
+
/**
|
|
10
|
+
* Минимальный интервал между обновлениями lastAccessAt при чтении.
|
|
11
|
+
* Без него каждый cache hit делал бы store.put с полным ArrayBuffer ради одного поля.
|
|
12
|
+
* При TTL в часы точность LRU до минут не нужна — 5 минут достаточно.
|
|
13
|
+
*/
|
|
14
|
+
export declare const TOUCH_INTERVAL_MS: number;
|
|
15
|
+
/** Тип записи: media-сегмент, init-сегмент, index-сегмент */
|
|
16
|
+
export declare enum CacheEntryType {
|
|
17
|
+
Media = 0,
|
|
18
|
+
Init = 1,
|
|
19
|
+
Index = 2
|
|
20
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { IndexedDbSegmentCacheStorage } from "./IndexedDbSegmentCacheStorage";
|
|
2
|
+
export { SegmentCache, CacheCheckResultType } from "./SegmentCache";
|
|
3
|
+
export type { CacheCheckResult } from "./SegmentCache";
|
|
4
|
+
export { normalizeSegmentCacheUrl, assemblePartialBuffer, toEntryType, createMediaKey, createInitKey, isQuotaExceededError } from "./segmentCacheUtils";
|
|
5
|
+
export type { SubRange } from "./segmentCacheUtils";
|
|
6
|
+
export { clearSegmentCacheDb } from "./segmentCacheDb";
|
|
7
|
+
export { DB_NAME, DB_VERSION, STORE, EVICTION_DEBOUNCE_MS, CacheEntryType } from "./constants";
|
|
8
|
+
export type { ISegmentCacheStorage, CacheMetadata, CacheMetadataEntry, SegmentCacheConfig, SegmentCacheEntry, InitSegmentParams, InitSegmentRangeType, SetMediaSegmentParams, SetInitSegmentParams, SetSegmentParams, CacheRecord, CachePrimaryKey } from "./types";
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export declare const INDEX_BY_LAST_ACCESS = "byLastAccess";
|
|
2
|
+
export declare const INDEX_BY_SIZE_AND_AGE = "bySizeAndAge";
|
|
3
|
+
export declare const INDEX_BY_LAST_ACCESS_AND_SIZE = "byLastAccessAndSize";
|
|
4
|
+
/**
|
|
5
|
+
* Открывает базу кэша, при первом создании поднимает store и индексы.
|
|
6
|
+
* onOpened (если передан) await-ится до resolve — используется только в clearSegmentCacheDb.
|
|
7
|
+
* Инстанс storage не использует onOpened: rehydrate запускается параллельно, чтобы не блокировать чтения.
|
|
8
|
+
*/
|
|
9
|
+
export declare const openSegmentCacheDb: (onOpened?: (db: IDBDatabase) => Promise<void>) => Promise<IDBDatabase>;
|
|
10
|
+
/** Выполняет операции в одной readwrite-транзакции, резолвится по её завершении. */
|
|
11
|
+
export declare const execStoreTx: (db: IDBDatabase, body: (store: IDBObjectStore) => void) => Promise<void>;
|
|
12
|
+
/**
|
|
13
|
+
* Гоняет курсор по индексу, вызывая visit на каждой записи.
|
|
14
|
+
* visit возвращает false — итерация останавливается, транзакция завершается.
|
|
15
|
+
* Работает только внутри execStoreTx: завершение итерации отслеживается транзакцией.
|
|
16
|
+
*/
|
|
17
|
+
export declare const iterateCursor: <T extends IDBCursor>(request: IDBRequest<T | null>, visit: (cursor: T) => boolean) => void;
|
|
18
|
+
/** Рассылает событие полной очистки кэша всем инстансам storage (вкладки, другие плееры на странице). */
|
|
19
|
+
export declare const broadcastCacheCleared: () => void;
|
|
20
|
+
/**
|
|
21
|
+
* Полностью очищает кэш без привязки к инстансу storage: можно звать из мест,
|
|
22
|
+
* где экземпляр IndexedDbSegmentCacheStorage недоступен (например, из ProviderContainer при ошибках).
|
|
23
|
+
* Живые инстансы узнают об очистке через broadcastCacheCleared и сбросят in-memory счётчики.
|
|
24
|
+
*/
|
|
25
|
+
export declare const clearSegmentCacheDb: () => Promise<void>;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { Byte, IRange } from "@vkontakte/videoplayer-shared";
|
|
2
|
+
import type { CacheMetadata, CacheMetadataEntry, InitSegmentRangeType, CachePrimaryKey } from "./types";
|
|
3
|
+
import { CacheEntryType } from "./constants";
|
|
4
|
+
/** Приводит URL к каноническому виду: заменяет hostname на cache.local и удаляет CDN-параметры (sig, expires, bytes, fromCache). */
|
|
5
|
+
export declare function normalizeSegmentCacheUrl(url: string): string;
|
|
6
|
+
export declare function toEntryType(rangeType: InitSegmentRangeType): CacheEntryType;
|
|
7
|
+
export declare function createMediaKey(normalizedUrl: string, segmentIndex: number): CachePrimaryKey;
|
|
8
|
+
export declare function createInitKey(normalizedUrl: string, entryType: CacheEntryType, rangeFrom: number, rangeTo: number): CachePrimaryKey;
|
|
9
|
+
export declare function isQuotaExceededError(error: unknown): boolean;
|
|
10
|
+
export type SubRange = {
|
|
11
|
+
range: IRange<Byte>;
|
|
12
|
+
segments: CacheMetadataEntry[];
|
|
13
|
+
};
|
|
14
|
+
/** Проверяет, что сегменты идут подряд по индексам — без разрывов между ними. Ожидает отсортированный массив. */
|
|
15
|
+
export declare function isContiguous(segments: CacheMetadataEntry[]): boolean;
|
|
16
|
+
/** Склеивает буферы закэшированных сегментов в один ArrayBuffer. Используется при full hit. */
|
|
17
|
+
export declare function assembleFromCached(metadata: CacheMetadata, cached: Map<number, ArrayBuffer>): ArrayBuffer;
|
|
18
|
+
/** Склеивает закэшированные и сетевые данные в один ArrayBuffer для partial hit. */
|
|
19
|
+
export declare function assemblePartialBuffer({ metadata, cached, missingRange, networkData, networkDataOffset }: {
|
|
20
|
+
metadata: CacheMetadata;
|
|
21
|
+
cached: Map<number, ArrayBuffer>;
|
|
22
|
+
missingRange: SubRange;
|
|
23
|
+
networkData: ArrayBuffer;
|
|
24
|
+
networkDataOffset?: number;
|
|
25
|
+
}): ArrayBuffer;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type { Byte, IRange } from "@vkontakte/videoplayer-shared";
|
|
2
|
+
import type { CacheEntryType } from "./constants";
|
|
3
|
+
export type InitSegmentRangeType = "init" | "index";
|
|
4
|
+
export interface SegmentCacheEntry {
|
|
5
|
+
data: ArrayBuffer;
|
|
6
|
+
segmentIndex: number;
|
|
7
|
+
}
|
|
8
|
+
export interface InitSegmentParams {
|
|
9
|
+
normalizedUrl: string;
|
|
10
|
+
rangeType: InitSegmentRangeType;
|
|
11
|
+
range: IRange<Byte>;
|
|
12
|
+
}
|
|
13
|
+
export interface SetMediaSegmentParams {
|
|
14
|
+
type: "media";
|
|
15
|
+
normalizedUrl: string;
|
|
16
|
+
segmentIndex: number;
|
|
17
|
+
data: ArrayBuffer;
|
|
18
|
+
}
|
|
19
|
+
export interface SetInitSegmentParams {
|
|
20
|
+
type: "init";
|
|
21
|
+
normalizedUrl: string;
|
|
22
|
+
rangeType: InitSegmentRangeType;
|
|
23
|
+
range: IRange<Byte>;
|
|
24
|
+
data: ArrayBuffer;
|
|
25
|
+
}
|
|
26
|
+
export type SetSegmentParams = SetMediaSegmentParams | SetInitSegmentParams;
|
|
27
|
+
export interface ISegmentCacheStorage {
|
|
28
|
+
getSegments(normalizedUrl: string, indices: number[]): Promise<Map<number, ArrayBuffer>>;
|
|
29
|
+
setSegment(params: SetSegmentParams): Promise<void>;
|
|
30
|
+
getInitSegment(params: InitSegmentParams): Promise<ArrayBuffer | null>;
|
|
31
|
+
/** Полная очистка кэша (все записи, без привязки к url) с рассылкой события другим инстансам */
|
|
32
|
+
clear(): Promise<void>;
|
|
33
|
+
destroy(): void;
|
|
34
|
+
}
|
|
35
|
+
export interface CacheMetadataEntry {
|
|
36
|
+
index: number;
|
|
37
|
+
byteRange: IRange<Byte>;
|
|
38
|
+
}
|
|
39
|
+
export interface CacheMetadata {
|
|
40
|
+
segments: CacheMetadataEntry[];
|
|
41
|
+
}
|
|
42
|
+
export interface SegmentCacheConfig {
|
|
43
|
+
/** Включает кэширование media-сегментов в IndexedDB */
|
|
44
|
+
enabled: boolean;
|
|
45
|
+
/** Лимит суммарного размера кэша (media + init/index сегменты) в байтах. При QuotaExceededError автоматически опускается до текущего размера */
|
|
46
|
+
maxTotalSizeBytes: number;
|
|
47
|
+
/** Доля от эффективного лимита, при превышении которой запускается LRU-эвикт (0.9 = 90%) */
|
|
48
|
+
evictionThreshold: number;
|
|
49
|
+
/** Доля от максимального хранимого кэша, до которой LRU-эвикт очищает кэш (0.7 = 70%).
|
|
50
|
+
* Должна быть ниже evictionThreshold: запас между ними не даёт эвикту срабатывать на каждую запись у границы лимита
|
|
51
|
+
* */
|
|
52
|
+
evictionTargetPercent: number;
|
|
53
|
+
/** Максимальный объём данных в байтах, который LRU-эвикт удаляет за один проход (ограничивает длительность одной транзакции) */
|
|
54
|
+
evictionBatchMaxBytes: number;
|
|
55
|
+
/** Доля от maxTotalStoredBytes, которую нужно освободить при QuotaExceededError (0.5 = 50%) */
|
|
56
|
+
quotaExceededEvictPercent: number;
|
|
57
|
+
/** TTL для media-сегментов в миллисекундах. Протухшие записи удаляются при чтении и при rehydrate */
|
|
58
|
+
ttlMs: number;
|
|
59
|
+
/** TTL для init/index-сегментов в миллисекундах (обычно длиннее, т.к. они стабильнее) */
|
|
60
|
+
initTtlMs: number;
|
|
61
|
+
/** Стратегия очистки кэша при ошибках декодера/фетчера: 'once' — один раз за жизнь контейнера, 'always' — на каждую ошибку */
|
|
62
|
+
clearOnErrorStrategy: "once" | "always";
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Единая запись кэша. Ключ передаётся явно (out-of-line) через createMediaKey / createInitKey.
|
|
66
|
+
*/
|
|
67
|
+
export interface CacheRecord {
|
|
68
|
+
normalizedUrl: string;
|
|
69
|
+
data: ArrayBuffer;
|
|
70
|
+
byteLength: number;
|
|
71
|
+
createdAt: number;
|
|
72
|
+
lastAccessAt: number;
|
|
73
|
+
}
|
|
74
|
+
export type CachePrimaryKey = [string, CacheEntryType, number, number];
|
|
@@ -5,6 +5,7 @@ import { IOSPreferredFormat } from "../enums/IOSPreferredFormat";
|
|
|
5
5
|
import type { Byte, Kbps, Milliseconds, RecursivePartial, Seconds, TimerModule } from "@vkontakte/videoplayer-shared";
|
|
6
6
|
import { type ExactVideoQuality, VideoQuality } from "@vkontakte/videoplayer-shared";
|
|
7
7
|
import { AudioRuleName, VideoRuleName } from "../providers/utils/Abr/types";
|
|
8
|
+
import type { SegmentCacheConfig } from "../providers/utils/segmentCache/types";
|
|
8
9
|
export type ITuningConfig = {
|
|
9
10
|
/** @deprecated */
|
|
10
11
|
configName?: string[];
|
|
@@ -13,6 +14,17 @@ export type ITuningConfig = {
|
|
|
13
14
|
playingUnstableThresholdMs: Milliseconds;
|
|
14
15
|
/** Список имён включённых эвристик. Пустой массив = все эвристики выключены */
|
|
15
16
|
heuristics: string[];
|
|
17
|
+
/** Множитель уменьшения grace-таймаута при каждом поступлении данных в StartupHangupHeuristic */
|
|
18
|
+
hangupGraceDecayFactor: number;
|
|
19
|
+
/** Минимальный grace-таймаут (мс). При достижении — следующий decay возвращает 0 (немедленный expire) */
|
|
20
|
+
hangupGraceMinTimeoutMs: Milliseconds;
|
|
21
|
+
/**
|
|
22
|
+
* Если true — audible (не muted) хэнгап в hidden-вкладке откладывается до возврата на visible (reinit),
|
|
23
|
+
* desired state при этом не меняется.
|
|
24
|
+
* Если false — audible хэнгап в hidden-вкладке мониторится: данные перезапускают decay-таймер,
|
|
25
|
+
* при ≥3 поступлениях данных без завершения перехода — эскалация в switch_codec/switch_provider.
|
|
26
|
+
*/
|
|
27
|
+
deferAudibleHangupOnHiddenTab: boolean;
|
|
16
28
|
};
|
|
17
29
|
/**
|
|
18
30
|
* Включает очистку состояния плеера при вызове метода stop()
|
|
@@ -107,6 +119,7 @@ export type ITuningConfig = {
|
|
|
107
119
|
activeVideoAreaThreshold: number;
|
|
108
120
|
trafficSavingLimit: ExactVideoQuality;
|
|
109
121
|
highQualityLimit: ExactVideoQuality;
|
|
122
|
+
lowQualityTelemetryLimit: ExactVideoQuality;
|
|
110
123
|
};
|
|
111
124
|
stallsManager: {
|
|
112
125
|
enabled: boolean;
|
|
@@ -168,6 +181,8 @@ export type ITuningConfig = {
|
|
|
168
181
|
useDelayedRepresentationSwitch: boolean;
|
|
169
182
|
useSmartRepresentationSwitch: boolean;
|
|
170
183
|
stallForceSeekOncePerStall: boolean;
|
|
184
|
+
brokenSegmentAppendDetection: boolean;
|
|
185
|
+
brokenSegmentAppendTolerance: Milliseconds;
|
|
171
186
|
useFetchPriorityHints: boolean;
|
|
172
187
|
enableBaseUrlSupport: boolean;
|
|
173
188
|
maxSegmentRetryCount: number;
|
|
@@ -402,15 +417,6 @@ export type ITuningConfig = {
|
|
|
402
417
|
*/
|
|
403
418
|
handleExtendedNetworkErrorsSet?: boolean;
|
|
404
419
|
/**
|
|
405
|
-
* Кэшируем ответы от сервера руками, так как из за динамичесокй природы некоторых параметров в урле
|
|
406
|
-
* браузер это не может сделать.
|
|
407
|
-
*/
|
|
408
|
-
useUrlCacheMechanism?: boolean;
|
|
409
|
-
/**
|
|
410
|
-
* Очищаем кэш урлов при падение провайдера.
|
|
411
|
-
*/
|
|
412
|
-
dropUrlCacheWhenProviderCrashed?: boolean;
|
|
413
|
-
/**
|
|
414
420
|
* При смене/реините провайдера игнорируем результат того, смогло видео заиграть или нет.
|
|
415
421
|
*/
|
|
416
422
|
ignoreForcePlayResultWhenProviderChanged?: boolean;
|
|
@@ -433,6 +439,7 @@ export type ITuningConfig = {
|
|
|
433
439
|
* провайдер по-прежнему ждёт canplay, чтобы play() не вызывался до появления данных.
|
|
434
440
|
*/
|
|
435
441
|
readyOnLoadedMetadata: boolean;
|
|
442
|
+
segmentCache: SegmentCacheConfig;
|
|
436
443
|
};
|
|
437
444
|
export type IOptionalTuningConfig = RecursivePartial<ITuningConfig>;
|
|
438
445
|
export declare const fillDefault: (partial: IOptionalTuningConfig) => ITuningConfig;
|
|
@@ -1,23 +0,0 @@
|
|
|
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>;
|
|
@@ -1,22 +0,0 @@
|
|
|
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,22 +0,0 @@
|
|
|
1
|
-
import type { IError } from "@vkontakte/videoplayer-shared";
|
|
2
|
-
import type { IHeuristicDeps } from "../types";
|
|
3
|
-
import type { IAsyncHeuristic, HeuristicResult } from "./IHeuristic";
|
|
4
|
-
export declare class HangupHeuristic implements IAsyncHeuristic {
|
|
5
|
-
private deps;
|
|
6
|
-
static readonly heuristicName = "HangupHeuristic";
|
|
7
|
-
readonly type = "async";
|
|
8
|
-
readonly recommendation$;
|
|
9
|
-
private timerId;
|
|
10
|
-
private sub;
|
|
11
|
-
private error;
|
|
12
|
-
private manifestRequested;
|
|
13
|
-
private manifestRequestedAt;
|
|
14
|
-
private manifestReceivedMs;
|
|
15
|
-
constructor(deps: IHeuristicDeps);
|
|
16
|
-
analyze(error: IError): HeuristicResult;
|
|
17
|
-
private restartTimer;
|
|
18
|
-
private expire;
|
|
19
|
-
private cancel;
|
|
20
|
-
reset(): void;
|
|
21
|
-
destroy(): void;
|
|
22
|
-
}
|