@meframe/core 0.2.8 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/dist/controllers/PlaybackController.d.ts +6 -0
  2. package/dist/controllers/PlaybackController.d.ts.map +1 -1
  3. package/dist/controllers/PlaybackController.js +66 -17
  4. package/dist/controllers/PlaybackController.js.map +1 -1
  5. package/dist/controllers/PlaybackStateMachine.d.ts.map +1 -1
  6. package/dist/controllers/PlaybackStateMachine.js +1 -3
  7. package/dist/controllers/PlaybackStateMachine.js.map +1 -1
  8. package/dist/controllers/types.d.ts +1 -4
  9. package/dist/controllers/types.d.ts.map +1 -1
  10. package/dist/controllers/types.js +0 -1
  11. package/dist/controllers/types.js.map +1 -1
  12. package/dist/index.d.ts +1 -1
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js.map +1 -1
  15. package/dist/orchestrator/OnDemandVideoSession.d.ts +8 -8
  16. package/dist/orchestrator/OnDemandVideoSession.d.ts.map +1 -1
  17. package/dist/orchestrator/OnDemandVideoSession.js +112 -39
  18. package/dist/orchestrator/OnDemandVideoSession.js.map +1 -1
  19. package/dist/orchestrator/Orchestrator.d.ts +0 -5
  20. package/dist/orchestrator/Orchestrator.d.ts.map +1 -1
  21. package/dist/orchestrator/Orchestrator.js +15 -43
  22. package/dist/orchestrator/Orchestrator.js.map +1 -1
  23. package/dist/orchestrator/types.d.ts +6 -1
  24. package/dist/orchestrator/types.d.ts.map +1 -1
  25. package/dist/stages/mux/MP4Muxer.d.ts +1 -0
  26. package/dist/stages/mux/MP4Muxer.d.ts.map +1 -1
  27. package/dist/stages/mux/MP4Muxer.js +7 -2
  28. package/dist/stages/mux/MP4Muxer.js.map +1 -1
  29. package/dist/utils/video-decoder-helpers.d.ts +28 -0
  30. package/dist/utils/video-decoder-helpers.d.ts.map +1 -1
  31. package/dist/utils/video-decoder-helpers.js +123 -0
  32. package/dist/utils/video-decoder-helpers.js.map +1 -1
  33. package/package.json +1 -1
@@ -24,6 +24,11 @@ export declare class PlaybackController implements IPlaybackController, PreviewH
24
24
  private lastAudioScheduleTime;
25
25
  private readonly AUDIO_SCHEDULE_INTERVAL;
26
26
  private fsm;
27
+ private pendingSeekTimeUs;
28
+ private pendingSeekWaiters;
29
+ private seekFlushRafId;
30
+ private seekInFlight;
31
+ private readonly SEEK_CANCEL_DISTANCE_US;
27
32
  private windowEnd;
28
33
  private readonly WINDOW_DURATION;
29
34
  private readonly PREHEAT_DISTANCE;
@@ -34,6 +39,7 @@ export declare class PlaybackController implements IPlaybackController, PreviewH
34
39
  pause(): void;
35
40
  stop(): void;
36
41
  seek(timeUs: TimeUs): Promise<void>;
42
+ private flushCoalescedSeek;
37
43
  setRate(rate: number): void;
38
44
  setVolume(volume: number): void;
39
45
  setMute(muted: boolean): void;
@@ -1 +1 @@
1
- {"version":3,"file":"PlaybackController.d.ts","sourceRoot":"","sources":["../../src/controllers/PlaybackController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,mBAAmB,EACnB,eAAe,EACf,SAAS,EACT,aAAa,EACb,MAAM,EACP,MAAM,SAAS,CAAC;AAUjB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AASpD;;;GAGG;AACH,qBAAa,kBAAmB,YAAW,mBAAmB,EAAE,aAAa;IAC3E,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,QAAQ,CAAY;IAC5B,OAAO,CAAC,MAAM,CAAsC;IACpD,OAAO,CAAC,aAAa,CAA8B;IAGnD,aAAa,EAAE,MAAM,CAAK;IAC1B,OAAO,CAAC,YAAY,CAAO;IAC3B,OAAO,CAAC,MAAM,CAAO;IACrB,OAAO,CAAC,IAAI,CAAS;IAGrB,OAAO,CAAC,KAAK,CAAuB;IACpC,OAAO,CAAC,WAAW,CAAa;IAGhC,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,GAAG,CAAK;IAGhB,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,YAAY,CAAsB;IAC1C,OAAO,CAAC,qBAAqB,CAAK;IAClC,OAAO,CAAC,QAAQ,CAAC,uBAAuB,CAAW;IAGnD,OAAO,CAAC,GAAG,CAA8B;IAGzC,OAAO,CAAC,SAAS,CAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAa;IAC7C,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAa;IAC9C,OAAO,CAAC,iBAAiB,CAAS;gBAEtB,YAAY,EAAE,YAAY,EAAE,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,eAAe;IAoC/E,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IAMlC,IAAI,IAAI,IAAI;IAIZ,KAAK,IAAI,IAAI;IAIb,IAAI,IAAI,IAAI;IAIN,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IASzC,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAW3B,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAM/B,OAAO,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI;IAU7B,OAAO,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI;IAI5B,IAAI,QAAQ,IAAI,MAAM,CAErB;IAED,IAAI,SAAS,IAAI,OAAO,CAEvB;IAED,MAAM,IAAI,IAAI;IAId,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,OAAO,EAAE,GAAG,KAAK,IAAI,GAAG,IAAI;IAIxD,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,OAAO,EAAE,GAAG,KAAK,IAAI,GAAG,IAAI;IAMzD,OAAO,CAAC,QAAQ;IAMhB,OAAO,CAAC,eAAe;IAKvB,OAAO,CAAC,UAAU;IAkBlB,OAAO,CAAC,UAAU;IAWlB,OAAO,CAAC,cAAc;IAyLtB,OAAO,CAAC,SAAS;IAOjB,OAAO,CAAC,cAAc;IAItB,OAAO,CAAC,iBAAiB;YAMX,SAAS;IAwEvB,OAAO,CAAC,wBAAwB;IAehC,OAAO,CAAC,SAAS;IAUjB,OAAO,CAAC,UAAU;IAMlB,OAAO,CAAC,qBAAqB;IAoBvB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC;YAuC1B,kBAAkB;YAwBlB,OAAO;IAYrB,OAAO,CAAC,WAAW;IAYnB,OAAO,IAAI,IAAI;IAUf,OAAO,CAAC,YAAY,CAIlB;IAEF,OAAO,CAAC,UAAU,CAoBhB;IAEF,OAAO,CAAC,mBAAmB;IAK3B,OAAO,CAAC,0BAA0B;IAgBlC,OAAO,CAAC,0BAA0B;CAanC"}
1
+ {"version":3,"file":"PlaybackController.d.ts","sourceRoot":"","sources":["../../src/controllers/PlaybackController.ts"],"names":[],"mappings":"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"}
@@ -30,6 +30,15 @@ class PlaybackController {
30
30
  // 250ms
31
31
  // State machine
32
32
  fsm = new PlaybackStateMachine();
33
+ // Coalesced seek (scrubbing): latest-wins, flush at most once per rAF.
34
+ // UI is fire-and-forget; this avoids spawning/canceling on-demand decoders too aggressively.
35
+ pendingSeekTimeUs = null;
36
+ pendingSeekWaiters = [];
37
+ seekFlushRafId = null;
38
+ seekInFlight = null;
39
+ // If user drags far away while a seek is decoding, cancel it to avoid visible lag.
40
+ SEEK_CANCEL_DISTANCE_US = 5e5;
41
+ // 500ms
33
42
  // Unified window management for both video and audio
34
43
  windowEnd = 0;
35
44
  WINDOW_DURATION = 3e6;
@@ -81,12 +90,57 @@ class PlaybackController {
81
90
  this.dispatch({ type: PlaybackActionType.Stop });
82
91
  }
83
92
  async seek(timeUs) {
93
+ this.pendingSeekTimeUs = timeUs;
94
+ const done = new Promise((resolve) => {
95
+ this.pendingSeekWaiters.push(resolve);
96
+ });
97
+ if (this.seekFlushRafId === null) {
98
+ this.seekFlushRafId = requestAnimationFrame(() => {
99
+ this.seekFlushRafId = null;
100
+ void this.flushCoalescedSeek();
101
+ });
102
+ }
103
+ await done;
104
+ }
105
+ async flushCoalescedSeek() {
106
+ const target = this.pendingSeekTimeUs;
107
+ if (target === null) {
108
+ const waiters = this.pendingSeekWaiters;
109
+ this.pendingSeekWaiters = [];
110
+ for (const resolve of waiters) resolve();
111
+ return;
112
+ }
113
+ if (this.seekInFlight) {
114
+ const distance = Math.abs(target - this.seekInFlight.targetUs);
115
+ if (distance <= this.SEEK_CANCEL_DISTANCE_US) {
116
+ return;
117
+ }
118
+ this.seekInFlight = null;
119
+ }
120
+ this.pendingSeekTimeUs = null;
84
121
  const { done } = this.dispatch({
85
122
  type: PlaybackActionType.Seek,
86
- timeUs,
123
+ timeUs: target,
87
124
  durationUs: this.duration
88
125
  });
89
- await done;
126
+ this.seekInFlight = { targetUs: target, done };
127
+ void done.finally(() => {
128
+ const waiters = this.pendingSeekWaiters;
129
+ this.pendingSeekWaiters = [];
130
+ for (const resolve of waiters) resolve();
131
+ if (this.seekInFlight?.targetUs === target) {
132
+ this.seekInFlight = null;
133
+ }
134
+ if (this.pendingSeekTimeUs === null && !this.orchestrator.cacheManager.isExporting) {
135
+ void this.preheatNextWindow();
136
+ }
137
+ if (this.pendingSeekTimeUs !== null && this.seekFlushRafId === null) {
138
+ this.seekFlushRafId = requestAnimationFrame(() => {
139
+ this.seekFlushRafId = null;
140
+ void this.flushCoalescedSeek();
141
+ });
142
+ }
143
+ });
90
144
  }
91
145
  setRate(rate) {
92
146
  const currentTimeUs = this.currentTimeUs;
@@ -279,20 +333,6 @@ class PlaybackController {
279
333
  relativeTimeUs: command.relativeTimeUs
280
334
  });
281
335
  }
282
- case PlaybackCommandType.MaybeRenderKeyframePreview: {
283
- return this.orchestrator.tryRenderKeyframe(command.timeUs).then((keyframeTimeUs) => {
284
- if (!this.isCurrentToken(token)) return;
285
- if (keyframeTimeUs === null) return;
286
- return this.orchestrator.getRenderState(command.timeUs, {
287
- mode: "probe",
288
- relativeTimeUs: keyframeTimeUs
289
- }).then((keyframeRenderState) => {
290
- if (!this.isCurrentToken(token)) return;
291
- if (!keyframeRenderState) return;
292
- return this.compose(command.timeUs, keyframeRenderState);
293
- });
294
- });
295
- }
296
336
  case PlaybackCommandType.EnsureAudio: {
297
337
  return this.audioSession.ensureAudioForTime(command.timeUs, {
298
338
  mode: command.mode
@@ -301,7 +341,8 @@ class PlaybackController {
301
341
  case PlaybackCommandType.GetFrame: {
302
342
  return this.orchestrator.getFrame(command.timeUs, {
303
343
  mode: command.mode,
304
- preheat: command.preheat
344
+ preheat: command.preheat,
345
+ scrub: command.scrub
305
346
  });
306
347
  }
307
348
  case PlaybackCommandType.StartAudioPlayback: {
@@ -492,6 +533,14 @@ class PlaybackController {
492
533
  // ========= Cleanup / event handlers =========
493
534
  dispose() {
494
535
  this.stop();
536
+ if (this.seekFlushRafId !== null) {
537
+ cancelAnimationFrame(this.seekFlushRafId);
538
+ this.seekFlushRafId = null;
539
+ }
540
+ this.pendingSeekTimeUs = null;
541
+ const waiters = this.pendingSeekWaiters;
542
+ this.pendingSeekWaiters = [];
543
+ for (const resolve of waiters) resolve();
495
544
  this.eventBus.off(MeframeEvent.CacheCover, this.onCacheCover);
496
545
  this.eventBus.off(MeframeEvent.ModelSet, this.onModelSet);
497
546
  if (this.videoComposer) {
@@ -1 +1 @@
1
- {"version":3,"file":"PlaybackController.js","sources":["../../src/controllers/PlaybackController.ts"],"sourcesContent":["import type {\n IPlaybackController,\n PlaybackOptions,\n IEventBus,\n PreviewHandle,\n TimeUs,\n} from './types';\nimport {\n PlaybackActionType,\n PlaybackCommandType,\n PlaybackState,\n type OpToken,\n type PlaybackAction,\n type PlaybackCommand,\n} from './types';\nimport { MeframeEvent } from '../event/events';\nimport type { Orchestrator } from '../orchestrator';\nimport type { RequestMode } from '../orchestrator/types';\nimport { MP4MoovNotFoundError, WaiterReplacedError } from '../utils/errors';\nimport { VideoComposer } from '../stages/compose/VideoComposer';\nimport { isVideoClip } from '../model/types';\nimport type { AudioPreviewSession } from '../orchestrator/AudioPreviewSession';\n\nimport { PlaybackStateMachine } from './PlaybackStateMachine';\n\n/**\n * Playback controller for preview\n * Internal implementation - not exposed directly to external consumers\n */\nexport class PlaybackController implements IPlaybackController, PreviewHandle {\n private orchestrator: Orchestrator;\n private eventBus: IEventBus;\n private canvas: HTMLCanvasElement | OffscreenCanvas;\n private videoComposer: VideoComposer | null = null;\n\n // Playback time (external)\n currentTimeUs: TimeUs = 0;\n private playbackRate = 1.0;\n private volume = 1.0;\n private loop = false;\n\n // Time base\n private rafId: number | null = null;\n private startTimeUs: TimeUs = 0; // AudioContext timeline origin (microseconds)\n\n // Frame stats\n private frameCount = 0;\n private lastFrameTime = 0;\n private fps = 0;\n\n // Audio\n private audioContext: AudioContext;\n private audioSession: AudioPreviewSession;\n private lastAudioScheduleTime = 0;\n private readonly AUDIO_SCHEDULE_INTERVAL = 250_000; // 250ms\n\n // State machine\n private fsm = new PlaybackStateMachine();\n\n // Unified window management for both video and audio\n private windowEnd: TimeUs = 0;\n private readonly WINDOW_DURATION = 3_000_000; // 3s decode window\n private readonly PREHEAT_DISTANCE = 1_000_000; // 1s preheat trigger distance\n private preheatInProgress = false;\n\n constructor(orchestrator: Orchestrator, eventBus: IEventBus, options: PlaybackOptions) {\n this.orchestrator = orchestrator;\n this.audioSession = orchestrator.audio.preview;\n this.eventBus = eventBus;\n this.canvas = options.canvas;\n this.audioContext = new AudioContext();\n\n const model = orchestrator.compositionModel;\n const width = model?.renderConfig?.width || this.canvas.width || 720;\n const height = model?.renderConfig?.height || this.canvas.height || 1280;\n\n this.videoComposer = new VideoComposer({\n width,\n height,\n fps: model?.fps || 30,\n backgroundColor: model?.renderConfig?.backgroundColor || '#000',\n externalCanvas: this.canvas,\n });\n\n if (options.startUs !== undefined) {\n this.currentTimeUs = options.startUs;\n }\n if (options.rate !== undefined) {\n this.playbackRate = options.rate;\n }\n if (options.loop !== undefined) {\n this.loop = options.loop;\n }\n\n this.setupEventListeners();\n\n if (options.autoStart) {\n this.play();\n }\n }\n\n async renderCover(): Promise<void> {\n await this.renderCurrentFrame(0, { mode: 'blocking' });\n }\n\n // ========= Public API =========\n\n play(): void {\n this.dispatch({ type: PlaybackActionType.Play });\n }\n\n pause(): void {\n this.dispatch({ type: PlaybackActionType.Pause });\n }\n\n stop(): void {\n this.dispatch({ type: PlaybackActionType.Stop });\n }\n\n async seek(timeUs: TimeUs): Promise<void> {\n const { done } = this.dispatch({\n type: PlaybackActionType.Seek,\n timeUs,\n durationUs: this.duration,\n });\n await done;\n }\n\n setRate(rate: number): void {\n const currentTimeUs = this.currentTimeUs;\n this.playbackRate = rate;\n\n // Keep currentTimeUs stable; update the time base for AudioContext clock mapping.\n this.startTimeUs = this.audioContext.currentTime * 1_000_000 - currentTimeUs / rate;\n this.audioSession.setPlaybackRate(this.playbackRate);\n\n this.eventBus.emit(MeframeEvent.PlaybackRateChange, { rate });\n }\n\n setVolume(volume: number): void {\n this.volume = Math.max(0, Math.min(1, volume));\n this.audioSession.setVolume(this.volume);\n this.eventBus.emit(MeframeEvent.PlaybackVolumeChange, { volume: this.volume });\n }\n\n setMute(muted: boolean): void {\n if (muted) {\n this.audioSession.stopPlayback();\n return;\n }\n if (this.fsm.snapshot.state === PlaybackState.Playing) {\n void this.audioSession.startPlayback(this.currentTimeUs, this.audioContext);\n }\n }\n\n setLoop(loop: boolean): void {\n this.loop = loop;\n }\n\n get duration(): TimeUs {\n return this.orchestrator.compositionModel?.durationUs ?? 0;\n }\n\n get isPlaying(): boolean {\n return this.fsm.snapshot.state === PlaybackState.Playing;\n }\n\n resume(): void {\n this.play();\n }\n\n on(event: string, handler: (payload: any) => void): void {\n this.eventBus.on(event as MeframeEvent, handler);\n }\n\n off(event: string, handler: (payload: any) => void): void {\n this.eventBus.off(event as MeframeEvent, handler);\n }\n\n // ========= State machine wiring =========\n\n private dispatch(action: PlaybackAction): { token: OpToken; done: Promise<void> } {\n const { token, commands } = this.fsm.dispatch(action, { currentTimeUs: this.currentTimeUs });\n const done = this.executeCommands(commands, token);\n return { token, done };\n }\n\n private executeCommands(commands: PlaybackCommand[], token: OpToken): Promise<void> {\n const maybe = this.executeSeq(commands, token, 0);\n return maybe ?? Promise.resolve();\n }\n\n private executeSeq(\n commands: PlaybackCommand[],\n token: OpToken,\n startIndex: number\n ): Promise<void> | void {\n for (let i = startIndex; i < commands.length; i++) {\n if (!this.isCurrentToken(token)) return;\n const maybe = this.executeCommand(commands[i]!, token);\n if (maybe) {\n return maybe.then(() => {\n if (!this.isCurrentToken(token)) return;\n const cont = this.executeSeq(commands, token, i + 1);\n return cont ?? Promise.resolve();\n });\n }\n }\n }\n\n private executePar(commands: PlaybackCommand[], token: OpToken): Promise<any> | void {\n const promises: Promise<void>[] = [];\n for (const c of commands) {\n if (!this.isCurrentToken(token)) return;\n const maybe = this.executeCommand(c, token);\n if (maybe) promises.push(maybe);\n }\n if (promises.length === 0) return;\n return Promise.all(promises);\n }\n\n private executeCommand(command: PlaybackCommand, token: OpToken): Promise<any> | void {\n if (!this.isCurrentToken(token)) return;\n\n switch (command.type) {\n case PlaybackCommandType.Seq:\n return this.executeSeq(command.commands, token, 0);\n case PlaybackCommandType.Par:\n return this.executePar(command.commands, token);\n case PlaybackCommandType.Try: {\n const handleError = (error: unknown): Promise<void> | void => {\n if (!this.isCurrentToken(token)) return;\n if (command.ignoreWaiterReplacedError && error instanceof WaiterReplacedError) return;\n if (command.logPrefix) console.error(command.logPrefix, error);\n const onErrorDone = command.onError ? this.dispatch(command.onError).done : undefined;\n const normalizeError = (e: unknown): Error => {\n if (e instanceof Error) return e;\n return new Error(typeof e === 'string' ? e : JSON.stringify(e));\n };\n const emit = () => {\n if (command.emitPlaybackError) {\n const err = normalizeError(error);\n const recoverable =\n // Waiter replaced is expected during rapid seek; safe to ignore.\n err instanceof WaiterReplacedError ||\n // Missing moov may be caused by incomplete/corrupted cache and can be retried via recovery.\n err instanceof MP4MoovNotFoundError;\n // PlaybackError: direct playback channel error for advanced consumers.\n this.eventBus.emit(MeframeEvent.PlaybackError, err);\n // Error: generic error channel expected by higher-level wrappers (e.g. @meframe/axii).\n this.eventBus.emit(MeframeEvent.Error, {\n source: 'playback',\n error: err,\n context: {\n command: command.logPrefix,\n onError: command.onError?.type,\n },\n recoverable,\n });\n }\n };\n if (onErrorDone) {\n return onErrorDone.then(() => {\n emit();\n });\n }\n emit();\n };\n\n try {\n const maybe = this.executeCommand(command.command, token);\n if (maybe) {\n return maybe.catch(handleError);\n }\n return;\n } catch (error) {\n return handleError(error) ?? Promise.resolve();\n }\n }\n case PlaybackCommandType.Dispatch:\n return this.dispatch(command.action).done;\n case PlaybackCommandType.SetTime: {\n this.currentTimeUs = command.timeUs;\n return;\n }\n case PlaybackCommandType.SetFrozenTime:\n case PlaybackCommandType.SetWantsPlay:\n case PlaybackCommandType.SetState: {\n // managed inside fsm\n return;\n }\n case PlaybackCommandType.CancelRaf: {\n this.cancelRaf();\n return;\n }\n case PlaybackCommandType.StopAudio: {\n this.audioSession.stopPlayback();\n return;\n }\n case PlaybackCommandType.ResetAudioPlaybackStates: {\n this.audioSession.resetPlaybackStates();\n return;\n }\n case PlaybackCommandType.ResetAudioSession: {\n this.audioSession.reset();\n return;\n }\n case PlaybackCommandType.ClearCanvas: {\n this.clearCanvas();\n return;\n }\n case PlaybackCommandType.SetLastAudioScheduleTime: {\n this.lastAudioScheduleTime = command.timeUs;\n return;\n }\n case PlaybackCommandType.SetStartTimeBase: {\n this.startTimeUs = command.startTimeUs;\n return;\n }\n case PlaybackCommandType.SyncTimeBaseToAudioClock: {\n this.startTimeUs =\n this.audioContext.currentTime * 1_000_000 - command.timeUs / this.playbackRate;\n return;\n }\n case PlaybackCommandType.InitWindow: {\n this.initWindow(command.timeUs);\n return;\n }\n case PlaybackCommandType.SetCacheWindow: {\n this.orchestrator.cacheManager.setWindow(command.timeUs);\n return;\n }\n case PlaybackCommandType.Emit: {\n if (command.payload === undefined) {\n this.eventBus.emit(command.event as any);\n } else {\n this.eventBus.emit(command.event as any, command.payload);\n }\n return;\n }\n case PlaybackCommandType.RenderFrame: {\n return this.renderCurrentFrame(command.timeUs, {\n mode: command.mode,\n relativeTimeUs: command.relativeTimeUs,\n });\n }\n case PlaybackCommandType.MaybeRenderKeyframePreview: {\n return this.orchestrator.tryRenderKeyframe(command.timeUs).then((keyframeTimeUs) => {\n if (!this.isCurrentToken(token)) return;\n if (keyframeTimeUs === null) return;\n return this.orchestrator\n .getRenderState(command.timeUs, {\n mode: 'probe',\n relativeTimeUs: keyframeTimeUs,\n })\n .then((keyframeRenderState) => {\n if (!this.isCurrentToken(token)) return;\n if (!keyframeRenderState) return;\n return this.compose(command.timeUs, keyframeRenderState);\n });\n });\n }\n case PlaybackCommandType.EnsureAudio: {\n return this.audioSession.ensureAudioForTime(command.timeUs, {\n mode: command.mode,\n });\n }\n case PlaybackCommandType.GetFrame: {\n return this.orchestrator.getFrame(command.timeUs, {\n mode: command.mode,\n preheat: command.preheat,\n });\n }\n case PlaybackCommandType.StartAudioPlayback: {\n return this.audioSession.startPlayback(command.timeUs, this.audioContext);\n }\n case PlaybackCommandType.ProbeStartReady: {\n const audioReady = this.audioSession.isPreviewMixBlockCached(command.timeUs);\n const videoReady = this.isVideoResourceReadyAtTime(command.timeUs);\n\n if (audioReady && videoReady) return;\n\n // Kick background preparation (best-effort).\n if (!audioReady) {\n void this.audioSession.ensureAudioForTime(command.timeUs, { mode: 'probe' });\n }\n if (!videoReady) {\n void this.orchestrator.getFrame(command.timeUs, { mode: 'probe' });\n }\n\n // Enter buffering and bump token to cancel the remaining start sequence.\n this.dispatch({\n type: PlaybackActionType.EnterBuffering,\n timeUs: command.timeUs,\n bumpToken: true,\n reason: 'startup',\n });\n return;\n }\n case PlaybackCommandType.StartRafLoop: {\n this.startPlaybackLoop(token);\n return;\n }\n }\n }\n\n private cancelRaf(): void {\n if (this.rafId !== null) {\n cancelAnimationFrame(this.rafId);\n this.rafId = null;\n }\n }\n\n private isCurrentToken(token: OpToken): boolean {\n return token === this.fsm.snapshot.token;\n }\n\n private startPlaybackLoop(token: OpToken): void {\n this.rafId = requestAnimationFrame(() => {\n void this.onRafTick(token);\n });\n }\n\n private async onRafTick(token: OpToken): Promise<void> {\n if (!this.isCurrentToken(token) || this.fsm.snapshot.state !== PlaybackState.Playing) {\n return;\n }\n\n const candidateTimeUs =\n (this.audioContext.currentTime * 1_000_000 - this.startTimeUs) * this.playbackRate;\n this.dispatch({\n type: PlaybackActionType.ClockTick,\n candidateTimeUs,\n durationUs: this.duration,\n loop: this.loop,\n audioNowUs: this.audioContext.currentTime * 1_000_000,\n });\n\n if (!this.isCurrentToken(token) || this.fsm.snapshot.state !== PlaybackState.Playing) {\n return;\n }\n\n // Audio probe: if the audio window isn't ready, enter buffering (freeze timeline)\n // and kick background audio preparation.\n // Note: preview audio readiness is driven by 60s mix-block cache inside AudioPreviewSession.\n // We intentionally avoid additional resource-window probing here to prevent buffering oscillation.\n\n // Throttle audio scheduling.\n if (this.currentTimeUs - this.lastAudioScheduleTime >= this.AUDIO_SCHEDULE_INTERVAL) {\n // Fire-and-forget: AudioPreviewSession runs its own background scheduling loop.\n // We avoid awaiting here to keep the render loop responsive.\n void this.audioSession.scheduleAudio(this.currentTimeUs, this.audioContext);\n this.lastAudioScheduleTime = this.currentTimeUs;\n }\n\n // If we're close to the 60s block boundary and the next mixed block isn't ready yet,\n // enter buffering to avoid hard silence at the boundary.\n if (this.audioSession.shouldEnterBufferingForUpcomingPreviewAudio(this.currentTimeUs)) {\n // Best-effort preheat; buffering path will call EnsureAudio(blocking).\n void this.audioSession.ensureAudioForTime(this.currentTimeUs, { mode: 'probe' });\n this.dispatch({\n type: PlaybackActionType.EnterBuffering,\n timeUs: this.currentTimeUs,\n reason: 'audio',\n });\n return;\n }\n\n const renderState = await this.orchestrator.getRenderState(this.currentTimeUs, {\n mode: 'probe',\n });\n if (!this.isCurrentToken(token) || this.fsm.snapshot.state !== PlaybackState.Playing) {\n return;\n }\n\n if (!renderState) {\n // If the current clip's resource is in a terminal error state, buffering will oscillate\n // (probe keeps returning null, buffering resolves quickly, then repeats). In this case,\n // keep playing and present an empty frame instead.\n if (this.isTerminalVideoErrorAtTime(this.currentTimeUs)) {\n this.clearCanvas();\n this.finalizeFrameAndContinue(token);\n return;\n }\n\n this.dispatch({ type: PlaybackActionType.EnterBuffering, timeUs: this.currentTimeUs });\n return;\n }\n\n await this.compose(this.currentTimeUs, renderState);\n if (!this.isCurrentToken(token) || this.fsm.snapshot.state !== PlaybackState.Playing) return;\n\n this.finalizeFrameAndContinue(token);\n }\n\n private finalizeFrameAndContinue(token: OpToken): void {\n this.updateFps();\n this.frameCount++;\n\n // Unified cache window update.\n this.orchestrator.cacheManager.setWindow(this.currentTimeUs);\n this.checkAndPreheatWindow();\n\n if (!this.isCurrentToken(token) || this.fsm.snapshot.state !== PlaybackState.Playing) {\n return;\n }\n\n this.startPlaybackLoop(token);\n }\n\n private updateFps(): void {\n const now = performance.now();\n if (this.lastFrameTime > 0) {\n const deltaTime = now - this.lastFrameTime;\n const instantFps = 1000 / deltaTime;\n this.fps = this.fps > 0 ? this.fps * 0.9 + instantFps * 0.1 : instantFps;\n }\n this.lastFrameTime = now;\n }\n\n private initWindow(timeUs: TimeUs): void {\n this.windowEnd = timeUs + this.WINDOW_DURATION;\n this.preheatInProgress = false;\n this.orchestrator.cacheManager.setWindow(timeUs);\n }\n\n private checkAndPreheatWindow(): void {\n // Export uses main-thread decode + heavy OPFS IO; disable preview preheat to avoid contention.\n if (this.orchestrator.cacheManager.isExporting) {\n return;\n }\n if (this.preheatInProgress || this.fsm.snapshot.state !== PlaybackState.Playing) {\n return;\n }\n\n const distanceToWindowEnd = this.windowEnd - this.currentTimeUs;\n if (distanceToWindowEnd < 0) {\n this.initWindow(this.currentTimeUs);\n return;\n }\n\n if (distanceToWindowEnd > 0 && distanceToWindowEnd <= this.PREHEAT_DISTANCE) {\n void this.preheatNextWindow();\n }\n }\n\n async preheatNextWindow(): Promise<void> {\n // Export uses main-thread decode + heavy OPFS IO; disable preview preheat to avoid contention.\n if (this.orchestrator.cacheManager.isExporting) {\n return;\n }\n if (this.preheatInProgress) return;\n\n this.preheatInProgress = true;\n try {\n const windowStart = this.currentTimeUs;\n const windowEnd = windowStart + this.WINDOW_DURATION;\n\n const clipsInWindow =\n this.orchestrator.compositionModel?.getClipsInRange(windowStart, windowEnd) ?? [];\n const preheatPromises: Promise<any>[] = [];\n\n for (const clip of clipsInWindow) {\n if (!isVideoClip(clip)) continue;\n\n const clipWindowStart = Math.max(0, windowStart - clip.startUs);\n const clipWindowEnd = Math.min(clip.durationUs, windowEnd - clip.startUs);\n if (clipWindowStart >= clipWindowEnd) continue;\n\n preheatPromises.push(\n this.orchestrator.preheatClipWindow(clip.id, clipWindowStart, clipWindowEnd, windowStart)\n );\n }\n\n // Audio preheat is handled inside AudioPreviewSession via mix-block scheduling & cache.\n\n await Promise.all(preheatPromises);\n this.windowEnd = windowEnd;\n } catch (error) {\n console.warn('[PlaybackController] Preheat failed:', error);\n } finally {\n this.preheatInProgress = false;\n }\n }\n\n private async renderCurrentFrame(\n timeUs: TimeUs,\n options: { mode: RequestMode; relativeTimeUs?: TimeUs }\n ): Promise<void> {\n if (!this.videoComposer) {\n console.error('[PlaybackController] VideoComposer not initialized');\n return;\n }\n\n const renderState = await this.orchestrator.getRenderState(timeUs, {\n mode: options.mode,\n relativeTimeUs: options.relativeTimeUs,\n });\n\n if (!renderState) {\n // No render state (e.g. missing clip, resource error, or probe returned null).\n // Present an empty frame instead of freezing the last canvas content.\n this.clearCanvas();\n return;\n }\n\n await this.compose(timeUs, renderState);\n }\n\n private async compose(\n timeUs: TimeUs,\n renderState: { layers: any[]; transition?: any }\n ): Promise<void> {\n if (!this.videoComposer) return;\n await this.videoComposer.composeFrame({\n timeUs,\n layers: renderState.layers,\n transition: renderState.transition,\n });\n }\n\n private clearCanvas(): void {\n const ctx = this.canvas.getContext('2d') as\n | CanvasRenderingContext2D\n | OffscreenCanvasRenderingContext2D\n | null;\n if (ctx && 'clearRect' in ctx) {\n ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);\n }\n }\n\n // ========= Cleanup / event handlers =========\n\n dispose(): void {\n this.stop();\n this.eventBus.off(MeframeEvent.CacheCover, this.onCacheCover);\n this.eventBus.off(MeframeEvent.ModelSet, this.onModelSet);\n if (this.videoComposer) {\n this.videoComposer.dispose();\n this.videoComposer = null;\n }\n }\n\n private onCacheCover = (): void => {\n if (this.fsm.snapshot.state === PlaybackState.Idle && this.currentTimeUs === 0) {\n void this.renderCurrentFrame(0, { mode: 'blocking' });\n }\n };\n\n private onModelSet = (): void => {\n if (!this.videoComposer || !this.orchestrator.compositionModel) return;\n\n // Model switching cancels in-flight async chains, but must NOT enter buffering or reset time/state.\n // Buffering runs a long async sequence; if cancelled mid-way it can leave the FSM stuck.\n this.dispatch({ type: PlaybackActionType.ModelSet });\n\n const model = this.orchestrator.compositionModel;\n this.videoComposer.updateConfig({\n width: model.renderConfig?.width || 720,\n height: model.renderConfig?.height || 1280,\n fps: model.fps || 30,\n backgroundColor: model.renderConfig?.backgroundColor || '#000',\n });\n\n // Best-effort background audio preheat (non-blocking).\n if (!this.orchestrator.cacheManager.isExporting) {\n void this.audioSession.ensureAudioForTime(this.currentTimeUs, { mode: 'probe' });\n }\n void this.renderCurrentFrame(this.currentTimeUs, { mode: 'blocking' });\n };\n\n private setupEventListeners(): void {\n this.eventBus.on(MeframeEvent.CacheCover, this.onCacheCover);\n this.eventBus.on(MeframeEvent.ModelSet, this.onModelSet);\n }\n\n private isVideoResourceReadyAtTime(timeUs: TimeUs): boolean {\n const model = this.orchestrator.compositionModel;\n if (!model) return true;\n const clip = model.getClipsAtTime(timeUs, model.mainTrackId)[0];\n if (!clip || !('resourceId' in clip) || typeof (clip as any).resourceId !== 'string')\n return true;\n const resourceId = (clip as any).resourceId as string;\n const resource = model.getResource(resourceId);\n // For terminal errors, do NOT enter buffering loops.\n // getRenderState() will return null and we will present an empty frame.\n return (\n resource?.state === 'ready' ||\n (resource?.state === 'error' && resource.error?.terminal === true)\n );\n }\n\n private isTerminalVideoErrorAtTime(timeUs: TimeUs): boolean {\n const model = this.orchestrator.compositionModel;\n if (!model) return false;\n const clip = model.getClipsAtTime(timeUs, model.mainTrackId)[0];\n if (!clip || !('resourceId' in clip) || typeof (clip as any).resourceId !== 'string') {\n return false;\n }\n const resourceId = (clip as any).resourceId as string;\n const resource = model.getResource(resourceId);\n return (\n resource?.type === 'video' && resource.state === 'error' && resource.error?.terminal === true\n );\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"PlaybackController.js","sources":["../../src/controllers/PlaybackController.ts"],"sourcesContent":["import type {\n IPlaybackController,\n PlaybackOptions,\n IEventBus,\n PreviewHandle,\n TimeUs,\n} from './types';\nimport {\n PlaybackActionType,\n PlaybackCommandType,\n PlaybackState,\n type OpToken,\n type PlaybackAction,\n type PlaybackCommand,\n} from './types';\nimport { MeframeEvent } from '../event/events';\nimport type { Orchestrator } from '../orchestrator';\nimport type { RequestMode } from '../orchestrator/types';\nimport { MP4MoovNotFoundError, WaiterReplacedError } from '../utils/errors';\nimport { VideoComposer } from '../stages/compose/VideoComposer';\nimport { isVideoClip } from '../model/types';\nimport type { AudioPreviewSession } from '../orchestrator/AudioPreviewSession';\n\nimport { PlaybackStateMachine } from './PlaybackStateMachine';\n\n/**\n * Playback controller for preview\n * Internal implementation - not exposed directly to external consumers\n */\nexport class PlaybackController implements IPlaybackController, PreviewHandle {\n private orchestrator: Orchestrator;\n private eventBus: IEventBus;\n private canvas: HTMLCanvasElement | OffscreenCanvas;\n private videoComposer: VideoComposer | null = null;\n\n // Playback time (external)\n currentTimeUs: TimeUs = 0;\n private playbackRate = 1.0;\n private volume = 1.0;\n private loop = false;\n\n // Time base\n private rafId: number | null = null;\n private startTimeUs: TimeUs = 0; // AudioContext timeline origin (microseconds)\n\n // Frame stats\n private frameCount = 0;\n private lastFrameTime = 0;\n private fps = 0;\n\n // Audio\n private audioContext: AudioContext;\n private audioSession: AudioPreviewSession;\n private lastAudioScheduleTime = 0;\n private readonly AUDIO_SCHEDULE_INTERVAL = 250_000; // 250ms\n\n // State machine\n private fsm = new PlaybackStateMachine();\n\n // Coalesced seek (scrubbing): latest-wins, flush at most once per rAF.\n // UI is fire-and-forget; this avoids spawning/canceling on-demand decoders too aggressively.\n private pendingSeekTimeUs: TimeUs | null = null;\n private pendingSeekWaiters: Array<() => void> = [];\n private seekFlushRafId: number | null = null;\n private seekInFlight: { targetUs: TimeUs; done: Promise<void> } | null = null;\n // If user drags far away while a seek is decoding, cancel it to avoid visible lag.\n private readonly SEEK_CANCEL_DISTANCE_US: TimeUs = 500_000; // 500ms\n\n // Unified window management for both video and audio\n private windowEnd: TimeUs = 0;\n private readonly WINDOW_DURATION = 3_000_000; // 3s decode window\n private readonly PREHEAT_DISTANCE = 1_000_000; // 1s preheat trigger distance\n private preheatInProgress = false;\n\n constructor(orchestrator: Orchestrator, eventBus: IEventBus, options: PlaybackOptions) {\n this.orchestrator = orchestrator;\n this.audioSession = orchestrator.audio.preview;\n this.eventBus = eventBus;\n this.canvas = options.canvas;\n this.audioContext = new AudioContext();\n\n const model = orchestrator.compositionModel;\n const width = model?.renderConfig?.width || this.canvas.width || 720;\n const height = model?.renderConfig?.height || this.canvas.height || 1280;\n\n this.videoComposer = new VideoComposer({\n width,\n height,\n fps: model?.fps || 30,\n backgroundColor: model?.renderConfig?.backgroundColor || '#000',\n externalCanvas: this.canvas,\n });\n\n if (options.startUs !== undefined) {\n this.currentTimeUs = options.startUs;\n }\n if (options.rate !== undefined) {\n this.playbackRate = options.rate;\n }\n if (options.loop !== undefined) {\n this.loop = options.loop;\n }\n\n this.setupEventListeners();\n\n if (options.autoStart) {\n this.play();\n }\n }\n\n async renderCover(): Promise<void> {\n await this.renderCurrentFrame(0, { mode: 'blocking' });\n }\n\n // ========= Public API =========\n\n play(): void {\n this.dispatch({ type: PlaybackActionType.Play });\n }\n\n pause(): void {\n this.dispatch({ type: PlaybackActionType.Pause });\n }\n\n stop(): void {\n this.dispatch({ type: PlaybackActionType.Stop });\n }\n\n async seek(timeUs: TimeUs): Promise<void> {\n this.pendingSeekTimeUs = timeUs;\n\n const done = new Promise<void>((resolve) => {\n this.pendingSeekWaiters.push(resolve);\n });\n\n if (this.seekFlushRafId === null) {\n this.seekFlushRafId = requestAnimationFrame(() => {\n this.seekFlushRafId = null;\n void this.flushCoalescedSeek();\n });\n }\n\n // Fire-and-forget in typical UI, but keep await semantics:\n // resolve only after the seek that includes this request has completed.\n await done;\n }\n\n private async flushCoalescedSeek(): Promise<void> {\n const target = this.pendingSeekTimeUs;\n if (target === null) {\n const waiters = this.pendingSeekWaiters;\n this.pendingSeekWaiters = [];\n for (const resolve of waiters) resolve();\n return;\n }\n\n // If a seek is in flight, prefer letting it complete to keep scrubbing continuous.\n // But if the user jumps far enough, cancel the in-flight seek to reduce lag.\n if (this.seekInFlight) {\n const distance = Math.abs(target - this.seekInFlight.targetUs);\n if (distance <= this.SEEK_CANCEL_DISTANCE_US) {\n // Keep latest pending and wait for in-flight completion.\n return;\n }\n // Far jump: cancel by starting a new seek (token bump cancels old chain at await boundaries).\n this.seekInFlight = null;\n }\n\n // Start a seek for the latest target and clear pending.\n this.pendingSeekTimeUs = null;\n const { done } = this.dispatch({\n type: PlaybackActionType.Seek,\n timeUs: target,\n durationUs: this.duration,\n });\n\n this.seekInFlight = { targetUs: target, done };\n\n void done.finally(() => {\n // Resolve awaiters after the seek finishes (tests and some callers rely on this).\n const waiters = this.pendingSeekWaiters;\n this.pendingSeekWaiters = [];\n for (const resolve of waiters) resolve();\n\n // Only clear if this in-flight is still the same one.\n if (this.seekInFlight?.targetUs === target) {\n this.seekInFlight = null;\n }\n\n // If we are continuing playback after a seek, proactively preheat the upcoming window.\n // Otherwise playback can \"stick\" on the seek frame until the normal preheat threshold is reached.\n if (this.pendingSeekTimeUs === null && !this.orchestrator.cacheManager.isExporting) {\n void this.preheatNextWindow();\n }\n\n // If new seek came in while we were decoding, flush again next frame.\n if (this.pendingSeekTimeUs !== null && this.seekFlushRafId === null) {\n this.seekFlushRafId = requestAnimationFrame(() => {\n this.seekFlushRafId = null;\n void this.flushCoalescedSeek();\n });\n }\n });\n }\n\n setRate(rate: number): void {\n const currentTimeUs = this.currentTimeUs;\n this.playbackRate = rate;\n\n // Keep currentTimeUs stable; update the time base for AudioContext clock mapping.\n this.startTimeUs = this.audioContext.currentTime * 1_000_000 - currentTimeUs / rate;\n this.audioSession.setPlaybackRate(this.playbackRate);\n\n this.eventBus.emit(MeframeEvent.PlaybackRateChange, { rate });\n }\n\n setVolume(volume: number): void {\n this.volume = Math.max(0, Math.min(1, volume));\n this.audioSession.setVolume(this.volume);\n this.eventBus.emit(MeframeEvent.PlaybackVolumeChange, { volume: this.volume });\n }\n\n setMute(muted: boolean): void {\n if (muted) {\n this.audioSession.stopPlayback();\n return;\n }\n if (this.fsm.snapshot.state === PlaybackState.Playing) {\n void this.audioSession.startPlayback(this.currentTimeUs, this.audioContext);\n }\n }\n\n setLoop(loop: boolean): void {\n this.loop = loop;\n }\n\n get duration(): TimeUs {\n return this.orchestrator.compositionModel?.durationUs ?? 0;\n }\n\n get isPlaying(): boolean {\n return this.fsm.snapshot.state === PlaybackState.Playing;\n }\n\n resume(): void {\n this.play();\n }\n\n on(event: string, handler: (payload: any) => void): void {\n this.eventBus.on(event as MeframeEvent, handler);\n }\n\n off(event: string, handler: (payload: any) => void): void {\n this.eventBus.off(event as MeframeEvent, handler);\n }\n\n // ========= State machine wiring =========\n\n private dispatch(action: PlaybackAction): { token: OpToken; done: Promise<void> } {\n const { token, commands } = this.fsm.dispatch(action, { currentTimeUs: this.currentTimeUs });\n const done = this.executeCommands(commands, token);\n return { token, done };\n }\n\n private executeCommands(commands: PlaybackCommand[], token: OpToken): Promise<void> {\n const maybe = this.executeSeq(commands, token, 0);\n return maybe ?? Promise.resolve();\n }\n\n private executeSeq(\n commands: PlaybackCommand[],\n token: OpToken,\n startIndex: number\n ): Promise<void> | void {\n for (let i = startIndex; i < commands.length; i++) {\n if (!this.isCurrentToken(token)) return;\n const maybe = this.executeCommand(commands[i]!, token);\n if (maybe) {\n return maybe.then(() => {\n if (!this.isCurrentToken(token)) return;\n const cont = this.executeSeq(commands, token, i + 1);\n return cont ?? Promise.resolve();\n });\n }\n }\n }\n\n private executePar(commands: PlaybackCommand[], token: OpToken): Promise<any> | void {\n const promises: Promise<void>[] = [];\n for (const c of commands) {\n if (!this.isCurrentToken(token)) return;\n const maybe = this.executeCommand(c, token);\n if (maybe) promises.push(maybe);\n }\n if (promises.length === 0) return;\n return Promise.all(promises);\n }\n\n private executeCommand(command: PlaybackCommand, token: OpToken): Promise<any> | void {\n if (!this.isCurrentToken(token)) return;\n\n switch (command.type) {\n case PlaybackCommandType.Seq:\n return this.executeSeq(command.commands, token, 0);\n case PlaybackCommandType.Par:\n return this.executePar(command.commands, token);\n case PlaybackCommandType.Try: {\n const handleError = (error: unknown): Promise<void> | void => {\n if (!this.isCurrentToken(token)) return;\n if (command.ignoreWaiterReplacedError && error instanceof WaiterReplacedError) return;\n if (command.logPrefix) console.error(command.logPrefix, error);\n const onErrorDone = command.onError ? this.dispatch(command.onError).done : undefined;\n const normalizeError = (e: unknown): Error => {\n if (e instanceof Error) return e;\n return new Error(typeof e === 'string' ? e : JSON.stringify(e));\n };\n const emit = () => {\n if (command.emitPlaybackError) {\n const err = normalizeError(error);\n const recoverable =\n // Waiter replaced is expected during rapid seek; safe to ignore.\n err instanceof WaiterReplacedError ||\n // Missing moov may be caused by incomplete/corrupted cache and can be retried via recovery.\n err instanceof MP4MoovNotFoundError;\n // PlaybackError: direct playback channel error for advanced consumers.\n this.eventBus.emit(MeframeEvent.PlaybackError, err);\n // Error: generic error channel expected by higher-level wrappers (e.g. @meframe/axii).\n this.eventBus.emit(MeframeEvent.Error, {\n source: 'playback',\n error: err,\n context: {\n command: command.logPrefix,\n onError: command.onError?.type,\n },\n recoverable,\n });\n }\n };\n if (onErrorDone) {\n return onErrorDone.then(() => {\n emit();\n });\n }\n emit();\n };\n\n try {\n const maybe = this.executeCommand(command.command, token);\n if (maybe) {\n return maybe.catch(handleError);\n }\n return;\n } catch (error) {\n return handleError(error) ?? Promise.resolve();\n }\n }\n case PlaybackCommandType.Dispatch:\n return this.dispatch(command.action).done;\n case PlaybackCommandType.SetTime: {\n this.currentTimeUs = command.timeUs;\n return;\n }\n case PlaybackCommandType.SetFrozenTime:\n case PlaybackCommandType.SetWantsPlay:\n case PlaybackCommandType.SetState: {\n // managed inside fsm\n return;\n }\n case PlaybackCommandType.CancelRaf: {\n this.cancelRaf();\n return;\n }\n case PlaybackCommandType.StopAudio: {\n this.audioSession.stopPlayback();\n return;\n }\n case PlaybackCommandType.ResetAudioPlaybackStates: {\n this.audioSession.resetPlaybackStates();\n return;\n }\n case PlaybackCommandType.ResetAudioSession: {\n this.audioSession.reset();\n return;\n }\n case PlaybackCommandType.ClearCanvas: {\n this.clearCanvas();\n return;\n }\n case PlaybackCommandType.SetLastAudioScheduleTime: {\n this.lastAudioScheduleTime = command.timeUs;\n return;\n }\n case PlaybackCommandType.SetStartTimeBase: {\n this.startTimeUs = command.startTimeUs;\n return;\n }\n case PlaybackCommandType.SyncTimeBaseToAudioClock: {\n this.startTimeUs =\n this.audioContext.currentTime * 1_000_000 - command.timeUs / this.playbackRate;\n return;\n }\n case PlaybackCommandType.InitWindow: {\n this.initWindow(command.timeUs);\n return;\n }\n case PlaybackCommandType.SetCacheWindow: {\n this.orchestrator.cacheManager.setWindow(command.timeUs);\n return;\n }\n case PlaybackCommandType.Emit: {\n if (command.payload === undefined) {\n this.eventBus.emit(command.event as any);\n } else {\n this.eventBus.emit(command.event as any, command.payload);\n }\n return;\n }\n case PlaybackCommandType.RenderFrame: {\n return this.renderCurrentFrame(command.timeUs, {\n mode: command.mode,\n relativeTimeUs: command.relativeTimeUs,\n });\n }\n case PlaybackCommandType.EnsureAudio: {\n return this.audioSession.ensureAudioForTime(command.timeUs, {\n mode: command.mode,\n });\n }\n case PlaybackCommandType.GetFrame: {\n return this.orchestrator.getFrame(command.timeUs, {\n mode: command.mode,\n preheat: command.preheat,\n scrub: command.scrub,\n });\n }\n case PlaybackCommandType.StartAudioPlayback: {\n return this.audioSession.startPlayback(command.timeUs, this.audioContext);\n }\n case PlaybackCommandType.ProbeStartReady: {\n const audioReady = this.audioSession.isPreviewMixBlockCached(command.timeUs);\n const videoReady = this.isVideoResourceReadyAtTime(command.timeUs);\n\n if (audioReady && videoReady) return;\n\n // Kick background preparation (best-effort).\n if (!audioReady) {\n void this.audioSession.ensureAudioForTime(command.timeUs, { mode: 'probe' });\n }\n if (!videoReady) {\n void this.orchestrator.getFrame(command.timeUs, { mode: 'probe' });\n }\n\n // Enter buffering and bump token to cancel the remaining start sequence.\n this.dispatch({\n type: PlaybackActionType.EnterBuffering,\n timeUs: command.timeUs,\n bumpToken: true,\n reason: 'startup',\n });\n return;\n }\n case PlaybackCommandType.StartRafLoop: {\n this.startPlaybackLoop(token);\n return;\n }\n }\n }\n\n private cancelRaf(): void {\n if (this.rafId !== null) {\n cancelAnimationFrame(this.rafId);\n this.rafId = null;\n }\n }\n\n private isCurrentToken(token: OpToken): boolean {\n return token === this.fsm.snapshot.token;\n }\n\n private startPlaybackLoop(token: OpToken): void {\n this.rafId = requestAnimationFrame(() => {\n void this.onRafTick(token);\n });\n }\n\n private async onRafTick(token: OpToken): Promise<void> {\n if (!this.isCurrentToken(token) || this.fsm.snapshot.state !== PlaybackState.Playing) {\n return;\n }\n\n const candidateTimeUs =\n (this.audioContext.currentTime * 1_000_000 - this.startTimeUs) * this.playbackRate;\n this.dispatch({\n type: PlaybackActionType.ClockTick,\n candidateTimeUs,\n durationUs: this.duration,\n loop: this.loop,\n audioNowUs: this.audioContext.currentTime * 1_000_000,\n });\n\n if (!this.isCurrentToken(token) || this.fsm.snapshot.state !== PlaybackState.Playing) {\n return;\n }\n\n // Audio probe: if the audio window isn't ready, enter buffering (freeze timeline)\n // and kick background audio preparation.\n // Note: preview audio readiness is driven by 60s mix-block cache inside AudioPreviewSession.\n // We intentionally avoid additional resource-window probing here to prevent buffering oscillation.\n\n // Throttle audio scheduling.\n if (this.currentTimeUs - this.lastAudioScheduleTime >= this.AUDIO_SCHEDULE_INTERVAL) {\n // Fire-and-forget: AudioPreviewSession runs its own background scheduling loop.\n // We avoid awaiting here to keep the render loop responsive.\n void this.audioSession.scheduleAudio(this.currentTimeUs, this.audioContext);\n this.lastAudioScheduleTime = this.currentTimeUs;\n }\n\n // If we're close to the 60s block boundary and the next mixed block isn't ready yet,\n // enter buffering to avoid hard silence at the boundary.\n if (this.audioSession.shouldEnterBufferingForUpcomingPreviewAudio(this.currentTimeUs)) {\n // Best-effort preheat; buffering path will call EnsureAudio(blocking).\n void this.audioSession.ensureAudioForTime(this.currentTimeUs, { mode: 'probe' });\n this.dispatch({\n type: PlaybackActionType.EnterBuffering,\n timeUs: this.currentTimeUs,\n reason: 'audio',\n });\n return;\n }\n\n const renderState = await this.orchestrator.getRenderState(this.currentTimeUs, {\n mode: 'probe',\n });\n if (!this.isCurrentToken(token) || this.fsm.snapshot.state !== PlaybackState.Playing) {\n return;\n }\n\n if (!renderState) {\n // If the current clip's resource is in a terminal error state, buffering will oscillate\n // (probe keeps returning null, buffering resolves quickly, then repeats). In this case,\n // keep playing and present an empty frame instead.\n if (this.isTerminalVideoErrorAtTime(this.currentTimeUs)) {\n this.clearCanvas();\n this.finalizeFrameAndContinue(token);\n return;\n }\n\n this.dispatch({ type: PlaybackActionType.EnterBuffering, timeUs: this.currentTimeUs });\n return;\n }\n\n await this.compose(this.currentTimeUs, renderState);\n if (!this.isCurrentToken(token) || this.fsm.snapshot.state !== PlaybackState.Playing) return;\n\n this.finalizeFrameAndContinue(token);\n }\n\n private finalizeFrameAndContinue(token: OpToken): void {\n this.updateFps();\n this.frameCount++;\n\n // Unified cache window update.\n this.orchestrator.cacheManager.setWindow(this.currentTimeUs);\n this.checkAndPreheatWindow();\n\n if (!this.isCurrentToken(token) || this.fsm.snapshot.state !== PlaybackState.Playing) {\n return;\n }\n\n this.startPlaybackLoop(token);\n }\n\n private updateFps(): void {\n const now = performance.now();\n if (this.lastFrameTime > 0) {\n const deltaTime = now - this.lastFrameTime;\n const instantFps = 1000 / deltaTime;\n this.fps = this.fps > 0 ? this.fps * 0.9 + instantFps * 0.1 : instantFps;\n }\n this.lastFrameTime = now;\n }\n\n private initWindow(timeUs: TimeUs): void {\n this.windowEnd = timeUs + this.WINDOW_DURATION;\n this.preheatInProgress = false;\n this.orchestrator.cacheManager.setWindow(timeUs);\n }\n\n private checkAndPreheatWindow(): void {\n // Export uses main-thread decode + heavy OPFS IO; disable preview preheat to avoid contention.\n if (this.orchestrator.cacheManager.isExporting) {\n return;\n }\n if (this.preheatInProgress || this.fsm.snapshot.state !== PlaybackState.Playing) {\n return;\n }\n\n const distanceToWindowEnd = this.windowEnd - this.currentTimeUs;\n if (distanceToWindowEnd < 0) {\n this.initWindow(this.currentTimeUs);\n return;\n }\n\n if (distanceToWindowEnd > 0 && distanceToWindowEnd <= this.PREHEAT_DISTANCE) {\n void this.preheatNextWindow();\n }\n }\n\n async preheatNextWindow(): Promise<void> {\n // Export uses main-thread decode + heavy OPFS IO; disable preview preheat to avoid contention.\n if (this.orchestrator.cacheManager.isExporting) {\n return;\n }\n if (this.preheatInProgress) return;\n\n this.preheatInProgress = true;\n try {\n const windowStart = this.currentTimeUs;\n const windowEnd = windowStart + this.WINDOW_DURATION;\n\n const clipsInWindow =\n this.orchestrator.compositionModel?.getClipsInRange(windowStart, windowEnd) ?? [];\n const preheatPromises: Promise<any>[] = [];\n\n for (const clip of clipsInWindow) {\n if (!isVideoClip(clip)) continue;\n\n const clipWindowStart = Math.max(0, windowStart - clip.startUs);\n const clipWindowEnd = Math.min(clip.durationUs, windowEnd - clip.startUs);\n if (clipWindowStart >= clipWindowEnd) continue;\n\n preheatPromises.push(\n this.orchestrator.preheatClipWindow(clip.id, clipWindowStart, clipWindowEnd, windowStart)\n );\n }\n\n // Audio preheat is handled inside AudioPreviewSession via mix-block scheduling & cache.\n\n await Promise.all(preheatPromises);\n this.windowEnd = windowEnd;\n } catch (error) {\n console.warn('[PlaybackController] Preheat failed:', error);\n } finally {\n this.preheatInProgress = false;\n }\n }\n\n private async renderCurrentFrame(\n timeUs: TimeUs,\n options: { mode: RequestMode; relativeTimeUs?: TimeUs }\n ): Promise<void> {\n if (!this.videoComposer) {\n console.error('[PlaybackController] VideoComposer not initialized');\n return;\n }\n\n const renderState = await this.orchestrator.getRenderState(timeUs, {\n mode: options.mode,\n relativeTimeUs: options.relativeTimeUs,\n });\n\n if (!renderState) {\n // No render state (e.g. missing clip, resource error, or probe returned null).\n // Present an empty frame instead of freezing the last canvas content.\n this.clearCanvas();\n return;\n }\n\n await this.compose(timeUs, renderState);\n }\n\n private async compose(\n timeUs: TimeUs,\n renderState: { layers: any[]; transition?: any }\n ): Promise<void> {\n if (!this.videoComposer) return;\n await this.videoComposer.composeFrame({\n timeUs,\n layers: renderState.layers,\n transition: renderState.transition,\n });\n }\n\n private clearCanvas(): void {\n const ctx = this.canvas.getContext('2d') as\n | CanvasRenderingContext2D\n | OffscreenCanvasRenderingContext2D\n | null;\n if (ctx && 'clearRect' in ctx) {\n ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);\n }\n }\n\n // ========= Cleanup / event handlers =========\n\n dispose(): void {\n this.stop();\n\n if (this.seekFlushRafId !== null) {\n cancelAnimationFrame(this.seekFlushRafId);\n this.seekFlushRafId = null;\n }\n this.pendingSeekTimeUs = null;\n const waiters = this.pendingSeekWaiters;\n this.pendingSeekWaiters = [];\n for (const resolve of waiters) resolve();\n\n this.eventBus.off(MeframeEvent.CacheCover, this.onCacheCover);\n this.eventBus.off(MeframeEvent.ModelSet, this.onModelSet);\n if (this.videoComposer) {\n this.videoComposer.dispose();\n this.videoComposer = null;\n }\n }\n\n private onCacheCover = (): void => {\n if (this.fsm.snapshot.state === PlaybackState.Idle && this.currentTimeUs === 0) {\n void this.renderCurrentFrame(0, { mode: 'blocking' });\n }\n };\n\n private onModelSet = (): void => {\n if (!this.videoComposer || !this.orchestrator.compositionModel) return;\n\n // Model switching cancels in-flight async chains, but must NOT enter buffering or reset time/state.\n // Buffering runs a long async sequence; if cancelled mid-way it can leave the FSM stuck.\n this.dispatch({ type: PlaybackActionType.ModelSet });\n\n const model = this.orchestrator.compositionModel;\n this.videoComposer.updateConfig({\n width: model.renderConfig?.width || 720,\n height: model.renderConfig?.height || 1280,\n fps: model.fps || 30,\n backgroundColor: model.renderConfig?.backgroundColor || '#000',\n });\n\n // Best-effort background audio preheat (non-blocking).\n if (!this.orchestrator.cacheManager.isExporting) {\n void this.audioSession.ensureAudioForTime(this.currentTimeUs, { mode: 'probe' });\n }\n void this.renderCurrentFrame(this.currentTimeUs, { mode: 'blocking' });\n };\n\n private setupEventListeners(): void {\n this.eventBus.on(MeframeEvent.CacheCover, this.onCacheCover);\n this.eventBus.on(MeframeEvent.ModelSet, this.onModelSet);\n }\n\n private isVideoResourceReadyAtTime(timeUs: TimeUs): boolean {\n const model = this.orchestrator.compositionModel;\n if (!model) return true;\n const clip = model.getClipsAtTime(timeUs, model.mainTrackId)[0];\n if (!clip || !('resourceId' in clip) || typeof (clip as any).resourceId !== 'string')\n return true;\n const resourceId = (clip as any).resourceId as string;\n const resource = model.getResource(resourceId);\n // For terminal errors, do NOT enter buffering loops.\n // getRenderState() will return null and we will present an empty frame.\n return (\n resource?.state === 'ready' ||\n (resource?.state === 'error' && resource.error?.terminal === true)\n );\n }\n\n private isTerminalVideoErrorAtTime(timeUs: TimeUs): boolean {\n const model = this.orchestrator.compositionModel;\n if (!model) return false;\n const clip = model.getClipsAtTime(timeUs, model.mainTrackId)[0];\n if (!clip || !('resourceId' in clip) || typeof (clip as any).resourceId !== 'string') {\n return false;\n }\n const resourceId = (clip as any).resourceId as string;\n const resource = model.getResource(resourceId);\n return (\n resource?.type === 'video' && resource.state === 'error' && resource.error?.terminal === true\n );\n }\n}\n"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"PlaybackStateMachine.d.ts","sourceRoot":"","sources":["../../src/controllers/PlaybackStateMachine.ts"],"names":[],"mappings":"AACA,OAAO,EAIL,KAAK,OAAO,EACZ,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,KAAK,uBAAuB,EAC5B,KAAK,MAAM,EACZ,MAAM,SAAS,CAAC;AAEjB,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,KAAK,CAAqC;IAClD,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,YAAY,CAAuB;IAC3C,OAAO,CAAC,KAAK,CAAc;IAE3B,IAAI,QAAQ,IAAI,uBAAuB,CAOtC;IAED,QAAQ,CACN,MAAM,EAAE,cAAc,EACtB,GAAG,EAAE;QAAE,aAAa,EAAE,MAAM,CAAA;KAAE,GAC7B;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,QAAQ,EAAE,eAAe,EAAE,CAAA;KAAE;CA4WnD"}
1
+ {"version":3,"file":"PlaybackStateMachine.d.ts","sourceRoot":"","sources":["../../src/controllers/PlaybackStateMachine.ts"],"names":[],"mappings":"AACA,OAAO,EAIL,KAAK,OAAO,EACZ,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,KAAK,uBAAuB,EAC5B,KAAK,MAAM,EACZ,MAAM,SAAS,CAAC;AAEjB,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,KAAK,CAAqC;IAClD,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,YAAY,CAAuB;IAC3C,OAAO,CAAC,KAAK,CAAc;IAE3B,IAAI,QAAQ,IAAI,uBAAuB,CAOtC;IAED,QAAQ,CACN,MAAM,EAAE,cAAc,EACtB,GAAG,EAAE;QAAE,aAAa,EAAE,MAAM,CAAA;KAAE,GAC7B;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,QAAQ,EAAE,eAAe,EAAE,CAAA;KAAE;CA0WnD"}
@@ -139,16 +139,14 @@ class PlaybackStateMachine {
139
139
  command: {
140
140
  type: PlaybackCommandType.Seq,
141
141
  commands: [
142
- { type: PlaybackCommandType.MaybeRenderKeyframePreview, timeUs: toUs },
143
142
  {
144
143
  type: PlaybackCommandType.Par,
145
144
  commands: [
146
- { type: PlaybackCommandType.EnsureAudio, timeUs: toUs, mode: "blocking" },
147
145
  {
148
146
  type: PlaybackCommandType.GetFrame,
149
147
  timeUs: toUs,
150
148
  mode: "blocking",
151
- preheat: true
149
+ scrub: true
152
150
  }
153
151
  ]
154
152
  },
@@ -1 +1 @@
1
- {"version":3,"file":"PlaybackStateMachine.js","sources":["../../src/controllers/PlaybackStateMachine.ts"],"sourcesContent":["import { MeframeEvent } from '../event/events';\nimport {\n PlaybackActionType,\n PlaybackCommandType,\n PlaybackState,\n type OpToken,\n type PlaybackAction,\n type PlaybackCommand,\n type PlaybackMachineSnapshot,\n type TimeUs,\n} from './types';\n\nexport class PlaybackStateMachine {\n private state: PlaybackState = PlaybackState.Idle;\n private wantsPlay = false;\n private frozenTimeUs: TimeUs | null = null;\n private token: OpToken = 0;\n\n get snapshot(): PlaybackMachineSnapshot {\n return {\n state: this.state,\n wantsPlay: this.wantsPlay,\n frozenTimeUs: this.frozenTimeUs,\n token: this.token,\n };\n }\n\n dispatch(\n action: PlaybackAction,\n ctx: { currentTimeUs: TimeUs }\n ): { token: OpToken; commands: PlaybackCommand[] } {\n const commands: PlaybackCommand[] = [];\n\n const bumpToken = () => {\n this.token++;\n return this.token;\n };\n\n const setState = (state: PlaybackState) => {\n this.state = state;\n commands.push({ type: PlaybackCommandType.SetState, state });\n };\n\n const setWantsPlay = (wantsPlay: boolean) => {\n this.wantsPlay = wantsPlay;\n commands.push({ type: PlaybackCommandType.SetWantsPlay, wantsPlay });\n };\n\n const setFrozenTime = (timeUs: TimeUs | null) => {\n this.frozenTimeUs = timeUs;\n commands.push({ type: PlaybackCommandType.SetFrozenTime, timeUs });\n };\n\n const setTime = (timeUs: TimeUs) => {\n commands.push({ type: PlaybackCommandType.SetTime, timeUs });\n };\n\n const clampTime = (timeUs: TimeUs, durationUs: TimeUs) => {\n // Timeline point queries are defined on [0, durationUs).\n // Seeking to durationUs would have no active clip and can cause persistent buffering.\n const maxTimeUs = durationUs > 0 ? durationUs - 1 : 0;\n return Math.max(0, Math.min(timeUs, maxTimeUs));\n };\n\n switch (action.type) {\n case PlaybackActionType.ModelSet: {\n bumpToken();\n // Cancel any in-flight async chains and leave the machine in a stable state.\n // Important: do NOT enter buffering here; buffering runs a long async sequence and can be\n // cancelled mid-way, leaving the state stuck in Buffering/Seeking.\n commands.push({ type: PlaybackCommandType.CancelRaf });\n commands.push({ type: PlaybackCommandType.StopAudio });\n commands.push({ type: PlaybackCommandType.SetLastAudioScheduleTime, timeUs: 0 });\n setFrozenTime(null);\n\n if (\n this.state === PlaybackState.Playing ||\n this.state === PlaybackState.Buffering ||\n this.state === PlaybackState.Seeking\n ) {\n setState(PlaybackState.Paused);\n }\n return { token: this.token, commands };\n }\n\n case PlaybackActionType.Play: {\n const token = bumpToken();\n const prevState = this.state;\n setWantsPlay(true);\n\n if (this.state === PlaybackState.Ended) {\n setTime(0);\n }\n\n if (this.state === PlaybackState.Playing) {\n return { token, commands };\n }\n\n // Set playing immediately; failures will rollback via START_FAILED.\n setState(PlaybackState.Playing);\n setFrozenTime(null);\n commands.push({ type: PlaybackCommandType.SetLastAudioScheduleTime, timeUs: 0 });\n commands.push({ type: PlaybackCommandType.CancelRaf });\n\n const fallbackState =\n prevState === PlaybackState.Idle || prevState === PlaybackState.Ended\n ? PlaybackState.Idle\n : PlaybackState.Paused;\n\n commands.push({\n type: PlaybackCommandType.Try,\n logPrefix: '[PlaybackController] Failed to start playback:',\n emitPlaybackError: true,\n ignoreWaiterReplacedError: true,\n onError: { type: PlaybackActionType.StartFailed, fallbackState },\n command: {\n type: PlaybackCommandType.Seq,\n commands: [\n { type: PlaybackCommandType.ProbeStartReady, timeUs: ctx.currentTimeUs },\n {\n type: PlaybackCommandType.RenderFrame,\n timeUs: ctx.currentTimeUs,\n mode: 'blocking',\n },\n { type: PlaybackCommandType.InitWindow, timeUs: ctx.currentTimeUs },\n { type: PlaybackCommandType.StartAudioPlayback, timeUs: ctx.currentTimeUs },\n { type: PlaybackCommandType.SyncTimeBaseToAudioClock, timeUs: ctx.currentTimeUs },\n { type: PlaybackCommandType.StartRafLoop },\n { type: PlaybackCommandType.Emit, event: MeframeEvent.PlaybackPlay },\n ],\n },\n });\n return { token, commands };\n }\n\n case PlaybackActionType.Pause: {\n bumpToken();\n const prev = this.state;\n setWantsPlay(false);\n setFrozenTime(null);\n commands.push({ type: PlaybackCommandType.CancelRaf });\n commands.push({ type: PlaybackCommandType.StopAudio });\n\n if (prev !== PlaybackState.Idle && prev !== PlaybackState.Ended) {\n setState(PlaybackState.Paused);\n }\n\n if (\n prev === PlaybackState.Playing ||\n prev === PlaybackState.Buffering ||\n prev === PlaybackState.Seeking\n ) {\n commands.push({ type: PlaybackCommandType.Emit, event: MeframeEvent.PlaybackPause });\n }\n\n return { token: this.token, commands };\n }\n\n case PlaybackActionType.Stop: {\n bumpToken();\n setWantsPlay(false);\n setFrozenTime(null);\n setState(PlaybackState.Idle);\n setTime(0);\n\n commands.push({ type: PlaybackCommandType.CancelRaf });\n commands.push({ type: PlaybackCommandType.StopAudio });\n commands.push({ type: PlaybackCommandType.ClearCanvas });\n commands.push({ type: PlaybackCommandType.ResetAudioSession });\n commands.push({ type: PlaybackCommandType.ResetAudioPlaybackStates });\n commands.push({ type: PlaybackCommandType.SetLastAudioScheduleTime, timeUs: 0 });\n commands.push({ type: PlaybackCommandType.Emit, event: MeframeEvent.PlaybackStop });\n\n return { token: this.token, commands };\n }\n\n case PlaybackActionType.Seek: {\n const token = bumpToken();\n const previousState = this.state;\n const toUs = clampTime(action.timeUs, action.durationUs);\n\n setTime(toUs);\n setFrozenTime(toUs);\n setState(PlaybackState.Seeking);\n commands.push({ type: PlaybackCommandType.CancelRaf });\n commands.push({ type: PlaybackCommandType.StopAudio });\n commands.push({ type: PlaybackCommandType.SetLastAudioScheduleTime, timeUs: 0 });\n commands.push({\n type: PlaybackCommandType.Try,\n logPrefix: '[PlaybackController] Seek error:',\n emitPlaybackError: true,\n ignoreWaiterReplacedError: true,\n onError: { type: PlaybackActionType.Pause },\n command: {\n type: PlaybackCommandType.Seq,\n commands: [\n { type: PlaybackCommandType.MaybeRenderKeyframePreview, timeUs: toUs },\n {\n type: PlaybackCommandType.Par,\n commands: [\n { type: PlaybackCommandType.EnsureAudio, timeUs: toUs, mode: 'blocking' },\n {\n type: PlaybackCommandType.GetFrame,\n timeUs: toUs,\n mode: 'blocking',\n preheat: true,\n },\n ],\n },\n { type: PlaybackCommandType.InitWindow, timeUs: toUs },\n { type: PlaybackCommandType.RenderFrame, timeUs: toUs, mode: 'blocking' },\n {\n type: PlaybackCommandType.Dispatch,\n action: { type: PlaybackActionType.SeekResolved, previousState },\n },\n ],\n },\n });\n\n return { token, commands };\n }\n\n case PlaybackActionType.EnterBuffering: {\n const shouldBump = action.bumpToken ?? false;\n if (shouldBump) {\n bumpToken();\n }\n if (this.state !== PlaybackState.Playing) {\n return { token: this.token, commands };\n }\n // Do NOT bump token; buffering is part of the current playback operation.\n setFrozenTime(action.timeUs);\n setState(PlaybackState.Buffering);\n commands.push({ type: PlaybackCommandType.Emit, event: MeframeEvent.PlaybackBuffering });\n commands.push({ type: PlaybackCommandType.CancelRaf });\n commands.push({ type: PlaybackCommandType.StopAudio });\n commands.push({\n type: PlaybackCommandType.Try,\n logPrefix: '[PlaybackController] Buffering error:',\n emitPlaybackError: true,\n ignoreWaiterReplacedError: true,\n onError: { type: PlaybackActionType.Pause },\n command: {\n type: PlaybackCommandType.Seq,\n commands: [\n { type: PlaybackCommandType.SetCacheWindow, timeUs: action.timeUs },\n {\n type: PlaybackCommandType.Par,\n commands: [\n { type: PlaybackCommandType.GetFrame, timeUs: action.timeUs, mode: 'blocking' },\n {\n type: PlaybackCommandType.EnsureAudio,\n timeUs: action.timeUs,\n mode: 'blocking',\n },\n ],\n },\n {\n type: PlaybackCommandType.Dispatch,\n action: { type: PlaybackActionType.BufferingResolved, timeUs: action.timeUs },\n },\n ],\n },\n });\n return { token: this.token, commands };\n }\n\n case PlaybackActionType.BufferingResolved: {\n if (this.state !== PlaybackState.Buffering) {\n return { token: this.token, commands };\n }\n setFrozenTime(null);\n if (this.wantsPlay) {\n setState(PlaybackState.Playing);\n commands.push({\n type: PlaybackCommandType.Try,\n logPrefix: '[PlaybackController] Failed to start playback:',\n emitPlaybackError: true,\n onError: { type: PlaybackActionType.StartFailed, fallbackState: PlaybackState.Paused },\n command: {\n type: PlaybackCommandType.Seq,\n commands: [\n { type: PlaybackCommandType.RenderFrame, timeUs: action.timeUs, mode: 'blocking' },\n { type: PlaybackCommandType.InitWindow, timeUs: action.timeUs },\n { type: PlaybackCommandType.StartAudioPlayback, timeUs: action.timeUs },\n { type: PlaybackCommandType.SyncTimeBaseToAudioClock, timeUs: action.timeUs },\n { type: PlaybackCommandType.StartRafLoop },\n { type: PlaybackCommandType.Emit, event: MeframeEvent.PlaybackPlay },\n ],\n },\n });\n } else {\n setState(PlaybackState.Paused);\n }\n return { token: this.token, commands };\n }\n\n case PlaybackActionType.SeekResolved: {\n if (this.state !== PlaybackState.Seeking) {\n return { token: this.token, commands };\n }\n setFrozenTime(null);\n commands.push({\n type: PlaybackCommandType.Emit,\n event: MeframeEvent.PlaybackSeek,\n payload: { timeUs: ctx.currentTimeUs },\n });\n if (this.wantsPlay) {\n setState(PlaybackState.Playing);\n commands.push({\n type: PlaybackCommandType.Try,\n logPrefix: '[PlaybackController] Failed to start playback:',\n emitPlaybackError: true,\n onError: { type: PlaybackActionType.StartFailed, fallbackState: PlaybackState.Paused },\n command: {\n type: PlaybackCommandType.Seq,\n commands: [\n {\n type: PlaybackCommandType.RenderFrame,\n timeUs: ctx.currentTimeUs,\n mode: 'blocking',\n },\n { type: PlaybackCommandType.InitWindow, timeUs: ctx.currentTimeUs },\n { type: PlaybackCommandType.StartAudioPlayback, timeUs: ctx.currentTimeUs },\n { type: PlaybackCommandType.SyncTimeBaseToAudioClock, timeUs: ctx.currentTimeUs },\n { type: PlaybackCommandType.StartRafLoop },\n { type: PlaybackCommandType.Emit, event: MeframeEvent.PlaybackPlay },\n ],\n },\n });\n } else {\n setState(\n action.previousState === PlaybackState.Idle ? PlaybackState.Idle : PlaybackState.Paused\n );\n }\n return { token: this.token, commands };\n }\n\n case PlaybackActionType.StartFailed: {\n // Startup failed: leave a stable non-playing state and clear intent.\n setWantsPlay(false);\n setFrozenTime(null);\n setState(action.fallbackState);\n commands.push({ type: PlaybackCommandType.CancelRaf });\n commands.push({ type: PlaybackCommandType.StopAudio });\n commands.push({ type: PlaybackCommandType.SetLastAudioScheduleTime, timeUs: 0 });\n return { token: this.token, commands };\n }\n\n case PlaybackActionType.ClockTick: {\n if (this.state !== PlaybackState.Playing) {\n return { token: this.token, commands };\n }\n if (this.frozenTimeUs !== null) {\n return { token: this.token, commands };\n }\n\n const t = action.candidateTimeUs;\n\n if (t >= action.durationUs) {\n if (action.loop) {\n setTime(0);\n commands.push({\n type: PlaybackCommandType.SetStartTimeBase,\n startTimeUs: action.audioNowUs,\n });\n commands.push({ type: PlaybackCommandType.ResetAudioPlaybackStates });\n commands.push({ type: PlaybackCommandType.SetLastAudioScheduleTime, timeUs: 0 });\n commands.push({ type: PlaybackCommandType.InitWindow, timeUs: 0 });\n } else {\n setWantsPlay(false);\n setState(PlaybackState.Ended);\n commands.push({ type: PlaybackCommandType.CancelRaf });\n commands.push({ type: PlaybackCommandType.StopAudio });\n setTime(0);\n commands.push({\n type: PlaybackCommandType.Emit,\n event: MeframeEvent.PlaybackEnded,\n payload: { timeUs: action.durationUs },\n });\n }\n return { token: this.token, commands };\n }\n\n setTime(t);\n commands.push({\n type: PlaybackCommandType.Emit,\n event: MeframeEvent.PlaybackTimeUpdate,\n payload: { timeUs: t },\n });\n return { token: this.token, commands };\n }\n }\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"PlaybackStateMachine.js","sources":["../../src/controllers/PlaybackStateMachine.ts"],"sourcesContent":["import { MeframeEvent } from '../event/events';\nimport {\n PlaybackActionType,\n PlaybackCommandType,\n PlaybackState,\n type OpToken,\n type PlaybackAction,\n type PlaybackCommand,\n type PlaybackMachineSnapshot,\n type TimeUs,\n} from './types';\n\nexport class PlaybackStateMachine {\n private state: PlaybackState = PlaybackState.Idle;\n private wantsPlay = false;\n private frozenTimeUs: TimeUs | null = null;\n private token: OpToken = 0;\n\n get snapshot(): PlaybackMachineSnapshot {\n return {\n state: this.state,\n wantsPlay: this.wantsPlay,\n frozenTimeUs: this.frozenTimeUs,\n token: this.token,\n };\n }\n\n dispatch(\n action: PlaybackAction,\n ctx: { currentTimeUs: TimeUs }\n ): { token: OpToken; commands: PlaybackCommand[] } {\n const commands: PlaybackCommand[] = [];\n\n const bumpToken = () => {\n this.token++;\n return this.token;\n };\n\n const setState = (state: PlaybackState) => {\n this.state = state;\n commands.push({ type: PlaybackCommandType.SetState, state });\n };\n\n const setWantsPlay = (wantsPlay: boolean) => {\n this.wantsPlay = wantsPlay;\n commands.push({ type: PlaybackCommandType.SetWantsPlay, wantsPlay });\n };\n\n const setFrozenTime = (timeUs: TimeUs | null) => {\n this.frozenTimeUs = timeUs;\n commands.push({ type: PlaybackCommandType.SetFrozenTime, timeUs });\n };\n\n const setTime = (timeUs: TimeUs) => {\n commands.push({ type: PlaybackCommandType.SetTime, timeUs });\n };\n\n const clampTime = (timeUs: TimeUs, durationUs: TimeUs) => {\n // Timeline point queries are defined on [0, durationUs).\n // Seeking to durationUs would have no active clip and can cause persistent buffering.\n const maxTimeUs = durationUs > 0 ? durationUs - 1 : 0;\n return Math.max(0, Math.min(timeUs, maxTimeUs));\n };\n\n switch (action.type) {\n case PlaybackActionType.ModelSet: {\n bumpToken();\n // Cancel any in-flight async chains and leave the machine in a stable state.\n // Important: do NOT enter buffering here; buffering runs a long async sequence and can be\n // cancelled mid-way, leaving the state stuck in Buffering/Seeking.\n commands.push({ type: PlaybackCommandType.CancelRaf });\n commands.push({ type: PlaybackCommandType.StopAudio });\n commands.push({ type: PlaybackCommandType.SetLastAudioScheduleTime, timeUs: 0 });\n setFrozenTime(null);\n\n if (\n this.state === PlaybackState.Playing ||\n this.state === PlaybackState.Buffering ||\n this.state === PlaybackState.Seeking\n ) {\n setState(PlaybackState.Paused);\n }\n return { token: this.token, commands };\n }\n\n case PlaybackActionType.Play: {\n const token = bumpToken();\n const prevState = this.state;\n setWantsPlay(true);\n\n if (this.state === PlaybackState.Ended) {\n setTime(0);\n }\n\n if (this.state === PlaybackState.Playing) {\n return { token, commands };\n }\n\n // Set playing immediately; failures will rollback via START_FAILED.\n setState(PlaybackState.Playing);\n setFrozenTime(null);\n commands.push({ type: PlaybackCommandType.SetLastAudioScheduleTime, timeUs: 0 });\n commands.push({ type: PlaybackCommandType.CancelRaf });\n\n const fallbackState =\n prevState === PlaybackState.Idle || prevState === PlaybackState.Ended\n ? PlaybackState.Idle\n : PlaybackState.Paused;\n\n commands.push({\n type: PlaybackCommandType.Try,\n logPrefix: '[PlaybackController] Failed to start playback:',\n emitPlaybackError: true,\n ignoreWaiterReplacedError: true,\n onError: { type: PlaybackActionType.StartFailed, fallbackState },\n command: {\n type: PlaybackCommandType.Seq,\n commands: [\n { type: PlaybackCommandType.ProbeStartReady, timeUs: ctx.currentTimeUs },\n {\n type: PlaybackCommandType.RenderFrame,\n timeUs: ctx.currentTimeUs,\n mode: 'blocking',\n },\n { type: PlaybackCommandType.InitWindow, timeUs: ctx.currentTimeUs },\n { type: PlaybackCommandType.StartAudioPlayback, timeUs: ctx.currentTimeUs },\n { type: PlaybackCommandType.SyncTimeBaseToAudioClock, timeUs: ctx.currentTimeUs },\n { type: PlaybackCommandType.StartRafLoop },\n { type: PlaybackCommandType.Emit, event: MeframeEvent.PlaybackPlay },\n ],\n },\n });\n return { token, commands };\n }\n\n case PlaybackActionType.Pause: {\n bumpToken();\n const prev = this.state;\n setWantsPlay(false);\n setFrozenTime(null);\n commands.push({ type: PlaybackCommandType.CancelRaf });\n commands.push({ type: PlaybackCommandType.StopAudio });\n\n if (prev !== PlaybackState.Idle && prev !== PlaybackState.Ended) {\n setState(PlaybackState.Paused);\n }\n\n if (\n prev === PlaybackState.Playing ||\n prev === PlaybackState.Buffering ||\n prev === PlaybackState.Seeking\n ) {\n commands.push({ type: PlaybackCommandType.Emit, event: MeframeEvent.PlaybackPause });\n }\n\n return { token: this.token, commands };\n }\n\n case PlaybackActionType.Stop: {\n bumpToken();\n setWantsPlay(false);\n setFrozenTime(null);\n setState(PlaybackState.Idle);\n setTime(0);\n\n commands.push({ type: PlaybackCommandType.CancelRaf });\n commands.push({ type: PlaybackCommandType.StopAudio });\n commands.push({ type: PlaybackCommandType.ClearCanvas });\n commands.push({ type: PlaybackCommandType.ResetAudioSession });\n commands.push({ type: PlaybackCommandType.ResetAudioPlaybackStates });\n commands.push({ type: PlaybackCommandType.SetLastAudioScheduleTime, timeUs: 0 });\n commands.push({ type: PlaybackCommandType.Emit, event: MeframeEvent.PlaybackStop });\n\n return { token: this.token, commands };\n }\n\n case PlaybackActionType.Seek: {\n const token = bumpToken();\n const previousState = this.state;\n const toUs = clampTime(action.timeUs, action.durationUs);\n\n setTime(toUs);\n setFrozenTime(toUs);\n setState(PlaybackState.Seeking);\n commands.push({ type: PlaybackCommandType.CancelRaf });\n commands.push({ type: PlaybackCommandType.StopAudio });\n commands.push({ type: PlaybackCommandType.SetLastAudioScheduleTime, timeUs: 0 });\n commands.push({\n type: PlaybackCommandType.Try,\n logPrefix: '[PlaybackController] Seek error:',\n emitPlaybackError: true,\n ignoreWaiterReplacedError: true,\n onError: { type: PlaybackActionType.Pause },\n command: {\n type: PlaybackCommandType.Seq,\n commands: [\n {\n type: PlaybackCommandType.Par,\n commands: [\n {\n type: PlaybackCommandType.GetFrame,\n timeUs: toUs,\n mode: 'blocking',\n scrub: true,\n },\n ],\n },\n { type: PlaybackCommandType.InitWindow, timeUs: toUs },\n { type: PlaybackCommandType.RenderFrame, timeUs: toUs, mode: 'blocking' },\n {\n type: PlaybackCommandType.Dispatch,\n action: { type: PlaybackActionType.SeekResolved, previousState },\n },\n ],\n },\n });\n\n return { token, commands };\n }\n\n case PlaybackActionType.EnterBuffering: {\n const shouldBump = action.bumpToken ?? false;\n if (shouldBump) {\n bumpToken();\n }\n if (this.state !== PlaybackState.Playing) {\n return { token: this.token, commands };\n }\n // Do NOT bump token; buffering is part of the current playback operation.\n setFrozenTime(action.timeUs);\n setState(PlaybackState.Buffering);\n commands.push({ type: PlaybackCommandType.Emit, event: MeframeEvent.PlaybackBuffering });\n commands.push({ type: PlaybackCommandType.CancelRaf });\n commands.push({ type: PlaybackCommandType.StopAudio });\n commands.push({\n type: PlaybackCommandType.Try,\n logPrefix: '[PlaybackController] Buffering error:',\n emitPlaybackError: true,\n ignoreWaiterReplacedError: true,\n onError: { type: PlaybackActionType.Pause },\n command: {\n type: PlaybackCommandType.Seq,\n commands: [\n { type: PlaybackCommandType.SetCacheWindow, timeUs: action.timeUs },\n {\n type: PlaybackCommandType.Par,\n commands: [\n { type: PlaybackCommandType.GetFrame, timeUs: action.timeUs, mode: 'blocking' },\n {\n type: PlaybackCommandType.EnsureAudio,\n timeUs: action.timeUs,\n mode: 'blocking',\n },\n ],\n },\n {\n type: PlaybackCommandType.Dispatch,\n action: { type: PlaybackActionType.BufferingResolved, timeUs: action.timeUs },\n },\n ],\n },\n });\n return { token: this.token, commands };\n }\n\n case PlaybackActionType.BufferingResolved: {\n if (this.state !== PlaybackState.Buffering) {\n return { token: this.token, commands };\n }\n setFrozenTime(null);\n if (this.wantsPlay) {\n setState(PlaybackState.Playing);\n commands.push({\n type: PlaybackCommandType.Try,\n logPrefix: '[PlaybackController] Failed to start playback:',\n emitPlaybackError: true,\n onError: { type: PlaybackActionType.StartFailed, fallbackState: PlaybackState.Paused },\n command: {\n type: PlaybackCommandType.Seq,\n commands: [\n { type: PlaybackCommandType.RenderFrame, timeUs: action.timeUs, mode: 'blocking' },\n { type: PlaybackCommandType.InitWindow, timeUs: action.timeUs },\n { type: PlaybackCommandType.StartAudioPlayback, timeUs: action.timeUs },\n { type: PlaybackCommandType.SyncTimeBaseToAudioClock, timeUs: action.timeUs },\n { type: PlaybackCommandType.StartRafLoop },\n { type: PlaybackCommandType.Emit, event: MeframeEvent.PlaybackPlay },\n ],\n },\n });\n } else {\n setState(PlaybackState.Paused);\n }\n return { token: this.token, commands };\n }\n\n case PlaybackActionType.SeekResolved: {\n if (this.state !== PlaybackState.Seeking) {\n return { token: this.token, commands };\n }\n setFrozenTime(null);\n commands.push({\n type: PlaybackCommandType.Emit,\n event: MeframeEvent.PlaybackSeek,\n payload: { timeUs: ctx.currentTimeUs },\n });\n if (this.wantsPlay) {\n setState(PlaybackState.Playing);\n commands.push({\n type: PlaybackCommandType.Try,\n logPrefix: '[PlaybackController] Failed to start playback:',\n emitPlaybackError: true,\n onError: { type: PlaybackActionType.StartFailed, fallbackState: PlaybackState.Paused },\n command: {\n type: PlaybackCommandType.Seq,\n commands: [\n {\n type: PlaybackCommandType.RenderFrame,\n timeUs: ctx.currentTimeUs,\n mode: 'blocking',\n },\n { type: PlaybackCommandType.InitWindow, timeUs: ctx.currentTimeUs },\n { type: PlaybackCommandType.StartAudioPlayback, timeUs: ctx.currentTimeUs },\n { type: PlaybackCommandType.SyncTimeBaseToAudioClock, timeUs: ctx.currentTimeUs },\n { type: PlaybackCommandType.StartRafLoop },\n { type: PlaybackCommandType.Emit, event: MeframeEvent.PlaybackPlay },\n ],\n },\n });\n } else {\n setState(\n action.previousState === PlaybackState.Idle ? PlaybackState.Idle : PlaybackState.Paused\n );\n }\n return { token: this.token, commands };\n }\n\n case PlaybackActionType.StartFailed: {\n // Startup failed: leave a stable non-playing state and clear intent.\n setWantsPlay(false);\n setFrozenTime(null);\n setState(action.fallbackState);\n commands.push({ type: PlaybackCommandType.CancelRaf });\n commands.push({ type: PlaybackCommandType.StopAudio });\n commands.push({ type: PlaybackCommandType.SetLastAudioScheduleTime, timeUs: 0 });\n return { token: this.token, commands };\n }\n\n case PlaybackActionType.ClockTick: {\n if (this.state !== PlaybackState.Playing) {\n return { token: this.token, commands };\n }\n if (this.frozenTimeUs !== null) {\n return { token: this.token, commands };\n }\n\n const t = action.candidateTimeUs;\n\n if (t >= action.durationUs) {\n if (action.loop) {\n setTime(0);\n commands.push({\n type: PlaybackCommandType.SetStartTimeBase,\n startTimeUs: action.audioNowUs,\n });\n commands.push({ type: PlaybackCommandType.ResetAudioPlaybackStates });\n commands.push({ type: PlaybackCommandType.SetLastAudioScheduleTime, timeUs: 0 });\n commands.push({ type: PlaybackCommandType.InitWindow, timeUs: 0 });\n } else {\n setWantsPlay(false);\n setState(PlaybackState.Ended);\n commands.push({ type: PlaybackCommandType.CancelRaf });\n commands.push({ type: PlaybackCommandType.StopAudio });\n setTime(0);\n commands.push({\n type: PlaybackCommandType.Emit,\n event: MeframeEvent.PlaybackEnded,\n payload: { timeUs: action.durationUs },\n });\n }\n return { token: this.token, commands };\n }\n\n setTime(t);\n commands.push({\n type: PlaybackCommandType.Emit,\n event: MeframeEvent.PlaybackTimeUpdate,\n payload: { timeUs: t },\n });\n return { token: this.token, commands };\n }\n }\n }\n}\n"],"names":[],"mappings":"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"}
@@ -94,7 +94,6 @@ export declare const PlaybackCommandType: {
94
94
  readonly Emit: "emit";
95
95
  readonly ProbeStartReady: "probeStartReady";
96
96
  readonly RenderFrame: "renderFrame";
97
- readonly MaybeRenderKeyframePreview: "maybeRenderKeyframePreview";
98
97
  readonly EnsureAudio: "ensureAudio";
99
98
  readonly GetFrame: "getFrame";
100
99
  readonly StartAudioPlayback: "startAudioPlayback";
@@ -166,9 +165,6 @@ export type PlaybackCommand = {
166
165
  timeUs: TimeUs;
167
166
  mode: RequestMode;
168
167
  relativeTimeUs?: TimeUs;
169
- } | {
170
- type: typeof PlaybackCommandType.MaybeRenderKeyframePreview;
171
- timeUs: TimeUs;
172
168
  } | {
173
169
  type: typeof PlaybackCommandType.EnsureAudio;
174
170
  timeUs: TimeUs;
@@ -178,6 +174,7 @@ export type PlaybackCommand = {
178
174
  timeUs: TimeUs;
179
175
  mode: RequestMode;
180
176
  preheat?: boolean;
177
+ scrub?: boolean;
181
178
  } | {
182
179
  type: typeof PlaybackCommandType.StartAudioPlayback;
183
180
  timeUs: TimeUs;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/controllers/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/controllers/types.ts"],"names":[],"mappings":"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"}
@@ -41,7 +41,6 @@ const PlaybackCommandType = {
41
41
  Emit: "emit",
42
42
  ProbeStartReady: "probeStartReady",
43
43
  RenderFrame: "renderFrame",
44
- MaybeRenderKeyframePreview: "maybeRenderKeyframePreview",
45
44
  EnsureAudio: "ensureAudio",
46
45
  GetFrame: "getFrame",
47
46
  StartAudioPlayback: "startAudioPlayback",
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sources":["../../src/controllers/types.ts"],"sourcesContent":["import type { TimeUs } from '../model/types';\nimport type { EventBus } from '../event/EventBus';\nimport type { EventPayloadMap } from '../event/events';\nimport type { MeframeEvent } from '../event/events';\nimport type { RequestMode } from '../orchestrator/types';\n\n// Re-export TimeUs for convenience\nexport type { TimeUs } from '../model/types';\n\n// ========= PlaybackController Types =========\n\nexport interface IPlaybackController {\n // Playback control\n play(): void;\n pause(): void;\n stop(): void;\n seek(timeUs: TimeUs): void;\n\n // Playback properties\n setRate(rate: number): void;\n setVolume(volume: number): void;\n setLoop(loop: boolean): void;\n setMute(muted: boolean): void;\n\n // State queries\n currentTimeUs: TimeUs;\n readonly duration: TimeUs;\n readonly isPlaying: boolean;\n}\n\nexport enum PlaybackState {\n Idle = 'idle',\n Buffering = 'buffering',\n Playing = 'playing',\n Paused = 'paused',\n Seeking = 'seeking',\n Ended = 'ended',\n}\n\n// ========= Playback State Machine Types (internal protocol) =========\n\nexport type OpToken = number;\n\nexport const PlaybackActionType = {\n Play: 'play',\n Pause: 'pause',\n Stop: 'stop',\n Seek: 'seek',\n ModelSet: 'modelSet',\n ClockTick: 'clockTick',\n EnterBuffering: 'enterBuffering',\n BufferingResolved: 'bufferingResolved',\n SeekResolved: 'seekResolved',\n StartFailed: 'startFailed',\n} as const;\n\nexport type PlaybackActionTypeValue = (typeof PlaybackActionType)[keyof typeof PlaybackActionType];\n\nexport type PlaybackAction =\n | { type: typeof PlaybackActionType.Play }\n | { type: typeof PlaybackActionType.Pause }\n | { type: typeof PlaybackActionType.Stop }\n | { type: typeof PlaybackActionType.Seek; timeUs: TimeUs; durationUs: TimeUs }\n | { type: typeof PlaybackActionType.ModelSet }\n | {\n type: typeof PlaybackActionType.ClockTick;\n candidateTimeUs: TimeUs;\n durationUs: TimeUs;\n loop: boolean;\n audioNowUs: TimeUs;\n }\n | {\n type: typeof PlaybackActionType.EnterBuffering;\n timeUs: TimeUs;\n bumpToken?: boolean;\n reason?: 'startup' | 'video' | 'audio';\n }\n | { type: typeof PlaybackActionType.BufferingResolved; timeUs: TimeUs }\n | { type: typeof PlaybackActionType.SeekResolved; previousState: PlaybackState }\n | { type: typeof PlaybackActionType.StartFailed; fallbackState: PlaybackState };\n\nexport const PlaybackCommandType = {\n Seq: 'seq',\n Par: 'par',\n Try: 'try',\n Dispatch: 'dispatch',\n\n SetTime: 'setTime',\n SetFrozenTime: 'setFrozenTime',\n SetWantsPlay: 'setWantsPlay',\n SetState: 'setState',\n CancelRaf: 'cancelRaf',\n StopAudio: 'stopAudio',\n ResetAudioPlaybackStates: 'resetAudioPlaybackStates',\n ResetAudioSession: 'resetAudioSession',\n ClearCanvas: 'clearCanvas',\n SetLastAudioScheduleTime: 'setLastAudioScheduleTime',\n SetStartTimeBase: 'setStartTimeBase',\n SyncTimeBaseToAudioClock: 'syncTimeBaseToAudioClock',\n InitWindow: 'initWindow',\n SetCacheWindow: 'setCacheWindow',\n Emit: 'emit',\n\n ProbeStartReady: 'probeStartReady',\n RenderFrame: 'renderFrame',\n MaybeRenderKeyframePreview: 'maybeRenderKeyframePreview',\n EnsureAudio: 'ensureAudio',\n GetFrame: 'getFrame',\n StartAudioPlayback: 'startAudioPlayback',\n StartRafLoop: 'startRafLoop',\n} as const;\n\nexport type PlaybackCommandTypeValue =\n (typeof PlaybackCommandType)[keyof typeof PlaybackCommandType];\n\nexport type PlaybackCommand =\n | { type: typeof PlaybackCommandType.Seq; commands: PlaybackCommand[] }\n | { type: typeof PlaybackCommandType.Par; commands: PlaybackCommand[] }\n | {\n type: typeof PlaybackCommandType.Try;\n command: PlaybackCommand;\n ignoreWaiterReplacedError?: boolean;\n onError?: PlaybackAction;\n emitPlaybackError?: boolean;\n logPrefix?: string;\n }\n | { type: typeof PlaybackCommandType.Dispatch; action: PlaybackAction }\n | { type: typeof PlaybackCommandType.SetTime; timeUs: TimeUs }\n | { type: typeof PlaybackCommandType.SetFrozenTime; timeUs: TimeUs | null }\n | { type: typeof PlaybackCommandType.SetWantsPlay; wantsPlay: boolean }\n | { type: typeof PlaybackCommandType.SetState; state: PlaybackState }\n | { type: typeof PlaybackCommandType.CancelRaf }\n | { type: typeof PlaybackCommandType.StopAudio }\n | { type: typeof PlaybackCommandType.ResetAudioPlaybackStates }\n | { type: typeof PlaybackCommandType.ResetAudioSession }\n | { type: typeof PlaybackCommandType.ClearCanvas }\n | { type: typeof PlaybackCommandType.SetLastAudioScheduleTime; timeUs: TimeUs }\n | { type: typeof PlaybackCommandType.SetStartTimeBase; startTimeUs: TimeUs }\n | { type: typeof PlaybackCommandType.SyncTimeBaseToAudioClock; timeUs: TimeUs }\n | { type: typeof PlaybackCommandType.InitWindow; timeUs: TimeUs }\n | { type: typeof PlaybackCommandType.SetCacheWindow; timeUs: TimeUs }\n | { type: typeof PlaybackCommandType.Emit; event: MeframeEvent; payload?: any }\n | { type: typeof PlaybackCommandType.ProbeStartReady; timeUs: TimeUs }\n | {\n type: typeof PlaybackCommandType.RenderFrame;\n timeUs: TimeUs;\n mode: RequestMode;\n relativeTimeUs?: TimeUs;\n }\n | { type: typeof PlaybackCommandType.MaybeRenderKeyframePreview; timeUs: TimeUs }\n | { type: typeof PlaybackCommandType.EnsureAudio; timeUs: TimeUs; mode: RequestMode }\n | {\n type: typeof PlaybackCommandType.GetFrame;\n timeUs: TimeUs;\n mode: RequestMode;\n preheat?: boolean;\n }\n | { type: typeof PlaybackCommandType.StartAudioPlayback; timeUs: TimeUs }\n | { type: typeof PlaybackCommandType.StartRafLoop };\n\nexport interface PlaybackMachineSnapshot {\n state: PlaybackState;\n wantsPlay: boolean;\n frozenTimeUs: TimeUs | null;\n token: OpToken;\n}\n\nexport type PlaybackEvent =\n | 'play'\n | 'pause'\n | 'ended'\n | 'seek'\n | 'timeupdate'\n | 'ratechange'\n | 'error'\n | 'frame'\n | 'stop';\n\nexport interface PlaybackOptions {\n canvas: HTMLCanvasElement | OffscreenCanvas;\n startUs?: TimeUs;\n endUs?: TimeUs;\n loop?: boolean;\n rate?: number;\n autoStart?: boolean;\n}\n\nexport interface PreviewHandle {\n play(): void;\n seek(timeUs: TimeUs): void;\n setRate(rate: number): void;\n setVolume(volume: number): void;\n pause(): void;\n resume(): void;\n stop(): void;\n readonly currentTimeUs: TimeUs;\n readonly isPlaying: boolean;\n on(event: string, handler: Function): void;\n off(event: string, handler: Function): void;\n}\n\n// ========= PlaybackWindowPlanner Types =========\n\nexport interface TimeRange {\n startUs: TimeUs;\n endUs: TimeUs;\n}\n\nexport interface PrioritizedClip {\n id: string;\n startUs: TimeUs;\n endUs: TimeUs;\n priority: number;\n}\n\n// ========= Event Bus Type =========\n// Using EventBus from orchestrator module\nexport type IEventBus = EventBus<EventPayloadMap>;\n\n// ========= Performance Types =========\n\nexport interface FrameStats {\n timeUs: TimeUs;\n fps: number;\n frameTime: number;\n dropped: boolean;\n}\n"],"names":["PlaybackState"],"mappings":"AA8BO,IAAK,kCAAAA,mBAAL;AACLA,iBAAA,MAAA,IAAO;AACPA,iBAAA,WAAA,IAAY;AACZA,iBAAA,SAAA,IAAU;AACVA,iBAAA,QAAA,IAAS;AACTA,iBAAA,SAAA,IAAU;AACVA,iBAAA,OAAA,IAAQ;AANE,SAAAA;AAAA,GAAA,iBAAA,CAAA,CAAA;AAaL,MAAM,qBAAqB;AAAA,EAChC,MAAM;AAAA,EACN,OAAO;AAAA,EACP,MAAM;AAAA,EACN,MAAM;AAAA,EACN,UAAU;AAAA,EACV,WAAW;AAAA,EACX,gBAAgB;AAAA,EAChB,mBAAmB;AAAA,EACnB,cAAc;AAAA,EACd,aAAa;AACf;AA2BO,MAAM,sBAAsB;AAAA,EACjC,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,UAAU;AAAA,EAEV,SAAS;AAAA,EACT,eAAe;AAAA,EACf,cAAc;AAAA,EACd,UAAU;AAAA,EACV,WAAW;AAAA,EACX,WAAW;AAAA,EACX,0BAA0B;AAAA,EAC1B,mBAAmB;AAAA,EACnB,aAAa;AAAA,EACb,0BAA0B;AAAA,EAC1B,kBAAkB;AAAA,EAClB,0BAA0B;AAAA,EAC1B,YAAY;AAAA,EACZ,gBAAgB;AAAA,EAChB,MAAM;AAAA,EAEN,iBAAiB;AAAA,EACjB,aAAa;AAAA,EACb,4BAA4B;AAAA,EAC5B,aAAa;AAAA,EACb,UAAU;AAAA,EACV,oBAAoB;AAAA,EACpB,cAAc;AAChB;"}
1
+ {"version":3,"file":"types.js","sources":["../../src/controllers/types.ts"],"sourcesContent":["import type { TimeUs } from '../model/types';\nimport type { EventBus } from '../event/EventBus';\nimport type { EventPayloadMap } from '../event/events';\nimport type { MeframeEvent } from '../event/events';\nimport type { RequestMode } from '../orchestrator/types';\n\n// Re-export TimeUs for convenience\nexport type { TimeUs } from '../model/types';\n\n// ========= PlaybackController Types =========\n\nexport interface IPlaybackController {\n // Playback control\n play(): void;\n pause(): void;\n stop(): void;\n seek(timeUs: TimeUs): void;\n\n // Playback properties\n setRate(rate: number): void;\n setVolume(volume: number): void;\n setLoop(loop: boolean): void;\n setMute(muted: boolean): void;\n\n // State queries\n currentTimeUs: TimeUs;\n readonly duration: TimeUs;\n readonly isPlaying: boolean;\n}\n\nexport enum PlaybackState {\n Idle = 'idle',\n Buffering = 'buffering',\n Playing = 'playing',\n Paused = 'paused',\n Seeking = 'seeking',\n Ended = 'ended',\n}\n\n// ========= Playback State Machine Types (internal protocol) =========\n\nexport type OpToken = number;\n\nexport const PlaybackActionType = {\n Play: 'play',\n Pause: 'pause',\n Stop: 'stop',\n Seek: 'seek',\n ModelSet: 'modelSet',\n ClockTick: 'clockTick',\n EnterBuffering: 'enterBuffering',\n BufferingResolved: 'bufferingResolved',\n SeekResolved: 'seekResolved',\n StartFailed: 'startFailed',\n} as const;\n\nexport type PlaybackActionTypeValue = (typeof PlaybackActionType)[keyof typeof PlaybackActionType];\n\nexport type PlaybackAction =\n | { type: typeof PlaybackActionType.Play }\n | { type: typeof PlaybackActionType.Pause }\n | { type: typeof PlaybackActionType.Stop }\n | { type: typeof PlaybackActionType.Seek; timeUs: TimeUs; durationUs: TimeUs }\n | { type: typeof PlaybackActionType.ModelSet }\n | {\n type: typeof PlaybackActionType.ClockTick;\n candidateTimeUs: TimeUs;\n durationUs: TimeUs;\n loop: boolean;\n audioNowUs: TimeUs;\n }\n | {\n type: typeof PlaybackActionType.EnterBuffering;\n timeUs: TimeUs;\n bumpToken?: boolean;\n reason?: 'startup' | 'video' | 'audio';\n }\n | { type: typeof PlaybackActionType.BufferingResolved; timeUs: TimeUs }\n | { type: typeof PlaybackActionType.SeekResolved; previousState: PlaybackState }\n | { type: typeof PlaybackActionType.StartFailed; fallbackState: PlaybackState };\n\nexport const PlaybackCommandType = {\n Seq: 'seq',\n Par: 'par',\n Try: 'try',\n Dispatch: 'dispatch',\n\n SetTime: 'setTime',\n SetFrozenTime: 'setFrozenTime',\n SetWantsPlay: 'setWantsPlay',\n SetState: 'setState',\n CancelRaf: 'cancelRaf',\n StopAudio: 'stopAudio',\n ResetAudioPlaybackStates: 'resetAudioPlaybackStates',\n ResetAudioSession: 'resetAudioSession',\n ClearCanvas: 'clearCanvas',\n SetLastAudioScheduleTime: 'setLastAudioScheduleTime',\n SetStartTimeBase: 'setStartTimeBase',\n SyncTimeBaseToAudioClock: 'syncTimeBaseToAudioClock',\n InitWindow: 'initWindow',\n SetCacheWindow: 'setCacheWindow',\n Emit: 'emit',\n\n ProbeStartReady: 'probeStartReady',\n RenderFrame: 'renderFrame',\n EnsureAudio: 'ensureAudio',\n GetFrame: 'getFrame',\n StartAudioPlayback: 'startAudioPlayback',\n StartRafLoop: 'startRafLoop',\n} as const;\n\nexport type PlaybackCommandTypeValue =\n (typeof PlaybackCommandType)[keyof typeof PlaybackCommandType];\n\nexport type PlaybackCommand =\n | { type: typeof PlaybackCommandType.Seq; commands: PlaybackCommand[] }\n | { type: typeof PlaybackCommandType.Par; commands: PlaybackCommand[] }\n | {\n type: typeof PlaybackCommandType.Try;\n command: PlaybackCommand;\n ignoreWaiterReplacedError?: boolean;\n onError?: PlaybackAction;\n emitPlaybackError?: boolean;\n logPrefix?: string;\n }\n | { type: typeof PlaybackCommandType.Dispatch; action: PlaybackAction }\n | { type: typeof PlaybackCommandType.SetTime; timeUs: TimeUs }\n | { type: typeof PlaybackCommandType.SetFrozenTime; timeUs: TimeUs | null }\n | { type: typeof PlaybackCommandType.SetWantsPlay; wantsPlay: boolean }\n | { type: typeof PlaybackCommandType.SetState; state: PlaybackState }\n | { type: typeof PlaybackCommandType.CancelRaf }\n | { type: typeof PlaybackCommandType.StopAudio }\n | { type: typeof PlaybackCommandType.ResetAudioPlaybackStates }\n | { type: typeof PlaybackCommandType.ResetAudioSession }\n | { type: typeof PlaybackCommandType.ClearCanvas }\n | { type: typeof PlaybackCommandType.SetLastAudioScheduleTime; timeUs: TimeUs }\n | { type: typeof PlaybackCommandType.SetStartTimeBase; startTimeUs: TimeUs }\n | { type: typeof PlaybackCommandType.SyncTimeBaseToAudioClock; timeUs: TimeUs }\n | { type: typeof PlaybackCommandType.InitWindow; timeUs: TimeUs }\n | { type: typeof PlaybackCommandType.SetCacheWindow; timeUs: TimeUs }\n | { type: typeof PlaybackCommandType.Emit; event: MeframeEvent; payload?: any }\n | { type: typeof PlaybackCommandType.ProbeStartReady; timeUs: TimeUs }\n | {\n type: typeof PlaybackCommandType.RenderFrame;\n timeUs: TimeUs;\n mode: RequestMode;\n relativeTimeUs?: TimeUs;\n }\n | { type: typeof PlaybackCommandType.EnsureAudio; timeUs: TimeUs; mode: RequestMode }\n | {\n type: typeof PlaybackCommandType.GetFrame;\n timeUs: TimeUs;\n mode: RequestMode;\n preheat?: boolean;\n scrub?: boolean;\n }\n | { type: typeof PlaybackCommandType.StartAudioPlayback; timeUs: TimeUs }\n | { type: typeof PlaybackCommandType.StartRafLoop };\n\nexport interface PlaybackMachineSnapshot {\n state: PlaybackState;\n wantsPlay: boolean;\n frozenTimeUs: TimeUs | null;\n token: OpToken;\n}\n\nexport type PlaybackEvent =\n | 'play'\n | 'pause'\n | 'ended'\n | 'seek'\n | 'timeupdate'\n | 'ratechange'\n | 'error'\n | 'frame'\n | 'stop';\n\nexport interface PlaybackOptions {\n canvas: HTMLCanvasElement | OffscreenCanvas;\n startUs?: TimeUs;\n endUs?: TimeUs;\n loop?: boolean;\n rate?: number;\n autoStart?: boolean;\n}\n\nexport interface PreviewHandle {\n play(): void;\n seek(timeUs: TimeUs): void;\n setRate(rate: number): void;\n setVolume(volume: number): void;\n pause(): void;\n resume(): void;\n stop(): void;\n readonly currentTimeUs: TimeUs;\n readonly isPlaying: boolean;\n on(event: string, handler: Function): void;\n off(event: string, handler: Function): void;\n}\n\n// ========= PlaybackWindowPlanner Types =========\n\nexport interface TimeRange {\n startUs: TimeUs;\n endUs: TimeUs;\n}\n\nexport interface PrioritizedClip {\n id: string;\n startUs: TimeUs;\n endUs: TimeUs;\n priority: number;\n}\n\n// ========= Event Bus Type =========\n// Using EventBus from orchestrator module\nexport type IEventBus = EventBus<EventPayloadMap>;\n\n// ========= Performance Types =========\n\nexport interface FrameStats {\n timeUs: TimeUs;\n fps: number;\n frameTime: number;\n dropped: boolean;\n}\n"],"names":["PlaybackState"],"mappings":"AA8BO,IAAK,kCAAAA,mBAAL;AACLA,iBAAA,MAAA,IAAO;AACPA,iBAAA,WAAA,IAAY;AACZA,iBAAA,SAAA,IAAU;AACVA,iBAAA,QAAA,IAAS;AACTA,iBAAA,SAAA,IAAU;AACVA,iBAAA,OAAA,IAAQ;AANE,SAAAA;AAAA,GAAA,iBAAA,CAAA,CAAA;AAaL,MAAM,qBAAqB;AAAA,EAChC,MAAM;AAAA,EACN,OAAO;AAAA,EACP,MAAM;AAAA,EACN,MAAM;AAAA,EACN,UAAU;AAAA,EACV,WAAW;AAAA,EACX,gBAAgB;AAAA,EAChB,mBAAmB;AAAA,EACnB,cAAc;AAAA,EACd,aAAa;AACf;AA2BO,MAAM,sBAAsB;AAAA,EACjC,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,UAAU;AAAA,EAEV,SAAS;AAAA,EACT,eAAe;AAAA,EACf,cAAc;AAAA,EACd,UAAU;AAAA,EACV,WAAW;AAAA,EACX,WAAW;AAAA,EACX,0BAA0B;AAAA,EAC1B,mBAAmB;AAAA,EACnB,aAAa;AAAA,EACb,0BAA0B;AAAA,EAC1B,kBAAkB;AAAA,EAClB,0BAA0B;AAAA,EAC1B,YAAY;AAAA,EACZ,gBAAgB;AAAA,EAChB,MAAM;AAAA,EAEN,iBAAiB;AAAA,EACjB,aAAa;AAAA,EACb,aAAa;AAAA,EACb,UAAU;AAAA,EACV,oBAAoB;AAAA,EACpB,cAAc;AAChB;"}
package/dist/index.d.ts CHANGED
@@ -6,7 +6,7 @@ export { Meframe } from './Meframe';
6
6
  export type { MeframeConfig, MeframeState } from './types';
7
7
  export { MeframeEvent } from './event/events';
8
8
  export { CompositionModel } from './model/CompositionModel';
9
- export type { CompositionModelData, CompositionPatch, DirtyRange, TimeUs, Track, Clip, Resource, Effect, Transition, Attachment, AnimationEffect, AnimationKeyframe, Transform2D, } from './model/types';
9
+ export type { CompositionModelData, CompositionPatch, DirtyRange, TimeUs, Track, Clip, VideoClip, AudioClip, CaptionClip, Resource, Effect, Transition, Attachment, AnimationEffect, AnimationKeyframe, Transform2D, } from './model/types';
10
10
  export type { CacheConfig, CacheStats } from './cache/types';
11
11
  export type { Plugin, PluginHook } from './plugins/types';
12
12
  export { setupCanvasDPI, createHiDPICanvas, checkCanvasDPI } from './utils/canvas-utils';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAG9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,YAAY,EACV,oBAAoB,EACpB,gBAAgB,EAChB,UAAU,EACV,MAAM,EACN,KAAK,EACL,IAAI,EACJ,QAAQ,EACR,MAAM,EACN,UAAU,EACV,UAAU,EACV,eAAe,EACf,iBAAiB,EACjB,WAAW,GACZ,MAAM,eAAe,CAAC;AAGvB,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAG7D,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAG1D,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEzF,OAAO,EAAE,yBAAyB,EAAE,MAAM,gBAAgB,CAAC;AAG3D,eAAO,MAAM,OAAO,UAAU,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAG9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,YAAY,EACV,oBAAoB,EACpB,gBAAgB,EAChB,UAAU,EACV,MAAM,EACN,KAAK,EACL,IAAI,EACJ,SAAS,EACT,SAAS,EACT,WAAW,EACX,QAAQ,EACR,MAAM,EACN,UAAU,EACV,UAAU,EACV,eAAe,EACf,iBAAiB,EACjB,WAAW,GACZ,MAAM,eAAe,CAAC;AAGvB,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAG7D,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAG1D,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEzF,OAAO,EAAE,yBAAyB,EAAE,MAAM,gBAAgB,CAAC;AAG3D,eAAO,MAAM,OAAO,UAAU,CAAC"}
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/index.ts"],"sourcesContent":["/**\n * @meframe/core-next - Next generation media processing framework\n * Based on WebCodecs API for high-performance video/audio processing\n */\n\n// Core exports\nexport { Meframe } from './Meframe';\nexport type { MeframeConfig, MeframeState } from './types';\nexport { MeframeEvent } from './event/events';\n\n// Model exports\nexport { CompositionModel } from './model/CompositionModel';\nexport type {\n CompositionModelData,\n CompositionPatch,\n DirtyRange,\n TimeUs,\n Track,\n Clip,\n Resource,\n Effect,\n Transition,\n Attachment,\n AnimationEffect,\n AnimationKeyframe,\n Transform2D,\n} from './model/types';\n\n// Cache exports\nexport type { CacheConfig, CacheStats } from './cache/types';\n\n// Plugin exports\nexport type { Plugin, PluginHook } from './plugins/types';\n\n// Utility exports\nexport { setupCanvasDPI, createHiDPICanvas, checkCanvasDPI } from './utils/canvas-utils';\n\nexport { BrowserCompatibilityError } from './utils/errors';\n\n// Re-export version\nexport const VERSION = '0.0.1';\n"],"names":[],"mappings":";;;;;AAwCO,MAAM,UAAU;"}
1
+ {"version":3,"file":"index.js","sources":["../src/index.ts"],"sourcesContent":["/**\n * @meframe/core-next - Next generation media processing framework\n * Based on WebCodecs API for high-performance video/audio processing\n */\n\n// Core exports\nexport { Meframe } from './Meframe';\nexport type { MeframeConfig, MeframeState } from './types';\nexport { MeframeEvent } from './event/events';\n\n// Model exports\nexport { CompositionModel } from './model/CompositionModel';\nexport type {\n CompositionModelData,\n CompositionPatch,\n DirtyRange,\n TimeUs,\n Track,\n Clip,\n VideoClip,\n AudioClip,\n CaptionClip,\n Resource,\n Effect,\n Transition,\n Attachment,\n AnimationEffect,\n AnimationKeyframe,\n Transform2D,\n} from './model/types';\n\n// Cache exports\nexport type { CacheConfig, CacheStats } from './cache/types';\n\n// Plugin exports\nexport type { Plugin, PluginHook } from './plugins/types';\n\n// Utility exports\nexport { setupCanvasDPI, createHiDPICanvas, checkCanvasDPI } from './utils/canvas-utils';\n\nexport { BrowserCompatibilityError } from './utils/errors';\n\n// Re-export version\nexport const VERSION = '0.0.1';\n"],"names":[],"mappings":";;;;;AA2CO,MAAM,UAAU;"}