first commit

This commit is contained in:
2026-05-29 08:20:56 +01:00
commit 949299f58d
6368 changed files with 527176 additions and 0 deletions

View File

@@ -0,0 +1,76 @@
# control-channel
## Purpose
The control-channel module is the wire-protocol heart of transport sharing. It defines the envelope shapes that flow between the granting peer (the "driver") and every connected receiver, and it implements the `TransportShareCoordinator` — a small state-aware adapter that wires a local `SharedTransportTarget` to a peer-level `ControlChannel`.
The coordinator is the only place in the package where transport events become wire messages. Everything else — hooks, components, session glue — observes the coordinator's mode and applied envelopes rather than touching the transport or channel directly. Keeping the translation pinned to one module means the protocol is straightforward to audit and to evolve without touching React code paths.
## Features
- Four-envelope wire protocol: `play`, `pause`, `seek`, `setTempo`.
- Driver-side listener attaches to the transport's `start`, `pause`, and `bpm` events and forwards each as the matching envelope.
- Receiver-side listener applies each inbound envelope to the local transport target via `start`, `pause`, `seek`, `setTempo`.
- Mode-flip safety: switching between `local`, `driving`, and `receiving` always detaches the previous direction's listeners with no leaks.
- Imperative `notifySeek(seconds)` for callers performing programmatic seeks (the underlying transport does not emit a `seek` event).
- `onModeChange` and `onEnvelope` subscriptions for higher layers (the hook).
- `dispose()` releases all listeners and the channel subscription.
## Usage: Basic
```ts
import {
createTransportShareCoordinator,
type ControlChannel,
type SharedTransportTarget,
} from "@suaveplan/react-audio-stream/transport-share";
declare const transport: SharedTransportTarget;
declare const channel: ControlChannel;
const coordinator = createTransportShareCoordinator({ transport, channel });
coordinator.drive(); // become the driver — local events now propagate
```
## Usage: Advanced
```ts
const coordinator = createTransportShareCoordinator({ transport, channel });
const unsubscribeMode = coordinator.onModeChange((mode) => {
console.info("share role is now", mode);
});
const unsubscribeEnvelope = coordinator.onEnvelope((envelope) => {
if (envelope.type === "setTempo") {
console.info("tempo synced to", envelope.bpm);
}
});
coordinator.receive(); // apply inbound envelopes to the local transport
// ... share session runs ...
coordinator.release(); // return to local-only mode
unsubscribeMode();
unsubscribeEnvelope();
coordinator.dispose();
```
## API Reference
- `createTransportShareCoordinator(opts): TransportShareCoordinator` — factory.
- `TransportShareCoordinator`
- `getMode(): TransportShareMode`
- `drive(): void`
- `receive(): void`
- `release(): void`
- `notifySeek(seconds: number): void`
- `onModeChange(listener): () => void`
- `onEnvelope(listener): () => void`
- `dispose(): void`
- `TransportShareControlMessage` — discriminated union of envelope types.
- `ControlChannel` — `{ send, onMessage }` adapter implemented by chunk A's session over the peer transport.
- `SharedTransportTarget` — structural `{ start, pause, seek, setTempo, on }` shape that the real `Transport` satisfies via the `useTransport` adapter from `@suaveplan/react-audio`.
## Implementation Notes
The coordinator is intentionally stateless beyond its current mode and the cached detach callbacks. Mode changes are atomic: detach previous direction, attach new direction, then flip the role flag and notify subscribers. The driver-side listener defensively reads `payload.time` / `payload.offset` / `payload.bpm` as `number | undefined` because the upstream `TransportEventMap` declares those keys as plain `unknown`; the coordinator coerces missing values to safe defaults rather than relying on transport internals. Disposal is idempotent so the React hook's cleanup effect can call it on unmount without guards. The factory exists so tests can construct the coordinator with the same call shape consumers use through the package's barrel.