# use-stream-mixer _(no submodules)_ ## Purpose `useStreamMixer` exposes per-peer mixer controls — level, mute, solo, and the per-peer FX slot count — and implements DAW-correct solo semantics on top of the session's track mutators. It is the only hook in chunk C that owns cross-peer behaviour: when any peer is soloed, every non-soloed peer's track-volume is set to 0; when no peer is soloed, every track keeps its last user-set volume (the session is the source of truth for "last set" because the mutations go through `setTrackVolume`). Every mutation routes through `session.setTrackVolume`, `session.setTrackMute`, and `session.setTrackSolo` rather than being re-implemented inside the hook — this is the explicit Requirement-6 constraint and the reason the test asserts on `session.calls.setTrackSolo` / `setTrackVolume`. ## Features - DAW solo semantics: any solo activates the per-track ducking pass; clearing the last solo lets non-soloed tracks resume their stored volume. - Pure delegation: zero local volume state — the session owns it. - Stable callbacks via `useCallback`. - Throws `REACT_AUDIO_STREAM.NO_PROVIDER` outside a ``. ## Usage: Basic ```tsx const { peers, setVolume, setMute, setSolo } = useStreamMixer(); return peers.map((p) => ( setVolume(p.id, v)} onMute={(m) => setMute(p.id, m)} onSolo={(s) => setSolo(p.id, s)} /> )); ``` ## Usage: Advanced ```tsx const { peers, setSolo } = useStreamMixer(); const soloExclusive = useCallback((id: string) => { // Solo one peer and clear all others' solos in a single React tick. peers.forEach((p) => p.soloed && p.id !== id && setSolo(p.id, false)); setSolo(id, true); }, [peers, setSolo]); ``` ## API Reference - `UseStreamMixerResult` — `{ peers, setVolume, setMute, setSolo }` - `useStreamMixer(): UseStreamMixerResult` ## Implementation Notes `setSolo` reads the current mixer snapshot from `session.getPeerMixerStates()`, applies the requested solo change in a local copy, computes `anySoloed`, and — when true — issues `setTrackVolume(otherId, 0)` for every non-soloed peer whose current volume is not already 0. The non-zero check avoids redundant mutations that would otherwise show up as extra `calls.setTrackVolume` entries in tests. The "restore previous volume on un-solo" arm is delegated to the session: chunk A's session implementation stores the user-set volume independently from the live mixer volume, so when the last solo clears, the session emits a `mixer-changed` event that restores the stored values. The hook does not have to keep its own restore-map, which keeps the React surface stateless.