@meframe/core 0.0.31 → 0.0.33

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 (72) hide show
  1. package/dist/Meframe.d.ts +2 -2
  2. package/dist/Meframe.d.ts.map +1 -1
  3. package/dist/Meframe.js +3 -2
  4. package/dist/Meframe.js.map +1 -1
  5. package/dist/cache/CacheManager.d.ts +12 -17
  6. package/dist/cache/CacheManager.d.ts.map +1 -1
  7. package/dist/cache/CacheManager.js +18 -280
  8. package/dist/cache/CacheManager.js.map +1 -1
  9. package/dist/cache/l1/AudioL1Cache.d.ts +36 -19
  10. package/dist/cache/l1/AudioL1Cache.d.ts.map +1 -1
  11. package/dist/cache/l1/AudioL1Cache.js +182 -282
  12. package/dist/cache/l1/AudioL1Cache.js.map +1 -1
  13. package/dist/controllers/PlaybackController.d.ts +5 -3
  14. package/dist/controllers/PlaybackController.d.ts.map +1 -1
  15. package/dist/controllers/PlaybackController.js +58 -16
  16. package/dist/controllers/PlaybackController.js.map +1 -1
  17. package/dist/event/events.d.ts +1 -1
  18. package/dist/event/events.d.ts.map +1 -1
  19. package/dist/event/events.js.map +1 -1
  20. package/dist/model/CompositionModel.d.ts +8 -0
  21. package/dist/model/CompositionModel.d.ts.map +1 -1
  22. package/dist/model/CompositionModel.js +18 -0
  23. package/dist/model/CompositionModel.js.map +1 -1
  24. package/dist/model/types.d.ts +0 -4
  25. package/dist/model/types.d.ts.map +1 -1
  26. package/dist/model/types.js.map +1 -1
  27. package/dist/orchestrator/ExportScheduler.d.ts +10 -0
  28. package/dist/orchestrator/ExportScheduler.d.ts.map +1 -1
  29. package/dist/orchestrator/ExportScheduler.js +66 -83
  30. package/dist/orchestrator/ExportScheduler.js.map +1 -1
  31. package/dist/orchestrator/GlobalAudioSession.d.ts +35 -28
  32. package/dist/orchestrator/GlobalAudioSession.d.ts.map +1 -1
  33. package/dist/orchestrator/GlobalAudioSession.js +213 -422
  34. package/dist/orchestrator/GlobalAudioSession.js.map +1 -1
  35. package/dist/orchestrator/OnDemandVideoSession.d.ts +3 -3
  36. package/dist/orchestrator/OnDemandVideoSession.d.ts.map +1 -1
  37. package/dist/orchestrator/OnDemandVideoSession.js +4 -4
  38. package/dist/orchestrator/OnDemandVideoSession.js.map +1 -1
  39. package/dist/orchestrator/Orchestrator.d.ts +11 -4
  40. package/dist/orchestrator/Orchestrator.d.ts.map +1 -1
  41. package/dist/orchestrator/Orchestrator.js +75 -68
  42. package/dist/orchestrator/Orchestrator.js.map +1 -1
  43. package/dist/orchestrator/VideoClipSession.d.ts +0 -2
  44. package/dist/orchestrator/VideoClipSession.d.ts.map +1 -1
  45. package/dist/orchestrator/VideoClipSession.js +0 -49
  46. package/dist/orchestrator/VideoClipSession.js.map +1 -1
  47. package/dist/stages/compose/OfflineAudioMixer.d.ts.map +1 -1
  48. package/dist/stages/compose/OfflineAudioMixer.js +13 -18
  49. package/dist/stages/compose/OfflineAudioMixer.js.map +1 -1
  50. package/dist/stages/decode/AudioChunkDecoder.js +169 -0
  51. package/dist/stages/decode/AudioChunkDecoder.js.map +1 -0
  52. package/dist/stages/demux/MP3FrameParser.js +186 -0
  53. package/dist/stages/demux/MP3FrameParser.js.map +1 -0
  54. package/dist/stages/load/ResourceLoader.d.ts +49 -30
  55. package/dist/stages/load/ResourceLoader.d.ts.map +1 -1
  56. package/dist/stages/load/ResourceLoader.js +255 -189
  57. package/dist/stages/load/ResourceLoader.js.map +1 -1
  58. package/dist/stages/load/TaskManager.d.ts +4 -0
  59. package/dist/stages/load/TaskManager.d.ts.map +1 -1
  60. package/dist/stages/load/TaskManager.js +11 -0
  61. package/dist/stages/load/TaskManager.js.map +1 -1
  62. package/dist/stages/load/types.d.ts +1 -0
  63. package/dist/stages/load/types.d.ts.map +1 -1
  64. package/dist/utils/audio-data.d.ts +16 -0
  65. package/dist/utils/audio-data.d.ts.map +1 -0
  66. package/dist/utils/audio-data.js +111 -0
  67. package/dist/utils/audio-data.js.map +1 -0
  68. package/package.json +1 -1
  69. package/dist/cache/resource/ImageBitmapCache.d.ts +0 -65
  70. package/dist/cache/resource/ImageBitmapCache.d.ts.map +0 -1
  71. package/dist/cache/resource/ImageBitmapCache.js +0 -101
  72. package/dist/cache/resource/ImageBitmapCache.js.map +0 -1
@@ -1,6 +1,7 @@
1
1
  import { MeframeEvent } from "../event/events.js";
2
2
  import { WaiterReplacedError } from "../utils/errors.js";
3
3
  import { VideoComposer } from "../stages/compose/VideoComposer.js";
4
+ import { isVideoClip } from "../model/types.js";
4
5
  class PlaybackController {
5
6
  orchestrator;
6
7
  eventBus;
@@ -26,10 +27,12 @@ class PlaybackController {
26
27
  isBuffering = false;
27
28
  currentSeekId = 0;
28
29
  wasPlayingBeforeSeek = false;
29
- // Window management: sliding window strategy
30
+ // Unified window management for both video and audio
30
31
  windowEnd = 0;
31
32
  WINDOW_DURATION = 3e6;
33
+ // 3s decode window
32
34
  PREHEAT_DISTANCE = 1e6;
35
+ // 1s preheat trigger distance
33
36
  preheatInProgress = false;
34
37
  constructor(orchestrator, eventBus, options) {
35
38
  this.orchestrator = orchestrator;
@@ -64,8 +67,10 @@ class PlaybackController {
64
67
  }
65
68
  // Playback control
66
69
  play() {
67
- console.log(">>>>>>>>>>>> play", this.state);
68
70
  if (this.state === "playing") return;
71
+ if (this.state === "ended") {
72
+ this.audioSession?.resetPlaybackStates();
73
+ }
69
74
  this.wasPlayingBeforeSeek = true;
70
75
  void this.startPlayback();
71
76
  }
@@ -79,11 +84,11 @@ class PlaybackController {
79
84
  }
80
85
  this.state = "playing";
81
86
  await this.ensureAudioContext();
87
+ this.initWindow(this.currentTimeUs);
82
88
  if (this.audioSession && this.audioContext) {
83
89
  await this.audioSession.startPlayback(this.currentTimeUs, this.audioContext);
84
90
  }
85
91
  this.startTimeUs = this.audioContext.currentTime * 1e6 - this.currentTimeUs / this.playbackRate;
86
- this.initWindow(this.currentTimeUs);
87
92
  this.playbackLoop();
88
93
  this.eventBus.emit(MeframeEvent.PlaybackPlay);
89
94
  } catch (error) {
@@ -110,22 +115,22 @@ class PlaybackController {
110
115
  this.wasPlayingBeforeSeek = false;
111
116
  this.frameCount = 0;
112
117
  this.lastFrameTime = 0;
113
- this.fps = 0;
114
118
  const ctx = this.canvas.getContext("2d");
115
119
  if (ctx && "clearRect" in ctx) {
116
120
  ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
117
121
  }
118
122
  this.audioSession?.reset();
123
+ this.audioSession?.resetPlaybackStates();
119
124
  this.eventBus.emit(MeframeEvent.PlaybackStop);
120
125
  }
121
126
  async seek(timeUs) {
122
- console.log(">>>>>>>>>>>> seek", this.state);
123
127
  const previousState = this.state;
124
128
  if (this.rafId !== null) {
125
129
  cancelAnimationFrame(this.rafId);
126
130
  this.rafId = null;
127
131
  }
128
132
  this.audioSession?.stopPlayback();
133
+ this.audioSession?.resetPlaybackStates();
129
134
  const clamped = this.clampTime(timeUs);
130
135
  this.currentTimeUs = clamped;
131
136
  this.currentSeekId++;
@@ -134,6 +139,9 @@ class PlaybackController {
134
139
  this.state = "seeking";
135
140
  const seekId = this.currentSeekId;
136
141
  try {
142
+ if (this.audioSession) {
143
+ await this.audioSession.ensureAudioForTime(clamped, { immediate: false });
144
+ }
137
145
  await this.renderCurrentFrame(clamped);
138
146
  if (seekId !== this.currentSeekId) {
139
147
  return;
@@ -213,7 +221,15 @@ class PlaybackController {
213
221
  return;
214
222
  }
215
223
  this.updateTime();
216
- this.audioSession?.updateTime(this.currentTimeUs);
224
+ if (this.state !== "playing") {
225
+ return;
226
+ }
227
+ if (this.audioSession) {
228
+ await this.audioSession.ensureAudioForTime(this.currentTimeUs, { immediate: true });
229
+ }
230
+ if (this.audioContext && this.audioSession) {
231
+ await this.audioSession.scheduleAudio(this.currentTimeUs, this.audioContext);
232
+ }
217
233
  await this.renderCurrentFrame(this.currentTimeUs);
218
234
  if (this.state !== "playing") {
219
235
  return;
@@ -226,6 +242,7 @@ class PlaybackController {
226
242
  }
227
243
  this.lastFrameTime = now;
228
244
  this.frameCount++;
245
+ this.orchestrator.cacheManager.setWindow(this.currentTimeUs);
229
246
  this.playbackLoop();
230
247
  });
231
248
  }
@@ -236,11 +253,13 @@ class PlaybackController {
236
253
  if (this.loop) {
237
254
  this.currentTimeUs = 0;
238
255
  this.startTimeUs = this.audioContext.currentTime * 1e6;
256
+ this.audioSession?.resetPlaybackStates();
257
+ this.initWindow(0);
239
258
  } else {
240
- this.currentTimeUs = this.duration;
241
259
  this.pause();
260
+ this.currentTimeUs = 0;
242
261
  this.state = "ended";
243
- this.eventBus.emit(MeframeEvent.PlaybackEnded, { timeUs: this.currentTimeUs });
262
+ this.eventBus.emit(MeframeEvent.PlaybackEnded, { timeUs: this.duration });
244
263
  }
245
264
  }
246
265
  this.eventBus.emit(MeframeEvent.PlaybackTimeUpdate, { timeUs: this.currentTimeUs });
@@ -248,15 +267,17 @@ class PlaybackController {
248
267
  }
249
268
  /**
250
269
  * Initialize window at given time (called on play/seek)
270
+ * Sets unified window for both video and audio
251
271
  */
252
272
  initWindow(timeUs) {
253
273
  this.windowEnd = timeUs + this.WINDOW_DURATION;
254
274
  this.preheatInProgress = false;
275
+ this.orchestrator.cacheManager.setWindow(timeUs);
255
276
  }
256
277
  /**
257
278
  * Check if approaching window end and trigger preheat for next window
258
279
  *
259
- * Strategy: Sliding window
280
+ * Strategy: Unified sliding window for both video and audio
260
281
  * - Current window: [windowStart, windowEnd] (3s duration)
261
282
  * - When playback reaches windowEnd - 1s, preheat next window
262
283
  * - Next window: [windowEnd, windowEnd + 3s]
@@ -278,15 +299,32 @@ class PlaybackController {
278
299
  }
279
300
  }
280
301
  /**
281
- * Preheat next window by decoding from current windowEnd
282
- * Updates windowStart and windowEnd after preheat completes
302
+ * Preheat next window by decoding from current playback time
303
+ * Supports cross-clip window preheating for seamless playback
304
+ * Preheats both video and audio in parallel
283
305
  */
284
306
  async preheatNextWindow() {
285
307
  try {
286
- const newWindowStart = this.windowEnd;
287
- const newWindowEnd = newWindowStart + this.WINDOW_DURATION;
288
- await this.orchestrator.getFrame(newWindowStart, { immediate: false, preheat: true });
289
- this.windowEnd = newWindowEnd;
308
+ const windowStart = this.currentTimeUs;
309
+ const windowEnd = windowStart + this.WINDOW_DURATION;
310
+ const clipsInWindow = this.orchestrator.compositionModel?.getClipsInRange(windowStart, windowEnd) ?? [];
311
+ const preheatPromises = [];
312
+ for (const clip of clipsInWindow) {
313
+ if (!isVideoClip(clip)) continue;
314
+ const clipWindowStart = Math.max(0, windowStart - clip.startUs);
315
+ const clipWindowEnd = Math.min(clip.durationUs, windowEnd - clip.startUs);
316
+ if (clipWindowStart >= clipWindowEnd) continue;
317
+ preheatPromises.push(
318
+ this.orchestrator.preheatClipWindow(clip.id, clipWindowStart, clipWindowEnd, windowStart)
319
+ );
320
+ }
321
+ if (this.audioSession) {
322
+ preheatPromises.push(
323
+ this.audioSession.ensureAudioForTime(windowStart, { immediate: false })
324
+ );
325
+ }
326
+ await Promise.all(preheatPromises);
327
+ this.windowEnd = windowEnd;
290
328
  } catch (error) {
291
329
  console.warn("[PlaybackController] Preheat failed:", error);
292
330
  }
@@ -326,8 +364,9 @@ class PlaybackController {
326
364
  this.eventBus.emit(MeframeEvent.PlaybackBuffering);
327
365
  this.audioSession?.stopPlayback();
328
366
  try {
367
+ this.orchestrator.cacheManager.setWindow(timeUs);
329
368
  await this.orchestrator.getFrame(timeUs, { immediate: false });
330
- await this.orchestrator.audioSession.ensureAudioForTime(timeUs);
369
+ await this.orchestrator.audioSession.ensureAudioForTime(timeUs, { immediate: false });
331
370
  if (seekId !== this.currentSeekId) {
332
371
  return;
333
372
  }
@@ -381,6 +420,9 @@ class PlaybackController {
381
420
  fps: model.fps || 30,
382
421
  backgroundColor: model.renderConfig?.backgroundColor || "#000"
383
422
  });
423
+ if (this.audioSession) {
424
+ void this.audioSession.ensureAudioForTime(0, { immediate: false });
425
+ }
384
426
  void this.renderCurrentFrame(this.currentTimeUs);
385
427
  };
386
428
  setupEventListeners() {
@@ -1 +1 @@
1
- {"version":3,"file":"PlaybackController.js","sources":["../../src/controllers/PlaybackController.ts"],"sourcesContent":["import type {\n IPlaybackController,\n PlaybackState,\n PlaybackOptions,\n IEventBus,\n PreviewHandle,\n TimeUs,\n} from './types';\nimport { MeframeEvent } from '../event/events';\nimport type { GlobalAudioSession } from '../orchestrator/GlobalAudioSession';\nimport type { Orchestrator } from '../orchestrator';\nimport { WaiterReplacedError } from '../utils/errors';\nimport { VideoComposer } from '../stages/compose/VideoComposer';\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 state\n currentTimeUs: TimeUs = 0;\n private state: PlaybackState = 'idle';\n private playbackRate = 1.0;\n private volume = 1.0;\n private loop = false;\n\n // Animation loop\n private rafId: number | null = null;\n private startTimeUs: TimeUs = 0; // Playback start position in AudioContext timeline (microseconds)\n\n // Frame tracking\n private frameCount = 0;\n private lastFrameTime = 0;\n private fps = 0;\n private audioContext: AudioContext | null = null;\n private audioSession: GlobalAudioSession | null = null;\n\n // Buffering state\n private isBuffering = false;\n private currentSeekId = 0;\n private wasPlayingBeforeSeek = false;\n\n // Window management: sliding window strategy\n private windowEnd: TimeUs = 0;\n private readonly WINDOW_DURATION = 3_000_000;\n private readonly PREHEAT_DISTANCE = 1_000_000;\n private preheatInProgress = false;\n\n constructor(orchestrator: Orchestrator, eventBus: IEventBus, options: PlaybackOptions) {\n this.orchestrator = orchestrator;\n this.eventBus = eventBus;\n this.canvas = options.canvas;\n\n // Initialize VideoComposer for real-time composition\n // Pass canvas as externalCanvas for direct rendering\n const model = orchestrator.compositionModel;\n\n // FIX: Prioritize model renderConfig over canvas current dimensions\n // The canvas should act as a viewport into the renderConfig resolution\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 // Set initial time if provided\n if (options.startUs !== undefined) {\n this.currentTimeUs = options.startUs;\n }\n\n if (options.rate !== undefined) {\n this.playbackRate = options.rate;\n }\n\n if (options.loop !== undefined) {\n this.loop = options.loop;\n }\n\n if (options.autoStart) {\n this.play();\n }\n\n this.setupEventListeners();\n }\n\n async renderCover(): Promise<void> {\n await this.renderCurrentFrame(0);\n }\n\n // Playback control\n play(): void {\n console.log('>>>>>>>>>>>> play', this.state);\n if (this.state === 'playing') return;\n\n this.wasPlayingBeforeSeek = true; // User wants to play\n void this.startPlayback();\n }\n\n private async startPlayback(): Promise<void> {\n const wasIdle = this.state === 'idle';\n const seekId = this.currentSeekId;\n\n try {\n // Render first frame (may trigger buffering if cache miss)\n await this.renderCurrentFrame(this.currentTimeUs);\n\n // Check if seek happened during render\n if (seekId !== this.currentSeekId) {\n return;\n }\n\n this.state = 'playing';\n await this.ensureAudioContext();\n\n if (this.audioSession && this.audioContext) {\n await this.audioSession.startPlayback(this.currentTimeUs, this.audioContext);\n }\n\n this.startTimeUs =\n this.audioContext!.currentTime * 1_000_000 - this.currentTimeUs / this.playbackRate;\n\n this.initWindow(this.currentTimeUs);\n this.playbackLoop();\n\n this.eventBus.emit(MeframeEvent.PlaybackPlay);\n } catch (error) {\n console.error('[PlaybackController] Failed to start playback:', error);\n this.state = wasIdle ? 'idle' : 'paused';\n this.eventBus.emit(MeframeEvent.PlaybackError, error as Error);\n }\n }\n\n pause(): void {\n if (this.state !== 'playing') return;\n\n this.state = 'paused';\n this.wasPlayingBeforeSeek = false; // User explicitly paused\n\n if (this.rafId !== null) {\n cancelAnimationFrame(this.rafId);\n this.rafId = null;\n }\n\n this.audioSession?.stopPlayback();\n\n this.eventBus.emit(MeframeEvent.PlaybackPause);\n }\n\n stop(): void {\n this.pause();\n this.currentTimeUs = 0;\n this.state = 'idle';\n this.wasPlayingBeforeSeek = false; // Reset seek state\n this.frameCount = 0; // Reset frame counter\n this.lastFrameTime = 0; // Reset frame timing\n this.fps = 0; // Reset FPS\n\n // Clear canvas\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 this.audioSession?.reset();\n\n this.eventBus.emit(MeframeEvent.PlaybackStop);\n }\n\n async seek(timeUs: TimeUs): Promise<void> {\n console.log('>>>>>>>>>>>> seek', this.state);\n const previousState = this.state;\n\n // Stop playback without changing wasPlayingBeforeSeek\n if (this.rafId !== null) {\n cancelAnimationFrame(this.rafId);\n this.rafId = null;\n }\n this.audioSession?.stopPlayback();\n\n const clamped = this.clampTime(timeUs);\n this.currentTimeUs = clamped;\n this.currentSeekId++; // Invalidate previous seek operations\n this.isBuffering = false; // Reset buffering flag\n\n // Initialize window at seek position\n this.initWindow(clamped);\n\n this.state = 'seeking';\n\n const seekId = this.currentSeekId;\n\n try {\n await this.renderCurrentFrame(clamped);\n\n // Check if another seek happened during render\n if (seekId !== this.currentSeekId) {\n return;\n }\n\n this.eventBus.emit(MeframeEvent.PlaybackSeek, { timeUs: this.currentTimeUs });\n\n if (this.wasPlayingBeforeSeek) {\n await this.startPlayback();\n } else {\n this.state = previousState === 'idle' ? 'idle' : 'paused';\n }\n } catch (error) {\n // Check if this seek is still current\n if (seekId !== this.currentSeekId) {\n return;\n }\n console.error('[PlaybackController] Seek error:', error);\n this.eventBus.emit(MeframeEvent.PlaybackError, error as Error);\n this.state = previousState === 'idle' ? 'idle' : 'paused';\n }\n }\n\n // Playback properties\n setRate(rate: number): void {\n // Adjust audio start time to maintain current position\n const currentTimeUs = this.currentTimeUs;\n this.playbackRate = rate;\n this.startTimeUs = this.audioContext!.currentTime * 1_000_000 - currentTimeUs / rate;\n\n this.eventBus.emit(MeframeEvent.PlaybackRateChange, { rate });\n\n this.audioSession?.setPlaybackRate(this.playbackRate);\n }\n\n setVolume(volume: number): void {\n this.volume = Math.max(0, Math.min(1, volume));\n this.eventBus.emit(MeframeEvent.PlaybackVolumeChange, { volume: this.volume });\n\n this.audioSession?.setVolume(this.volume);\n }\n\n setMute(muted: boolean): void {\n if (muted) {\n this.audioSession?.stopPlayback();\n } else if (this.state === 'playing' && this.audioContext) {\n 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 const modelDuration = this.orchestrator.compositionModel?.durationUs;\n if (modelDuration !== undefined) {\n return modelDuration;\n }\n\n return 0;\n }\n\n get isPlaying(): boolean {\n return this.state === 'playing';\n }\n\n setAudioSession(session: GlobalAudioSession): void {\n this.audioSession = session;\n }\n\n // Resume is just an alias for play\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 // Private methods\n private playbackLoop(): void {\n // Only continue loop if actively playing (not buffering/paused/etc)\n if (this.state !== 'playing') {\n if (this.rafId !== null) {\n cancelAnimationFrame(this.rafId);\n this.rafId = null;\n }\n return;\n }\n\n this.rafId = requestAnimationFrame(async () => {\n // Check state again after async boundary\n if (this.state !== 'playing') {\n return;\n }\n\n this.updateTime();\n\n // Update audio clips based on current time\n this.audioSession?.updateTime(this.currentTimeUs);\n\n await this.renderCurrentFrame(this.currentTimeUs);\n\n // Check if still playing after render (might have entered buffering)\n if (this.state !== 'playing') {\n return;\n }\n\n // Calculate FPS based on actual frame timing\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 this.frameCount++;\n\n // Note: setWindow is now called in Orchestrator.renderFrame()\n // this.orchestrator.cacheManager.setWindow(this.currentTimeUs);\n\n this.playbackLoop();\n });\n }\n\n private updateTime(): void {\n const elapsedUs =\n (this.audioContext!.currentTime * 1_000_000 - this.startTimeUs) * this.playbackRate;\n this.currentTimeUs = elapsedUs;\n\n // Check if reached end\n if (this.currentTimeUs >= this.duration) {\n if (this.loop) {\n this.currentTimeUs = 0;\n this.startTimeUs = this.audioContext!.currentTime * 1_000_000;\n } else {\n this.currentTimeUs = this.duration;\n this.pause();\n this.state = 'ended';\n this.eventBus.emit(MeframeEvent.PlaybackEnded, { timeUs: this.currentTimeUs });\n }\n }\n\n // Emit time update\n this.eventBus.emit(MeframeEvent.PlaybackTimeUpdate, { timeUs: this.currentTimeUs });\n\n // Check if approaching window edge - trigger async preheat\n this.checkAndPreheatWindow();\n // Note: setWindow is now called in Orchestrator.renderFrame()\n // this.orchestrator.cacheManager.setWindow(this.currentTimeUs);\n }\n\n /**\n * Initialize window at given time (called on play/seek)\n */\n private initWindow(timeUs: TimeUs): void {\n this.windowEnd = timeUs + this.WINDOW_DURATION;\n this.preheatInProgress = false; // Reset preheat state\n }\n\n /**\n * Check if approaching window end and trigger preheat for next window\n *\n * Strategy: Sliding window\n * - Current window: [windowStart, windowEnd] (3s duration)\n * - When playback reaches windowEnd - 1s, preheat next window\n * - Next window: [windowEnd, windowEnd + 3s]\n */\n private checkAndPreheatWindow(): void {\n // Skip if already preheating or not playing\n if (this.preheatInProgress || this.state !== 'playing') {\n return;\n }\n\n // Check if approaching window end\n const distanceToWindowEnd = this.windowEnd - this.currentTimeUs;\n if (distanceToWindowEnd < 0) {\n this.initWindow(this.currentTimeUs);\n return;\n }\n\n // Trigger preheat when 1s from window end\n if (distanceToWindowEnd > 0 && distanceToWindowEnd <= this.PREHEAT_DISTANCE) {\n this.preheatInProgress = true;\n\n void this.preheatNextWindow().finally(() => {\n this.preheatInProgress = false;\n });\n }\n }\n\n /**\n * Preheat next window by decoding from current windowEnd\n * Updates windowStart and windowEnd after preheat completes\n */\n private async preheatNextWindow(): Promise<void> {\n try {\n // Next window starts where current window ends\n const newWindowStart = this.windowEnd;\n const newWindowEnd = newWindowStart + this.WINDOW_DURATION;\n\n // Preheat without updating window center (to avoid shifting away from current playback)\n await this.orchestrator.getFrame(newWindowStart, { immediate: false, preheat: true });\n\n // Update window bounds after successful preheat\n this.windowEnd = newWindowEnd;\n } catch (error) {\n // Preheat failures are not critical\n console.warn('[PlaybackController] Preheat failed:', error);\n }\n }\n\n async renderCurrentFrame(timeUs: TimeUs): Promise<void> {\n if (!this.videoComposer) {\n console.error('[PlaybackController] VideoComposer not initialized');\n return;\n }\n\n try {\n // Get render state (layers) from orchestrator\n // Use immediate mode when playing to detect buffering\n const renderState = await this.orchestrator.getRenderState(timeUs, {\n immediate: this.state === 'playing',\n });\n\n if (!renderState) {\n // If renderState is null during playback, we hit a cache miss/buffer underrun\n if (this.state === 'playing' && !this.isBuffering) {\n await this.handlePlaybackBuffering(timeUs);\n }\n return;\n }\n\n // Compose directly to canvas\n await this.videoComposer.composeFrame({\n timeUs,\n layers: renderState.layers,\n transition: renderState.transition,\n });\n } catch (error) {\n console.error('Render error:', error);\n this.eventBus.emit(MeframeEvent.PlaybackError, error as Error);\n }\n }\n\n private async handlePlaybackBuffering(timeUs: TimeUs): Promise<void> {\n if (this.isBuffering || this.state !== 'playing') {\n return;\n }\n\n const seekId = this.currentSeekId;\n this.isBuffering = true;\n this.state = 'buffering';\n this.eventBus.emit(MeframeEvent.PlaybackBuffering);\n\n // Pause audio immediately to prevent desync\n this.audioSession?.stopPlayback();\n\n try {\n // Force load frame (blocking)\n // This ensures the resource is downloaded and decoded\n await this.orchestrator.getFrame(timeUs, { immediate: false });\n\n // Also ensure audio is ready\n await this.orchestrator.audioSession.ensureAudioForTime(timeUs);\n\n // Check if seek happened during buffering\n if (seekId !== this.currentSeekId) {\n return;\n }\n\n this.state = 'playing';\n this.startTimeUs = this.audioContext!.currentTime * 1_000_000 - timeUs / this.playbackRate;\n\n // Resume audio synced with timeline\n if (this.audioContext) {\n await this.audioSession?.startPlayback(timeUs, this.audioContext);\n }\n\n this.eventBus.emit(MeframeEvent.PlaybackPlay);\n\n if (!this.rafId) {\n this.playbackLoop();\n }\n } catch (error) {\n // Ignore WaiterReplacedError (happens during fast seeks)\n if (error instanceof WaiterReplacedError) {\n return;\n }\n // Check if seek happened during error handling\n if (seekId !== this.currentSeekId) {\n return;\n }\n console.error('[PlaybackController] Buffering error:', error);\n this.state = 'paused';\n this.eventBus.emit(MeframeEvent.PlaybackError, error as Error);\n } finally {\n this.isBuffering = false;\n }\n }\n\n private clampTime(timeUs: TimeUs): TimeUs {\n return Math.max(0, Math.min(timeUs, this.duration));\n }\n\n // Cleanup\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 // Optimization for Quick Start / Fast First Frame:\n // When the first frame of a resource is decoded (e.g. via side-channel parsing),\n // we immediately render it if we are at the start of the timeline.\n // This significantly improves perceived loading speed for compatible formats (e.g. fragmented MP4 with moov at start).\n // For standard formats or when not at time 0, this might be redundant as normal playback loop handles it.\n if (this.state === 'idle' && this.currentTimeUs === 0) {\n this.renderCurrentFrame(0);\n }\n };\n\n private onModelSet = (): void => {\n if (!this.videoComposer || !this.orchestrator.compositionModel) return;\n\n const model = this.orchestrator.compositionModel;\n // Update VideoComposer configuration with new model dimensions and fps\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 // Re-render current frame to reflect dimension changes immediately\n void this.renderCurrentFrame(this.currentTimeUs);\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 async ensureAudioContext(): Promise<void> {\n if (this.audioContext) {\n return;\n }\n\n this.audioContext = new AudioContext();\n }\n}\n"],"names":[],"mappings":";;;AAkBO,MAAM,mBAAiE;AAAA,EACpE;AAAA,EACA;AAAA,EACA;AAAA,EACA,gBAAsC;AAAA;AAAA,EAG9C,gBAAwB;AAAA,EAChB,QAAuB;AAAA,EACvB,eAAe;AAAA,EACf,SAAS;AAAA,EACT,OAAO;AAAA;AAAA,EAGP,QAAuB;AAAA,EACvB,cAAsB;AAAA;AAAA;AAAA,EAGtB,aAAa;AAAA,EACb,gBAAgB;AAAA,EAChB,MAAM;AAAA,EACN,eAAoC;AAAA,EACpC,eAA0C;AAAA;AAAA,EAG1C,cAAc;AAAA,EACd,gBAAgB;AAAA,EAChB,uBAAuB;AAAA;AAAA,EAGvB,YAAoB;AAAA,EACX,kBAAkB;AAAA,EAClB,mBAAmB;AAAA,EAC5B,oBAAoB;AAAA,EAE5B,YAAY,cAA4B,UAAqB,SAA0B;AACrF,SAAK,eAAe;AACpB,SAAK,WAAW;AAChB,SAAK,SAAS,QAAQ;AAItB,UAAM,QAAQ,aAAa;AAI3B,UAAM,QAAQ,OAAO,cAAc,SAAS,KAAK,OAAO,SAAS;AACjE,UAAM,SAAS,OAAO,cAAc,UAAU,KAAK,OAAO,UAAU;AAEpE,SAAK,gBAAgB,IAAI,cAAc;AAAA,MACrC;AAAA,MACA;AAAA,MACA,KAAK,OAAO,OAAO;AAAA,MACnB,iBAAiB,OAAO,cAAc,mBAAmB;AAAA,MACzD,gBAAgB,KAAK;AAAA,IAAA,CACtB;AAGD,QAAI,QAAQ,YAAY,QAAW;AACjC,WAAK,gBAAgB,QAAQ;AAAA,IAC/B;AAEA,QAAI,QAAQ,SAAS,QAAW;AAC9B,WAAK,eAAe,QAAQ;AAAA,IAC9B;AAEA,QAAI,QAAQ,SAAS,QAAW;AAC9B,WAAK,OAAO,QAAQ;AAAA,IACtB;AAEA,QAAI,QAAQ,WAAW;AACrB,WAAK,KAAA;AAAA,IACP;AAEA,SAAK,oBAAA;AAAA,EACP;AAAA,EAEA,MAAM,cAA6B;AACjC,UAAM,KAAK,mBAAmB,CAAC;AAAA,EACjC;AAAA;AAAA,EAGA,OAAa;AACX,YAAQ,IAAI,qBAAqB,KAAK,KAAK;AAC3C,QAAI,KAAK,UAAU,UAAW;AAE9B,SAAK,uBAAuB;AAC5B,SAAK,KAAK,cAAA;AAAA,EACZ;AAAA,EAEA,MAAc,gBAA+B;AAC3C,UAAM,UAAU,KAAK,UAAU;AAC/B,UAAM,SAAS,KAAK;AAEpB,QAAI;AAEF,YAAM,KAAK,mBAAmB,KAAK,aAAa;AAGhD,UAAI,WAAW,KAAK,eAAe;AACjC;AAAA,MACF;AAEA,WAAK,QAAQ;AACb,YAAM,KAAK,mBAAA;AAEX,UAAI,KAAK,gBAAgB,KAAK,cAAc;AAC1C,cAAM,KAAK,aAAa,cAAc,KAAK,eAAe,KAAK,YAAY;AAAA,MAC7E;AAEA,WAAK,cACH,KAAK,aAAc,cAAc,MAAY,KAAK,gBAAgB,KAAK;AAEzE,WAAK,WAAW,KAAK,aAAa;AAClC,WAAK,aAAA;AAEL,WAAK,SAAS,KAAK,aAAa,YAAY;AAAA,IAC9C,SAAS,OAAO;AACd,cAAQ,MAAM,kDAAkD,KAAK;AACrE,WAAK,QAAQ,UAAU,SAAS;AAChC,WAAK,SAAS,KAAK,aAAa,eAAe,KAAc;AAAA,IAC/D;AAAA,EACF;AAAA,EAEA,QAAc;AACZ,QAAI,KAAK,UAAU,UAAW;AAE9B,SAAK,QAAQ;AACb,SAAK,uBAAuB;AAE5B,QAAI,KAAK,UAAU,MAAM;AACvB,2BAAqB,KAAK,KAAK;AAC/B,WAAK,QAAQ;AAAA,IACf;AAEA,SAAK,cAAc,aAAA;AAEnB,SAAK,SAAS,KAAK,aAAa,aAAa;AAAA,EAC/C;AAAA,EAEA,OAAa;AACX,SAAK,MAAA;AACL,SAAK,gBAAgB;AACrB,SAAK,QAAQ;AACb,SAAK,uBAAuB;AAC5B,SAAK,aAAa;AAClB,SAAK,gBAAgB;AACrB,SAAK,MAAM;AAGX,UAAM,MAAM,KAAK,OAAO,WAAW,IAAI;AAIvC,QAAI,OAAO,eAAe,KAAK;AAC7B,UAAI,UAAU,GAAG,GAAG,KAAK,OAAO,OAAO,KAAK,OAAO,MAAM;AAAA,IAC3D;AAEA,SAAK,cAAc,MAAA;AAEnB,SAAK,SAAS,KAAK,aAAa,YAAY;AAAA,EAC9C;AAAA,EAEA,MAAM,KAAK,QAA+B;AACxC,YAAQ,IAAI,qBAAqB,KAAK,KAAK;AAC3C,UAAM,gBAAgB,KAAK;AAG3B,QAAI,KAAK,UAAU,MAAM;AACvB,2BAAqB,KAAK,KAAK;AAC/B,WAAK,QAAQ;AAAA,IACf;AACA,SAAK,cAAc,aAAA;AAEnB,UAAM,UAAU,KAAK,UAAU,MAAM;AACrC,SAAK,gBAAgB;AACrB,SAAK;AACL,SAAK,cAAc;AAGnB,SAAK,WAAW,OAAO;AAEvB,SAAK,QAAQ;AAEb,UAAM,SAAS,KAAK;AAEpB,QAAI;AACF,YAAM,KAAK,mBAAmB,OAAO;AAGrC,UAAI,WAAW,KAAK,eAAe;AACjC;AAAA,MACF;AAEA,WAAK,SAAS,KAAK,aAAa,cAAc,EAAE,QAAQ,KAAK,eAAe;AAE5E,UAAI,KAAK,sBAAsB;AAC7B,cAAM,KAAK,cAAA;AAAA,MACb,OAAO;AACL,aAAK,QAAQ,kBAAkB,SAAS,SAAS;AAAA,MACnD;AAAA,IACF,SAAS,OAAO;AAEd,UAAI,WAAW,KAAK,eAAe;AACjC;AAAA,MACF;AACA,cAAQ,MAAM,oCAAoC,KAAK;AACvD,WAAK,SAAS,KAAK,aAAa,eAAe,KAAc;AAC7D,WAAK,QAAQ,kBAAkB,SAAS,SAAS;AAAA,IACnD;AAAA,EACF;AAAA;AAAA,EAGA,QAAQ,MAAoB;AAE1B,UAAM,gBAAgB,KAAK;AAC3B,SAAK,eAAe;AACpB,SAAK,cAAc,KAAK,aAAc,cAAc,MAAY,gBAAgB;AAEhF,SAAK,SAAS,KAAK,aAAa,oBAAoB,EAAE,MAAM;AAE5D,SAAK,cAAc,gBAAgB,KAAK,YAAY;AAAA,EACtD;AAAA,EAEA,UAAU,QAAsB;AAC9B,SAAK,SAAS,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,MAAM,CAAC;AAC7C,SAAK,SAAS,KAAK,aAAa,sBAAsB,EAAE,QAAQ,KAAK,QAAQ;AAE7E,SAAK,cAAc,UAAU,KAAK,MAAM;AAAA,EAC1C;AAAA,EAEA,QAAQ,OAAsB;AAC5B,QAAI,OAAO;AACT,WAAK,cAAc,aAAA;AAAA,IACrB,WAAW,KAAK,UAAU,aAAa,KAAK,cAAc;AACxD,WAAK,cAAc,cAAc,KAAK,eAAe,KAAK,YAAY;AAAA,IACxE;AAAA,EACF;AAAA,EAEA,QAAQ,MAAqB;AAC3B,SAAK,OAAO;AAAA,EACd;AAAA,EAEA,IAAI,WAAmB;AACrB,UAAM,gBAAgB,KAAK,aAAa,kBAAkB;AAC1D,QAAI,kBAAkB,QAAW;AAC/B,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,IAAI,YAAqB;AACvB,WAAO,KAAK,UAAU;AAAA,EACxB;AAAA,EAEA,gBAAgB,SAAmC;AACjD,SAAK,eAAe;AAAA,EACtB;AAAA;AAAA,EAGA,SAAe;AACb,SAAK,KAAA;AAAA,EACP;AAAA,EAEA,GAAG,OAAe,SAAuC;AACvD,SAAK,SAAS,GAAG,OAAuB,OAAO;AAAA,EACjD;AAAA,EAEA,IAAI,OAAe,SAAuC;AACxD,SAAK,SAAS,IAAI,OAAuB,OAAO;AAAA,EAClD;AAAA;AAAA,EAGQ,eAAqB;AAE3B,QAAI,KAAK,UAAU,WAAW;AAC5B,UAAI,KAAK,UAAU,MAAM;AACvB,6BAAqB,KAAK,KAAK;AAC/B,aAAK,QAAQ;AAAA,MACf;AACA;AAAA,IACF;AAEA,SAAK,QAAQ,sBAAsB,YAAY;AAE7C,UAAI,KAAK,UAAU,WAAW;AAC5B;AAAA,MACF;AAEA,WAAK,WAAA;AAGL,WAAK,cAAc,WAAW,KAAK,aAAa;AAEhD,YAAM,KAAK,mBAAmB,KAAK,aAAa;AAGhD,UAAI,KAAK,UAAU,WAAW;AAC5B;AAAA,MACF;AAGA,YAAM,MAAM,YAAY,IAAA;AACxB,UAAI,KAAK,gBAAgB,GAAG;AAC1B,cAAM,YAAY,MAAM,KAAK;AAC7B,cAAM,aAAa,MAAO;AAC1B,aAAK,MAAM,KAAK,MAAM,IAAI,KAAK,MAAM,MAAM,aAAa,MAAM;AAAA,MAChE;AACA,WAAK,gBAAgB;AAErB,WAAK;AAKL,WAAK,aAAA;AAAA,IACP,CAAC;AAAA,EACH;AAAA,EAEQ,aAAmB;AACzB,UAAM,aACH,KAAK,aAAc,cAAc,MAAY,KAAK,eAAe,KAAK;AACzE,SAAK,gBAAgB;AAGrB,QAAI,KAAK,iBAAiB,KAAK,UAAU;AACvC,UAAI,KAAK,MAAM;AACb,aAAK,gBAAgB;AACrB,aAAK,cAAc,KAAK,aAAc,cAAc;AAAA,MACtD,OAAO;AACL,aAAK,gBAAgB,KAAK;AAC1B,aAAK,MAAA;AACL,aAAK,QAAQ;AACb,aAAK,SAAS,KAAK,aAAa,eAAe,EAAE,QAAQ,KAAK,eAAe;AAAA,MAC/E;AAAA,IACF;AAGA,SAAK,SAAS,KAAK,aAAa,oBAAoB,EAAE,QAAQ,KAAK,eAAe;AAGlF,SAAK,sBAAA;AAAA,EAGP;AAAA;AAAA;AAAA;AAAA,EAKQ,WAAW,QAAsB;AACvC,SAAK,YAAY,SAAS,KAAK;AAC/B,SAAK,oBAAoB;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUQ,wBAA8B;AAEpC,QAAI,KAAK,qBAAqB,KAAK,UAAU,WAAW;AACtD;AAAA,IACF;AAGA,UAAM,sBAAsB,KAAK,YAAY,KAAK;AAClD,QAAI,sBAAsB,GAAG;AAC3B,WAAK,WAAW,KAAK,aAAa;AAClC;AAAA,IACF;AAGA,QAAI,sBAAsB,KAAK,uBAAuB,KAAK,kBAAkB;AAC3E,WAAK,oBAAoB;AAEzB,WAAK,KAAK,oBAAoB,QAAQ,MAAM;AAC1C,aAAK,oBAAoB;AAAA,MAC3B,CAAC;AAAA,IACH;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,oBAAmC;AAC/C,QAAI;AAEF,YAAM,iBAAiB,KAAK;AAC5B,YAAM,eAAe,iBAAiB,KAAK;AAG3C,YAAM,KAAK,aAAa,SAAS,gBAAgB,EAAE,WAAW,OAAO,SAAS,MAAM;AAGpF,WAAK,YAAY;AAAA,IACnB,SAAS,OAAO;AAEd,cAAQ,KAAK,wCAAwC,KAAK;AAAA,IAC5D;AAAA,EACF;AAAA,EAEA,MAAM,mBAAmB,QAA+B;AACtD,QAAI,CAAC,KAAK,eAAe;AACvB,cAAQ,MAAM,oDAAoD;AAClE;AAAA,IACF;AAEA,QAAI;AAGF,YAAM,cAAc,MAAM,KAAK,aAAa,eAAe,QAAQ;AAAA,QACjE,WAAW,KAAK,UAAU;AAAA,MAAA,CAC3B;AAED,UAAI,CAAC,aAAa;AAEhB,YAAI,KAAK,UAAU,aAAa,CAAC,KAAK,aAAa;AACjD,gBAAM,KAAK,wBAAwB,MAAM;AAAA,QAC3C;AACA;AAAA,MACF;AAGA,YAAM,KAAK,cAAc,aAAa;AAAA,QACpC;AAAA,QACA,QAAQ,YAAY;AAAA,QACpB,YAAY,YAAY;AAAA,MAAA,CACzB;AAAA,IACH,SAAS,OAAO;AACd,cAAQ,MAAM,iBAAiB,KAAK;AACpC,WAAK,SAAS,KAAK,aAAa,eAAe,KAAc;AAAA,IAC/D;AAAA,EACF;AAAA,EAEA,MAAc,wBAAwB,QAA+B;AACnE,QAAI,KAAK,eAAe,KAAK,UAAU,WAAW;AAChD;AAAA,IACF;AAEA,UAAM,SAAS,KAAK;AACpB,SAAK,cAAc;AACnB,SAAK,QAAQ;AACb,SAAK,SAAS,KAAK,aAAa,iBAAiB;AAGjD,SAAK,cAAc,aAAA;AAEnB,QAAI;AAGF,YAAM,KAAK,aAAa,SAAS,QAAQ,EAAE,WAAW,OAAO;AAG7D,YAAM,KAAK,aAAa,aAAa,mBAAmB,MAAM;AAG9D,UAAI,WAAW,KAAK,eAAe;AACjC;AAAA,MACF;AAEA,WAAK,QAAQ;AACb,WAAK,cAAc,KAAK,aAAc,cAAc,MAAY,SAAS,KAAK;AAG9E,UAAI,KAAK,cAAc;AACrB,cAAM,KAAK,cAAc,cAAc,QAAQ,KAAK,YAAY;AAAA,MAClE;AAEA,WAAK,SAAS,KAAK,aAAa,YAAY;AAE5C,UAAI,CAAC,KAAK,OAAO;AACf,aAAK,aAAA;AAAA,MACP;AAAA,IACF,SAAS,OAAO;AAEd,UAAI,iBAAiB,qBAAqB;AACxC;AAAA,MACF;AAEA,UAAI,WAAW,KAAK,eAAe;AACjC;AAAA,MACF;AACA,cAAQ,MAAM,yCAAyC,KAAK;AAC5D,WAAK,QAAQ;AACb,WAAK,SAAS,KAAK,aAAa,eAAe,KAAc;AAAA,IAC/D,UAAA;AACE,WAAK,cAAc;AAAA,IACrB;AAAA,EACF;AAAA,EAEQ,UAAU,QAAwB;AACxC,WAAO,KAAK,IAAI,GAAG,KAAK,IAAI,QAAQ,KAAK,QAAQ,CAAC;AAAA,EACpD;AAAA;AAAA,EAGA,UAAgB;AACd,SAAK,KAAA;AACL,SAAK,SAAS,IAAI,aAAa,YAAY,KAAK,YAAY;AAC5D,SAAK,SAAS,IAAI,aAAa,UAAU,KAAK,UAAU;AACxD,QAAI,KAAK,eAAe;AACtB,WAAK,cAAc,QAAA;AACnB,WAAK,gBAAgB;AAAA,IACvB;AAAA,EACF;AAAA,EAEQ,eAAe,MAAY;AAMjC,QAAI,KAAK,UAAU,UAAU,KAAK,kBAAkB,GAAG;AACrD,WAAK,mBAAmB,CAAC;AAAA,IAC3B;AAAA,EACF;AAAA,EAEQ,aAAa,MAAY;AAC/B,QAAI,CAAC,KAAK,iBAAiB,CAAC,KAAK,aAAa,iBAAkB;AAEhE,UAAM,QAAQ,KAAK,aAAa;AAEhC,SAAK,cAAc,aAAa;AAAA,MAC9B,OAAO,MAAM,cAAc,SAAS;AAAA,MACpC,QAAQ,MAAM,cAAc,UAAU;AAAA,MACtC,KAAK,MAAM,OAAO;AAAA,MAClB,iBAAiB,MAAM,cAAc,mBAAmB;AAAA,IAAA,CACzD;AAGD,SAAK,KAAK,mBAAmB,KAAK,aAAa;AAAA,EACjD;AAAA,EAEQ,sBAA4B;AAClC,SAAK,SAAS,GAAG,aAAa,YAAY,KAAK,YAAY;AAC3D,SAAK,SAAS,GAAG,aAAa,UAAU,KAAK,UAAU;AAAA,EACzD;AAAA,EAEA,MAAc,qBAAoC;AAChD,QAAI,KAAK,cAAc;AACrB;AAAA,IACF;AAEA,SAAK,eAAe,IAAI,aAAA;AAAA,EAC1B;AACF;"}
1
+ {"version":3,"file":"PlaybackController.js","sources":["../../src/controllers/PlaybackController.ts"],"sourcesContent":["import type {\n IPlaybackController,\n PlaybackState,\n PlaybackOptions,\n IEventBus,\n PreviewHandle,\n TimeUs,\n} from './types';\nimport { MeframeEvent } from '../event/events';\nimport type { GlobalAudioSession } from '../orchestrator/GlobalAudioSession';\nimport type { Orchestrator } from '../orchestrator';\nimport { WaiterReplacedError } from '../utils/errors';\nimport { VideoComposer } from '../stages/compose/VideoComposer';\nimport { isVideoClip } from '../model/types';\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 state\n currentTimeUs: TimeUs = 0;\n private state: PlaybackState = 'idle';\n private playbackRate = 1.0;\n private volume = 1.0;\n private loop = false;\n\n // Animation loop\n private rafId: number | null = null;\n private startTimeUs: TimeUs = 0; // Playback start position in AudioContext timeline (microseconds)\n\n // Frame tracking\n private frameCount = 0;\n private lastFrameTime = 0;\n private fps = 0;\n private audioContext: AudioContext | null = null;\n private audioSession: GlobalAudioSession | null = null;\n\n // Buffering state\n private isBuffering = false;\n private currentSeekId = 0;\n private wasPlayingBeforeSeek = false;\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.eventBus = eventBus;\n this.canvas = options.canvas;\n\n // Initialize VideoComposer for real-time composition\n // Pass canvas as externalCanvas for direct rendering\n const model = orchestrator.compositionModel;\n\n // FIX: Prioritize model renderConfig over canvas current dimensions\n // The canvas should act as a viewport into the renderConfig resolution\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 // Set initial time if provided\n if (options.startUs !== undefined) {\n this.currentTimeUs = options.startUs;\n }\n\n if (options.rate !== undefined) {\n this.playbackRate = options.rate;\n }\n\n if (options.loop !== undefined) {\n this.loop = options.loop;\n }\n\n if (options.autoStart) {\n this.play();\n }\n\n this.setupEventListeners();\n }\n\n async renderCover(): Promise<void> {\n await this.renderCurrentFrame(0);\n }\n\n // Playback control\n play(): void {\n if (this.state === 'playing') return;\n\n // If playback has ended, reset audio scheduling states for clean replay\n if (this.state === 'ended') {\n this.audioSession?.resetPlaybackStates();\n }\n\n this.wasPlayingBeforeSeek = true; // User wants to play\n void this.startPlayback();\n }\n\n private async startPlayback(): Promise<void> {\n const wasIdle = this.state === 'idle';\n const seekId = this.currentSeekId;\n\n try {\n // Render first frame (may trigger buffering if cache miss)\n await this.renderCurrentFrame(this.currentTimeUs);\n\n // Check if seek happened during render\n if (seekId !== this.currentSeekId) {\n return;\n }\n\n this.state = 'playing';\n await this.ensureAudioContext();\n\n // Initialize windows BEFORE starting audio playback\n this.initWindow(this.currentTimeUs);\n\n if (this.audioSession && this.audioContext) {\n await this.audioSession.startPlayback(this.currentTimeUs, this.audioContext);\n }\n\n this.startTimeUs =\n this.audioContext!.currentTime * 1_000_000 - this.currentTimeUs / this.playbackRate;\n\n this.playbackLoop();\n\n this.eventBus.emit(MeframeEvent.PlaybackPlay);\n } catch (error) {\n console.error('[PlaybackController] Failed to start playback:', error);\n this.state = wasIdle ? 'idle' : 'paused';\n this.eventBus.emit(MeframeEvent.PlaybackError, error as Error);\n }\n }\n\n pause(): void {\n if (this.state !== 'playing') return;\n\n this.state = 'paused';\n this.wasPlayingBeforeSeek = false; // User explicitly paused\n\n if (this.rafId !== null) {\n cancelAnimationFrame(this.rafId);\n this.rafId = null;\n }\n\n this.audioSession?.stopPlayback();\n\n this.eventBus.emit(MeframeEvent.PlaybackPause);\n }\n\n stop(): void {\n this.pause();\n this.currentTimeUs = 0;\n this.state = 'idle';\n this.wasPlayingBeforeSeek = false; // Reset seek state\n this.frameCount = 0; // Reset frame counter\n this.lastFrameTime = 0; // Reset frame timing\n\n // Clear canvas\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 this.audioSession?.reset();\n this.audioSession?.resetPlaybackStates();\n\n this.eventBus.emit(MeframeEvent.PlaybackStop);\n }\n\n async seek(timeUs: TimeUs): Promise<void> {\n const previousState = this.state;\n\n // Stop playback without changing wasPlayingBeforeSeek\n if (this.rafId !== null) {\n cancelAnimationFrame(this.rafId);\n this.rafId = null;\n }\n this.audioSession?.stopPlayback();\n\n // Reset audio playback states for all clips\n this.audioSession?.resetPlaybackStates();\n\n const clamped = this.clampTime(timeUs);\n this.currentTimeUs = clamped;\n this.currentSeekId++; // Invalidate previous seek operations\n this.isBuffering = false; // Reset buffering flag\n\n // Initialize window at seek position\n this.initWindow(clamped);\n\n this.state = 'seeking';\n\n const seekId = this.currentSeekId;\n\n try {\n // Ensure audio windows ready for seek position (blocking mode)\n if (this.audioSession) {\n await this.audioSession.ensureAudioForTime(clamped, { immediate: false });\n }\n\n await this.renderCurrentFrame(clamped);\n\n // Check if another seek happened during render\n if (seekId !== this.currentSeekId) {\n return;\n }\n\n this.eventBus.emit(MeframeEvent.PlaybackSeek, { timeUs: this.currentTimeUs });\n\n if (this.wasPlayingBeforeSeek) {\n await this.startPlayback();\n } else {\n this.state = previousState === 'idle' ? 'idle' : 'paused';\n }\n } catch (error) {\n // Check if this seek is still current\n if (seekId !== this.currentSeekId) {\n return;\n }\n console.error('[PlaybackController] Seek error:', error);\n this.eventBus.emit(MeframeEvent.PlaybackError, error as Error);\n this.state = previousState === 'idle' ? 'idle' : 'paused';\n }\n }\n\n // Playback properties\n setRate(rate: number): void {\n // Adjust audio start time to maintain current position\n const currentTimeUs = this.currentTimeUs;\n this.playbackRate = rate;\n this.startTimeUs = this.audioContext!.currentTime * 1_000_000 - currentTimeUs / rate;\n\n this.eventBus.emit(MeframeEvent.PlaybackRateChange, { rate });\n\n this.audioSession?.setPlaybackRate(this.playbackRate);\n }\n\n setVolume(volume: number): void {\n this.volume = Math.max(0, Math.min(1, volume));\n this.eventBus.emit(MeframeEvent.PlaybackVolumeChange, { volume: this.volume });\n\n this.audioSession?.setVolume(this.volume);\n }\n\n setMute(muted: boolean): void {\n if (muted) {\n this.audioSession?.stopPlayback();\n } else if (this.state === 'playing' && this.audioContext) {\n 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 const modelDuration = this.orchestrator.compositionModel?.durationUs;\n if (modelDuration !== undefined) {\n return modelDuration;\n }\n\n return 0;\n }\n\n get isPlaying(): boolean {\n return this.state === 'playing';\n }\n\n setAudioSession(session: GlobalAudioSession): void {\n this.audioSession = session;\n }\n\n // Resume is just an alias for play\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 // Private methods\n private playbackLoop(): void {\n // State Check #1: Loop entry (from recursive call)\n // Prevents next frame from starting if state changed during previous frame\n // Captures: pause(), stop(), seek() called during frame processing\n if (this.state !== 'playing') {\n if (this.rafId !== null) {\n cancelAnimationFrame(this.rafId);\n this.rafId = null;\n }\n return;\n }\n\n this.rafId = requestAnimationFrame(async () => {\n // State Check #2: RAF callback start (async boundary)\n // Captures state changes during RAF delay (~16ms)\n // Scenario: User pauses/seeks between requestAnimationFrame call and callback execution\n if (this.state !== 'playing') {\n return;\n }\n\n this.updateTime();\n\n // State Check #3: After updateTime (playback end detection)\n // CRITICAL: Prevents ensureAudioForTime/scheduleAudio from polluting cache\n // When playback ends, currentTimeUs is reset to 0 for clean replay\n // Without this check, audio operations would execute with wrong position\n if (this.state !== 'playing') {\n return;\n }\n\n // Ensure audio windows ready (aligned with video architecture)\n // Use immediate mode during playback (non-blocking)\n if (this.audioSession) {\n await this.audioSession.ensureAudioForTime(this.currentTimeUs, { immediate: true });\n }\n\n // Lookahead audio scheduling (OfflineAudioMixer approach)\n if (this.audioContext && this.audioSession) {\n await this.audioSession.scheduleAudio(this.currentTimeUs, this.audioContext);\n }\n\n await this.renderCurrentFrame(this.currentTimeUs);\n\n // State Check #4: After render (buffering detection)\n // Captures: renderCurrentFrame() triggered buffering (cache miss)\n // Optimization: Early exit to avoid unnecessary FPS calculation and setWindow\n // Not strictly required (next loop's Check #1 would catch it), but improves responsiveness\n if (this.state !== 'playing') {\n return;\n }\n\n // Calculate FPS based on actual frame timing\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 this.frameCount++;\n\n // Update unified window for video and audio\n this.orchestrator.cacheManager.setWindow(this.currentTimeUs);\n\n this.playbackLoop();\n });\n }\n\n private updateTime(): void {\n const elapsedUs =\n (this.audioContext!.currentTime * 1_000_000 - this.startTimeUs) * this.playbackRate;\n this.currentTimeUs = elapsedUs;\n\n // Check if reached end\n if (this.currentTimeUs >= this.duration) {\n if (this.loop) {\n this.currentTimeUs = 0;\n this.startTimeUs = this.audioContext!.currentTime * 1_000_000;\n // Reset audio scheduling states to avoid stale state from previous playback\n this.audioSession?.resetPlaybackStates();\n // Reset window to start position\n this.initWindow(0);\n } else {\n this.pause();\n // Set to 0 instead of duration to prevent audio operations in final frame\n // from polluting cache with wrong position data\n this.currentTimeUs = 0;\n this.state = 'ended';\n this.eventBus.emit(MeframeEvent.PlaybackEnded, { timeUs: this.duration });\n }\n }\n\n // Emit time update\n this.eventBus.emit(MeframeEvent.PlaybackTimeUpdate, { timeUs: this.currentTimeUs });\n\n // Check if approaching window edge - trigger async preheat\n this.checkAndPreheatWindow();\n // Note: setWindow is now called in Orchestrator.renderFrame()\n // this.orchestrator.cacheManager.setWindow(this.currentTimeUs);\n }\n\n /**\n * Initialize window at given time (called on play/seek)\n * Sets unified window for both video and audio\n */\n private initWindow(timeUs: TimeUs): void {\n this.windowEnd = timeUs + this.WINDOW_DURATION;\n this.preheatInProgress = false; // Reset preheat state\n\n // Set unified window center for both video and audio\n this.orchestrator.cacheManager.setWindow(timeUs);\n }\n\n /**\n * Check if approaching window end and trigger preheat for next window\n *\n * Strategy: Unified sliding window for both video and audio\n * - Current window: [windowStart, windowEnd] (3s duration)\n * - When playback reaches windowEnd - 1s, preheat next window\n * - Next window: [windowEnd, windowEnd + 3s]\n */\n private checkAndPreheatWindow(): void {\n // Skip if already preheating or not playing\n if (this.preheatInProgress || this.state !== 'playing') {\n return;\n }\n\n // Check if approaching window end\n const distanceToWindowEnd = this.windowEnd - this.currentTimeUs;\n if (distanceToWindowEnd < 0) {\n this.initWindow(this.currentTimeUs);\n return;\n }\n\n // Trigger preheat when 1s from window end\n if (distanceToWindowEnd > 0 && distanceToWindowEnd <= this.PREHEAT_DISTANCE) {\n this.preheatInProgress = true;\n\n void this.preheatNextWindow().finally(() => {\n this.preheatInProgress = false;\n });\n }\n }\n\n /**\n * Preheat next window by decoding from current playback time\n * Supports cross-clip window preheating for seamless playback\n * Preheats both video and audio in parallel\n */\n private async preheatNextWindow(): Promise<void> {\n try {\n const windowStart = this.currentTimeUs;\n const windowEnd = windowStart + this.WINDOW_DURATION;\n\n // Get all clips in window range (may span multiple clips)\n const clipsInWindow =\n this.orchestrator.compositionModel?.getClipsInRange(windowStart, windowEnd) ?? [];\n\n const preheatPromises: Promise<any>[] = [];\n\n // Preheat video for each clip in window\n for (const clip of clipsInWindow) {\n if (!isVideoClip(clip)) continue;\n\n // Calculate clip-relative window boundaries\n const clipWindowStart = Math.max(0, windowStart - clip.startUs);\n const clipWindowEnd = Math.min(clip.durationUs, windowEnd - clip.startUs);\n\n // Skip if window doesn't overlap with this clip\n if (clipWindowStart >= clipWindowEnd) continue;\n\n preheatPromises.push(\n this.orchestrator.preheatClipWindow(clip.id, clipWindowStart, clipWindowEnd, windowStart)\n );\n }\n\n // Preheat audio (non-blocking mode for background decoding)\n if (this.audioSession) {\n preheatPromises.push(\n this.audioSession.ensureAudioForTime(windowStart, { immediate: false })\n );\n }\n\n await Promise.all(preheatPromises);\n\n // Update window bounds after successful preheat\n this.windowEnd = windowEnd;\n } catch (error) {\n // Preheat failures are not critical\n console.warn('[PlaybackController] Preheat failed:', error);\n }\n }\n\n async renderCurrentFrame(timeUs: TimeUs): Promise<void> {\n if (!this.videoComposer) {\n console.error('[PlaybackController] VideoComposer not initialized');\n return;\n }\n\n try {\n // Get render state (layers) from orchestrator\n // Use immediate mode when playing to detect buffering\n const renderState = await this.orchestrator.getRenderState(timeUs, {\n immediate: this.state === 'playing',\n });\n\n if (!renderState) {\n // If renderState is null during playback, we hit a cache miss/buffer underrun\n if (this.state === 'playing' && !this.isBuffering) {\n await this.handlePlaybackBuffering(timeUs);\n }\n return;\n }\n\n // Compose directly to canvas\n await this.videoComposer.composeFrame({\n timeUs,\n layers: renderState.layers,\n transition: renderState.transition,\n });\n } catch (error) {\n console.error('Render error:', error);\n this.eventBus.emit(MeframeEvent.PlaybackError, error as Error);\n }\n }\n\n private async handlePlaybackBuffering(timeUs: TimeUs): Promise<void> {\n if (this.isBuffering || this.state !== 'playing') {\n return;\n }\n\n const seekId = this.currentSeekId;\n this.isBuffering = true;\n this.state = 'buffering';\n this.eventBus.emit(MeframeEvent.PlaybackBuffering);\n\n // Pause audio immediately to prevent desync\n this.audioSession?.stopPlayback();\n\n try {\n // Update window center for buffering position\n this.orchestrator.cacheManager.setWindow(timeUs);\n\n // Force load frame (blocking)\n // This ensures the resource is downloaded and decoded\n await this.orchestrator.getFrame(timeUs, { immediate: false });\n\n // Also ensure audio is ready (blocking mode for buffering)\n await this.orchestrator.audioSession.ensureAudioForTime(timeUs, { immediate: false });\n\n // Check if seek happened during buffering\n if (seekId !== this.currentSeekId) {\n return;\n }\n\n this.state = 'playing';\n this.startTimeUs = this.audioContext!.currentTime * 1_000_000 - timeUs / this.playbackRate;\n\n // Resume audio synced with timeline\n if (this.audioContext) {\n await this.audioSession?.startPlayback(timeUs, this.audioContext);\n }\n\n this.eventBus.emit(MeframeEvent.PlaybackPlay);\n\n if (!this.rafId) {\n this.playbackLoop();\n }\n } catch (error) {\n // Ignore WaiterReplacedError (happens during fast seeks)\n if (error instanceof WaiterReplacedError) {\n return;\n }\n // Check if seek happened during error handling\n if (seekId !== this.currentSeekId) {\n return;\n }\n console.error('[PlaybackController] Buffering error:', error);\n this.state = 'paused';\n this.eventBus.emit(MeframeEvent.PlaybackError, error as Error);\n } finally {\n this.isBuffering = false;\n }\n }\n\n private clampTime(timeUs: TimeUs): TimeUs {\n return Math.max(0, Math.min(timeUs, this.duration));\n }\n\n // Cleanup\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 // Optimization for Quick Start / Fast First Frame:\n // When the first frame of a resource is decoded (e.g. via side-channel parsing),\n // we immediately render it if we are at the start of the timeline.\n // This significantly improves perceived loading speed for compatible formats (e.g. fragmented MP4 with moov at start).\n // For standard formats or when not at time 0, this might be redundant as normal playback loop handles it.\n if (this.state === 'idle' && this.currentTimeUs === 0) {\n this.renderCurrentFrame(0);\n }\n };\n\n private onModelSet = (): void => {\n if (!this.videoComposer || !this.orchestrator.compositionModel) return;\n\n const model = this.orchestrator.compositionModel;\n // Update VideoComposer configuration with new model dimensions and fps\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 // Preheat audio for first frame (non-blocking)\n if (this.audioSession) {\n void this.audioSession.ensureAudioForTime(0, { immediate: false });\n }\n\n // Re-render current frame to reflect dimension changes immediately\n void this.renderCurrentFrame(this.currentTimeUs);\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 async ensureAudioContext(): Promise<void> {\n if (this.audioContext) {\n return;\n }\n\n this.audioContext = new AudioContext();\n }\n}\n"],"names":[],"mappings":"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"}
@@ -227,7 +227,7 @@ export interface EventPayloadMap {
227
227
  };
228
228
  [MeframeEvent.ExportProgress]: {
229
229
  progress: number;
230
- stage?: 'preparing' | 'muxing';
230
+ stage?: 'preparing' | 'encoding' | 'muxing';
231
231
  message?: string;
232
232
  currentFrame?: number;
233
233
  totalFrames?: number;
@@ -1 +1 @@
1
- {"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../src/event/events.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../src/event/events.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"events.js","sources":["../../src/event/events.ts"],"sourcesContent":["/**\n * Core event definitions for the Meframe engine\n * These are public events exposed to plugins and external components\n */\n\nimport { CompositionModel, Resource, type TimeUs } from '../model';\nimport type { MP4Index } from '../stages/demux/types';\n\nexport interface ResourceEvent {\n type: MeframeEvent;\n resourceId: string;\n resource?: Resource;\n oldState?: Resource['state'];\n newState?: Resource['state'];\n workerType?: string;\n}\n\n/**\n * Core event types\n */\nexport enum MeframeEvent {\n // Composition model events\n ModelSet = 'model:set',\n\n // Resource events\n ResourceAdd = 'resource:add',\n ResourceUpdate = 'resource:update',\n ResourceRemove = 'resource:remove',\n ResourceStageChange = 'resource:state',\n ResourceFirstFrameReady = 'resource:firstFrameReady',\n\n // Load stage events\n LoadStart = 'load:start',\n LoadProgress = 'load:progress',\n LoadComplete = 'load:complete',\n LoadError = 'load:error',\n\n // Demux stage events\n DemuxStart = 'demux:start',\n DemuxProgress = 'demux:progress',\n DemuxComplete = 'demux:complete',\n DemuxError = 'demux:error',\n\n // Decode stage events\n DecodeStart = 'decode:start',\n DecodeProgress = 'decode:progress',\n DecodeComplete = 'decode:complete',\n DecodeError = 'decode:error',\n\n // Compose stage events\n ComposeStart = 'compose:start',\n ComposeProgress = 'compose:progress',\n ComposeComplete = 'compose:complete',\n\n // Composition frame events (L1 cache)\n ComposeFrameReady = 'compose:frameReady',\n ComposeFrameDropped = 'compose:frameDropped',\n\n // Encode events (L2 cache)\n EncodeChunkReady = 'encode:chunkReady',\n EncodeChunkError = 'encode:chunkError',\n\n // Cache events\n CacheHit = 'cache:hit',\n CacheMiss = 'cache:miss',\n CacheEvict = 'cache:evict',\n CacheWrite = 'cache:write',\n CacheCover = 'cache:cover',\n\n // Export events\n ExportPreparing = 'export:preparing',\n ExportStart = 'export:start',\n ExportProgress = 'export:progress',\n ExportComplete = 'export:complete',\n ExportError = 'export:error',\n\n // Composition model events\n CompositionUpdated = 'composition:updated',\n PatchApplied = 'patch:applied',\n Ready = 'ready',\n\n // Worker events\n WorkerStarted = 'worker:started',\n WorkerReady = 'worker:ready',\n WorkerError = 'worker:error',\n WorkerRestarted = 'worker:restarted',\n\n // Playback events\n PlaybackBuffering = 'playback:buffering',\n PlaybackPlay = 'playback:play',\n PlaybackPause = 'playback:pause',\n PlaybackStop = 'playback:stop',\n PlaybackSeek = 'playback:seek',\n PlaybackEnded = 'playback:ended',\n PlaybackTimeUpdate = 'playback:timeupdate',\n PlaybackRateChange = 'playback:ratechange',\n PlaybackVolumeChange = 'playback:volumechange',\n PlaybackError = 'playback:error',\n PlaybackStarted = 'playback:started',\n PlaybackPaused = 'playback:paused',\n PlaybackSeeked = 'playback:seeked',\n\n // General error event\n Error = 'error',\n\n // Plugin events\n PluginLoaded = 'plugin:loaded',\n PluginError = 'plugin:error',\n PluginUnloaded = 'plugin:unloaded',\n\n // Clip lifecycle events\n ClipActivated = 'clip:activated',\n ClipDeactivated = 'clip:deactivated',\n}\n\n/**\n * Event payload definitions\n */\nexport interface EventPayloadMap {\n // Composition model events\n [MeframeEvent.ModelSet]: CompositionModel;\n\n // Resource events\n [MeframeEvent.ResourceAdd]: ResourceEvent;\n [MeframeEvent.ResourceUpdate]: ResourceEvent;\n [MeframeEvent.ResourceRemove]: ResourceEvent;\n [MeframeEvent.ResourceStageChange]: ResourceEvent;\n [MeframeEvent.ResourceFirstFrameReady]: {\n resourceId: string;\n clipId: string;\n index: MP4Index;\n chunks: EncodedVideoChunk[];\n };\n\n // Load events\n [MeframeEvent.LoadStart]: {\n resourceId: string;\n url: string;\n size?: number;\n };\n\n [MeframeEvent.LoadProgress]: {\n resourceId: string;\n loaded: number;\n total: number;\n progress: number;\n };\n\n [MeframeEvent.LoadComplete]: {\n resourceId: string;\n bytes: number;\n durationMs: number;\n };\n\n [MeframeEvent.LoadError]: {\n resourceId: string;\n error: Error;\n retry?: boolean;\n };\n\n // Demux events\n [MeframeEvent.DemuxStart]: {\n clipId: string;\n trackId?: string;\n format?: string;\n };\n\n [MeframeEvent.DemuxProgress]: {\n clipId: string;\n progress: number;\n };\n\n [MeframeEvent.DemuxComplete]: {\n clipId: string;\n trackCount: number;\n durationUs: TimeUs;\n };\n\n [MeframeEvent.DemuxError]: {\n clipId: string;\n error: Error;\n };\n\n // Decode events\n [MeframeEvent.DecodeStart]: {\n clipId: string;\n frameCount?: number;\n trackType: 'video' | 'audio';\n };\n\n [MeframeEvent.DecodeProgress]: {\n clipId: string;\n decodedFrames: number;\n totalFrames: number;\n progress: number;\n };\n\n [MeframeEvent.DecodeComplete]: {\n clipId: string;\n frameCount: number;\n durationUs: TimeUs;\n };\n\n [MeframeEvent.DecodeError]: {\n clipId: string;\n error: Error;\n frame?: number;\n };\n\n // Compose events\n [MeframeEvent.ComposeStart]: {\n timeUs: TimeUs;\n clipIds: string[];\n };\n\n [MeframeEvent.ComposeProgress]: {\n timeUs: TimeUs;\n progress: number;\n };\n\n [MeframeEvent.ComposeComplete]: {\n timeUs: TimeUs;\n frameNumber: number;\n };\n\n // Composition frame events\n [MeframeEvent.ComposeFrameReady]: {\n timeUs: TimeUs;\n frameNumber: number;\n renderTimeMs: number;\n trackId: string;\n clipId: string;\n };\n\n [MeframeEvent.ComposeFrameDropped]: {\n timeUs: TimeUs;\n reason: 'decode_slow' | 'compose_slow' | 'backpressure';\n };\n\n // Encode events\n [MeframeEvent.EncodeChunkReady]: {\n timeUs: TimeUs;\n durationUs: TimeUs;\n track: 'video' | 'audio';\n size: number;\n };\n\n [MeframeEvent.EncodeChunkError]: {\n timeUs: TimeUs;\n track: 'video' | 'audio';\n error: Error;\n };\n\n // Cache events\n [MeframeEvent.CacheHit]: {\n timeUs: TimeUs;\n level: 'L1' | 'L2';\n key?: string;\n };\n\n [MeframeEvent.CacheMiss]: {\n timeUs: TimeUs;\n level: 'L1' | 'L2';\n key?: string;\n };\n\n [MeframeEvent.CacheEvict]: {\n clipId: string;\n count: number;\n level: 'L1' | 'L2';\n reason: 'size' | 'ttl' | 'manual';\n };\n\n [MeframeEvent.CacheWrite]: {\n clipId: string;\n timeUs: TimeUs;\n level: 'L1' | 'L2';\n size: number;\n };\n [MeframeEvent.CacheCover]: {\n clipId: string;\n timeUs: TimeUs;\n level: 'L1' | 'L2';\n size: number;\n };\n\n // Export events\n [MeframeEvent.ExportPreparing]: {\n totalClips: number;\n cachedClips: number;\n missingClips: string[];\n estimatedTimeMs?: number;\n };\n\n [MeframeEvent.ExportStart]: {\n format: string;\n width: number;\n height: number;\n fps: number;\n durationUs: TimeUs;\n };\n\n [MeframeEvent.ExportProgress]: {\n progress: number;\n stage?: 'preparing' | 'muxing';\n message?: string;\n currentFrame?: number;\n totalFrames?: number;\n timeUs?: TimeUs;\n };\n\n [MeframeEvent.ExportComplete]: {\n size: number;\n durationMs: number;\n format: string;\n };\n\n [MeframeEvent.ExportError]: {\n error: Error;\n stage?: string;\n };\n\n // Composition events\n [MeframeEvent.CompositionUpdated]: {\n trackCount: number;\n clipCount: number;\n durationUs: TimeUs;\n };\n\n [MeframeEvent.PatchApplied]: {\n operations: number;\n affectedClips: string[];\n };\n\n [MeframeEvent.Ready]: {\n trackCount: number;\n clipCount: number;\n durationUs: TimeUs;\n };\n\n // Worker events\n [MeframeEvent.WorkerStarted]: {\n type: string;\n workerId: string;\n };\n\n [MeframeEvent.WorkerReady]: {\n type: string;\n workerId: string;\n };\n\n [MeframeEvent.WorkerError]: {\n type: string;\n workerId: string;\n error: Error;\n };\n\n [MeframeEvent.WorkerRestarted]: {\n type: string;\n workerId: string;\n reason: string;\n };\n\n // Playback events\n [MeframeEvent.PlaybackBuffering]: undefined;\n\n [MeframeEvent.PlaybackPlay]: undefined;\n\n [MeframeEvent.PlaybackPause]: undefined;\n\n [MeframeEvent.PlaybackStop]: undefined;\n\n [MeframeEvent.PlaybackSeek]: {\n timeUs: TimeUs;\n };\n\n [MeframeEvent.PlaybackStarted]: {\n timeUs: TimeUs;\n };\n\n [MeframeEvent.PlaybackPaused]: {\n timeUs: TimeUs;\n };\n\n [MeframeEvent.PlaybackSeeked]: {\n fromUs: TimeUs;\n toUs: TimeUs;\n };\n\n [MeframeEvent.PlaybackEnded]: {\n timeUs: TimeUs;\n };\n\n [MeframeEvent.PlaybackTimeUpdate]: {\n timeUs: TimeUs;\n };\n\n [MeframeEvent.PlaybackRateChange]: {\n rate: number;\n };\n\n [MeframeEvent.PlaybackVolumeChange]: {\n volume: number;\n };\n\n [MeframeEvent.PlaybackError]: Error;\n\n // Error event\n [MeframeEvent.Error]: {\n source: string;\n error: Error;\n context?: any;\n recoverable?: boolean;\n };\n\n // Plugin events\n [MeframeEvent.PluginLoaded]: {\n name: string;\n version?: string;\n };\n\n [MeframeEvent.PluginError]: {\n plugin: string;\n error: Error;\n };\n\n [MeframeEvent.PluginUnloaded]: {\n name: string;\n };\n\n // Clip events\n [MeframeEvent.ClipActivated]: {\n clipId: string;\n };\n\n [MeframeEvent.ClipDeactivated]: {\n clipId: string;\n };\n}\n"],"names":["MeframeEvent"],"mappings":"AAoBO,IAAK,iCAAAA,kBAAL;AAELA,gBAAA,UAAA,IAAW;AAGXA,gBAAA,aAAA,IAAc;AACdA,gBAAA,gBAAA,IAAiB;AACjBA,gBAAA,gBAAA,IAAiB;AACjBA,gBAAA,qBAAA,IAAsB;AACtBA,gBAAA,yBAAA,IAA0B;AAG1BA,gBAAA,WAAA,IAAY;AACZA,gBAAA,cAAA,IAAe;AACfA,gBAAA,cAAA,IAAe;AACfA,gBAAA,WAAA,IAAY;AAGZA,gBAAA,YAAA,IAAa;AACbA,gBAAA,eAAA,IAAgB;AAChBA,gBAAA,eAAA,IAAgB;AAChBA,gBAAA,YAAA,IAAa;AAGbA,gBAAA,aAAA,IAAc;AACdA,gBAAA,gBAAA,IAAiB;AACjBA,gBAAA,gBAAA,IAAiB;AACjBA,gBAAA,aAAA,IAAc;AAGdA,gBAAA,cAAA,IAAe;AACfA,gBAAA,iBAAA,IAAkB;AAClBA,gBAAA,iBAAA,IAAkB;AAGlBA,gBAAA,mBAAA,IAAoB;AACpBA,gBAAA,qBAAA,IAAsB;AAGtBA,gBAAA,kBAAA,IAAmB;AACnBA,gBAAA,kBAAA,IAAmB;AAGnBA,gBAAA,UAAA,IAAW;AACXA,gBAAA,WAAA,IAAY;AACZA,gBAAA,YAAA,IAAa;AACbA,gBAAA,YAAA,IAAa;AACbA,gBAAA,YAAA,IAAa;AAGbA,gBAAA,iBAAA,IAAkB;AAClBA,gBAAA,aAAA,IAAc;AACdA,gBAAA,gBAAA,IAAiB;AACjBA,gBAAA,gBAAA,IAAiB;AACjBA,gBAAA,aAAA,IAAc;AAGdA,gBAAA,oBAAA,IAAqB;AACrBA,gBAAA,cAAA,IAAe;AACfA,gBAAA,OAAA,IAAQ;AAGRA,gBAAA,eAAA,IAAgB;AAChBA,gBAAA,aAAA,IAAc;AACdA,gBAAA,aAAA,IAAc;AACdA,gBAAA,iBAAA,IAAkB;AAGlBA,gBAAA,mBAAA,IAAoB;AACpBA,gBAAA,cAAA,IAAe;AACfA,gBAAA,eAAA,IAAgB;AAChBA,gBAAA,cAAA,IAAe;AACfA,gBAAA,cAAA,IAAe;AACfA,gBAAA,eAAA,IAAgB;AAChBA,gBAAA,oBAAA,IAAqB;AACrBA,gBAAA,oBAAA,IAAqB;AACrBA,gBAAA,sBAAA,IAAuB;AACvBA,gBAAA,eAAA,IAAgB;AAChBA,gBAAA,iBAAA,IAAkB;AAClBA,gBAAA,gBAAA,IAAiB;AACjBA,gBAAA,gBAAA,IAAiB;AAGjBA,gBAAA,OAAA,IAAQ;AAGRA,gBAAA,cAAA,IAAe;AACfA,gBAAA,aAAA,IAAc;AACdA,gBAAA,gBAAA,IAAiB;AAGjBA,gBAAA,eAAA,IAAgB;AAChBA,gBAAA,iBAAA,IAAkB;AA5FR,SAAAA;AAAA,GAAA,gBAAA,CAAA,CAAA;"}
1
+ {"version":3,"file":"events.js","sources":["../../src/event/events.ts"],"sourcesContent":["/**\n * Core event definitions for the Meframe engine\n * These are public events exposed to plugins and external components\n */\n\nimport { CompositionModel, Resource, type TimeUs } from '../model';\nimport type { MP4Index } from '../stages/demux/types';\n\nexport interface ResourceEvent {\n type: MeframeEvent;\n resourceId: string;\n resource?: Resource;\n oldState?: Resource['state'];\n newState?: Resource['state'];\n workerType?: string;\n}\n\n/**\n * Core event types\n */\nexport enum MeframeEvent {\n // Composition model events\n ModelSet = 'model:set',\n\n // Resource events\n ResourceAdd = 'resource:add',\n ResourceUpdate = 'resource:update',\n ResourceRemove = 'resource:remove',\n ResourceStageChange = 'resource:state',\n ResourceFirstFrameReady = 'resource:firstFrameReady',\n\n // Load stage events\n LoadStart = 'load:start',\n LoadProgress = 'load:progress',\n LoadComplete = 'load:complete',\n LoadError = 'load:error',\n\n // Demux stage events\n DemuxStart = 'demux:start',\n DemuxProgress = 'demux:progress',\n DemuxComplete = 'demux:complete',\n DemuxError = 'demux:error',\n\n // Decode stage events\n DecodeStart = 'decode:start',\n DecodeProgress = 'decode:progress',\n DecodeComplete = 'decode:complete',\n DecodeError = 'decode:error',\n\n // Compose stage events\n ComposeStart = 'compose:start',\n ComposeProgress = 'compose:progress',\n ComposeComplete = 'compose:complete',\n\n // Composition frame events (L1 cache)\n ComposeFrameReady = 'compose:frameReady',\n ComposeFrameDropped = 'compose:frameDropped',\n\n // Encode events (L2 cache)\n EncodeChunkReady = 'encode:chunkReady',\n EncodeChunkError = 'encode:chunkError',\n\n // Cache events\n CacheHit = 'cache:hit',\n CacheMiss = 'cache:miss',\n CacheEvict = 'cache:evict',\n CacheWrite = 'cache:write',\n CacheCover = 'cache:cover',\n\n // Export events\n ExportPreparing = 'export:preparing',\n ExportStart = 'export:start',\n ExportProgress = 'export:progress',\n ExportComplete = 'export:complete',\n ExportError = 'export:error',\n\n // Composition model events\n CompositionUpdated = 'composition:updated',\n PatchApplied = 'patch:applied',\n Ready = 'ready',\n\n // Worker events\n WorkerStarted = 'worker:started',\n WorkerReady = 'worker:ready',\n WorkerError = 'worker:error',\n WorkerRestarted = 'worker:restarted',\n\n // Playback events\n PlaybackBuffering = 'playback:buffering',\n PlaybackPlay = 'playback:play',\n PlaybackPause = 'playback:pause',\n PlaybackStop = 'playback:stop',\n PlaybackSeek = 'playback:seek',\n PlaybackEnded = 'playback:ended',\n PlaybackTimeUpdate = 'playback:timeupdate',\n PlaybackRateChange = 'playback:ratechange',\n PlaybackVolumeChange = 'playback:volumechange',\n PlaybackError = 'playback:error',\n PlaybackStarted = 'playback:started',\n PlaybackPaused = 'playback:paused',\n PlaybackSeeked = 'playback:seeked',\n\n // General error event\n Error = 'error',\n\n // Plugin events\n PluginLoaded = 'plugin:loaded',\n PluginError = 'plugin:error',\n PluginUnloaded = 'plugin:unloaded',\n\n // Clip lifecycle events\n ClipActivated = 'clip:activated',\n ClipDeactivated = 'clip:deactivated',\n}\n\n/**\n * Event payload definitions\n */\nexport interface EventPayloadMap {\n // Composition model events\n [MeframeEvent.ModelSet]: CompositionModel;\n\n // Resource events\n [MeframeEvent.ResourceAdd]: ResourceEvent;\n [MeframeEvent.ResourceUpdate]: ResourceEvent;\n [MeframeEvent.ResourceRemove]: ResourceEvent;\n [MeframeEvent.ResourceStageChange]: ResourceEvent;\n [MeframeEvent.ResourceFirstFrameReady]: {\n resourceId: string;\n clipId: string;\n index: MP4Index;\n chunks: EncodedVideoChunk[];\n };\n\n // Load events\n [MeframeEvent.LoadStart]: {\n resourceId: string;\n url: string;\n size?: number;\n };\n\n [MeframeEvent.LoadProgress]: {\n resourceId: string;\n loaded: number;\n total: number;\n progress: number;\n };\n\n [MeframeEvent.LoadComplete]: {\n resourceId: string;\n bytes: number;\n durationMs: number;\n };\n\n [MeframeEvent.LoadError]: {\n resourceId: string;\n error: Error;\n retry?: boolean;\n };\n\n // Demux events\n [MeframeEvent.DemuxStart]: {\n clipId: string;\n trackId?: string;\n format?: string;\n };\n\n [MeframeEvent.DemuxProgress]: {\n clipId: string;\n progress: number;\n };\n\n [MeframeEvent.DemuxComplete]: {\n clipId: string;\n trackCount: number;\n durationUs: TimeUs;\n };\n\n [MeframeEvent.DemuxError]: {\n clipId: string;\n error: Error;\n };\n\n // Decode events\n [MeframeEvent.DecodeStart]: {\n clipId: string;\n frameCount?: number;\n trackType: 'video' | 'audio';\n };\n\n [MeframeEvent.DecodeProgress]: {\n clipId: string;\n decodedFrames: number;\n totalFrames: number;\n progress: number;\n };\n\n [MeframeEvent.DecodeComplete]: {\n clipId: string;\n frameCount: number;\n durationUs: TimeUs;\n };\n\n [MeframeEvent.DecodeError]: {\n clipId: string;\n error: Error;\n frame?: number;\n };\n\n // Compose events\n [MeframeEvent.ComposeStart]: {\n timeUs: TimeUs;\n clipIds: string[];\n };\n\n [MeframeEvent.ComposeProgress]: {\n timeUs: TimeUs;\n progress: number;\n };\n\n [MeframeEvent.ComposeComplete]: {\n timeUs: TimeUs;\n frameNumber: number;\n };\n\n // Composition frame events\n [MeframeEvent.ComposeFrameReady]: {\n timeUs: TimeUs;\n frameNumber: number;\n renderTimeMs: number;\n trackId: string;\n clipId: string;\n };\n\n [MeframeEvent.ComposeFrameDropped]: {\n timeUs: TimeUs;\n reason: 'decode_slow' | 'compose_slow' | 'backpressure';\n };\n\n // Encode events\n [MeframeEvent.EncodeChunkReady]: {\n timeUs: TimeUs;\n durationUs: TimeUs;\n track: 'video' | 'audio';\n size: number;\n };\n\n [MeframeEvent.EncodeChunkError]: {\n timeUs: TimeUs;\n track: 'video' | 'audio';\n error: Error;\n };\n\n // Cache events\n [MeframeEvent.CacheHit]: {\n timeUs: TimeUs;\n level: 'L1' | 'L2';\n key?: string;\n };\n\n [MeframeEvent.CacheMiss]: {\n timeUs: TimeUs;\n level: 'L1' | 'L2';\n key?: string;\n };\n\n [MeframeEvent.CacheEvict]: {\n clipId: string;\n count: number;\n level: 'L1' | 'L2';\n reason: 'size' | 'ttl' | 'manual';\n };\n\n [MeframeEvent.CacheWrite]: {\n clipId: string;\n timeUs: TimeUs;\n level: 'L1' | 'L2';\n size: number;\n };\n [MeframeEvent.CacheCover]: {\n clipId: string;\n timeUs: TimeUs;\n level: 'L1' | 'L2';\n size: number;\n };\n\n // Export events\n [MeframeEvent.ExportPreparing]: {\n totalClips: number;\n cachedClips: number;\n missingClips: string[];\n estimatedTimeMs?: number;\n };\n\n [MeframeEvent.ExportStart]: {\n format: string;\n width: number;\n height: number;\n fps: number;\n durationUs: TimeUs;\n };\n\n [MeframeEvent.ExportProgress]: {\n progress: number;\n stage?: 'preparing' | 'encoding' | 'muxing';\n message?: string;\n currentFrame?: number;\n totalFrames?: number;\n timeUs?: TimeUs;\n };\n\n [MeframeEvent.ExportComplete]: {\n size: number;\n durationMs: number;\n format: string;\n };\n\n [MeframeEvent.ExportError]: {\n error: Error;\n stage?: string;\n };\n\n // Composition events\n [MeframeEvent.CompositionUpdated]: {\n trackCount: number;\n clipCount: number;\n durationUs: TimeUs;\n };\n\n [MeframeEvent.PatchApplied]: {\n operations: number;\n affectedClips: string[];\n };\n\n [MeframeEvent.Ready]: {\n trackCount: number;\n clipCount: number;\n durationUs: TimeUs;\n };\n\n // Worker events\n [MeframeEvent.WorkerStarted]: {\n type: string;\n workerId: string;\n };\n\n [MeframeEvent.WorkerReady]: {\n type: string;\n workerId: string;\n };\n\n [MeframeEvent.WorkerError]: {\n type: string;\n workerId: string;\n error: Error;\n };\n\n [MeframeEvent.WorkerRestarted]: {\n type: string;\n workerId: string;\n reason: string;\n };\n\n // Playback events\n [MeframeEvent.PlaybackBuffering]: undefined;\n\n [MeframeEvent.PlaybackPlay]: undefined;\n\n [MeframeEvent.PlaybackPause]: undefined;\n\n [MeframeEvent.PlaybackStop]: undefined;\n\n [MeframeEvent.PlaybackSeek]: {\n timeUs: TimeUs;\n };\n\n [MeframeEvent.PlaybackStarted]: {\n timeUs: TimeUs;\n };\n\n [MeframeEvent.PlaybackPaused]: {\n timeUs: TimeUs;\n };\n\n [MeframeEvent.PlaybackSeeked]: {\n fromUs: TimeUs;\n toUs: TimeUs;\n };\n\n [MeframeEvent.PlaybackEnded]: {\n timeUs: TimeUs;\n };\n\n [MeframeEvent.PlaybackTimeUpdate]: {\n timeUs: TimeUs;\n };\n\n [MeframeEvent.PlaybackRateChange]: {\n rate: number;\n };\n\n [MeframeEvent.PlaybackVolumeChange]: {\n volume: number;\n };\n\n [MeframeEvent.PlaybackError]: Error;\n\n // Error event\n [MeframeEvent.Error]: {\n source: string;\n error: Error;\n context?: any;\n recoverable?: boolean;\n };\n\n // Plugin events\n [MeframeEvent.PluginLoaded]: {\n name: string;\n version?: string;\n };\n\n [MeframeEvent.PluginError]: {\n plugin: string;\n error: Error;\n };\n\n [MeframeEvent.PluginUnloaded]: {\n name: string;\n };\n\n // Clip events\n [MeframeEvent.ClipActivated]: {\n clipId: string;\n };\n\n [MeframeEvent.ClipDeactivated]: {\n clipId: string;\n };\n}\n"],"names":["MeframeEvent"],"mappings":"AAoBO,IAAK,iCAAAA,kBAAL;AAELA,gBAAA,UAAA,IAAW;AAGXA,gBAAA,aAAA,IAAc;AACdA,gBAAA,gBAAA,IAAiB;AACjBA,gBAAA,gBAAA,IAAiB;AACjBA,gBAAA,qBAAA,IAAsB;AACtBA,gBAAA,yBAAA,IAA0B;AAG1BA,gBAAA,WAAA,IAAY;AACZA,gBAAA,cAAA,IAAe;AACfA,gBAAA,cAAA,IAAe;AACfA,gBAAA,WAAA,IAAY;AAGZA,gBAAA,YAAA,IAAa;AACbA,gBAAA,eAAA,IAAgB;AAChBA,gBAAA,eAAA,IAAgB;AAChBA,gBAAA,YAAA,IAAa;AAGbA,gBAAA,aAAA,IAAc;AACdA,gBAAA,gBAAA,IAAiB;AACjBA,gBAAA,gBAAA,IAAiB;AACjBA,gBAAA,aAAA,IAAc;AAGdA,gBAAA,cAAA,IAAe;AACfA,gBAAA,iBAAA,IAAkB;AAClBA,gBAAA,iBAAA,IAAkB;AAGlBA,gBAAA,mBAAA,IAAoB;AACpBA,gBAAA,qBAAA,IAAsB;AAGtBA,gBAAA,kBAAA,IAAmB;AACnBA,gBAAA,kBAAA,IAAmB;AAGnBA,gBAAA,UAAA,IAAW;AACXA,gBAAA,WAAA,IAAY;AACZA,gBAAA,YAAA,IAAa;AACbA,gBAAA,YAAA,IAAa;AACbA,gBAAA,YAAA,IAAa;AAGbA,gBAAA,iBAAA,IAAkB;AAClBA,gBAAA,aAAA,IAAc;AACdA,gBAAA,gBAAA,IAAiB;AACjBA,gBAAA,gBAAA,IAAiB;AACjBA,gBAAA,aAAA,IAAc;AAGdA,gBAAA,oBAAA,IAAqB;AACrBA,gBAAA,cAAA,IAAe;AACfA,gBAAA,OAAA,IAAQ;AAGRA,gBAAA,eAAA,IAAgB;AAChBA,gBAAA,aAAA,IAAc;AACdA,gBAAA,aAAA,IAAc;AACdA,gBAAA,iBAAA,IAAkB;AAGlBA,gBAAA,mBAAA,IAAoB;AACpBA,gBAAA,cAAA,IAAe;AACfA,gBAAA,eAAA,IAAgB;AAChBA,gBAAA,cAAA,IAAe;AACfA,gBAAA,cAAA,IAAe;AACfA,gBAAA,eAAA,IAAgB;AAChBA,gBAAA,oBAAA,IAAqB;AACrBA,gBAAA,oBAAA,IAAqB;AACrBA,gBAAA,sBAAA,IAAuB;AACvBA,gBAAA,eAAA,IAAgB;AAChBA,gBAAA,iBAAA,IAAkB;AAClBA,gBAAA,gBAAA,IAAiB;AACjBA,gBAAA,gBAAA,IAAiB;AAGjBA,gBAAA,OAAA,IAAQ;AAGRA,gBAAA,cAAA,IAAe;AACfA,gBAAA,aAAA,IAAc;AACdA,gBAAA,gBAAA,IAAiB;AAGjBA,gBAAA,eAAA,IAAgB;AAChBA,gBAAA,iBAAA,IAAkB;AA5FR,SAAAA;AAAA,GAAA,gBAAA,CAAA,CAAA;"}
@@ -22,6 +22,14 @@ export declare class CompositionModel {
22
22
  findClip(id: string): Clip | null;
23
23
  getClipsAtTime(timeUs: TimeUs, trackId?: string): Clip[];
24
24
  getActiveClips(startUs: TimeUs, endUs: TimeUs): Clip[];
25
+ /**
26
+ * Get all clips in a specific track that overlap with the given time range
27
+ * Uses binary search for O(log n + k) performance
28
+ * @param startUs - Range start time (inclusive)
29
+ * @param endUs - Range end time (exclusive)
30
+ * @param trackId - Optional track ID to filter (defaults to main track)
31
+ */
32
+ getClipsInRange(startUs: TimeUs, endUs: TimeUs, trackId?: string): Clip[];
25
33
  getClipIdsByResourceId(resourceId: string): string[];
26
34
  getClipIdAtTime(trackId: string, timeUs: TimeUs): string | undefined;
27
35
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"CompositionModel.d.ts","sourceRoot":"","sources":["../../src/model/CompositionModel.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"CompositionModel.d.ts","sourceRoot":"","sources":["../../src/model/CompositionModel.ts"],"names":[],"mappings":"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"}
@@ -79,6 +79,24 @@ ${errors.map((e) => `${e.path}: ${e.message}`).join("\n")}`
79
79
  }
80
80
  return clips;
81
81
  }
82
+ /**
83
+ * Get all clips in a specific track that overlap with the given time range
84
+ * Uses binary search for O(log n + k) performance
85
+ * @param startUs - Range start time (inclusive)
86
+ * @param endUs - Range end time (exclusive)
87
+ * @param trackId - Optional track ID to filter (defaults to main track)
88
+ */
89
+ getClipsInRange(startUs, endUs, trackId) {
90
+ const targetTrackId = trackId ?? this.mainTrackId;
91
+ const track = this.findTrack(targetTrackId);
92
+ if (!track) {
93
+ return [];
94
+ }
95
+ return binarySearchOverlapping(track.clips, startUs, endUs, (clip) => ({
96
+ start: clip.startUs,
97
+ end: clip.startUs + clip.durationUs
98
+ }));
99
+ }
82
100
  getClipIdsByResourceId(resourceId) {
83
101
  const resource = this.resources.get(resourceId);
84
102
  return resource?.clipIds || [];