@vkontakte/videoplayer-core 2.0.167 → 2.0.168-beta.1
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 +49 -49
- package/es2015.esm.js +43 -43
- package/esnext.cjs +30 -30
- package/esnext.esm.js +35 -35
- package/evergreen.esm.js +30 -30
- package/package.json +2 -2
- package/types/providers/DashProvider/lib/buffer.d.ts +2 -0
- package/types/providers/DashProvider/lib/fetcher.d.ts +7 -1
- package/types/providers/DashProviderVirtual/lib/buffer/virtualBuffer/baseVirtualBufferManager.versionA.d.ts +110 -0
- package/types/providers/DashProviderVirtual/lib/buffer/virtualBuffer/byteRangeVirtualBufferManager.versionA.d.ts +21 -0
- package/types/providers/DashProviderVirtual/lib/buffer/virtualBuffer/templateVirtualBufferManager.versionA.d.ts +21 -0
- package/types/providers/DashProviderVirtual/lib/buffer/virtualBuffer/virtualBufferFactory.d.ts +2 -1
- package/types/providers/DashProviderVirtual/lib/fetcher.d.ts +7 -1
- package/types/providers/ProviderContainer/Mayday/MaydayService.d.ts +6 -5
- package/types/providers/ProviderContainer/Mayday/heuristics/FetcherErrorHeuristic.d.ts +5 -4
- package/types/providers/ProviderContainer/Mayday/heuristics/HangupHeuristic.d.ts +22 -0
- package/types/providers/ProviderContainer/Mayday/heuristics/IHeuristic.d.ts +14 -4
- package/types/providers/ProviderContainer/Mayday/heuristics/MediaErrorHeuristic.d.ts +5 -4
- package/types/providers/ProviderContainer/Mayday/index.d.ts +3 -2
- package/types/providers/ProviderContainer/Mayday/testUtils.d.ts +21 -0
- package/types/providers/ProviderContainer/Mayday/types.d.ts +21 -3
- package/types/providers/utils/parsers/types.d.ts +1 -0
- package/types/utils/tuningConfig.d.ts +23 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vkontakte/videoplayer-core",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.168-beta.1",
|
|
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.
|
|
45
|
+
"@vkontakte/videoplayer-shared": "1.0.97-beta.1"
|
|
46
46
|
}
|
|
47
47
|
}
|
|
@@ -74,6 +74,7 @@ export declare class BufferManager {
|
|
|
74
74
|
private index;
|
|
75
75
|
private lastDataObtainedTimestampMs;
|
|
76
76
|
private loadByteRangeSegmentsTimeoutId;
|
|
77
|
+
private preDownloadedFirstSegment;
|
|
77
78
|
constructor(kind: StreamKind, mediaSource: MediaSource, representations: Representation[], { fetcher, tuning, getCurrentPosition, isActiveLowLatency, compatibilityMode, manifest }: Dependencies);
|
|
78
79
|
startWith: ReturnType<typeof abortable<[Representation["id"]]>>;
|
|
79
80
|
switchToWithPreviousAbort(newRepresentationId: Representation["id"], dropBuffer?: boolean): Promise<void | undefined>;
|
|
@@ -102,6 +103,7 @@ export declare class BufferManager {
|
|
|
102
103
|
private loadSegments;
|
|
103
104
|
private loadTemplateSegment;
|
|
104
105
|
private updateRepresentationsBaseUrlIfNeeded;
|
|
106
|
+
private feedPreDownloadedFirstSegment;
|
|
105
107
|
private loadByteRangeSegments;
|
|
106
108
|
private prepareByteRangeFetchSegmentParams;
|
|
107
109
|
private prepareTemplateFetchSegmentParams;
|
|
@@ -25,6 +25,8 @@ export interface IParams {
|
|
|
25
25
|
handleExtendedNetworkErrorsSet?: boolean;
|
|
26
26
|
useUrlCacheMechanism?: boolean;
|
|
27
27
|
measureNonSegmentRequests?: boolean;
|
|
28
|
+
measureFastSamples?: boolean;
|
|
29
|
+
preloadFirstSegment?: boolean;
|
|
28
30
|
}
|
|
29
31
|
export type Priority = "high" | "low" | "auto";
|
|
30
32
|
export interface FetchParamsWithUrl extends FetchParams {
|
|
@@ -47,6 +49,7 @@ export type RepresentationFetchResult = {
|
|
|
47
49
|
init: CommonInit | null;
|
|
48
50
|
segments: Segment[];
|
|
49
51
|
dataView: DataView;
|
|
52
|
+
firstSegmentData?: ArrayBuffer;
|
|
50
53
|
};
|
|
51
54
|
export declare class Fetcher {
|
|
52
55
|
private throughputEstimator;
|
|
@@ -69,11 +72,13 @@ export declare class Fetcher {
|
|
|
69
72
|
private useEnableSubtitlesParam;
|
|
70
73
|
private useUrlCacheMechanism;
|
|
71
74
|
private measureNonSegmentRequests;
|
|
75
|
+
private measureFastSamples;
|
|
76
|
+
private preloadFirstSegment;
|
|
72
77
|
private startupPhase;
|
|
73
78
|
private performanceObserver;
|
|
74
79
|
private pendingConnectionMetrics;
|
|
75
80
|
private handleExtendedNetworkErrorsSet;
|
|
76
|
-
constructor({ throughputEstimator, requestQuic, tracer, compatibilityMode, useEnableSubtitlesParam, handleExtendedNetworkErrorsSet, useUrlCacheMechanism, measureNonSegmentRequests }: IParams);
|
|
81
|
+
constructor({ throughputEstimator, requestQuic, tracer, compatibilityMode, useEnableSubtitlesParam, handleExtendedNetworkErrorsSet, useUrlCacheMechanism, measureNonSegmentRequests, measureFastSamples, preloadFirstSegment }: IParams);
|
|
77
82
|
private onHeadersReceived;
|
|
78
83
|
private setupPerformanceObserver;
|
|
79
84
|
private processPerformanceResourceTiming;
|
|
@@ -87,6 +92,7 @@ export declare class Fetcher {
|
|
|
87
92
|
destroy(): void;
|
|
88
93
|
private fetchByteRangeRepresentation;
|
|
89
94
|
private fetchTemplateRepresentation;
|
|
95
|
+
private isLikelyCacheHitByTtfb;
|
|
90
96
|
private doFetch;
|
|
91
97
|
private unsubscribeAbortSubscription;
|
|
92
98
|
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import type { Fetcher, FetchParamsWithUrl, Priority, RepresentationFetchResult } from "../../fetcher";
|
|
2
|
+
import type { CommonInit, ContainerParser, Representation, Segment } from "../../../../utils/parsers/types";
|
|
3
|
+
import { StreamKind } from "../../../../utils/parsers/types";
|
|
4
|
+
import type { ITuningConfig } from "../../../../../utils/tuningConfig";
|
|
5
|
+
import type { Byte, IError, IRange, ISubject, ITracer, IValueSubject, Milliseconds, Seconds } from "@vkontakte/videoplayer-shared";
|
|
6
|
+
import { abortable, Subscription } from "@vkontakte/videoplayer-shared";
|
|
7
|
+
import type { NativeBufferManager } from "../nativeBufferManager";
|
|
8
|
+
import { SwithRepresentationMode, type Dependencies, type IBufferPlaybackQueueItem, type ISomeDataLoadedCallbackParams, type IVirtualBufferManager } from "../types";
|
|
9
|
+
import type { VideoSegmentLoadProgress } from "../../../../utils/Abr/types";
|
|
10
|
+
export declare abstract class BaseVirtualBufferManager<T extends Segment> implements IVirtualBufferManager<T> {
|
|
11
|
+
error$: ISubject<IError>;
|
|
12
|
+
playingRepresentation$: IValueSubject<Representation["id"] | undefined>;
|
|
13
|
+
playingRepresentationInit$: IValueSubject<CommonInit | undefined>;
|
|
14
|
+
currentSegmentLength$: IValueSubject<number>;
|
|
15
|
+
onLastSegment$: IValueSubject<boolean>;
|
|
16
|
+
fullyBuffered$: IValueSubject<boolean>;
|
|
17
|
+
protected readonly kind: StreamKind;
|
|
18
|
+
protected readonly nativeBufferManager: NativeBufferManager;
|
|
19
|
+
protected readonly fetcher: Fetcher;
|
|
20
|
+
protected readonly tracer: ITracer;
|
|
21
|
+
protected readonly tuning: ITuningConfig;
|
|
22
|
+
protected representations: Map<Representation["id"], Representation>;
|
|
23
|
+
protected playingRepresentationId: Representation["id"] | undefined;
|
|
24
|
+
protected downloadingRepresentationId: Representation["id"] | undefined;
|
|
25
|
+
protected switchingRepresentationId: Representation["id"] | null;
|
|
26
|
+
protected initData: Map<Representation["id"], ArrayBuffer>;
|
|
27
|
+
protected initDataPromises: Map<Representation["id"], Promise<RepresentationFetchResult<T> | null | undefined>>;
|
|
28
|
+
protected idleCallbacks: Map<Representation["id"], number>;
|
|
29
|
+
protected parsedInitData: Map<Representation["id"], CommonInit>;
|
|
30
|
+
protected forwardBufferRepresentations: Map<Representation["id"], T[]>;
|
|
31
|
+
protected segments: Map<Representation["id"], T[]>;
|
|
32
|
+
protected containerParser: ContainerParser;
|
|
33
|
+
protected bufferPlaybackQueue: IBufferPlaybackQueueItem<T>[];
|
|
34
|
+
protected downloadingBufferItems: IBufferPlaybackQueueItem<T>[];
|
|
35
|
+
protected preloadOnly: boolean;
|
|
36
|
+
protected forwardBufferTarget: Milliseconds;
|
|
37
|
+
protected failedDownloads: number;
|
|
38
|
+
protected lastDataObtainedTimestampMs: Milliseconds;
|
|
39
|
+
protected loadByteRangeSegmentsTimeoutId: number;
|
|
40
|
+
protected currentVirtualBufferSize: Byte;
|
|
41
|
+
private baseUrls;
|
|
42
|
+
private baseUrlsIndex;
|
|
43
|
+
protected maintainAbortController: AbortController;
|
|
44
|
+
protected maintainMutexPromise: Promise<void> | null;
|
|
45
|
+
protected bufferClearingMutex: boolean;
|
|
46
|
+
protected abortNativeBufferMutex: boolean;
|
|
47
|
+
protected switchMutex: boolean;
|
|
48
|
+
protected seekMutex: boolean;
|
|
49
|
+
protected destroyAbortController: AbortController;
|
|
50
|
+
protected switchAbortController: AbortController;
|
|
51
|
+
protected downloadAbortController: AbortController;
|
|
52
|
+
protected subscription: Subscription;
|
|
53
|
+
protected readonly getCurrentPosition: () => Milliseconds | undefined;
|
|
54
|
+
protected readonly getCurrentStallDuration: () => Milliseconds | undefined;
|
|
55
|
+
protected constructor(kind: StreamKind, nativeBufferManager: NativeBufferManager, representations: Representation[], { fetcher, tracer, tuning, getCurrentPosition, getCurrentStallDuration, manifest }: Dependencies);
|
|
56
|
+
protected abstract loadItems(itemsToLoad: IBufferPlaybackQueueItem<T>[], representation: Representation, priority?: Priority): Promise<void>;
|
|
57
|
+
protected abstract selectItemsToLoad(): IBufferPlaybackQueueItem<T>[];
|
|
58
|
+
protected abstract prepareFetchParams(items: IBufferPlaybackQueueItem<T>[], representation: Representation): FetchParamsWithUrl;
|
|
59
|
+
protected abstract onSomeDataLoaded(data: ISomeDataLoadedCallbackParams<T>): Promise<void>;
|
|
60
|
+
protected abstract updateRepresentationBaseUrl(representation: Representation, newBaseUrl: string): void;
|
|
61
|
+
startWith: ReturnType<typeof abortable<[Representation["id"]]>>;
|
|
62
|
+
switchTo(newRepresentationId: Representation["id"], mode?: SwithRepresentationMode): Promise<void>;
|
|
63
|
+
protected getSwitchWithAbort(switchToTracer: ITracer): ReturnType<typeof abortable<[Representation["id"], SwithRepresentationMode], void>>;
|
|
64
|
+
prepareSeek(): Promise<void>;
|
|
65
|
+
seek(position: Milliseconds | undefined): Promise<void>;
|
|
66
|
+
maintain(currentPosition?: Milliseconds | undefined): Promise<void>;
|
|
67
|
+
getForwardBufferRepresentations(currentPosition?: Milliseconds | undefined): Map<Representation["id"], T[]>;
|
|
68
|
+
getForwardPlaybackBufferDuration(currentPosition?: Milliseconds | undefined): Milliseconds;
|
|
69
|
+
getPlaybackBufferState(): IRange<Milliseconds> | null;
|
|
70
|
+
abort(): Promise<void>;
|
|
71
|
+
findSegmentStartTime(position: Milliseconds): Milliseconds | undefined;
|
|
72
|
+
getRepresentationInitialTime(): Seconds;
|
|
73
|
+
getMutexInfo(): string;
|
|
74
|
+
calculateDurationFromSegments(): Milliseconds;
|
|
75
|
+
getActiveSegmentProgress(): VideoSegmentLoadProgress | undefined;
|
|
76
|
+
getMpdSegmentDuration(): Milliseconds | undefined;
|
|
77
|
+
get lastDataObtainedTimestamp(): Milliseconds;
|
|
78
|
+
setTarget(time: Milliseconds): void;
|
|
79
|
+
setPreloadOnly(preloadOnly: boolean): void;
|
|
80
|
+
destroy(): void;
|
|
81
|
+
protected verifyBufferPlaybackQueue(position: Milliseconds): Promise<void>;
|
|
82
|
+
protected forceSwitchCondition(oldRepresentation: Representation, newRepresentation: Representation): boolean;
|
|
83
|
+
protected clearBuffer(): Promise<void>;
|
|
84
|
+
protected abortDownload(): void;
|
|
85
|
+
protected abortDownloadingItems(): void;
|
|
86
|
+
protected abortNativeBuffer(): Promise<boolean>;
|
|
87
|
+
protected loadInits(): Promise<void>;
|
|
88
|
+
protected loadInitIfNeeded(representation: Representation, requestedPriority?: Priority, critical?: boolean): Promise<void>;
|
|
89
|
+
protected loadInit(representation: Representation, requestedPriority?: Priority, critical?: boolean): Promise<void>;
|
|
90
|
+
private isMaintainNativeBufferMutexActive;
|
|
91
|
+
protected maintainNativeBuffer(signal: AbortSignal): Promise<void>;
|
|
92
|
+
protected maintainPlaybackBuffer(position: Milliseconds): Promise<void>;
|
|
93
|
+
protected actualizeLastSegmentInfo(currentPosition: Milliseconds): void;
|
|
94
|
+
protected selectDownloadingItems(position: Milliseconds, segments: T[]): IBufferPlaybackQueueItem<T>[];
|
|
95
|
+
protected processCachedItems(): void;
|
|
96
|
+
protected withinInterval(currentPosition: Milliseconds | undefined, { from, to }: IRange<Milliseconds>, leftTolerance?: Milliseconds, rightTolerance?: Milliseconds): boolean;
|
|
97
|
+
protected withinAppendInterval(currentPosition: Milliseconds | undefined, { from, to }: IRange<Milliseconds>): boolean;
|
|
98
|
+
protected withinRemoveInterval(currentPosition: Milliseconds | undefined, { to }: IRange<Milliseconds>): boolean;
|
|
99
|
+
protected getExponentialDownloadDelay(): ReturnType<typeof abortable>;
|
|
100
|
+
protected waitExponentialDownloadDelay(): Promise<void>;
|
|
101
|
+
protected appendSegmentFully(nextPlayingItem: IBufferPlaybackQueueItem<T>, signal: AbortSignal): Promise<void>;
|
|
102
|
+
protected appendSegmentPartially(nextPlayingItem: IBufferPlaybackQueueItem<T>, signal: AbortSignal): Promise<void>;
|
|
103
|
+
protected parseFeedableSegmentChunk(chunk: DataView): DataView | null;
|
|
104
|
+
protected onItemFullyDownloaded(downloadedItem: IBufferPlaybackQueueItem<T>): void;
|
|
105
|
+
protected onItemFullyAppended(appendedItem: IBufferPlaybackQueueItem<T>): void;
|
|
106
|
+
protected removeSegment(nextRemoveItem: IBufferPlaybackQueueItem<T>, signal: AbortSignal): Promise<void>;
|
|
107
|
+
protected onDownloadItem(downloadedItem: IBufferPlaybackQueueItem<T>): void;
|
|
108
|
+
protected pruneVirtualBuffer(currentPosition: Milliseconds): void;
|
|
109
|
+
protected updateRepresentationsBaseUrlIfNeeded(): void;
|
|
110
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { BaseVirtualBufferManager } from "./baseVirtualBufferManager.versionA";
|
|
2
|
+
import type { Dependencies, IBufferPlaybackQueueItem, ISomeDataLoadedCallbackParams, IVirtualBufferManager } from "../types";
|
|
3
|
+
import type { ByteRangeSegment, Representation, StreamKind } from "../../../../utils/parsers/types";
|
|
4
|
+
import type { NativeBufferManager } from "../nativeBufferManager";
|
|
5
|
+
import type { FetchParamsWithUrl, Priority } from "../../fetcher";
|
|
6
|
+
export declare class ByteRangeVirtualBufferManager extends BaseVirtualBufferManager<ByteRangeSegment> implements IVirtualBufferManager<ByteRangeSegment> {
|
|
7
|
+
constructor(kind: StreamKind, nativeBufferManager: NativeBufferManager, representations: Representation[], dependencies: Dependencies);
|
|
8
|
+
protected override loadItems(itemsToLoad: IBufferPlaybackQueueItem<ByteRangeSegment>[], representation: Representation, priority?: Priority): Promise<void>;
|
|
9
|
+
protected override selectItemsToLoad(): IBufferPlaybackQueueItem<ByteRangeSegment>[];
|
|
10
|
+
protected override prepareFetchParams(items: IBufferPlaybackQueueItem<ByteRangeSegment>[], representation: Representation): FetchParamsWithUrl;
|
|
11
|
+
/**
|
|
12
|
+
* Закидываем в буфер сегменты атомарнее чем сегмент целиком. Например, по боксам в мпеге и по блокам в вебме.
|
|
13
|
+
* Таким образом не ждём его полной загрузки и готовы играть его намного быстрее
|
|
14
|
+
* @param dataView – данные, размер буфера – весь запрос
|
|
15
|
+
* @param globalFrom – Отступ dataView от начала файла, совпадает с отсупами сегментов
|
|
16
|
+
* @param loaded – Объём загруженных в dataView данных (всё что больше – пока нули)
|
|
17
|
+
* @private
|
|
18
|
+
*/
|
|
19
|
+
protected override onSomeDataLoaded({ downloadingItems, dataView, representationId, globalFrom, loaded, signal }: ISomeDataLoadedCallbackParams<ByteRangeSegment>): Promise<void>;
|
|
20
|
+
protected override updateRepresentationBaseUrl(representation: Representation, newBaseUrl: string): void;
|
|
21
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { BaseVirtualBufferManager } from "./baseVirtualBufferManager.versionA";
|
|
2
|
+
import type { Dependencies, IBufferPlaybackQueueItem, ISomeDataLoadedCallbackParams, IVirtualBufferManager } from "../types";
|
|
3
|
+
import type { TemplateSegment, Representation, StreamKind } from "../../../../utils/parsers/types";
|
|
4
|
+
import type { NativeBufferManager } from "../nativeBufferManager";
|
|
5
|
+
import type { FetchParamsWithUrl, Priority } from "../../fetcher";
|
|
6
|
+
export declare class TemplateVirtualBufferManager extends BaseVirtualBufferManager<TemplateSegment> implements IVirtualBufferManager<TemplateSegment> {
|
|
7
|
+
constructor(kind: StreamKind, nativeBufferManager: NativeBufferManager, representations: Representation[], dependencies: Dependencies);
|
|
8
|
+
protected override loadItems(itemsToLoad: IBufferPlaybackQueueItem<TemplateSegment>[], representation: Representation, priority?: Priority): Promise<void>;
|
|
9
|
+
protected override selectItemsToLoad(): IBufferPlaybackQueueItem<TemplateSegment>[];
|
|
10
|
+
protected override prepareFetchParams(items: IBufferPlaybackQueueItem<TemplateSegment>[], representation: Representation): FetchParamsWithUrl;
|
|
11
|
+
protected getFetchUrl(items: IBufferPlaybackQueueItem<TemplateSegment>[], representation: Representation): URL;
|
|
12
|
+
/**
|
|
13
|
+
* Закидываем в буфер сегменты атомарнее чем сегмент целиком. Например, по боксам в мпеге и по блокам в вебме.
|
|
14
|
+
* Таким образом не ждём его полной загрузки и готовы играть его намного быстрее
|
|
15
|
+
* @param dataView – данные, размер буфера – весь запрос
|
|
16
|
+
* @param loaded – Объём загруженных в dataView данных (всё что больше – пока нули)
|
|
17
|
+
* @private
|
|
18
|
+
*/
|
|
19
|
+
protected override onSomeDataLoaded({ downloadingItems, dataView, representationId, loaded, signal }: ISomeDataLoadedCallbackParams<TemplateSegment>): Promise<void>;
|
|
20
|
+
protected override updateRepresentationBaseUrl(representation: Representation, newBaseUrl: string): void;
|
|
21
|
+
}
|
package/types/providers/DashProviderVirtual/lib/buffer/virtualBuffer/virtualBufferFactory.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Representation, StreamKind } from "../../../../utils/parsers/types";
|
|
2
2
|
import type { NativeBufferManager } from "../nativeBufferManager";
|
|
3
3
|
import type { Dependencies, IVirtualBufferManager } from "../types";
|
|
4
|
+
import type { ITuningConfig } from "../../../../../utils/tuningConfig";
|
|
4
5
|
export declare class VirtualBufferFactory {
|
|
5
|
-
static getBufferManager(kind: StreamKind, nativeBufferManager: NativeBufferManager, representations: Representation[], dependencies: Dependencies): IVirtualBufferManager;
|
|
6
|
+
static getBufferManager(kind: StreamKind, nativeBufferManager: NativeBufferManager, representations: Representation[], dependencies: Dependencies, tuning: ITuningConfig): IVirtualBufferManager;
|
|
6
7
|
}
|
|
@@ -25,6 +25,8 @@ export interface IParams {
|
|
|
25
25
|
handleExtendedNetworkErrorsSet?: boolean;
|
|
26
26
|
useUrlCacheMechanism?: boolean;
|
|
27
27
|
measureNonSegmentRequests?: boolean;
|
|
28
|
+
measureFastSamples?: boolean;
|
|
29
|
+
preloadFirstSegment?: boolean;
|
|
28
30
|
}
|
|
29
31
|
export type Priority = "high" | "low" | "auto";
|
|
30
32
|
export interface FetchParamsWithUrl extends FetchParams {
|
|
@@ -46,6 +48,7 @@ export type RepresentationFetchResult<T extends Segment> = {
|
|
|
46
48
|
initMetadata: CommonInit | null;
|
|
47
49
|
initDataView: DataView;
|
|
48
50
|
segments: T[];
|
|
51
|
+
firstSegmentData?: ArrayBuffer;
|
|
49
52
|
};
|
|
50
53
|
export declare class Fetcher {
|
|
51
54
|
private throughputEstimator;
|
|
@@ -68,11 +71,13 @@ export declare class Fetcher {
|
|
|
68
71
|
private useEnableSubtitlesParam;
|
|
69
72
|
private useUrlCacheMechanism;
|
|
70
73
|
private measureNonSegmentRequests;
|
|
74
|
+
private measureFastSamples;
|
|
75
|
+
private preloadFirstSegment;
|
|
71
76
|
private startupPhase;
|
|
72
77
|
private performanceObserver;
|
|
73
78
|
private pendingConnectionMetrics;
|
|
74
79
|
private handleExtendedNetworkErrorsSet;
|
|
75
|
-
constructor({ throughputEstimator, requestQuic, tracer, compatibilityMode, useEnableSubtitlesParam, handleExtendedNetworkErrorsSet, useUrlCacheMechanism, measureNonSegmentRequests }: IParams);
|
|
80
|
+
constructor({ throughputEstimator, requestQuic, tracer, compatibilityMode, useEnableSubtitlesParam, handleExtendedNetworkErrorsSet, useUrlCacheMechanism, measureNonSegmentRequests, measureFastSamples, preloadFirstSegment }: IParams);
|
|
76
81
|
private onHeadersReceived;
|
|
77
82
|
private setupPerformanceObserver;
|
|
78
83
|
private processResourceTiming;
|
|
@@ -86,5 +91,6 @@ export declare class Fetcher {
|
|
|
86
91
|
destroy(): void;
|
|
87
92
|
private fetchByteRangeRepresentation;
|
|
88
93
|
private fetchTemplateRepresentation;
|
|
94
|
+
private isLikelyCacheHitByTtfb;
|
|
89
95
|
private doFetch;
|
|
90
96
|
}
|
|
@@ -1,19 +1,20 @@
|
|
|
1
|
+
import { Subject } from "@vkontakte/videoplayer-shared";
|
|
1
2
|
import type { IError } from "@vkontakte/videoplayer-shared";
|
|
2
|
-
import type { IMaydayDeps,
|
|
3
|
+
import type { IMaydayDeps, IMaydayEvent } from "./types";
|
|
3
4
|
export declare class MaydayService {
|
|
4
5
|
private deps;
|
|
5
6
|
private heuristics;
|
|
6
7
|
private tracer;
|
|
7
8
|
private providerFailures;
|
|
8
9
|
private failoverUrlIndex;
|
|
10
|
+
readonly recommendation$: Subject<IMaydayEvent>;
|
|
11
|
+
private subscription;
|
|
9
12
|
constructor(deps: IMaydayDeps);
|
|
10
13
|
get currentFailoverUrlIndex(): number | undefined;
|
|
11
|
-
|
|
14
|
+
handleError(error: IError): void;
|
|
15
|
+
private emitRecommendation;
|
|
12
16
|
private validateRecommendation;
|
|
13
17
|
private hasAvailableFailoverHost;
|
|
14
|
-
/**
|
|
15
|
-
* Если рекомендаций от эвристик нету, то идем по общему сценарию.
|
|
16
|
-
*/
|
|
17
18
|
private computeFallbackRecommendation;
|
|
18
19
|
private applyStateChange;
|
|
19
20
|
reset(): void;
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import type { IError } from "@vkontakte/videoplayer-shared";
|
|
2
|
-
import type {
|
|
3
|
-
import type {
|
|
4
|
-
export declare class FetcherErrorHeuristic implements
|
|
2
|
+
import type { IHeuristicDeps } from "../types";
|
|
3
|
+
import type { ISyncHeuristic, HeuristicResult } from "./IHeuristic";
|
|
4
|
+
export declare class FetcherErrorHeuristic implements ISyncHeuristic {
|
|
5
5
|
private _deps;
|
|
6
6
|
static readonly heuristicName = "FetcherErrorHeuristic";
|
|
7
|
+
readonly type = "sync";
|
|
7
8
|
constructor(_deps: IHeuristicDeps);
|
|
8
|
-
analyze(error: IError):
|
|
9
|
+
analyze(error: IError): HeuristicResult;
|
|
9
10
|
}
|
|
@@ -0,0 +1,22 @@
|
|
|
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
|
+
}
|
|
@@ -1,7 +1,17 @@
|
|
|
1
|
-
import type { IError } from "@vkontakte/videoplayer-shared";
|
|
2
|
-
import type { IRecommendation } from "../types";
|
|
3
|
-
export
|
|
4
|
-
|
|
1
|
+
import type { IError, ISubject } from "@vkontakte/videoplayer-shared";
|
|
2
|
+
import type { IMaydayEvent, IRecommendation } from "../types";
|
|
3
|
+
export type HeuristicResult = IRecommendation | null;
|
|
4
|
+
interface IHeuristicBase {
|
|
5
|
+
analyze(error: IError): HeuristicResult;
|
|
5
6
|
reset?(): void;
|
|
6
7
|
destroy?(): void;
|
|
7
8
|
}
|
|
9
|
+
export interface ISyncHeuristic extends IHeuristicBase {
|
|
10
|
+
readonly type: "sync";
|
|
11
|
+
}
|
|
12
|
+
export interface IAsyncHeuristic extends IHeuristicBase {
|
|
13
|
+
readonly type: "async";
|
|
14
|
+
readonly recommendation$: ISubject<IMaydayEvent>;
|
|
15
|
+
}
|
|
16
|
+
export type IHeuristic = ISyncHeuristic | IAsyncHeuristic;
|
|
17
|
+
export {};
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import type { IError } from "@vkontakte/videoplayer-shared";
|
|
2
|
-
import type {
|
|
3
|
-
import type {
|
|
4
|
-
export declare class MediaErrorHeuristic implements
|
|
2
|
+
import type { IHeuristicDeps } from "../types";
|
|
3
|
+
import type { ISyncHeuristic, HeuristicResult } from "./IHeuristic";
|
|
4
|
+
export declare class MediaErrorHeuristic implements ISyncHeuristic {
|
|
5
5
|
private deps;
|
|
6
6
|
static readonly heuristicName = "MediaErrorHeuristic";
|
|
7
|
+
readonly type = "sync";
|
|
7
8
|
constructor(deps: IHeuristicDeps);
|
|
8
|
-
analyze(error: IError):
|
|
9
|
+
analyze(error: IError): HeuristicResult;
|
|
9
10
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { MaydayService } from "./MaydayService";
|
|
2
|
-
export type { IMaydayDeps, IFallbackContext, IRecommendation, RecoveryAction } from "./types";
|
|
3
|
-
export type {
|
|
2
|
+
export type { IMaydayDeps, IFallbackContext, IRecommendation, RecoveryAction, IMaydayEvent } from "./types";
|
|
3
|
+
export type { ISyncHeuristic, IAsyncHeuristic, HeuristicResult } from "./heuristics/IHeuristic";
|
|
4
4
|
export { MediaErrorHeuristic } from "./heuristics/MediaErrorHeuristic";
|
|
5
5
|
export { FetcherErrorHeuristic } from "./heuristics/FetcherErrorHeuristic";
|
|
6
|
+
export { HangupHeuristic } from "./heuristics/HangupHeuristic";
|
|
6
7
|
export { MaydayStatistics } from "./MaydayStatistics";
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Subject } from "@vkontakte/videoplayer-shared";
|
|
2
|
+
import type { ITracer } from "@vkontakte/videoplayer-shared";
|
|
3
|
+
import { PlaybackState } from "../../../player/types";
|
|
4
|
+
import type { ITransition } from "../../../utils/StateMachine/types";
|
|
5
|
+
import type { IHeuristicDeps, IMaydayProviderOutput, IMaydayDeps } from "./types";
|
|
6
|
+
export declare function createMockTracer(): ITracer;
|
|
7
|
+
export declare function createMockProviderOutput(overrides?: Partial<IMaydayProviderOutput>): IMaydayProviderOutput;
|
|
8
|
+
export declare function createMockDesiredPlaybackState$(): {
|
|
9
|
+
stateChangeStarted$: Subject<unknown>;
|
|
10
|
+
stateChangeEnded$: Subject<ITransition<PlaybackState>>;
|
|
11
|
+
transitionEnded$: Subject<unknown>;
|
|
12
|
+
getState: () => PlaybackState;
|
|
13
|
+
};
|
|
14
|
+
export declare function createMockHeuristicDeps(params?: {
|
|
15
|
+
overrides?: Partial<IHeuristicDeps>;
|
|
16
|
+
tuningOverrides?: Record<string, unknown>;
|
|
17
|
+
}): IHeuristicDeps;
|
|
18
|
+
export declare function createMockMaydayDeps(params?: {
|
|
19
|
+
overrides?: Partial<IMaydayDeps>;
|
|
20
|
+
tuningOverrides?: Record<string, unknown>;
|
|
21
|
+
}): IMaydayDeps;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import type { IVideoTrack, IVideoStream, IAudioStream } from "../../../player/types";
|
|
2
|
-
import type { IValueSubject, Milliseconds, Seconds, IRange, ITracer } from "@vkontakte/videoplayer-shared";
|
|
1
|
+
import type { IVideoTrack, IVideoStream, IAudioStream, PlaybackState } from "../../../player/types";
|
|
2
|
+
import type { IError, IValueSubject, ISubject, IObservable, Milliseconds, Seconds, IRange, ITracer } from "@vkontakte/videoplayer-shared";
|
|
3
|
+
import type { IStateMachine } from "../../../utils/StateMachine/types";
|
|
3
4
|
import type { ITuningConfig } from "../../../utils/tuningConfig";
|
|
4
5
|
export interface IFallbackContext {
|
|
5
6
|
hasProviderStarted: boolean;
|
|
@@ -17,11 +18,17 @@ export interface IMaydayProviderOutput {
|
|
|
17
18
|
bufferRangeCount$: IValueSubject<number | undefined>;
|
|
18
19
|
availableVideoStreams$: IValueSubject<IVideoStream[]>;
|
|
19
20
|
currentAudioStream$: IValueSubject<IAudioStream | undefined>;
|
|
21
|
+
videoLastDataObtainedTimestamp$: IValueSubject<Milliseconds | undefined>;
|
|
22
|
+
soundProhibitedEvent$: ISubject<void>;
|
|
23
|
+
element$: IValueSubject<HTMLVideoElement | undefined>;
|
|
24
|
+
manifestRequested$: IObservable<void>;
|
|
25
|
+
manifestReceived$: IObservable<void>;
|
|
20
26
|
}
|
|
21
27
|
export interface IMaydayDeps {
|
|
22
28
|
tuning: ITuningConfig;
|
|
23
29
|
failoverHosts: string[];
|
|
24
30
|
providerOutput: IMaydayProviderOutput;
|
|
31
|
+
desiredPlaybackState$: IStateMachine<PlaybackState>;
|
|
25
32
|
maydayStatistics: {
|
|
26
33
|
getInitiatedAt: () => number;
|
|
27
34
|
getReinitHistory: () => IReinitHistory;
|
|
@@ -45,9 +52,20 @@ export interface IHeuristicDeps {
|
|
|
45
52
|
getVideoCodec: () => string | undefined;
|
|
46
53
|
getAudioCodec: () => string | undefined;
|
|
47
54
|
getVisibilityState: () => DocumentVisibilityState | undefined;
|
|
55
|
+
getReadyState: () => number | undefined;
|
|
56
|
+
getVideoPaused: () => boolean | undefined;
|
|
57
|
+
currentNativeBuffer$: IValueSubject<IRange<Seconds> | undefined>;
|
|
58
|
+
videoLastDataObtainedTimestamp$: IValueSubject<Milliseconds | undefined>;
|
|
59
|
+
desiredPlaybackState$: IStateMachine<PlaybackState>;
|
|
60
|
+
manifestRequested$: IObservable<void>;
|
|
61
|
+
manifestReceived$: IObservable<void>;
|
|
48
62
|
}
|
|
49
|
-
export type RecoveryAction = "reinit" | "failover_host" | "switch_codec" | "switch_provider";
|
|
63
|
+
export type RecoveryAction = "reinit" | "failover_host" | "switch_codec" | "switch_provider" | "wait";
|
|
50
64
|
export interface IRecommendation {
|
|
51
65
|
action: RecoveryAction;
|
|
52
66
|
reason: string;
|
|
53
67
|
}
|
|
68
|
+
export interface IMaydayEvent {
|
|
69
|
+
error: IError;
|
|
70
|
+
recommendation: IRecommendation;
|
|
71
|
+
}
|
|
@@ -43,6 +43,25 @@ export type ITuningConfig = {
|
|
|
43
43
|
measureNonSegmentRequests: boolean;
|
|
44
44
|
smallSampleMinDuration: Milliseconds;
|
|
45
45
|
cacheThresholdSize: Milliseconds;
|
|
46
|
+
/**
|
|
47
|
+
* Фичафлаг UVP-10855: лечит залипание throughput на быстрых соединениях.
|
|
48
|
+
*
|
|
49
|
+
* Проблема: на быстром соединении крупный сегмент реально скачивается за ≤ cacheThresholdSize
|
|
50
|
+
* (например 200 КБ за 10 мс = 160 Мбит/с), а sanityCheck режет такие сэмплы как «кэш».
|
|
51
|
+
* Промежуточных сэмплов нет (нужно streamMinSampleTime=300 мс), поэтому эстиматор не получает
|
|
52
|
+
* ни одного значения, throughput стоит на стартовой оценке → ABR не поднимает качество
|
|
53
|
+
* (мелкие сегменты качаются быстро → замкнутый круг).
|
|
54
|
+
*
|
|
55
|
+
* При true:
|
|
56
|
+
* 1. Фетчер детектит кэш-хиты двумя сигналами (OR) и НЕ измеряет их:
|
|
57
|
+
* - fromCache — попадание в Cache API (doFetch дёргает onCacheHit);
|
|
58
|
+
* - TTFB — headersReceivedAt - requestStartedAt < max(rtt*0.5, 2мс) (кэш ~0, реал ≥ RTT).
|
|
59
|
+
* 2. sanityCheck отключает порог time ≤ cacheThresholdSize → реальные быстрые сэмплы проходят.
|
|
60
|
+
* Честный кэш (мгновенная отдача → rate > 1 Гбит/с) по-прежнему режется проверкой rate выше.
|
|
61
|
+
*
|
|
62
|
+
* По умолчанию false — поведение не меняется.
|
|
63
|
+
*/
|
|
64
|
+
measureFastSamples: boolean;
|
|
46
65
|
rttPenaltyRequestSize: Byte;
|
|
47
66
|
streamMinSampleSize: Byte;
|
|
48
67
|
streamMinSampleTime: Milliseconds;
|
|
@@ -156,6 +175,7 @@ export type ITuningConfig = {
|
|
|
156
175
|
virtualBufferEmptinessTolerance: Milliseconds;
|
|
157
176
|
useBufferQueueVerification: boolean;
|
|
158
177
|
useVirtualBufferImplicitSeek: boolean;
|
|
178
|
+
bufferQueueVerificationMinPosition: Milliseconds;
|
|
159
179
|
useNewRepresentationSwitch: boolean;
|
|
160
180
|
useDelayedRepresentationSwitch: boolean;
|
|
161
181
|
useSmartRepresentationSwitch: boolean;
|
|
@@ -231,6 +251,7 @@ export type ITuningConfig = {
|
|
|
231
251
|
filterOnDemandQualityList: boolean;
|
|
232
252
|
dashMaxTvVideoQuality: boolean;
|
|
233
253
|
checkRepresentationCanPlayType: Extract<CanPlayTypeResult, "maybe" | "probably"> | false;
|
|
254
|
+
preloadFirstSegment: boolean;
|
|
234
255
|
downloadTime: {
|
|
235
256
|
minLookaheadSegments: number;
|
|
236
257
|
safetyFactor: number;
|
|
@@ -311,6 +332,7 @@ export type ITuningConfig = {
|
|
|
311
332
|
dashSeekInSegmentAlwaysSeekDelta: Milliseconds;
|
|
312
333
|
useDelayedPlaybackHangupWithData: boolean;
|
|
313
334
|
playbackHangupNoDataThreshold: Milliseconds;
|
|
335
|
+
hangupTimeoutMs: Milliseconds;
|
|
314
336
|
endGapTolerance: Milliseconds;
|
|
315
337
|
/**
|
|
316
338
|
* Время после перехода в состояние buffering, когда мы считаем что происходит stall
|
|
@@ -332,6 +354,7 @@ export type ITuningConfig = {
|
|
|
332
354
|
useNewSwitchTo: boolean;
|
|
333
355
|
alwaysAbortPreviousSwitch: boolean;
|
|
334
356
|
useDashProviderVirtual: boolean;
|
|
357
|
+
useDashProviderVirtualVersionA: boolean;
|
|
335
358
|
useDashProviderVirtualMobile: boolean;
|
|
336
359
|
useNewAutoSelectVideoTrack: boolean;
|
|
337
360
|
useSafariEndlessRequestBugfix: boolean;
|