Watch
1
0
Fork
You've already forked SouveraineOS
0
SouveraineOS/docs/AUDIO-PRIVACY.md
2026-08-10 17:00:23 -04:00

156 lines
6.3 KiB
Markdown

---
task_id: souveraine-native-audio-001
title: "Souveraine audio and privacy surfaces"
status: in_progress
priority: high
phase: delivery
created: 2026-07-18
updated: 2026-08-07
references:
- PAF/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 `PAF/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:
```text
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:
```text
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.