@linker-design-plus/timeline-track 2.0.23 → 2.1.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/README.md +4 -0
- package/dist/components/panel/ClipConfigPanelRenderer.d.ts +2 -0
- package/dist/core/controllers/previewBackend.d.ts +23 -7
- package/dist/core/controllers/previewPendingOverlayRenderer.d.ts +1 -2
- package/dist/core/controllers/previewRecoveryExecution.d.ts +25 -0
- package/dist/core/controllers/previewSlotCoordinator.d.ts +18 -0
- package/dist/core/controllers/previewSlotLifecycle.d.ts +41 -0
- package/dist/core/controllers/previewSlotPolicy.d.ts +59 -0
- package/dist/core/controllers/previewTrackPlanner.d.ts +24 -0
- package/dist/core/controllers/previewTransformOverlay.d.ts +2 -0
- package/dist/core/controllers/timelinePreviewSession.d.ts +27 -8
- package/dist/core/controllers/timelinePreviewStateController.d.ts +6 -15
- package/dist/core/facade/timelineManager.d.ts +15 -8
- package/dist/core/models/types.d.ts +6 -6
- package/dist/index.cjs.js +108 -108
- package/dist/index.es.js +4676 -4143
- package/dist/utils/diagnostics/types.d.ts +4 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -176,6 +176,9 @@ interface ClipConfig {
|
|
|
176
176
|
- 当前代码路径实际只会创建 `DomPreviewBackend`
|
|
177
177
|
- `previewBackend` 字段被保留,目的是不给后续预览实现扩展制造额外 breaking change
|
|
178
178
|
- 如果你在业务接入层看到 `canvas` / `auto` 配置,请把它当作保留参数,而不是当前版本的有效能力
|
|
179
|
+
- 挂载预览且当前时间命中视频片段时,播放时间由预览视频的真实媒体时钟驱动;媒体 buffering 或 stalled 导致画面没有前进时,播放指针也不会继续超前
|
|
180
|
+
- 多视频叠加播放时,任意一路 active 视频仍在加载或卡顿,预览层会暂停整个 active 播放组,等当前时刻所有视频都 ready 后统一恢复
|
|
181
|
+
- 空白段、纯音频、文本或未挂载预览时,播放仍回退到 `TimelineManager` 的 wall-clock 推进
|
|
179
182
|
|
|
180
183
|
## 架构概览
|
|
181
184
|
|
|
@@ -229,6 +232,7 @@ pnpm exec tsc -p tsconfig.json --noEmit
|
|
|
229
232
|
## 相关文档
|
|
230
233
|
|
|
231
234
|
- [docs/interaction-model.md](./docs/interaction-model.md): 指针交互分层和拖拽约束
|
|
235
|
+
- [docs/preview-playback-recovery-flow.md](./docs/preview-playback-recovery-flow.md): 预览媒体时钟驱动播放、buffering 阻塞与恢复续播流程
|
|
232
236
|
- [docs/refactor-roadmap.md](./docs/refactor-roadmap.md): 主线重构归档与后续收敛方向
|
|
233
237
|
- [docs/maintenance-audit.md](./docs/maintenance-audit.md): 本轮仓库审计、验证结果和依赖建议
|
|
234
238
|
- [docs/review-remediation-plan.md](./docs/review-remediation-plan.md): 基于审查结论的修复计划与阶段性落地建议
|
|
@@ -15,8 +15,6 @@ export interface TimelinePreviewSyncPayload {
|
|
|
15
15
|
syncRequestId?: number;
|
|
16
16
|
}
|
|
17
17
|
export interface TimelinePreviewBackendCallbacks {
|
|
18
|
-
onBufferingStateChange?: (isBuffering: boolean) => void;
|
|
19
|
-
onSourceLoadingChange?: (pending: number) => void;
|
|
20
18
|
onSyncProcessed?: (syncRequestId?: number) => void;
|
|
21
19
|
onRuntimeStateChange?: (state: PreviewRuntimeState) => void;
|
|
22
20
|
onAspectRatioChange?: (aspectRatio: PreviewAspectRatio) => void;
|
|
@@ -26,16 +24,34 @@ export interface TimelinePreviewBackendCallbacks {
|
|
|
26
24
|
onTextRotationCommit?: (clipId: string, rotation: number) => void;
|
|
27
25
|
onPendingPreviewRetry?: () => void;
|
|
28
26
|
onRuntimeError?: (error: unknown) => void;
|
|
27
|
+
/** 预览层文字交互(点击字幕或文字变换控件)时若时间线处于播放中,用于请求暂停 */
|
|
28
|
+
onPauseIfPlaying?: () => void;
|
|
29
|
+
}
|
|
30
|
+
export type PreviewLoadingStatus = 'idle' | 'loading' | 'ready' | 'failed';
|
|
31
|
+
export type PreviewLoadingReason = 'syncing' | 'resolving-source' | 'seeking' | 'media-pending' | 'failed' | null;
|
|
32
|
+
export interface PreviewLoadingState {
|
|
33
|
+
status: PreviewLoadingStatus;
|
|
34
|
+
isLoading: boolean;
|
|
35
|
+
reason: PreviewLoadingReason;
|
|
29
36
|
}
|
|
30
37
|
export interface PreviewPendingState {
|
|
31
|
-
mode: 'seek' | 'scrub';
|
|
38
|
+
mode: 'seek' | 'scrub' | 'playback';
|
|
32
39
|
targetTime: TimeMs;
|
|
33
|
-
|
|
34
|
-
isBuffering: boolean;
|
|
40
|
+
loading: PreviewLoadingState;
|
|
35
41
|
errorMessage: string | null;
|
|
36
42
|
}
|
|
37
43
|
export type PreviewRuntimePhase = 'idle' | 'awaiting-sync' | 'awaiting-media' | 'ready' | 'failed';
|
|
38
44
|
export type PreviewSlotPhase = 'idle' | 'binding' | 'primed' | 'active' | 'recovering' | 'failed';
|
|
45
|
+
export type PreviewClockStatus = 'unavailable' | 'priming' | 'running' | 'blocked' | 'failed';
|
|
46
|
+
export type PreviewClockBlockedReason = 'no-video-clock' | 'syncing' | 'resolving-source' | 'seeking' | 'media-pending' | 'media-paused' | 'media-stalled' | 'failed' | null;
|
|
47
|
+
export interface PreviewClockState {
|
|
48
|
+
status: PreviewClockStatus;
|
|
49
|
+
timelineTime: TimeMs | null;
|
|
50
|
+
mediaTime: TimeMs | null;
|
|
51
|
+
clipId: string | null;
|
|
52
|
+
trackId: string | null;
|
|
53
|
+
reason: PreviewClockBlockedReason;
|
|
54
|
+
}
|
|
39
55
|
export interface PreviewSlotDiagnostic {
|
|
40
56
|
trackId: string;
|
|
41
57
|
role: 'current' | 'preload';
|
|
@@ -50,8 +66,8 @@ export interface PreviewSlotDiagnostic {
|
|
|
50
66
|
export interface PreviewRuntimeState {
|
|
51
67
|
syncRequestId?: number;
|
|
52
68
|
phase: PreviewRuntimePhase;
|
|
53
|
-
|
|
54
|
-
|
|
69
|
+
loading: PreviewLoadingState;
|
|
70
|
+
clock?: PreviewClockState;
|
|
55
71
|
errorMessage: string | null;
|
|
56
72
|
slots: PreviewSlotDiagnostic[];
|
|
57
73
|
}
|
|
@@ -3,16 +3,15 @@ import type { DomRenderer } from '../renderers/domRenderer';
|
|
|
3
3
|
export interface PreviewPendingOverlayViewModel {
|
|
4
4
|
pendingState: PreviewPendingState | null;
|
|
5
5
|
runtimeState: PreviewRuntimeState;
|
|
6
|
-
isBuffering: boolean;
|
|
7
6
|
}
|
|
8
7
|
export declare class PreviewPendingOverlayRenderer implements DomRenderer<PreviewPendingOverlayViewModel> {
|
|
9
8
|
private container;
|
|
10
9
|
private statusElement;
|
|
11
|
-
private detailElement;
|
|
12
10
|
private actionElement;
|
|
13
11
|
private readonly onRetry;
|
|
14
12
|
constructor(onRetry: () => void);
|
|
15
13
|
mount(container: HTMLElement): void;
|
|
16
14
|
update(viewModel: PreviewPendingOverlayViewModel): void;
|
|
15
|
+
private resolveLoadingStatusText;
|
|
17
16
|
destroy(): void;
|
|
18
17
|
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { ActiveClipPlaybackInfo } from '../models/types';
|
|
2
|
+
import { type PreviewSlotRecoveryReason } from './previewSlotPolicy';
|
|
3
|
+
export interface PreviewRecoveryAttemptInput {
|
|
4
|
+
entry: ActiveClipPlaybackInfo;
|
|
5
|
+
desiredSource: string;
|
|
6
|
+
reason: PreviewSlotRecoveryReason;
|
|
7
|
+
previousRecoveryKey: string | null;
|
|
8
|
+
previousRetryCount: number;
|
|
9
|
+
maxImmediateRecoveryRetries: number;
|
|
10
|
+
recoveryTimeBucketMs: number;
|
|
11
|
+
isBackgroundPreload: boolean;
|
|
12
|
+
}
|
|
13
|
+
export type PreviewRecoveryAttemptResult = {
|
|
14
|
+
status: 'continue';
|
|
15
|
+
recoveryKey: string;
|
|
16
|
+
retryCount: number;
|
|
17
|
+
} | {
|
|
18
|
+
status: 'park';
|
|
19
|
+
message: string;
|
|
20
|
+
parkReason: 'retries-exhausted';
|
|
21
|
+
} | {
|
|
22
|
+
status: 'fail';
|
|
23
|
+
message: string;
|
|
24
|
+
};
|
|
25
|
+
export declare function resolveRecoveryAttempt(input: PreviewRecoveryAttemptInput): PreviewRecoveryAttemptResult;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ActiveClipPlaybackInfo, PlayState } from '../models/types';
|
|
2
|
+
import type { PreviewSlotTarget } from './previewTrackPlanner';
|
|
3
|
+
export interface PreviewSlotLike {
|
|
4
|
+
role: 'current' | 'preload';
|
|
5
|
+
trackId: string;
|
|
6
|
+
entry: ActiveClipPlaybackInfo | null;
|
|
7
|
+
requestedPlayState: PlayState;
|
|
8
|
+
}
|
|
9
|
+
export interface TrackSlotPairLike<TSlot extends PreviewSlotLike = PreviewSlotLike> {
|
|
10
|
+
current: TSlot;
|
|
11
|
+
preload: TSlot;
|
|
12
|
+
}
|
|
13
|
+
export declare function slotHasEntry(slot: PreviewSlotLike, clipId?: string | null): boolean;
|
|
14
|
+
export declare function shouldSwapTrackSlotsForPlan(slots: TrackSlotPairLike, currentEntry: ActiveClipPlaybackInfo | null): boolean;
|
|
15
|
+
export declare function swapTrackSlotPair<TSlot extends PreviewSlotLike>(slots: TrackSlotPairLike<TSlot>): TrackSlotPairLike<TSlot>;
|
|
16
|
+
export declare function buildSlotKey(slot: Pick<PreviewSlotLike, 'trackId' | 'role'>): string;
|
|
17
|
+
export declare function buildDeferredPreloadTarget(slot: PreviewSlotLike, syncRequestId?: number): PreviewSlotTarget | null;
|
|
18
|
+
export declare function resolveSlotFromKey<TSlot extends PreviewSlotLike>(trackSlots: Map<string, TrackSlotPairLike<TSlot>>, slotKey: string): TSlot | null;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { PlayState } from '../models/types';
|
|
2
|
+
import type { PreviewSlotPhase } from './previewBackend';
|
|
3
|
+
export interface PreviewSlotRecoveryStateLike {
|
|
4
|
+
isActive: boolean;
|
|
5
|
+
phase: PreviewSlotPhase;
|
|
6
|
+
errorMessage: string | null;
|
|
7
|
+
retryCount: number;
|
|
8
|
+
recoveryKey: string | null;
|
|
9
|
+
forceRecover: boolean;
|
|
10
|
+
isLoading: boolean;
|
|
11
|
+
isResolvingSource: boolean;
|
|
12
|
+
isBuffering: boolean;
|
|
13
|
+
isSeeking: boolean;
|
|
14
|
+
consecutiveStalledCount: number;
|
|
15
|
+
expectedEmptiedEvents: number;
|
|
16
|
+
recoverableEventCount: number;
|
|
17
|
+
loadStartedSinceRecover: boolean;
|
|
18
|
+
}
|
|
19
|
+
export interface PreviewTrackedCurrentVideoSlotStatus {
|
|
20
|
+
failed: boolean;
|
|
21
|
+
resolving: boolean;
|
|
22
|
+
seeking: boolean;
|
|
23
|
+
mediaUnready: boolean;
|
|
24
|
+
ready: boolean;
|
|
25
|
+
}
|
|
26
|
+
export declare function resetSlotRecoveryTrackingState(slot: PreviewSlotRecoveryStateLike, forceRecover?: boolean): void;
|
|
27
|
+
export declare function clearSlotState(slot: PreviewSlotRecoveryStateLike): void;
|
|
28
|
+
export declare function parkPreloadSlotState(slot: PreviewSlotRecoveryStateLike): void;
|
|
29
|
+
export declare function settleResolvedSourceWithoutRecoveryState(slot: Pick<PreviewSlotRecoveryStateLike, 'isActive' | 'phase' | 'isResolvingSource' | 'isLoading' | 'isBuffering' | 'errorMessage'>): void;
|
|
30
|
+
export declare function finalizeAppliedSlotPhase(slot: Pick<PreviewSlotRecoveryStateLike, 'isActive' | 'isLoading' | 'isSeeking' | 'phase'>): void;
|
|
31
|
+
export declare function beginDeferredPreloadState(slot: Pick<PreviewSlotRecoveryStateLike, 'phase' | 'forceRecover' | 'isLoading' | 'isResolvingSource' | 'isSeeking' | 'isBuffering' | 'errorMessage'>, hasAssignedSource: boolean): void;
|
|
32
|
+
export declare function reconcileTrackedCurrentVideoSlotState(slot: PreviewSlotRecoveryStateLike, input: {
|
|
33
|
+
hasDesiredSource: boolean;
|
|
34
|
+
sourceMatched: boolean;
|
|
35
|
+
withinSeekThreshold: boolean;
|
|
36
|
+
readyState: number;
|
|
37
|
+
haveCurrentDataState: number;
|
|
38
|
+
}): PreviewTrackedCurrentVideoSlotStatus;
|
|
39
|
+
export declare function failSlotState(slot: Pick<PreviewSlotRecoveryStateLike, 'phase' | 'isLoading' | 'isResolvingSource' | 'isSeeking' | 'isBuffering' | 'errorMessage' | 'forceRecover' | 'expectedEmptiedEvents'>, errorMessage: string): void;
|
|
40
|
+
export declare function beginPreloadPrimingState(slot: Pick<PreviewSlotRecoveryStateLike, 'isActive' | 'isBuffering' | 'isSeeking'>): void;
|
|
41
|
+
export declare function beginSlotRecoveryState(slot: PreviewSlotRecoveryStateLike, playState: PlayState): void;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { ActiveClipPlaybackInfo, PlayState } from '../models/types';
|
|
2
|
+
import type { PreviewSlotPhase } from './previewBackend';
|
|
3
|
+
export type PreviewSlotRecoveryReason = 'reconcile' | 'stalled' | 'abort' | 'emptied' | 'error';
|
|
4
|
+
export interface ResolvedSlotSourceLike {
|
|
5
|
+
stableSourceUrl: string;
|
|
6
|
+
url: string;
|
|
7
|
+
objectUrl: string | null;
|
|
8
|
+
}
|
|
9
|
+
export interface ReusableBoundSlotSourceInput {
|
|
10
|
+
currentSourceKey: string;
|
|
11
|
+
nextSourceKey: string;
|
|
12
|
+
desiredSource: string | null;
|
|
13
|
+
stableSourceUrl: string | null;
|
|
14
|
+
objectUrl: string | null;
|
|
15
|
+
}
|
|
16
|
+
export interface PreviewSlotRecoveryNeedInput {
|
|
17
|
+
desiredSource: string;
|
|
18
|
+
configuredSource: string | null;
|
|
19
|
+
assignedSource: string | null;
|
|
20
|
+
forceRecover: boolean;
|
|
21
|
+
isActive: boolean;
|
|
22
|
+
isLoading: boolean;
|
|
23
|
+
isSeeking: boolean;
|
|
24
|
+
isBuffering: boolean;
|
|
25
|
+
phase: PreviewSlotPhase;
|
|
26
|
+
networkState: number | null;
|
|
27
|
+
readyState: number | null;
|
|
28
|
+
networkEmptyState: number;
|
|
29
|
+
haveCurrentDataState: number;
|
|
30
|
+
}
|
|
31
|
+
export interface PreviewSlotRecoveryNeedResult {
|
|
32
|
+
needsRecovery: boolean;
|
|
33
|
+
recoveryReason: string | null;
|
|
34
|
+
actualSource: string | null;
|
|
35
|
+
configuredSource: string | null;
|
|
36
|
+
shouldWarn: boolean;
|
|
37
|
+
}
|
|
38
|
+
export declare function buildRecoveryKey(entry: ActiveClipPlaybackInfo, desiredSource: string, reason: PreviewSlotRecoveryReason, recoveryTimeBucketMs: number): string;
|
|
39
|
+
export declare function getReusableBoundSlotSource(input: ReusableBoundSlotSourceInput): ResolvedSlotSourceLike | null;
|
|
40
|
+
export declare function doesSlotSourceMatchDesired(configuredSource: string | null, assignedSource: string | null, desiredSource: string | null): boolean;
|
|
41
|
+
export declare function evaluateSlotRecoveryNeed(input: PreviewSlotRecoveryNeedInput): PreviewSlotRecoveryNeedResult;
|
|
42
|
+
export declare function getSlotSeekThresholdSeconds(role: 'current' | 'preload', playbackRate: number): number;
|
|
43
|
+
export declare function shouldHardResetRecoveredSource(previousActualSource: string | null, reason: PreviewSlotRecoveryReason, retryCount: number): boolean;
|
|
44
|
+
export declare function buildCurrentSlotTarget(input: {
|
|
45
|
+
role: 'current' | 'preload';
|
|
46
|
+
entry: ActiveClipPlaybackInfo;
|
|
47
|
+
requestedPlayState: PlayState;
|
|
48
|
+
isActive: boolean;
|
|
49
|
+
playbackRate: number;
|
|
50
|
+
syncRequestId?: number;
|
|
51
|
+
}): {
|
|
52
|
+
role: 'current' | 'preload';
|
|
53
|
+
entry: ActiveClipPlaybackInfo;
|
|
54
|
+
playState: PlayState;
|
|
55
|
+
speed: number;
|
|
56
|
+
visible: boolean;
|
|
57
|
+
zIndex: number;
|
|
58
|
+
syncRequestId?: number;
|
|
59
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { ActiveClipPlaybackInfo, TrackType } from '../models/types';
|
|
2
|
+
import type { TimelinePreviewSyncPayload } from './previewBackend';
|
|
3
|
+
export interface PreviewSlotTarget {
|
|
4
|
+
role: 'current' | 'preload';
|
|
5
|
+
entry: ActiveClipPlaybackInfo | null;
|
|
6
|
+
playState: TimelinePreviewSyncPayload['playState'];
|
|
7
|
+
speed: number;
|
|
8
|
+
visible: boolean;
|
|
9
|
+
zIndex: number;
|
|
10
|
+
syncRequestId?: number;
|
|
11
|
+
}
|
|
12
|
+
export interface PreviewTrackPlan {
|
|
13
|
+
trackId: string;
|
|
14
|
+
kind: TrackType;
|
|
15
|
+
order: number;
|
|
16
|
+
current: PreviewSlotTarget;
|
|
17
|
+
preload: PreviewSlotTarget;
|
|
18
|
+
}
|
|
19
|
+
export interface ExistingPreviewTrack {
|
|
20
|
+
trackId: string;
|
|
21
|
+
kind: TrackType;
|
|
22
|
+
order: number;
|
|
23
|
+
}
|
|
24
|
+
export declare function projectPreviewPlan(payload: TimelinePreviewSyncPayload, existingTracks: ExistingPreviewTrack[]): PreviewTrackPlan[];
|
|
@@ -17,6 +17,8 @@ interface PreviewTransformOverlayCallbacks {
|
|
|
17
17
|
onFontSizeCommit?: (clipId: string, fontSize: number) => void;
|
|
18
18
|
onRotationChange?: (clipId: string, rotation: number | null) => void;
|
|
19
19
|
onRotationCommit?: (clipId: string, rotation: number) => void;
|
|
20
|
+
/** 文字片段预览变换框上开始拖拽/缩放/旋转(播放中时应暂停) */
|
|
21
|
+
onTextTransformInteractionStart?: () => void;
|
|
20
22
|
}
|
|
21
23
|
export declare class PreviewTransformOverlay {
|
|
22
24
|
private frameElement;
|
|
@@ -4,8 +4,6 @@ import type { ResourceCacheManager } from '../resources/resourceCache';
|
|
|
4
4
|
import type { PreviewPendingState, PreviewRuntimeState } from './previewBackend';
|
|
5
5
|
import { type DiagnosticEmitInput, type DiagnosticsCenter } from '../../utils/diagnostics';
|
|
6
6
|
interface TimelinePreviewSessionCallbacks {
|
|
7
|
-
onBufferingStateChange?: (isBuffering: boolean) => void;
|
|
8
|
-
onSourceLoadingChange?: (pending: number) => void;
|
|
9
7
|
onSyncProcessed?: (syncRequestId?: number) => void;
|
|
10
8
|
onRuntimeStateChange?: (state: PreviewRuntimeState) => void;
|
|
11
9
|
onAspectRatioChange?: (aspectRatio: PreviewAspectRatio) => void;
|
|
@@ -14,6 +12,7 @@ interface TimelinePreviewSessionCallbacks {
|
|
|
14
12
|
onTextFontSizeCommit?: (clipId: string, fontSize: number) => void;
|
|
15
13
|
onTextRotationCommit?: (clipId: string, rotation: number) => void;
|
|
16
14
|
onPendingPreviewRetry?: () => void;
|
|
15
|
+
onPauseIfPlaying?: () => void;
|
|
17
16
|
}
|
|
18
17
|
interface TimelinePreviewSessionDependencies {
|
|
19
18
|
createMediaElement?: (kind: TrackType, role: 'current' | 'preload') => HTMLMediaElement;
|
|
@@ -53,9 +52,9 @@ export declare class TimelinePreviewSession {
|
|
|
53
52
|
private readonly textPreviewEntries;
|
|
54
53
|
private audioContext;
|
|
55
54
|
private masterGainNode;
|
|
56
|
-
private
|
|
57
|
-
private
|
|
58
|
-
private
|
|
55
|
+
private loadingProbeTimeoutId;
|
|
56
|
+
private clockProbeTimeoutId;
|
|
57
|
+
private playbackGroupSuspended;
|
|
59
58
|
private lastRuntimeSignature;
|
|
60
59
|
private lastRuntimeState;
|
|
61
60
|
private lastSettledSyncRequestId;
|
|
@@ -80,13 +79,14 @@ export declare class TimelinePreviewSession {
|
|
|
80
79
|
private aspectRatioProbe;
|
|
81
80
|
private aspectRatioProbeSrc;
|
|
82
81
|
private aspectRatioProbeResolveToken;
|
|
83
|
-
private isAspectRatioProbeLoading;
|
|
84
82
|
private pendingState;
|
|
85
83
|
private activeSyncRequestId;
|
|
86
84
|
private isSyncProjecting;
|
|
87
85
|
private readonly deferredPreloadSlotKeys;
|
|
88
86
|
private deferredPreloadFlushScheduled;
|
|
87
|
+
private lastSyncedPlayState;
|
|
89
88
|
constructor(callbacks?: TimelinePreviewSessionCallbacks, dependencies?: TimelinePreviewSessionDependencies);
|
|
89
|
+
private requestPauseIfPlaying;
|
|
90
90
|
private emitDiagnostic;
|
|
91
91
|
private buildSlotTraceData;
|
|
92
92
|
hasPreview(): boolean;
|
|
@@ -114,11 +114,13 @@ export declare class TimelinePreviewSession {
|
|
|
114
114
|
private resolvePlayableSlotSource;
|
|
115
115
|
private emitRuntimeSourceDiagnostic;
|
|
116
116
|
private getReusableResolvedSlotSource;
|
|
117
|
+
private getReusableBoundSlotSource;
|
|
117
118
|
private slotNeedsRecovery;
|
|
118
119
|
private recoverSlot;
|
|
119
120
|
private finishSlotRecovery;
|
|
120
121
|
private getSlotKey;
|
|
121
122
|
private isActiveCurrentSlot;
|
|
123
|
+
private isTrackedActiveCurrentVideoSlot;
|
|
122
124
|
private hasBlockingActiveCurrentSlot;
|
|
123
125
|
private shouldDeferPreloadTarget;
|
|
124
126
|
private shouldDeferPreloadRecovery;
|
|
@@ -140,6 +142,9 @@ export declare class TimelinePreviewSession {
|
|
|
140
142
|
private failSlot;
|
|
141
143
|
private configureAudioRouting;
|
|
142
144
|
private syncCurrentSlot;
|
|
145
|
+
private resetSlotPlaybackProgressProbe;
|
|
146
|
+
private updateSlotPlaybackProgressState;
|
|
147
|
+
private maybeResumeRequestedPlayback;
|
|
143
148
|
private preparePreloadSlot;
|
|
144
149
|
private setSlotVisible;
|
|
145
150
|
private getAudioContext;
|
|
@@ -153,9 +158,23 @@ export declare class TimelinePreviewSession {
|
|
|
153
158
|
private tryResolveAutoAspectRatioFromSlot;
|
|
154
159
|
private handleResolvedAutoAspectRatio;
|
|
155
160
|
private refreshRuntimeState;
|
|
156
|
-
private
|
|
157
|
-
private
|
|
161
|
+
private buildPreviewClockState;
|
|
162
|
+
private buildPreviewClockStateFromSlot;
|
|
163
|
+
private resolveClockBlockedReason;
|
|
164
|
+
private getPreviewClockSourceSlot;
|
|
165
|
+
private syncActivePlaybackGroupSuspension;
|
|
166
|
+
private getSlotMediaTimeMs;
|
|
167
|
+
private getSlotTimelineTime;
|
|
158
168
|
private refreshPendingOverlay;
|
|
169
|
+
private buildPreviewLoadingState;
|
|
170
|
+
private evaluateTrackedCurrentVideoSlot;
|
|
171
|
+
private doesSlotSourceMatchDesired;
|
|
172
|
+
private getSlotSeekThresholdSeconds;
|
|
173
|
+
private finalizeSourceResolutionResult;
|
|
174
|
+
private syncLoadingProbe;
|
|
175
|
+
private syncClockProbe;
|
|
176
|
+
private clearLoadingProbe;
|
|
177
|
+
private clearClockProbe;
|
|
159
178
|
private handlePreviewTransformChange;
|
|
160
179
|
private refreshVisualLayout;
|
|
161
180
|
private syncTextPreviewEntries;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { TimeMs } from '../models/types';
|
|
2
|
-
import type { PreviewPendingState, PreviewRuntimeState } from './previewBackend';
|
|
2
|
+
import type { PreviewLoadingState, PreviewPendingState, PreviewRuntimeState } from './previewBackend';
|
|
3
3
|
export interface TimelinePendingPreviewState {
|
|
4
4
|
mode: 'seek' | 'scrub';
|
|
5
5
|
targetTime: TimeMs;
|
|
@@ -13,36 +13,26 @@ export interface TimelinePendingPreviewState {
|
|
|
13
13
|
}
|
|
14
14
|
interface TimelinePreviewStateControllerCallbacks {
|
|
15
15
|
applyPendingState: (state: PreviewPendingState | null) => void;
|
|
16
|
-
|
|
17
|
-
emitSourceLoadingStateChange: () => void;
|
|
16
|
+
emitLoadingStateChange: (state: PreviewLoadingState) => void;
|
|
18
17
|
resumePlayback: () => void;
|
|
19
18
|
requestPreviewSync: () => void;
|
|
20
19
|
}
|
|
21
20
|
interface TimelinePreviewStateControllerOptions {
|
|
22
21
|
callbacks: TimelinePreviewStateControllerCallbacks;
|
|
23
|
-
pendingTimeoutMs?: number;
|
|
24
22
|
failedOverlayDelayMs?: number;
|
|
25
23
|
}
|
|
26
24
|
export declare class TimelinePreviewStateController {
|
|
27
25
|
private readonly callbacks;
|
|
28
|
-
private readonly pendingTimeoutMs;
|
|
29
26
|
private readonly failedOverlayDelayMs;
|
|
30
|
-
private
|
|
31
|
-
private _previewBuffering;
|
|
32
|
-
private _previewAwaitingMedia;
|
|
27
|
+
private _previewLoadingState;
|
|
33
28
|
private _pendingPreviewState;
|
|
34
29
|
private _nextPendingPreviewSyncRequestId;
|
|
35
30
|
constructor(options: TimelinePreviewStateControllerOptions);
|
|
36
|
-
get
|
|
37
|
-
set previewSourceLoadingCount(value: number);
|
|
38
|
-
get previewBuffering(): boolean;
|
|
39
|
-
set previewBuffering(value: boolean);
|
|
31
|
+
get previewLoadingState(): PreviewLoadingState;
|
|
40
32
|
get pendingPreviewState(): TimelinePendingPreviewState | null;
|
|
41
33
|
set pendingPreviewState(value: TimelinePendingPreviewState | null);
|
|
42
34
|
get nextPendingPreviewSyncRequestId(): number;
|
|
43
35
|
set nextPendingPreviewSyncRequestId(value: number);
|
|
44
|
-
handleBufferingStateChange(isBuffering: boolean): void;
|
|
45
|
-
handleSourceLoadingChange(pending: number): void;
|
|
46
36
|
handleRuntimeStateChange(state: PreviewRuntimeState): void;
|
|
47
37
|
markSyncProcessed(syncRequestId?: number): void;
|
|
48
38
|
beginPendingPreview(time: TimeMs, mode: 'seek' | 'scrub', resumePlayOnReady: boolean): void;
|
|
@@ -51,7 +41,8 @@ export declare class TimelinePreviewStateController {
|
|
|
51
41
|
retryPendingPreview(): void;
|
|
52
42
|
clearPendingPreviewState(): void;
|
|
53
43
|
resetPreviewRuntimeState(): void;
|
|
54
|
-
private
|
|
44
|
+
private resolvePendingLoadingState;
|
|
45
|
+
private buildPlaybackLoadingOverlayState;
|
|
55
46
|
private clearPendingPreviewTimeout;
|
|
56
47
|
private scheduleFailedOverlay;
|
|
57
48
|
private clearFailedOverlayTimeout;
|
|
@@ -58,7 +58,6 @@ export declare class TimelineManager {
|
|
|
58
58
|
private previewStateController?;
|
|
59
59
|
private previewPlaybackSuspendedByBuffering;
|
|
60
60
|
private previewPlaybackAutoResume;
|
|
61
|
-
private previewBufferingSuspendTimeoutId;
|
|
62
61
|
private lastSelectedClipId;
|
|
63
62
|
private previewAspectRatio;
|
|
64
63
|
private readonly bodyViewportScrollListener;
|
|
@@ -106,10 +105,7 @@ export declare class TimelineManager {
|
|
|
106
105
|
set runtimePreviewBackendOverride(value: Exclude<PreviewBackendType, 'auto'> | null);
|
|
107
106
|
get activePreviewCallbackToken(): number;
|
|
108
107
|
set activePreviewCallbackToken(value: number);
|
|
109
|
-
private
|
|
110
|
-
private set previewSourceLoadingCount(value);
|
|
111
|
-
get previewBuffering(): boolean;
|
|
112
|
-
set previewBuffering(value: boolean);
|
|
108
|
+
private getPreviewLoadingState;
|
|
113
109
|
private get pendingPreviewState();
|
|
114
110
|
private set pendingPreviewState(value);
|
|
115
111
|
get nextPendingPreviewSyncRequestId(): number;
|
|
@@ -160,6 +156,8 @@ export declare class TimelineManager {
|
|
|
160
156
|
private getPlaybackTracksSnapshot;
|
|
161
157
|
private buildPlaybackPlan;
|
|
162
158
|
private hasTimelineVideoClip;
|
|
159
|
+
private playbackPlanHasActiveVideoClip;
|
|
160
|
+
private hasActiveTimelineVideoClip;
|
|
163
161
|
private getPreviewAutoAspectRatioClipOrderMap;
|
|
164
162
|
private getNextPreviewAutoAspectRatioOrder;
|
|
165
163
|
private getAutoAspectRatioClip;
|
|
@@ -167,11 +165,16 @@ export declare class TimelineManager {
|
|
|
167
165
|
private buildPreviewSyncSignature;
|
|
168
166
|
private shouldSkipSteadyPlaybackPreviewSync;
|
|
169
167
|
private syncPreviewSession;
|
|
168
|
+
private resolvePreviewSyncPlayState;
|
|
170
169
|
private syncPreviewPlaybackStateIfNeeded;
|
|
170
|
+
private shouldUsePreviewClockPlayback;
|
|
171
|
+
private handlePreviewClockStateChange;
|
|
172
|
+
private commitPlaybackTimeFromPreviewClock;
|
|
173
|
+
private syncPreviewAfterPreviewClockCommitIfNeeded;
|
|
174
|
+
private resumeWallClockPlaybackIfPreviewClockUnavailable;
|
|
171
175
|
private beginPendingPreview;
|
|
172
176
|
updatePendingPreviewState(): void;
|
|
173
177
|
private buildPreviewPendingState;
|
|
174
|
-
private buildPreviewIndicatorState;
|
|
175
178
|
private clearPendingPreviewState;
|
|
176
179
|
private resetPreviewRuntimeState;
|
|
177
180
|
private destroyPreviewSession;
|
|
@@ -218,8 +221,12 @@ export declare class TimelineManager {
|
|
|
218
221
|
pause(): void;
|
|
219
222
|
togglePlay(): void;
|
|
220
223
|
private animate;
|
|
221
|
-
private
|
|
222
|
-
private
|
|
224
|
+
private cancelPlaybackAnimationFrame;
|
|
225
|
+
private emitPlayStateChangeEvent;
|
|
226
|
+
private suspendPlaybackForMediaPending;
|
|
227
|
+
private resumePlaybackAfterMediaPending;
|
|
228
|
+
private shouldSuspendPreviewPlaybackForLoadingState;
|
|
229
|
+
private syncPlaybackClockToPreviewLoadingState;
|
|
223
230
|
/** 播放头不得超过全部片段的最大 endTime(与 canPlay / 播放结束对齐);无片段时不设上限(由别处处理空轨道) */
|
|
224
231
|
private clampPlaybackSeekTime;
|
|
225
232
|
setCurrentTime(time: TimeMs): void;
|
|
@@ -404,7 +404,7 @@ export interface HistoryState {
|
|
|
404
404
|
past: Action[];
|
|
405
405
|
future: Action[];
|
|
406
406
|
}
|
|
407
|
-
export type TimelineEvent = 'time_change' | 'play_state_change' | 'clip_added' | 'clip_removed' | 'clip_updated' | 'zoom_change' | 'history_change' | 'track_duration_change' | 'clip_selected' | 'selected_clip_change' | 'speed_change' | 'can_play_change' | '
|
|
407
|
+
export type TimelineEvent = 'time_change' | 'play_state_change' | 'clip_added' | 'clip_removed' | 'clip_updated' | 'zoom_change' | 'history_change' | 'track_duration_change' | 'clip_selected' | 'selected_clip_change' | 'speed_change' | 'can_play_change' | 'loading_state_change' | 'preview_aspect_ratio_change' | 'draft_loaded' | 'selection_change';
|
|
408
408
|
export interface TimeChangeData {
|
|
409
409
|
time: TimeMs;
|
|
410
410
|
}
|
|
@@ -437,12 +437,12 @@ export interface ClipRemovedEventData {
|
|
|
437
437
|
export interface CanPlayChangeData {
|
|
438
438
|
canPlay: boolean;
|
|
439
439
|
}
|
|
440
|
-
export
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
440
|
+
export type LoadingStateStatus = 'idle' | 'loading' | 'ready' | 'failed';
|
|
441
|
+
export type LoadingStateReason = 'syncing' | 'resolving-source' | 'seeking' | 'media-pending' | 'failed' | null;
|
|
442
|
+
export interface LoadingStateChangeData {
|
|
443
|
+
status: LoadingStateStatus;
|
|
444
444
|
isLoading: boolean;
|
|
445
|
-
|
|
445
|
+
reason: LoadingStateReason;
|
|
446
446
|
}
|
|
447
447
|
export interface PreviewAspectRatioChangeData {
|
|
448
448
|
aspectRatio: PreviewAspectRatio;
|