Watch
1
0
Fork
You've already forked SouveraineOS
0
SouveraineOS/docs/AUDIO-PRIVACY.md
Fimeg bde961c6f2 saf: one spine — device, state, and work under the index
PAF becomes saf/device (history kept), STATE.md dissolves
into saf/state.md with the dated era archived, the substrate
SAF moves up from souveraine, and every agreement points at
saf/INDEX.md and nowhere else. one map, nothing to remember
2026-08-18 09:47:30 -04:00

6.3 KiB

task_id title status priority phase created updated references
souveraine-native-audio-001 Souveraine audio and privacy surfaces in_progress high delivery 2026-07-18 2026-08-07
saf/device/audio.md
docs/tasks/07-mic-wcd9340-slim-tx.md
docs/tasks/39-audio-levels-as-state.md
surfaces/quickshell/services/Audio.qml
surfaces/quickshell/modules/ii/sidebarRight/volumeMixer/VolumeDialogContent.qml
surfaces/quickshell/modules/ii/bar/UtilButtons.qml
/home/casey/Projects/Pixel3Arch/pkgs/souveraine-ucm-blueline
/home/casey/Projects/Pixel3Arch/pkgs/blueline-callaudio
/home/casey/Projects/Pixel3Arch/pkgs/souveraine-callaudiod
/home/casey/Projects/Pixel3Arch/pkgs/q6voiced

Souveraine audio and privacy surfaces

Current contract — 2026-08-07

The phone's audio stack works. PipeWire 1.6.8 owns the graph, WirePlumber 0.5.15 owns session policy, pipewire-pulse provides the Pulse compatibility API, and ALSA UCM describes the board routes. Native PulseAudio and the old ABI-provider shims are historical experiments, not the desired architecture.

  • HiFi exposes both CS35L36 speakers and clean mono WCD9340 capture through DMIC4 → DEC5/TX5. Casey uses the microphone for STT.
  • The Voice Call profile carries real two-way calls. The call packages manage the UCM transition, modem PCM, and earpiece/speaker selection.
  • WirePlumber restores device volume and selected profile correctly. TASK-39 owns the remaining role/default/lock-tier policy; it must not invent a second persistence writer.
  • TASK-07 owns the remaining hardware debt: the kernel holds codec sysclk and MICB2 permanently. That is a power and suspend defect, not an audio functionality defect.

The detailed hardware and lifecycle evidence lives in saf/device/audio.md. Do not reopen microphone bring-up from this surface document.

Authority

Concern Authority
Board verbs, devices, routes, and gains souveraine-ucm-blueline
Runtime graph, profiles, streams, and volume restoration PipeWire + WirePlumber
Pulse client compatibility pipewire-pulse
Call start/end UCM transition souveraine-callaudio
Modem voice PCM bridge souveraine-q6voiced
In-call earpiece/speaker action souveraine-callaudiod + callaudio hook
User-facing state, privacy truth, and guarded actions Souveraine surfaces

pactl remains a valid control and observation API because pipewire-pulse implements it. Calling that interface does not make native PulseAudio the authority.

Surface model

The owned audio service projects one truthful model:

serverReady
defaultSink / defaultSource
sinks[] / sources[]
playbackStreams[] / recordingStreams[]
activeProfile
outputActive / microphoneActive
lastError / generation

Each endpoint and stream needs a stable identifier, description, availability, volume, mute, application identity, media role, and running or corked state. Sink and source readiness are independent: loss of a microphone must not disable speaker controls.

The current pactl snapshots are acceptable scaffolding. The durable service should keep a long-lived pactl subscribe observer, debounce graph changes, and refresh from machine-readable JSON. A PipeWire restart increments generation, clears stale objects, and repopulates the model. Setters report failure; the UI does not optimistically lie.

Privacy truth

Privacy state comes from active clients and sessions, never from the appearance of a toggle.

  • microphoneActive: one or more recording streams exist; expose client identity and whether each stream is running or corked.
  • cameraActive: an active camera or portal session, not device presence.
  • screenCaptureActive: an active portal screencast or Souveraine recorder.

Muting and revoking access are different actions. A muted source can still be held by a recording client, so the privacy indicator remains visible until the stream ends. Unknown clients are shown as unknown, not omitted.

Active capture always has a persistent indicator on the unlocked shell and a safe ambient indication while locked. Details may name clients when unlocked; the lock surface must not leak private application metadata.

Owned surfaces and IPC

The present modules/ii files are working scaffolding. The destination is an original Souveraine service and presentation layer, with the same semantics on phone and laptop and form-factor-specific layout.

Expose JSON-over-string methods because Quickshell drops var returns:

audio.state()
audio.devices(direction)
audio.streams(direction)
audio.setVolume(direction, value, reason)
audio.setMuted(direction, muted, reason)
audio.setDefault(direction, endpointId, reason)
audio.stopStream(streamId, reason)

Read-only state is ambient. Volume and mute are ordinary audited actions. Stopping another application's recording is a privacy action and follows the common settings/capability authority. Every method validates direction, ranges, endpoint existence, graph generation, and lock state, then returns a structured success or refusal.

Verification

  • Speaker, microphone, STT, and two-way calls remain functional through the PipeWire/WirePlumber stack.
  • Volume, mute, and profile changes round-trip and survive a service refresh; WirePlumber remains the sole persistence writer.
  • Starting and stopping a recording updates the privacy indicator promptly and identifies the client when safe to do so.
  • Muting during recording leaves the access indicator visible.
  • A graph restart clears stale devices and streams without restarting the shell.
  • A missing source leaves output controls usable.
  • Call entry, earpiece/speaker switching, hangup, and HiFi restoration all preserve subsequent microphone capture.
  • Lock transitions retain an ambient capture warning without exposing client metadata.
  • IPC cannot bypass settings, step-up, or lock authority.

Done when

  • Active audio and privacy services are original Souveraine AGPL code with no borrowed widget dependency in their active graph.
  • Real endpoints and streams are modeled eventfully and recover after a graph restart.
  • Capture indicators distinguish access, mute, and revocation.
  • Phone and laptop share semantics without sharing inappropriate layout.
  • Role defaults and lock-tier behaviour are settled in TASK-39.
  • Agent IPC uses the common settings/capability policy.