3.5 KiB
3.5 KiB
@suaveplan/react-audio-stream — hooks + components (chunk C)
- Target path:
packages/ui/react/react-audio-stream/ - Tier: browser/react
- Date: 2026-05-23
- Status: PROPOSED — chunk C of the 4-chunk
enterprise-react-audio-streamsplit.
Why
Chunks A (session-core) and B (transports) deliver the headless engine — the FSM, transports, source-plugin bridge, error codes, telemetry. This chunk delivers the React surface that consumers actually touch: a Provider, 6 hooks, 4 accessible components. Transport-share concerns (the 7th hook and its component indicator) live in chunk D so this chunk stays disjoint.
What changes
<StreamProvider>—src/provider/stream-provider.tsxwires aStreamSessioninstance into React context.sessionFactoryinjectable (consumer creates the session with their chosen transport adapter); StrictMode-safe singleton; surfaces'state-changed'/'interruption'events into hook subscribers via a typed event bus.- Hooks (each in its own feature dir with
.ts+.types.ts+.test.tsx+.md+index.ts):useStreamSession()— returns the session + current FSM state + lifecycle methods (connect,join,leave,disconnect)useStreamRoom()— returns{ roomId, isJoined, joinedAt, participants }derived from session stateuseStreamPeers()— returns livePeer[](id + display name + connection state + RTT)useStreamMixer()— exposes per-peersetVolume,setMute,setSolo(DAW solo semantics — when any peer is soloed, every non-soloed peer's track-volume → 0); reads from each peer chain'ssetTrackVolume/setTrackMute/setTrackSolouseStreamLevels(peerId?)— returns realtime peak/RMS for the local mic or the named peer; piggybacks on@suaveplan/audio-analysis-spectrum's level computation via the peer chain's analyzer slotuseStreamRecording()—start(),stop()returning aBlob; mixes the active session output (or a subset of peers) into a single audio file viaaudio-engine-browser's offline renderuseStreamPermissions()— wrapsnavigator.mediaDevices.getUserMediapermission state with the typedMediaPermissionStateenum
- Components (each with
.tsx+.types.ts+.test.tsx+.stories.tsx+.md+index.ts):<StreamRoom>— controlled wrapper exposing room state + join/leave controls; render-prop pattern for layout flexibility<StreamMixer>— per-peer mixer strip with level meter + mute/solo buttons + volume slider; delegates touseStreamMixer()<StreamRecorder>— record/stop button with duration display; delegates touseStreamRecording()<StreamPermissionsBanner>— permission state banner with explicit request button; ARIA-live for state changes
- Subpath exports —
package.jsonadds./provider,./hooks,./hooks/use-stream-session(and 5 more),./components,./components/stream-room(and 3 more).
Requirements landed by this chunk
From the original spec:
- Per-peer stream mixer (full —
<StreamMixer>+useStreamMixer) - Subpath exports for
./provider,./hooks/*,./components/*
Impact
- ~35 files (6 hooks × 5 + 4 components × 6 + provider + barrel touches).
- Imports
StreamSession,StreamSourcePlugin,ReactAudioStreamErrorfrom chunk A — local-mirror types in tests if A hasn't merged. - Imports nothing from chunk B (consumers wire transports themselves via the session factory).
- No spec fold / no archive — chunk D performs both.