Source

A Source is one capture endpoint as a Kubernetes resource: an analog input, or the capture side of a USB card. The operator creates one for every capture endpoint it publishes, cluster-scoped like a Node, named the same way a Sink is. You never create or delete one. The operator writes the whole of status, and you write spec, which states the settings you want for the endpoint.

apiVersion: audio.liken.sh/v1alpha1
kind: Source
metadata:
  name: node-1-usb-0573-1573-a34004801402-usb-audio-capture
spec:
  mute: true
status:
  node: node-1
  location: "1-6"
  connectionType: usb
  pcm:
    device: 0
    id: USB Audio
  nodeName: liken.audio.card1-pcm0c
  capabilities:
    Mic Capture Volume:
      type: integer
      min: 0
      max: 16
      channels: 1
    Mic Capture Switch:
      type: boolean
      channels: 1
  observed:
    volume: 100
    mute: true
    controls:
      Mic Capture Volume: "8"
      Mic Capture Switch: "on"
  conditions:
    - type: Connected
      status: "True"
    - type: Ready
      status: "True"

For a microphone, mute is the field that matters most. Setting spec.mute: true on a Source closes that microphone for everyone, a rule that closes every microphone is one patch per Source, and kubectl get sources shows which ones are open. A pod that records still holds the microphone through a claim, and its stream reaches the node that status.nodeName names.

An HDA card serves several input jacks through one capture PCM and picks the live jack with its Input Source control, so the Source is the PCM and the jack is a control in spec.controls. A Bluetooth headset’s microphone is not published yet, because it needs the headset profiles the pod does not run.

One capture endpoint: an analog input, or a USB card’s capture side. A Bluetooth headset’s microphone is not published yet. An HDA card serves several input jacks through one capture PCM and picks the live jack with its Input Source control, so the Source is the PCM and the jack is a control. The name is the machine’s name and the card’s identity, as the Sink reference gives them. When a USB card’s name would pass 63 characters, it holds the first eight hex digits of the SHA-256 of the serial in place of the serial.

spec

The settings you want for the endpoint. Every field is optional. The operator writes volume and mute when they change and when the endpoint appears, and otherwise reports the level the endpoint holds. It writes a declared control back when the endpoint diverges from it. It never writes a field the spec leaves out.

Field Type Required Description
volume integer no The gain PipeWire applies to what the endpoint captures, as a percent of unity, applied to every channel alike. It applies at once, under a claim or not.
mute boolean no Whether the endpoint captures silence. It applies at once. A closed microphone is this field, on every Source, and kubectl get sources shows which ones are open.
controls map[string]string no The card’s own controls, keyed by the kernel’s control name as status.capabilities lists them, such as Capture Volume or Input Source. An integer control takes a number within its range, a boolean control takes on or off, and an enumerated control takes one of its values. The operator writes a control only when it is stated here.

status

What the hardware declares and what the operator last read. The operator owns every field here.

Field Type Required Description
node string no The machine that holds the endpoint. The name of every Source starts with this machine’s name, so a card that moves to another machine gets a new Source. The operator on each machine lists and watches the Sources by this field.
location string no Where the card is on the machine, in the kernel’s spelling: a PCI address such as 0000:00:1f.3, or a USB port path such as 1-6.
connectionType string no How sound enters the machine. One of: analog, usb.
card object no The ALSA card the endpoint is on. The number and the id are this boot’s, and a second card can change both, so nothing durable is keyed to them.
pcm object no The PCM device the endpoint captures through.
nodeName string no The PipeWire node a consumer’s capture streams target, the same value a prepared claim delivers as PIPEWIRE_NODE. Absent while PipeWire holds no node for the endpoint.
format object no The format the node runs at, from PipeWire’s own Format parameter. Absent while the node is not running.
capabilities map[string]object no The card’s own controls that belong to this endpoint, keyed by the kernel’s control name. A Capture control goes to the card’s sources, and a jack control is not listed because it is read-only and feeds the Connected condition.
observed object no The last value the operator read for each setting. The operator reads the card’s control device on every event it delivers, and PipeWire’s graph on every change it prints, so a change a person made with a knob or a client shows here without a poll.
claim object no The claim that holds the endpoint now, and absent between holders.
conditions []object no Connected reports that the endpoint can capture now: a plug in an analog jack, and always on USB. Ready reports that PipeWire holds a node for it.

status.card

The ALSA card the endpoint is on. The number and the id are this boot’s, and a second card can change both, so nothing durable is keyed to them.

Field Type Required Description
number integer no The card number the kernel assigned this boot.
id string no The card’s short id, such as PCH, with the suffix the kernel appends on a clash, such as PCH_1.
driver string no The kernel driver that binds the card, such as USB-Audio.
name string no The card’s name, as the driver states it, such as HDA Intel PCH.

status.pcm

The PCM device the endpoint captures through.

Field Type Required Description
device integer no The PCM device number on the card, this boot.
id string no The driver’s name for the PCM, such as USB Audio. It is the part of the endpoint’s name that outlives the number.

status.format

The format the node runs at, from PipeWire’s own Format parameter. Absent while the node is not running.

Field Type Required Description
rate integer no The sample rate in hertz.
channels integer no The channel count.
positions []string no The channel positions in order, in PipeWire’s names: FL, FR, MONO.

status.capabilities.*

The card’s own controls that belong to this endpoint, keyed by the kernel’s control name. A Capture control goes to the card’s sources, and a jack control is not listed because it is read-only and feeds the Connected condition.

Field Type Required Description
type string no What the control takes. One of: integer, boolean, enumerated.
min integer no The smallest number an integer control accepts.
max integer no The largest number an integer control accepts.
step integer no The step between numbers an integer control accepts, absent when every number in the range is accepted.
minDecibels string no The level at min, in decibels, when the control declares one, as a decimal string such as -65.25.
maxDecibels string no The level at max, in decibels, when the control declares one.
values []string no Every value an enumerated control accepts.
channels integer no How many channels the control carries. A write from spec sets every channel to the same value.

status.observed

The last value the operator read for each setting. The operator reads the card’s control device on every event it delivers, and PipeWire’s graph on every change it prints, so a change a person made with a knob or a client shows here without a poll.

Field Type Required Description
volume integer no The gain PipeWire applies, as a percent of unity. An idle node reports no level of its own, so an idle endpoint reports the level the operator last wrote to it, and nothing until a level is declared.
mute boolean no Whether the endpoint captures silence, on the same terms as volume.
controls map[string]string no The value of every control in capabilities, in the same spelling spec.controls takes. A control with several channels reports the first channel’s value.

status.claim

The claim that holds the endpoint now, and absent between holders.

Field Type Required Description
namespace string no
name string no

status.conditions[]

Connected reports that the endpoint can capture now: a plug in an analog jack, and always on USB. Ready reports that PipeWire holds a node for it.

Field Type Required Description
type string yes
status string yes One of: True, False, Unknown.
reason string yes
message string no
lastTransitionTime string yes

The name and the spec

A Source is named by the same rule as a Sink, and its spec works the same way: the operator writes a declared volume and mute when the declaration changes and when the endpoint appears, writes a declared control back only where the hardware diverges from it, validates a control against status.capabilities, and invents no value. A Source has no status.session, and its spec.volume is a number, the level alone. The Sink reference has the name table and the rules in full.

The one difference is which controls attach. A Capture control, Input Source, and a Mic Boost go to the card’s sources, and a Playback control goes to its sinks.

Events

The operator posts a Normal Event on a Source for each change of its Connected and Ready conditions, with the condition’s own reason and message, and a Warning when Ready becomes False while Connected is True. It posts SpecRefused when the spec states a value the endpoint does not take, and the capture API posts Captured for each recording a caller takes. The Events are in the default namespace. The Sink reference describes each reason.