# `Bluez.BlueAlsa`
[🔗](https://github.com/bbangert/bluez/blob/v0.1.0/lib/bluez/blue_alsa.ex#L1)

Persistent `rebus` D-Bus client to `org.bluealsa` (the bluez-alsa
`bluealsad` daemon), used to learn which A2DP-playback PCMs are *ready to
open* right now. This is the control-plane half of the Bluetooth-headphone
audio path; the data plane is sendspin opening the ALSA PCM string directly.

`pcms/0` returns, for every connected A2DP headset, what a host needs
to open (or surface) its playback PCM:

    %{
      mac: "AA:BB:CC:DD:EE:FF",
      pcm_path: "/org/bluealsa/hci0/dev_.../a2dpsrc/sink",
      alsa_string: "bluealsa:DEV=AA:BB:CC:DD:EE:FF,PROFILE=a2dp",
      alias: "WH-1000XM4"   # org.bluez Device1.Alias, falls back to the MAC
    }

## Connection, not the daemon

This client connects to the **system bus** (owned by `dbus-daemon`, the first
child of `Bluez`), not to `bluealsad`. So it comes up whether
or not `bluealsad` has claimed `org.bluealsa` yet; the `GetManagedObjects`
call simply errors (→ `[]`) until the daemon is up, and starts returning PCMs
once a headset connects. It survives a `bluealsad` restart without reconnecting.

## PCM enumeration (bluez-alsa v4 API)

PCMs are discovered via the freedesktop `ObjectManager` at `/org/bluealsa`
(each connected A2DP playback PCM is an `org.bluealsa.PCM1` object), **not**
the v3 `org.bluealsa.Manager1.GetPCMs` method — buildroot ships bluez-alsa
4.x, where that method no longer exists (it returns `UnknownMethod`, which the
error path would silently swallow into `[]`).

## Inert off-target / when not started

The `Bluez` subtree only runs on the BT targets, so on
host/CI this GenServer isn't started. `pcms/0` catches the `:exit` from
calling a non-existent process and returns `[]`, mirroring the exit-safe
pattern used elsewhere in the Bluez layer — callers stay inert.

Enrichment with the device `Alias` is a best-effort `org.bluez`
`Properties.Get` on the same connection (BlueAlsa already proves D-Bus is
reachable); a failed Alias lookup falls back to the MAC, never raises.

# `child_spec`

Returns a specification to start this module under a supervisor.

See `Supervisor`.

# `pcms`

```elixir
@spec pcms() :: [
  %{
    mac: String.t(),
    pcm_path: String.t(),
    alsa_string: String.t(),
    alias: String.t()
  }
]
```

Connected A2DP-playback PCMs as a list of maps (see the moduledoc). `[]` when
the daemon is down, no headset is connected, or this client isn't running.

# `pcms_topic`

```elixir
@spec pcms_topic() :: String.t()
```

PubSub topic broadcast when the BlueALSA PCM set changes.

# `start_link`

---

*Consult [api-reference.md](api-reference.md) for complete listing*
