fix: further layer A (per-app) glitches

This commit is contained in:
atagen 2026-05-24 18:12:31 +10:00
parent 2978318019
commit 7797f60128
16 changed files with 1589 additions and 155 deletions

41
IPC.md
View file

@ -163,9 +163,20 @@ schemas. `args` is omitted from the request when its schema is empty.
| `setting.set` | `{ key: string, value: any }` | `null` |
| `setting.list` | — | `{ settings: object }` |
| `bypass.set` | `{ enabled: bool }` | `null` |
| `per-app.list` | — | `{ layer_a: LayerASnapshot[] }`|
| `per-app.set` | `{ app: string, enabled: bool }` | `null` |
| `per-app.master` | `{ enabled: bool }` | `null` |
| `per-app.reset` | `{ node_id: u32 }` | `null` |
| `subscribe` | `{ topics: string[] }` | `{ subscribed: string[] }` |
| `unsubscribe` | `{ topics: string[] }` | `{ unsubscribed: string[] }` |
`per-app.set` / `per-app.master` persist to the user overlay (an
enable/disable override layered on the active profile's `[per_app]`).
`per-app.reset` is a one-shot that clears a managed stream's deference
lock (user-ceiling / strict mode) so the controller resumes normal
level control. Both `status` and `per-app.list` carry the
`LayerASnapshot[]` for currently-managed streams.
### Object schemas
#### `Status`
@ -177,6 +188,7 @@ schemas. `args` is omitted from the request when its schema is empty.
"uptime_s": 482,
"profile": "default",
"bypass": false,
"per_app": true,
"sinks": {
"processed": { "node_id": 51, "ready": true },
"real": { "node_id": 35, "name": "alsa_output.pci-0000_00_1f.3.analog-stereo" }
@ -184,10 +196,39 @@ schemas. `args` is omitted from the request when its schema is empty.
"streams": [
{ "node_id": 73, "app": "firefox", "route": "processed" },
{ "node_id": 81, "app": "spotify", "route": "bypass" }
],
"layer_a": [
{ "node_id": 73, "app": "firefox", "managed": true, "volume_lin": 0.71,
"reduction_db": 2.9, "user_ceiling_lin": null, "deferred": false }
]
}
```
`per_app` is the Layer A master switch. `layer_a` lists per-app
controller state for managed streams (omitted when empty); see
`LayerASnapshot` below.
#### `LayerASnapshot`
```json
{
"node_id": 73,
"app": "firefox",
"managed": true,
"volume_lin": 0.71,
"reduction_db": 2.9,
"user_ceiling_lin": 0.6,
"deferred": false
}
```
`reduction_db` is the smoothed gain reduction the controller currently
asserts (`>= 0`; `0` = no cut). `volume_lin` is the last
`channelVolumes` value written (1.0 = unity). `user_ceiling_lin` is
present only while ceiling-mode deference is active; `deferred` is true
when strict-mode deference has locked the controller pending a
`per-app.reset`.
#### `ProfileInfo`
```json