---
title: "PipeWire: Mehrere Audioausgänge gleichzeitig nutzen"
id: "2600"
type: "post"
slug: "ein-kombinierter-audio-ausgang-mit-pipewire"
published_at: "2026-02-16T00:36:20+00:00"
modified_at: "2026-02-16T12:28:03+00:00"
url: "https://www.geekbundle.org/ein-kombinierter-audio-ausgang-mit-pipewire/"
markdown_url: "https://www.geekbundle.org/ein-kombinierter-audio-ausgang-mit-pipewire.md"
excerpt: "Mit PipeWires combine-stream-Modul lässt sich ein virtueller Audio-Sink erzeugen, der den Ton gleichzeitig an mehrere Ausgänge verteilt, etwa USB-Headset, HDMI-Monitor und Bluetooth-Lautsprecher."
taxonomy_category:
  - "Linux"
taxonomy_post_tag:
  - "linux"
  - "pipewire"
---

Table of Contents

Es gibt diese Momente im Linux-Leben, in denen man denkt:  
 "Warum kann ich nicht einfach gleichzeitig über Headset *und* Monitor hören?"

Die Antwort lautet: Es geht.  
 Man muss PipeWire nur ein bisschen überreden.

## Das Problem: Mehrere Ausgänge, ein Sound

Typisches Setup:

- USB-Headset für Meetings und Games
- Lautsprecher eines HDMI-Monitor
- vielleicht noch Bluetooth Lautsprecher

Standardmäßig darf immer nur ein Sink (also ein Audio Ausgabegerät) das Standardgerät sein. Was wir aber wollen: Einen kombinierten virtuellen Sink, damit der Ton gleichzeitig an mehrere echte Ausgänge verteilt wird.

## PipeWire kann das mit "combine-stream"

PipeWire bringt ein Modul mit, das genau dafür gemacht wurde: `libpipewire-module-combine-stream`. Dieses Modul erzeugt einen neuen virtuellen Sink, das intern mehrere echte Sinks ansteuert.  
 Wichtig dabei:

- `combine.mode = sink` ==> Wir erstellen ein neues virtuelles Audio Ausgabegerät
- `combine.latency-compensate = true` ==> Latenzunterschiede (USB vs. HDMI vs. Bluetooth) werden ausgeglichen (soweit möglich)
- `audio.position = [ FL FR ]` ==> Stereo Ausgang

Stereo der einfachheit halber. Die meisten Headsets und HDMI-Ausgänge laufen ohnehin nur in 2.0.

## Node-Namen herausfinden

Für die eigentliche Konfiguration werden die internen `node.name` Bezeichnungen der Sinks, also der Audio Ausgänge, benötigt:

```
pw-link -o | grep -i output
alsa_output.usb-SteelSeries_Arctis_Nova_4X-00.analog-stereo:monitor_FL
alsa_output.usb-SteelSeries_Arctis_Nova_4X-00.analog-stereo:monitor_FR
alsa_output.usb-Generic_USB_Audio-00.HiFi__SPDIF__sink:monitor_FL
alsa_output.usb-Generic_USB_Audio-00.HiFi__SPDIF__sink:monitor_FR
alsa_output.usb-Generic_USB_Audio-00.HiFi__Speaker__sink:monitor_FL
alsa_output.usb-Generic_USB_Audio-00.HiFi__Speaker__sink:monitor_FR
alsa_output.usb-Generic_USB_Audio-00.HiFi__Headphones__sink:monitor_FL
alsa_output.usb-Generic_USB_Audio-00.HiFi__Headphones__sink:monitor_FR
alsa_output.pci-0000_01_00.1.hdmi-stereo:monitor_FL
alsa_output.pci-0000_01_00.1.hdmi-stereo:monitor_FR
bluez_output.4C_1B_86_70_93_63.1:monitor_FL
bluez_output.4C_1B_86_70_93_63.1:monitor_FR
```

## Konfiguration anlegen

Zuerst das Konfigurationsverzeichnis erzeugen:

```
mkdir -p $XDG_CONFIG_HOME/pipewire/pipewire.conf.d/
nano $XDG_CONFIG_HOME/pipewire/pipewire.conf.d/add-combined-sink.conf
```

Falls `$XDG_CONFIG_HOME` nicht gesetzt ist, ist es üblicherweise `~/.config`.

## Beispiel: Monitor + USB-Headset

```
context.modules = [
  { name = libpipewire-module-combine-stream
    args = {
      combine.mode = sink
      node.name = "combined_output_2"
      node.description = "Combined Output (Monitor / Headset)"

# gleicht Latenzdifferenzen aus (HDMI vs. USB vs. BT)
# Perfekte Synchronität ist physikalisch aber schwer erreichbar
      combine.latency-compensate = true

# Kombi-Sink ist Stereo
      combine.props = { audio.position = [ FL FR ] }

      stream.rules = [
# USB-Headset (SteelSeries)
        { matches = [
            { media.class = "Audio/Sink"
              node.name = "alsa_output.usb-SteelSeries_Arctis_Nova_4X-00.analog-stereo" }
          ]
          actions = { create-stream = {
            combine.audio.position = [ FL FR ]
            audio.position = [ FL FR ]
          } }
        },

# HDMI-Monitor (NVidia / Stereo)
        { matches = [
            { media.class = "Audio/Sink"
              node.name = "alsa_output.pci-0000_01_00.1.hdmi-stereo" }
          ]
          actions = { create-stream = {
            combine.audio.position = [ FL FR ]
            audio.position = [ FL FR ]
          } }
        }
      ]
    }
  }
]
```

Neustart nicht vergessen

```
systemctl --user restart pipewire.service
```

Danach erscheint ein neues Ausgabegerät mit Namen "Combined Output (Monitor / Headset)" in den Audioeinstellungen.

## Erweiterung: Bluetooth

Im nächsten Beispiel werden die beiden obigen Ausgänge um einen zusätzlichen Bluetooth Ausgang erweitert:

```
context.modules = [
  { name = libpipewire-module-combine-stream
    args = {
      combine.mode = sink
      node.name = "combined_output_3"
      node.description = "Combined Output (Monitor / Headset / Bluetooth)"

# gleicht Latenzdifferenzen aus (HDMI vs. USB vs. BT)
# Perfekte Synchronität ist physikalisch aber schwer erreichbar
      combine.latency-compensate = true

# Kombi-Sink ist Stereo
      combine.props = { audio.position = [ FL FR ] }

      stream.rules = [

# USB-Headset (SteelSeries)
        { matches = [
            { media.class = "Audio/Sink"
              node.name = "alsa_output.usb-SteelSeries_Arctis_Nova_4X-00.analog-stereo" }
          ]
          actions = { create-stream = {
            combine.audio.position = [ FL FR ]
            audio.position = [ FL FR ]
          } }
        },

# HDMI-Monitor (NVidia / Stereo)
        { matches = [
            { media.class = "Audio/Sink"
              node.name = "alsa_output.pci-0000_01_00.1.hdmi-stereo" }
          ]
          actions = { create-stream = {
            combine.audio.position = [ FL FR ]
            audio.position = [ FL FR ]
          } }
        },

# Bluetooth-Ausgabe
        { matches = [
            { media.class = "Audio/Sink"
              node.name = "bluez_output.4C_1B_86_70_93_63.1" }
          ]
          actions = { create-stream = {
            combine.audio.position = [ FL FR ]
            audio.position = [ FL FR ]
# optional: etwas größere Blockgröße hilft manchen BT-Stacks
# 10,7ms
# node.latency = "512/48000"
# 1s
            node.latency = "48000/48000"
          } }
        }
      ]
    }
  }
]
```

Im `node.name` lässt sich auch RegEx verwenden.

```
node.name = ~"bluez_output\\..*"
```

Das bedeutet: Alle BlueZ-Ausgänge werden automatisch angesteuert.  
 Praktisch, wenn der Kopfhörername wechselt oder man einfach mehrere Bluetooth Geräte hat.

## Und jetzt Audio Session Management

Bis hierhin haben wir einen neuen Audio-Sink erzeugt. Aber wer entscheidet eigentlich, welche Anwendung welchen Ausgang nutzt? Hier kommt **WirePlumber** ins Spiel.  
 PipeWire selbst ist "nur" der Medien-Server. Er verwaltet Nodes, Streams, Ports und Verbindungen.  
 Aber er entscheidet nicht aktiv:

- Welche Anwendung bekommt welchen Ausgang?
- Was passiert, wenn ein neues Gerät eingesteckt wird?
- Was passiert, wenn ein Gerät verschwindet?

Diese Logik übernimmt der **Session Manager**. In modernen Distributionen übernimmt das WirePlumber.

### Was macht WirePlumber konkret?

WirePlumber beobachtet permanent:

- Neue Streams (z. B. wenn Firefox Ton abspielt)
- Neue Geräte (z. B. wenn ein Bluetooth-Headset verbunden wird)
- Entfernte Geräte
- Manuelle Routing-Änderungen durch den Benutzer

Er trifft daraufhin Entscheidungen. Beispiel:

1. Du startest ein Spiel
2. Das Spiel erzeugt einen Audio-Stream
3. WirePlumber wählt einen geeigneten Sink
4. Du ziehst den Stream manuell auf "combined_output"
5. WirePlumber merkt sich diese Entscheidung

Beim nächsten Start desselben Spiels wird wieder dieser Sink genutzt.

### Wo speichert WirePlumber das?

Die Zustandsdaten liegen typischerweise unter:

```
~/.local/state/wireplumber/
```

Dort speichert WirePlumber:

- Zuordnungen von Streams zu Sinks
- Default-Geräte
- manuelle Routing-Änderungen
- Metadaten über Geräte

Löscht man dieses Verzeichnis, "vergisst" es alle bisherigen Zuordnungen.

#### Wichtige Notiz

Änderungen, die in der Desktopumgebung vorgenommen werden, also:

- Standard-Ausgabegerät wechseln
- Lautstärke einzelner Anwendungen ändern
- Streams manuell auf andere Ausgänge ziehen

werden in der Regel ebenfalls unter `~/.local/state/wireplumber/` gespeichert. Das Desktop-Soundpanel spricht über PipeWire mit WirePlumber, und WirePlumber schreibt den Zustand persistent weg.

### Wie erkennt WirePlumber eine Anwendung?

Nicht am Fenstertitel und auch nicht am sichtbaren Programmnamen, sondern an Stream-Properties wie:

- `application.name`
- `application.process.binary`
- `media.role`

Deshalb kann es Unterschiede geben zwischen:

- Firefox (native)
- Firefox (Flatpak)
- Chromium

Aus Sicht von WirePlumber sind das unterschiedliche Identities.

### Eigene Routing-Regeln definieren

WirePlumber erlaubt es, eigene Regeln zu definieren.  
 Beispiele für sinnvolle Policies:

- Alles mit `media.role = Communication` ==> Headset
- Alles mit `media.role = Game` ==> Combined Sink
- Alles mit `application.name = VLC` ==> HDMI

Neuere Versionen von WirePlumber (0.5+) nutzen eine deklarative Konfiguration in `~/.config/wireplumber/`. Damit wird Audio-Routing proaktiv steuerbar.

## Zusammenspiel mit dem Combined Sink

Technisch betrachtet ist der Combined Sink für WirePlumber einfach ein weiterer Audio-Knoten. Das bedeutet:

- Er kann Standard-Sink sein
- Er kann Ziel für einzelne Anwendungen sein
- Er kann Teil eigener Routing-Regeln werden

## Fazit

Mit "wenigen" Zeilen Konfiguration bekommt man:

- parallele Audioausgabe auf mehreren Geräten
- Latenzkompensation
- persistentes Routing pro Anwendung
- vollständige Kontrolle über Audio-Policies

PipeWire kümmert sich um die Signalverarbeitung. WirePlumber kümmert sich um die Entscheidungen.

**Ähnliche Beiträge**- [Check_MK: Selbstheilung mit Event Handler](https://www.geekbundle.org/selbstheilung-mit-check_mk-event-handler/)
- [QuickTip: Mobile Devices eines Exchange Users per…](https://www.geekbundle.org/quicktip-mobile-devices-eines-exchange-users-per-powershell-loeschen/)
- [Neue Kategorie: Microblog](https://www.geekbundle.org/neue-kategorie-microblog/)
- [iPXE Docker Build environment](https://www.geekbundle.org/ipxe-docker-build-environment/)

### Kommentar hinterlassen [Antwort abbrechen](/ein-kombinierter-audio-ausgang-mit-pipewire/#respond)
