Reference · Decisions
0038: One sound service, and 100% is 0 dB
One sound service sets every volume on one scale, where 100% is the device's own 0 dB, so a new microphone no longer clips.
Status: accepted (recorded in v0.12 for what the sound service already does; written from the round-6 audio audit). Builds on 0016 (Arch base: PipeWire and WirePlumber come from the distribution).
On this page
Context
PipeWire reports where a device's 0 dB sits (volumeBase) and WirePlumber starts a new source at the hardware maximum, which on most codecs is +20 to +30 dB of microphone boost, so every new microphone clipped, and a slider labelled 100% meant "as loud as the hardware can go". Three tools also moved volumes by their own scale: wpctl set-volume N% and pactl N% count from the hardware maximum, the Settings and Control Center sliders drew percent of 0 dB. Filters (echo cancel with automatic gain, RNNoise) and the App Mix for OBS are PipeWire-pulse modules that must exist only while someone asks. The sound pages in Settings and the Control Center each need the same devices, levels and rules.
Decision
- 100% on a slider is the device's 0 dB (
wol_core::audio::percent_of,linear_for, cubic like PulseAudio), never the hardware maximum. Above 100 only with the user's explicit "Allow louder" (one switch for the output and the input slider,Service::set_boost), up tomax_percent. - One service owns the rules:
crates/audio(wol_audio) runs one PipeWire main loop on its own thread and a service thread that applies the rules (service::Service) to events and emits commands; the pipewire backend only moves bytes, so every rule is tested againstfake::FakeBackend. Settings and the Control Center sendwol_core::audio::Actions and drawSnapshots; neither asks PipeWire itself. Every volume the sliders set (Action::MicVolume,Action::OutputVolume) goes through the service, through the device'sRoutewhen it has one (the hardware mixer moves, aswpctldoes), so the scale conversion lives in one place. The volume keys, the OSD andwol volumekeep thewpctlscale inwol_core::controls: the same number on a device whosevolumeBaseis 1.0. - Snap once: a microphone seen above 0 dB for the first time is put at 0 dB and remembered (
~/.local/state/wolos/audio-snapped); WirePlumber's default for new sources is lowered to 0.064 (71-wolos-input.conf) so the snap is rarely needed. The service exists only while a Sound page is open; it is not a resident client. - On demand, never static: filters and App Mix are pipewire-pulse modules loaded when switched on and unloaded when off; no fragment under
/usr/shareloads one. When PipeWire restarts the modules go with it, so the service loads them again once the microphone is back (Service::refilter). - The level meter is not a recorder: its capture stream carries a
node.link-group, which WirePlumber's Bluetooth autoswitch skips, so opening Sound does not move headphones to the call profile (model::METER_PROPS).
Consequences
the sliders are right on every device, including outputs with a gain range, at the cost of one more Action per slider and a service that must be running for them (a fixed preview or a machine with no PipeWire falls back to System's wpctl, capped at 100). The service runs only with a Sound page open, so a microphone is not snapped until then; the 0.064 default and wol audio doctor cover that gap. The volume keys can still disagree with the slider on a device whose volumeBase is below 1.0 (they count from the hardware maximum); moving them onto the service is future work and would need the service to run for the whole session. A change to the 0 dB rule or to what the service owns needs a new ADR that names this one.
Related
- SoundOne sound server with rules that keep microphones from clipping, low latency where it matters, and a choice of Bluetooth codecs.
- Sound for creatorsRecording, streaming and producing: buffers, OBS, a separate game track, DAWs.
- The wol commandEvery wol command, what it does, and which ones helpers may call.
- 0031: Plugins, themes and layoutsFolder plugins in a sandbox, themes for every toolkit, and layouts as data.
- 0032: Optional modulesAI, developer, creative and console stacks as removable modules and Kits.
From the developer documentation, wonderlandos/wolos docs/adr/0038-sound-service.md.