Files
skills/docs/ui/react/react-audio/src/provider/audio-provider.md
2026-05-29 08:20:56 +01:00

3.1 KiB

provider/audio-provider

Purpose

<AudioProvider> is the single React component that owns the audio engine bundle for a React subtree. It constructs exactly one BrowserTimelineAdapter, one TimelineEngine, one Transport, one ProviderBusRegistry, and one PluginRegistry, publishes the resolved bundle through AudioReactContext, and tears every one of them down on unmount.

The provider is React 19 Strict Mode safe: under the development double-invoke pattern (mount → unmount → re-mount) it never leaks an engine. The async init pipeline is gated by a cancellation flag and an AbortController; if the effect tears down before init resolves the flag suppresses the publish step and any partially-constructed adapter is force-disposed immediately.

Features

  • Strict-mode-safe async init with AbortSignal cancellation.
  • Synchronous unmount path that disposes adapter, then transport, then buses — each at most once.
  • Zod-validated options (AudioProviderOptions) — invalid input throws ReactAudioError(REACT_AUDIO.INVALID_OPTIONS) at construct time.
  • Auto-registers consumer-supplied plugin factories into the package registry.
  • Publishes engineState ('pending' | 'ready' | 'error') for the useEngineState hook and any consumer that wants to render a loading state.

Usage: Basic

import { AudioProvider } from "@suaveplan/react-audio";

function App() {
    return (
        <AudioProvider>
            <Workspace />
        </AudioProvider>
    );
}

Usage: Advanced

import { AudioProvider } from "@suaveplan/react-audio";

function App() {
    return (
        <AudioProvider
            options={{
                adapter: { sampleRate: 48000, latencyHint: "interactive" },
                transport: { bpm: 128 },
                plugins: [
                    { pluginType: "delay", factory: () => makeDelay() },
                ],
                sampleRateHz: 30,
            }}
        >
            <Workspace />
        </AudioProvider>
    );
}

API Reference

  • <AudioProvider options? children?> — renders a context provider.
  • AudioProviderProps — { options?: AudioProviderOptions, children?: ReactNode }.

Implementation Notes

The async init pipeline lives entirely inside useEffect's async IIFE so React's render path stays synchronous. A PendingInit value carries the in-flight adapter, transport, and bus-registry references so the cleanup callback can dispose anything already constructed if the effect is torn down mid-init — this is the linchpin of the Strict Mode guarantee. The AbortController is also passed to adapter.init({ signal }) so the engine package's own cancellable work paths short-circuit. State updates (setState, setEngineState, setVersion) are skipped when cancelled is true so a torn-down effect cannot mutate React state. The teardown path is unconditional and synchronous: every dispose is wrapped in nothing but a null check, no try/catch — disposing a class that hasn't fully initialised is the responsibility of the owning package's dispose() to handle.