import { UseTimelineMediaPlaybackOptions } from "./externalMediaPlaybackTransport.mjs"; import "../useTimelineMediaPlayback.mjs"; import { TimelineMediaPlayResult } from "./mediaPlayResult.mjs"; import { ActiveLayerResult, ActiveLayerSelector, PlaybackOptions, TimelineCommandResult, TimelineMediaError, TimelineMediaSyncAdapter } from "@techsquidtv/canvas-timeline-core"; //#region src/hooks/playback/internal/useTimelineMediaSyncInternal.d.ts /** * Options for high-level timeline media synchronization. * * @remarks * * The `layers` record names the media outputs your adapter can synchronize. * Those names flow through `LayerName`, allowing `activeLayers.primary.visuals` * or `activeLayers.layers.audio` to stay typed from the same object. * Each value is an {@link ActiveLayerSelector} passed through active layer * lookup before adapter callbacks receive an {@link ActiveLayerResult}. * * @template LayerName - Named media layer keys inferred from `layers`. */ interface UseTimelineMediaSyncOptions { /** Whether the external adapter can accept a playback request for configured media. */ ready?: boolean; /** Optional sequence frame rate used to lock media playback to project frames. */ frameRate?: UseTimelineMediaPlaybackOptions['frameRate']; /** Core playback range and looping policy captured when each playback run begins. */ playbackOptions?: Omit; /** Named active layer selectors used by the external media surface. */ layers: Record; /** External media adapter callbacks. */ adapter: TimelineMediaSyncAdapter; /** * Stable identity for the adapter resource lifetime. * * @remarks * * Pass the underlying controller or element-backed adapter when replacing it * must cancel pending playback and release its clock. Omit this for an inline * callback facade whose object identity may change on every render. */ adapterIdentity?: object; /** Receives structured media failures with a stable machine-readable reason. */ onError?: (error: TimelineMediaError) => void; } /** * Result returned by `useTimelineMediaSync`. * * @remarks * * Use the commands in this result for media-aware transport controls. The * `activeLayers` snapshot is useful for custom status panels, preview badges, * and adapter diagnostics. * * @template LayerName - Named media layer keys from * {@link UseTimelineMediaSyncOptions.layers}. */ interface UseTimelineMediaSyncResult { /** Active layers at the current playhead time. */ activeLayers: ActiveLayerResult; /** Whether synchronized timeline and external media playback is currently running. */ playing: boolean; /** Current synchronized playback speed multiplier. */ playbackRate: number; /** Starts external media playback and then advances the timeline from that clock. */ play: () => Promise; /** Stops synchronized timeline/media playback and pauses external media state. */ pause: () => TimelineCommandResult; /** Updates both clock rates and resolves after active layers resynchronize. */ setPlaybackRate: (playbackRate: number) => Promise; } /** * High-level synchronization for external media surfaces. * * @remarks * * The hook remains media-library agnostic: apps provide an adapter for decoding, * rendering, and audio scheduling, while the hook handles active layer lookup, * first-content seeking, external-clock playback, rate changes, and pause state. * It builds on {@link useTimelineMediaPlayback} for external-clock playback. * High-level `playbackOptions.loop` is translated into an adapter seek and clock * restart at the range start. Errors are delivered as {@link TimelineMediaError} * values and play commands also return a discriminated result. * Paused previews, startup, loop realignment, layer synchronization, and rate * changes share one ordered adapter-operation queue so older asynchronous media * work cannot overwrite a newer timeline position. * Replacing the adapter cancels an in-flight start, stops a clock owned by the * previous adapter, pauses timeline transport, and primes the replacement for * the current paused preview position. * For packaged adapters, prefer the higher-level HTML and Mediabunny hooks first; * use this hook when you are building a custom clock or preview surface. * * @param options - External media adapter, readiness state, active layers, and callbacks. * @template LayerName - Named media layer keys inferred from `options.layers`, * such as `"visuals" | "audio"`. * @returns Media transport state, active layer data, and synchronized playback commands. * * @example * ```tsx * import { useMemo, useRef } from 'react'; * import { useTimelineMediaSync } from '@techsquidtv/canvas-timeline-react'; * * const previewLayerSelectors = { * visuals: { trackKind: 'visual', sourceId: 'source-1' }, * audio: { trackKind: 'audio', sourceId: 'source-1' }, * } as const; * * export function CustomMediaPreview() { * const mediaTimeRef = useRef(0); * const layers = useMemo(() => previewLayerSelectors, []); * const mediaSync = useTimelineMediaSync({ * ready: true, * layers, * adapter: { * getClockTime: () => mediaTimeRef.current, * startClock: (timelineTime, playbackRate) => { * mediaTimeRef.current = timelineTime.v / timelineTime.r; * console.info(`Start media at ${playbackRate}x`); * return true; * }, * stopClock: () => { * console.info('Pause external media'); * }, * syncLayers: ({ activeLayers }) => { * const visualClip = activeLayers.primary.visuals?.clip; * console.info(visualClip ? `Render ${visualClip.id}` : 'No visual clip'); * }, * }, * }); * * return ( * * ); * } * ``` * * @see {@link ActiveLayerSelector} * @see {@link ActiveLayerResult} * @see {@link useTimelineMediaPlayback} * @see {@link https://canvastimeline.com/demos/media-preview-sync | Mediabunny media sync demo} * @see {@link https://canvastimeline.com/demos/html-media-sync | HTML media sync demo} */ declare function useTimelineMediaSync(options: UseTimelineMediaSyncOptions): UseTimelineMediaSyncResult; //#endregion export { type TimelineMediaPlayResult, UseTimelineMediaSyncOptions, UseTimelineMediaSyncResult, useTimelineMediaSync }; //# sourceMappingURL=useTimelineMediaSyncInternal.d.mts.map