Initial Commit
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
# `provider/provider-bus-registry`
|
||||
|
||||
## Purpose
|
||||
|
||||
`ProviderBusRegistry` is a thin wrapper around
|
||||
`DefaultBusRegistry` from `@suaveplan/audio-fx-plugin-base` that adds a
|
||||
synchronous `close()` method. The wrapper is owned by
|
||||
`<AudioProvider>` and torn down on unmount; closing it force-closes
|
||||
every still-active `SidechainPublisher` issued through this registry
|
||||
so no buses leak across remounts (especially relevant under React 19
|
||||
Strict Mode, which double-invokes effects).
|
||||
|
||||
## Features
|
||||
|
||||
- Implements `BusRegistry` so it is a drop-in for the inner default.
|
||||
- Tracks every `SidechainPublisher` returned by `publish()` and
|
||||
force-closes them on `close()`.
|
||||
- Inert after close — late `publish()` calls return a no-op publisher
|
||||
rather than throwing.
|
||||
- Forwards `get`, `list`, `subscribe` to the inner registry untouched.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import { ProviderBusRegistry } from "@suaveplan/react-audio/provider";
|
||||
|
||||
const buses = new ProviderBusRegistry();
|
||||
const pub = buses.publish("sidechain", 1);
|
||||
pub.write([new Float32Array(128)]);
|
||||
|
||||
buses.close(); // closes pub; subsequent publish() returns a no-op.
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
```ts
|
||||
import { ProviderBusRegistry } from "@suaveplan/react-audio/provider";
|
||||
|
||||
const buses = new ProviderBusRegistry();
|
||||
const pub = buses.publish("kick", 1);
|
||||
const off = buses.subscribe("kick", (bus) => {
|
||||
if (bus === undefined) console.log("bus closed");
|
||||
});
|
||||
|
||||
buses.close();
|
||||
off();
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `new ProviderBusRegistry()` — no constructor arguments.
|
||||
- `publish(name, channels): SidechainPublisher` — tracked and
|
||||
closed on `close()`.
|
||||
- `get(name)`, `list()`, `subscribe(name, listener)` — delegate.
|
||||
- `close()` — idempotent; closes all tracked publishers.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
Wrapping rather than subclassing keeps the implementation independent
|
||||
of the inner class's private state. The `Set<SidechainPublisher>`
|
||||
tracks the *outer* (wrapped) publisher so closing it removes itself
|
||||
from the set before delegating to the inner close — this avoids
|
||||
double-iteration concerns when `close()` calls each publisher's close
|
||||
which would in turn try to mutate the set. Iterating via
|
||||
`Array.from(this.active)` snapshots the set so concurrent mutation
|
||||
during the close loop is safe. Once closed, `publish()` returns an
|
||||
inert publisher whose `write` / `close` are no-ops, allowing late
|
||||
consumers to drain without throwing.
|
||||
Reference in New Issue
Block a user