first commit
This commit is contained in:
89
docs/ui/react/react-audio/src/provider/audio-provider.md
Normal file
89
docs/ui/react/react-audio/src/provider/audio-provider.md
Normal file
@@ -0,0 +1,89 @@
|
||||
# `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
|
||||
|
||||
```tsx
|
||||
import { AudioProvider } from "@suaveplan/react-audio";
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<AudioProvider>
|
||||
<Workspace />
|
||||
</AudioProvider>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
```tsx
|
||||
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.
|
||||
Reference in New Issue
Block a user