# OpenSpec Change: enterprise-react-audio-stream - **Change ID**: enterprise-react-audio-stream - **Package**: `@suaveplan/react-audio-stream` - **Category**: react - **Target path**: `packages/ui/react/react-audio-stream` - **Status**: PROPOSED - **Date**: 2026-05-15 - **Design**: `./design.md` - **Spec delta**: `./specs/react-audio-stream/spec.md` > Replaces the prior 2026-04-24 draft flagged `NEEDS-REWRITE`. See `../REACT_AUDIO_WAVE_REWRITE_COMPLETE.md`. --- ## Summary Deliver `@suaveplan/react-audio-stream` on genesis from scratch at enterprise quality. The package provides WebRTC-based real-time audio streaming for the React audio surface. It is **transport-agnostic at its core** (a `StreamSession` abstraction with peer fan-out) and ships two transport implementations: WebRTC (default) and WebSocket (server-relay fallback). Sessions are integrated with the unified architecture: a remote peer's incoming audio is materialised as an `AudioPlayerPlugin`-shaped source on a dedicated chain (so it benefits from FX, sidechain ducking, analyser readouts), and the local outgoing audio is captured via the engine's tap-to-bus surface from any track's post-FX point. The package exposes: 1. `` — owns one `StreamSession` instance per provider, nested under `` (or any ``); accepts an injectable signalling adapter (default: WebSocket signalling). 2. Hooks: `useAudioStream(participantId)`, `usePeerStreams()`, `useStreamControls()`, `useStreamReconnect()`, `useStreamMixer()`, `useStreamInterruption()`. 3. Components: ``, `` (per-peer level/mute/solo + transport-share toggle), `` (latency, packet loss, codec), ``. 4. Auto-reconnect with exponential back-off + interruption classification (network vs media-permission vs server-disconnect). 5. Transport-share mode: a designated peer's transport play/pause/seek events drive every connected peer's local transport so collaborative listening stays in sync. 6. OTel instrumentation (active sessions gauge, peer-connect / disconnect counters, ICE-failure counter, RTT histogram). The package owns **no DSP, no audio context, no codec implementation** — every audio surface goes through `@suaveplan/react-audio` hooks; WebRTC peer streams become first-class source plugins on dedicated chains. --- ## Current-state audit (genesis) The package does not exist on genesis yet — fresh build replacing the obsolete pre-tier 2026-04-24 draft. The upstream `react/media/react-audio-stream/` is layered on the monolithic `@suaveplan/react-audio` plugin surface; this rewrite re-derives every behaviour against the unified architecture. --- ## Parity Checklist (vs upstream) | Capability | Upstream | Migrated | Notes | |---|:---:|:---:|---| | `ReactAudioStream` plugin class | ✅ | ⬆️ | Replaced by the `StreamSession` abstraction + per-peer `AudioPlayerPlugin`-shaped sources. | | Session management | ✅ | ✅ | Now formal lifecycle: `connect`/`join`/`leave`/`disconnect` with FSM. | | Peer stream fan-out | ✅ | ✅ | Per-peer `MediaStream` → `MediaStreamTrack` → engine source plugin. | | Per-stream mixing controls | ✅ | ⬆️ | Each peer gets a track + chain in the engine; user controls = `` over `useStreamMixer`. | | Effect routing | ✅ | ⬆️ | Per-peer chains support any FX from `audio-fx-plugin-base`. | | Transport-control sharing | ✅ | ⬆️ | Single designated peer drives transport; explicit transfer-of-control. | | Auto-reconnect | ✅ | ✅ | Exponential back-off with cap; user-overridable. | | Interruption classification | ✅ | ✅ | Network / permission / signalling / peer / unknown buckets. | | WebSocket transport | partial | ✅ | First-class equal-peer transport. | | Storybook coverage | ⚠ | ✅ | Every component default + interactive + edge. | | Coverage | ~82 % | ✅ | 100/100/100/100. | No 🚫 rows. --- ## Available workspace deps on genesis | Package | Role | |---|---| | `@suaveplan/react-audio` (`workspace:^`) | Provider + hooks | | `@suaveplan/audio-fx-plugin-base` (`workspace:^`) | `PluginChain`, source plugin shape | | `@suaveplan/audio-transport` (`workspace:^`) | Transport for share mode | | `@suaveplan/network-transport-websockets` (`workspace:^`) | Default WebSocket transport | | `@suaveplan/network-discovery-trystero` (`workspace:^`) | Optional Trystero (BitTorrent-tracker WebRTC signalling) transport | | `@suaveplan/fsm` (`workspace:^`) | Session lifecycle state machine | | `@suaveplan/retry` (`workspace:^`) | Exponential back-off for reconnect | | `@suaveplan/error`, `@suaveplan/types`, `@suaveplan/opentelemetry`, `@suaveplan/events` | foundations | | `react` (peer), `zustand`, `zod` | --- ## File layout ```text packages/ui/react/react-audio-stream/ src/ index.ts error-codes.ts provider/ audio-stream-provider/ provider-options/ session/ stream-session/ session-fsm/ peer-channel/ stream-source-plugin/ interruption-classifier/ transports/ webrtc/ websocket/ trystero/ ← optional subpath hooks/ use-audio-stream/ use-peer-streams/ use-stream-controls/ use-stream-reconnect/ use-stream-mixer/ use-stream-interruption/ use-transport-share/ components/ remote-peer-strip/ stream-mixer/ stream-health-indicator/ stream-reconnect-toast/ __benchmarks__/ session-fanout.bench.ts tests/ integration.test.tsx purity.test.ts exports.test.ts e2e/ two-peer-sync.spec.ts ``` --- ## Impact **Breaking changes**: none — fresh build. **Prerequisites**: `react-audio`, `audio-fx-plugin-base`, `audio-transport`, `network-transport-websockets`, `fsm`, `retry`, foundations. ### Affected dependents - `@suaveplan/react-audio-player` — [ ] tests run / [ ] docs reviewed / [x] no action needed (reason: ``'s `multiPeer` option consumes this package's `use-multi-peer-sync` hook through an optional subpath; created against this spec) No other dependents (verified by `bunx turbo ls --filter=...@suaveplan/react-audio-stream`).