<!-- SPDX-License-Identifier: GPL-2.0-or-later -->
# Device profiles

Waveline is a mixer for any microphone. Everything that is true of *one*
microphone and not of the rest (a kernel quirk, a WirePlumber workaround, a
vendor USB protocol, the name to put on the window) lives in a profile here,
and nothing outside this directory has to know which devices exist.

```
devices/
  generic/           the fallback: no patches, no vendor protocol
    device.conf
  wave3/             Elgato Wave:3
    device.conf
    kernel/apply.py                        kernel patch
    kernel/0001-*.patch                    the same change as a readable diff
    wireplumber/51-waveline-wave3.conf     WirePlumber drop-in
    pipewire/51-waveline-wave3-quantum.conf
    udev/60-waveline-wave3.rules
```

`install.sh` reads every `devices/*/device.conf`, matches each profile's
`USB_IDS` against what is plugged in, and installs **only** the parts belonging
to profiles that matched. A machine with no recognised microphone gets the
`generic` profile: the mixer, and none of anyone else's workarounds.

The chosen profile is written to `~/.config/waveline/profile.conf`, which is
what `wavelined` reads at startup to decide its branding and whether to open a
vendor USB device at all.

## Adding a microphone

1. `mkdir devices/<id>` and copy `devices/generic/device.conf` into it.
2. Fill in `PROFILE_ID`, `PROFILE_LABEL`, `BRAND` and `USB_IDS`. `USB_IDS` is a
   space-separated list of `vvvv:pppp` as `lsusb` prints them.
3. Add only the pieces the device actually needs. Every path key is optional
   and relative to the profile directory:

   | Key | What it is | Installed to |
   |---|---|---|
   | `KERNEL_PATCH` | a Python script taking a staged `sound/usb/` copy as `argv[1]` | built and installed via DKMS |
   | `WIREPLUMBER_CONF` | a WirePlumber drop-in | `~/.config/wireplumber/wireplumber.conf.d/` |
   | `PIPEWIRE_CONF` | a PipeWire drop-in | `~/.config/pipewire/pipewire.conf.d/` |
   | `UDEV_RULES` | a udev rule | `/etc/udev/rules.d/` |

4. Leave `HARDWARE_CONTROLS=0` unless you have implemented a vendor transport
   for the device in `app/src/device/`. It gates the mixer's hardware panel,
   and the panel is useless without one.

That is the whole contract. `install.sh`, `uninstall.sh` and `wavelined` all
work off these keys, so a new profile needs no changes to any of them.

## Why `KERNEL_PATCH` is a script, not a diff

`sound/usb/` changes upstream every release, and a context diff that does not
apply is indistinguishable from a diff that applied to the wrong place. The
scripts assert their anchors instead: each edit checks its anchor text matches
exactly once and refuses the whole run otherwise, so a kernel that moved the
code under us fails loudly at prepare time rather than producing a module that
builds and misbehaves. `devices/wave3/kernel/0001-*.patch` is the same change
in ordinary diff form, kept for reading and for sending upstream.
