Sistema Audio Ubuntu 26.04 LTS Desktop

Dialogo con Gemini.

Ciao, ho installato Ubuntu 26.04 LTS desktop. Potresti descrivere il sistema audio?

Ubuntu 26.04 LTS adotta uno stack audio moderno incentrato interamente su PipeWire e WirePlumber, consolidando l’architettura introdotta nelle versioni recenti e mandando definitivamente in pensione la gestione legacy separata di PulseAudio e JACK.

L’architettura del sistema audio è strutturata in quattro livelli principali:

1. Il Core: PipeWire (pipewire)

  • Gestisce l’elaborazione dei flussi multimediali (audio e video) a bassissima latenza.
  • È progettato con un modello di sicurezza basato su permessi (cruciale per l’isolamento delle applicazioni Snap e Flatpak).
  • Offre un motore a grafo unificato capace di gestire contemporaneamente esigenze audio consumer e audio professionale.

2. Il Session Manager: WirePlumber (wireplumber)

  • Sostituisce il vecchio gestore pipewire-media-session.
  • Si occupa delle policy di routing (selezione automatica delle periferiche predefinite, priorità jack cuffie/Bluetooth, memoria dei livelli di volume per dispositivo).
  • È altamente configurabile tramite script in Lua e file di configurazione modulari in /etc/wireplumber/ o ~/.config/wireplumber/.

3. Livello di Compatibilità ed Emulazione PipeWire fornisce wrapper trasparenti che espongono le vecchie API alle applicazioni senza richiedere modifiche al software:

  • pipewire-pulse: Sostituisce il demone PulseAudio. I comandi classici come pactl, pacmd e le app che usano libpulse continuano a funzionare normalmente.
  • pipewire-jack: Offre un’implementazione drop-in per le applicazioni professionali (DAW, sintetizzatori) che richiedono il server audio JACK a bassa latenza.
  • ALSA Plugin: Intercetta i flussi delle applicazioni che comunicano direttamente con ALSA e li indirizza a PipeWire.

4. Driver Hardware: ALSA Kernel Modules

  • A basso livello, l’interfacciamento con i controller hardware (chip integrati Intel/AMD HDA, schede audio USB, codec Realtek) rimane gestito dai moduli del kernel Linux tramite ALSA (Advanced Linux Sound Architecture).

Comandi utili per la diagnostica e il controllo

  • Stato dei servizi:Bashsystemctl --user status pipewire wireplumber pipewire-pulse
  • Controllo server e routing in tempo reale:Bashwpctl status (Mostra l’albero di sorgenti, sink, nodi audio e consente di cambiare volume o endpoint predefiniti con wpctl set-volume o wpctl set-default).
  • Informazioni sul server audio:Bashpactl info (Indicherà Server Name: PulseAudio (on PipeWire...)).
  • Interfaccia grafica avanzata (opzionale): Per gestire il routing a grafo dei nodi e i buffer di latenza sono disponibili strumenti come helvum o qpwgraph:Bashsudo apt install qpwgraph

Se vuoi approfondire la configurazione o l’uso dello stack audio:

Configurare PipeWire per audio pro a bassa latenza

Guida alla gestione dei dispositivi con wpctl da terminale

Mostrami una guida pratica ai comandi di wpctl per gestire volumi, switch di output e microfoni da riga di comando.

wpctl è il tool di controllo da riga di comando di WirePlumber. Permette di ispezionare l’albero dei nodi multimediali, regolare i volumi e cambiare al volo sorgenti e uscite predefinite senza passare dall’interfaccia grafica.

1. Ispezione dello stato del sistema

Per visualizzare l’elenco dei dispositivi, delle sorgenti (Source) e delle uscite (Sink) con i relativi ID numerici:

Bash

wpctl status

Nell’output, il simbolo * accanto a un ID indica il dispositivo attualmente impostato come predefinito:

Plaintext

Audio
 ├─ Sinks:
 │  *   48. Built-in Audio Analog Stereo        [vol: 0.65]
 │      49. USB Audio DAC Output                [vol: 1.00]
 ├─ Sources:
 │  *   52. Built-in Audio Analog Stereo        [vol: 0.80]

Per ottenere dettagli tecnici completi su un nodo specifico (es. proprietà ALSA, formati supportati):

Bash

wpctl inspect <ID>

2. Gestione del Volume e Mute

I valori di volume in wpctl sono espressi come moltiplicatori decimali (es. 1.0 = 100%, 0.5 = 50%) o in percentuale con il suffisso %. È possibile usare @DEFAULT_AUDIO_SINK@ o @DEFAULT_AUDIO_SOURCE@ come alias invece dell’ID numerico.

AzioneComandoNote
Imposta volume assolutowpctl set-volume @DEFAULT_AUDIO_SINK@ 0.65Imposta l’uscita predefinita al 65%
Aumenta volumewpctl set-volume -l 1.5 @DEFAULT_AUDIO_SINK@ 5%+Aumenta del 5% (limite max 150%)
Abbassa volumewpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-Riduce del 5%
Toggle Mute uscitawpctl set-mute @DEFAULT_AUDIO_SINK@ toggleInverte lo stato (muta / smuta)
Mute esplicitowpctl set-mute @DEFAULT_AUDIO_SINK@ 11 per mutare, 0 per riattivare

Il flag -l <limite> (es. -l 1.5) previene aumenti accidentali oltre la soglia specificata quando si usano incrementi relativi.

3. Gestione del Microfono (Input/Source)

Le stesse operazioni di regolazione e silenziamento si applicano alle sorgenti audio:

Bash

# Imposta il volume del microfono predefinito all'80%
wpctl set-volume @DEFAULT_AUDIO_SOURCE@ 0.80

# Toggle mute del microfono predefinito (ideale per scorciatoie da tastiera)
wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle

# Silenzia esplicitamente il microfono
wpctl set-mute @DEFAULT_AUDIO_SOURCE@ 1

4. Cambio del Dispositivo Predefinito (Switch Output / Input)

Per commutare l’uscita audio o la sorgente del microfono su un altro dispositivo hardware:

  1. Esegui wpctl status per individuare l’ID del dispositivo desiderato.
  2. Imposta l’ID come default:

Bash

# Cambia l'uscita audio predefinita (es. passa alle cuffie o a un DAC USB con ID 49)
wpctl set-default 49

# Cambia il microfono predefinito (es. passa a un microfono USB con ID 55)
wpctl set-default 55

5. Esempi di Scripting e Keybinding

Per integrare wpctl in scorciatoie globali di sistema o script shell, puoi creare comandi a riga singola senza dipendere dagli ID numerici:

Bash

# Script per alzare il volume senza superare il 100%
wpctl set-volume -l 1.0 @DEFAULT_AUDIO_SINK@ 5%+

# Script per abbassare il volume
wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-

# Switch rapido per mutare/riattivare il microfono con feedback visivo/notifica
wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle && notify-send "Microfono" "$(wpctl get-volume @DEFAULT_AUDIO_SOURCE@)"

Scrivi uno script bash che utilizzi wpctl per ciclare a rotazione tra tutti i sink audio di output disponibili.

Questo script esegue il parsing dell’output di wpctl status, individua tutti gli ID dei dispositivi di output (Sinks), rileva quello attualmente predefinito (contrassegnato da *) e imposta il successivo nella lista in modo circolare. Include anche l’invio di una notifica desktop tramite notify-send.

Salva il codice in un file, ad esempio ~/bin/cycle-audio-sinks.sh:

Bash

#!/usr/bin/env bash
set -euo pipefail

# Estrae il blocco 'Sinks:' da wpctl status e raccoglie gli ID
sinks_block=$(wpctl status | sed -n '/Sinks:/,/Sources:/p' | sed '$d')

# Trova tutti gli ID numerici dei sink (escludendo eventuali header)
sink_ids=($(echo "$sinks_block" | grep -oE '[0-9]+\.' | tr -d '.'))

if [ ${#sink_ids[@]} -le 1 ]; then
    echo "Trovati ${#sink_ids[@]} sink disponibili: nessuno switch necessario."
    exit 0
fi

# Individua il sink attualmente attivo (quello con l'asterisco '*')
current_sink=$(echo "$sinks_block" | grep -E '\*\s+[0-9]+\.' | grep -oE '[0-9]+\.' | tr -d '.')

# Calcola l'indice del sink successivo nella lista circolare
next_sink=""
for i in "${!sink_ids[@]}"; do
    if [ "${sink_ids[$i]}" = "$current_sink" ]; then
        next_index=$(( (i + 1) % ${#sink_ids[@]} ))
        next_sink="${sink_ids[$next_index]}"
        break
    fi
done

# Fallback al primo sink se per qualsiasi motivo il default corrente non viene matchato
if [ -z "$next_sink" ]; then
    next_sink="${sink_ids[0]}"
fi

# Imposta il nuovo sink predefinito
wpctl set-default "$next_sink"

# Recupera la descrizione leggibile del nuovo sink per la notifica
sink_name=$(wpctl inspect "$next_sink" | grep -E 'node.description\s*=' | head -n1 | cut -d'"' -f2)
[ -z "$sink_name" ] && sink_name="Sink ID: $next_sink"

# Invia una notifica desktop (se disponibile libnotify)
if command -v notify-send >/dev/null 2>&1; then
    notify-send -t 2000 -a "PipeWire" "Output Audio Cambiato" "$sink_name"
fi

echo "Audio commutato su: $sink_name (ID: $next_sink)"

Installazione e Assegnazione Scorciatoia da Tastiera

  1. Rendi eseguibile lo script:Bashchmod +x ~/bin/cycle-audio-sinks.sh
  2. Assegna una scorciatoia su GNOME:
    • Apri Impostazioni → Tastiera → Visualizza e personalizza le scorciatoie.
    • Scorri fino a Scorciatoie personalizzate e clicca su Aggiungi scorciatoia.
    • Nome: Cicla Output Audio
    • Comando: /home/<tuo-utente>/bin/cycle-audio-sinks.sh (inserisci il percorso assoluto completo)
    • Tasto di scelta rapida: ad esempio Super + F12 o un tasto multimediale dedicato.

Come posso filtrare lo script bash di wpctl per ignorare i sink virtuali o le uscite HDMI non collegate?

Per filtrare i sink non desiderati, è preferibile interrogare i metadati di ciascun nodo tramite wpctl inspect <ID> oppure tramite pw-dump (che fornisce l’albero PipeWire in formato JSON). In questo modo possiamo verificare che:

  1. Il nodo sia hardware reale (api.alsa.path o device.api = "alsa" / device.bus = "usb" / device.bus = "bluetooth").
  2. Non sia un sink virtuale/loopback (escludendo node.virtual = true o stream generati da EasyEffects, OBS, ecc.).
  3. Se si tratta di un’uscita HDMI/DisplayPort, lo switch jack sia effettivamente inserito (alsa.jack = true o availability = "yes"), evitando le porte video senza monitor o casse connesse.

Ecco la versione aggiornata dello script bash che esegue questa validazione su ciascun sink prima di includerlo nel ciclo di rotazione:

Bash

#!/usr/bin/env bash
set -euo pipefail

# Estrae il blocco 'Sinks:' da wpctl status
sinks_block=$(wpctl status | sed -n '/Sinks:/,/Sources:/p' | sed '$d')

# Estrae tutti gli ID grezzi dei sink
raw_sink_ids=($(echo "$sinks_block" | grep -oE '[0-9]+\.' | tr -d '.'))

valid_sinks=()
valid_sink_names=()

# Funzione per validare ciascun sink
is_valid_sink() {
    local id="$1"
    local inspect_out
    inspect_out=$(wpctl inspect "$id" 2>/dev/null) || return 1

    # 1. Esclude nodi esplicitamente virtuali, null-sink o loopback
    if echo "$inspect_out" | grep -qE 'node.virtual\s*=\s*"true"|node.name\s*=\s*".*null-sink.*"|node.name\s*=\s*".*loopback.*"'; then
        return 1
    fi

    # 2. Gestione HDMI / DisplayPort disconnessi
    # Se il driver segnala un jack ALSA non connesso (availability = "no" o stato unplugged)
    if echo "$inspect_out" | grep -iqE 'hdmi|displayport'; then
        if echo "$inspect_out" | grep -qE 'device.connection\s*=\s*"unplugged"|alsa.jack\s*=\s*"false"'; then
            return 1
        fi
    fi

    return 0
}

# Popola l'array dei soli sink validi e attivi
for id in "${raw_sink_ids[@]}"; do
    if is_valid_sink "$id"; then
        valid_sinks+=("$id")
        name=$(wpctl inspect "$id" | grep -E 'node.description\s*=' | head -n1 | cut -d'"' -f2)
        [ -z "$name" ] && name="ID: $id"
        valid_sink_names+=("$name")
    fi
done

if [ ${#valid_sinks[@]} -eq 0 ]; then
    echo "Nessun sink audio valido trovato."
    exit 1
elif [ ${#valid_sinks[@]} -eq 1 ]; then
    echo "Trovato solo 1 sink valido (${valid_sink_names[0]}): switch non necessario."
    exit 0
fi

# Trova il sink attualmente predefinito
current_sink=$(echo "$sinks_block" | grep -E '\*\s+[0-9]+\.' | grep -oE '[0-9]+\.' | tr -d '.' || true)

# Calcola il sink successivo
next_sink=""
next_name=""

for i in "${!valid_sinks[@]}"; do
    if [ "${valid_sinks[$i]}" = "$current_sink" ]; then
        next_index=$(( (i + 1) % ${#valid_sinks[@]} ))
        next_sink="${valid_sinks[$next_index]}"
        next_name="${valid_sink_names[$next_index]}"
        break
    fi
done

# Se il default corrente non era nella lista dei validi, riparte dal primo
if [ -z "$next_sink" ]; then
    next_sink="${valid_sinks[0]}"
    next_name="${valid_sink_names[0]}"
fi

# Imposta il nuovo sink predefinito
wpctl set-default "$next_sink"

# Notifica desktop
if command -v notify-send >/dev/null 2>&1; then
    notify-send -t 2000 -a "PipeWire" "Output Audio Commutato" "$next_name"
fi

echo "Audio commutato su: $next_name (ID: $next_sink)"

Personalizzazione dei filtri (opzionale)

Se utilizzi plugin specifici come EasyEffects, NoiseTorch o ponti JACK e desideri escluderli esplicitamente per nome, puoi aggiungere pattern aggiuntivi al check dei nodi virtuali:

Bash

if echo "$inspect_out" | grep -qE 'node.name\s*=\s*".*easyeffects.*"|node.name\s*=\s*".*noisetorch.*"'; then
    return 1
fi

E si può creare un flusso audio attraverso il network tra due sistemi Ubuntu 26.04 ?

Sì, su Ubuntu 26.04 LTS questo si realizza nativamente sfruttando l’architettura di PipeWire.

Esistono due approcci principali:

  1. PipeWire Nativo (Modulo RAOP / Roc / Network Pulse): il modo più diretto e moderno tramite i moduli di PipeWire.
  2. Tunneling PipeWire-Pulse (TCP): sfrutta l’emulatore pipewire-pulse per mantenere la massima compatibilità e immediatezza di configurazione via comandi standard.

Metodo 1: Modulo Tunneling PipeWire-Pulse (TCP Diretto)

In questo schema, il Ricevitore (PC B – Casse) apre la porta TCP di PipeWire-Pulse, e il Trasmettitore (PC A – Sorgente) crea un tunnel sink verso l’IP del ricevitore.

1. Sul PC Ricevitore (es. IP 192.168.1.50): Abilita l’ascolto di connessioni di rete sul demone pipewire-pulse dell’utente:

Bash

pactl load-module module-native-protocol-tcp auth-ip-acl=127.0.0.1;192.168.1.0/24 auth-anonymous=1

(Se il firewall ufw è attivo sul ricevitore, apri la porta 4713: sudo ufw allow from 192.168.1.0/24 to any port 4713 proto tcp).

2. Sul PC Trasmettitore: Carica il modulo tunnel puntando all’indirizzo IP del ricevitore:

Bash

pactl load-module module-tunnel-sink server=192.168.1.50 sink_name=Remote_2604

Una volta caricato, il nuovo sink remoto comparirà tra le uscite audio:

  • Puoi verificarlo con wpctl status.
  • Puoi impostarlo come predefinito con wpctl set-default <ID_DEL_SINK_REMOTO> oppure selezionarlo graficamente dalle impostazioni audio di GNOME.

Metodo 2: Streaming Real-time a Bassissima Latenza con ROC / RTP (Nativo PipeWire)

PipeWire include moduli nativi per lo streaming in tempo reale sul network basati sulla libreria ROC Toolkit (progettata specificamente per audio di rete trasparente a perdita di pacchetti) o su RTP/SAP.

Per attivare uno stream nativo PipeWire RTP/AVB senza passare da Pulse:

  • Sul PC Trasmettitore:Bashpw-cli load-module libpipewire-module-rtp-source '{ destination.ip = "224.0.0.56" destination.port = 46998 }'
  • Sul PC Ricevitore:Bashpw-cli load-module libpipewire-module-rtp-sink '{ listen.ip = "224.0.0.56" listen.port = 46998 }'

Rendere la configurazione persistente su Ubuntu 26.04

Poiché in Ubuntu 26.04 i servizi multimediali sono gestiti da systemd a livello utente (systemd --user), per rendere persistente l’ascolto o il tunnel TCP senza dover rieseguire i comandi:

  1. Crea la directory di override per PipeWire:Bashmkdir -p ~/.config/pipewire/pipewire-pulse.conf.d/
  2. Crea un file ~/.config/pipewire/pipewire-pulse.conf.d/network.conf contenente:Snippet di codicepulse.cmd = [ { cmd = "load-module" args = "module-native-protocol-tcp auth-ip-acl=127.0.0.1;192.168.1.0/24 auth-anonymous=1" } ]
  3. Riavvia il servizio utente:Bashsystemctl --user restart pipewire-pulse

Vuoi configurare l’autenticazione sicura o la sincronizzazione multistanza con PipeWire?Sì

Come posso impostare l’autenticazione sicura e la sincronizzazione di clock a bassa latenza su una rete locale con PipeWire tra due macchine Ubuntu 26.04?

Per ottenere autenticazione sicura (evitando flag aperti come auth-anonymous=1) e sincronizzazione temporale deterministica a bassa latenza tra due macchine Ubuntu 26.04, l’architettura ideale prevede:

  1. Sincronizzazione di clock a livello hardware/rete (PTP/NTP) per prevenire drift e resampling audio.
  2. Streaming a bassissima latenza con ROC Toolkit o PTP-RTP nativo in PipeWire.
  3. Autenticazione crittografica e isolamento di rete tramite chiave condivisa (Cookie) o tunnel crittografato (WireGuard).

1. Sincronizzazione Temporale Hardware (PTP / Precision Time Protocol)

Quando si trasmettono flussi PCM grezzi tra due nodi senza accumulo di buffer, il disallineamento dei clock interni dei DAC provoca underrun, overrun e micro-scatti.

Installa e avvia linuxptp per sincronizzare i clock di sistema con precisione sub-microsecondo nella LAN:

Bash

sudo apt install linuxptp
  • Sul nodo principale (Master Clock – es. interfaccia eth0):Bashsudo ptp4l -i eth0 -m
  • Sul nodo secondario (Slave Clock):Bashsudo ptp4l -i eth0 -s -m # Sincronizza il clock del sistema operativo (CLOCK_REALTIME) con il clock PTP hardware: sudo phc2sys -a -r -m

2. Streaming a Bassa Latenza con ROC Toolkit in PipeWire

Il toolkit ROC (libpipewire-module-roc-*) è progettato specificamente per lo streaming audio in tempo reale su rete non garantita: include Forward Error Correction (Reed-Solomon) per tollerare pacchetti persi senza richiedere re-invii TCP, mantenendo la latenza al minimo (5–15 ms).

Installa i moduli necessari:

Bash

sudo apt install pipewire-module-roc libroc-dev

Configurazione Ricevitore (Sink – es. IP 192.168.1.50):

Crea ~/.config/pipewire/pipewire.conf.d/roc-sink.conf:

Snippet di codice

context.modules = [
    {   name = libpipewire-module-roc-sink
        args = {
            fec.code = "rs8m"
            local.ip = "0.0.0.0"
            local.source.port = 10001
            local.repair.port = 10002
            local.control.port = 10003
            sink.name = "ROC_Remote_Sink"
            sink.props = {
                node.description = "Altoparlanti Remoti (ROC HD)"
                media.class = "Audio/Sink"
            }
        }
    }
]

Configurazione Trasmettitore (Source):

Crea ~/.config/pipewire/pipewire.conf.d/roc-source.conf:

Snippet di codice

context.modules = [
    {   name = libpipewire-module-roc-source
        args = {
            fec.code = "rs8m"
            remote.ip = "192.168.1.50"
            remote.source.port = 10001
            remote.repair.port = 10002
            remote.control.port = 10003
            node.name = "ROC_Source_Out"
            node.props = {
                node.description = "Stream Remoto ROC"
                media.class = "Audio/Sink"
            }
        }
    }
]

Riavvia PipeWire su entrambi i nodi:

Bash

systemctl --user restart pipewire

3. Autenticazione e Sicurezza di Rete

I protocolli audio in tempo reale basati su UDP (RTP, ROC) non includono handshake TLS nativi per evitare overhead sul campionamento. La sicurezza si implementa a due livelli:

Opzione A: Autenticazione tramite Cookie di Sicurezza (per pipewire-pulse)

Se usi il protocollo TCP di PulseAudio/PipeWire:

  1. Genera un cookie crittografico binario a 256-bit sul Master:Bashdd if=/dev/urandom of=~/.config/pipewire/audio.cookie bs=256 count=1
  2. Copia in modo sicuro il file sulla macchina client via scp:Bashscp ~/.config/pipewire/audio.cookie utente@192.168.1.51:~/.config/pipewire/audio.cookie
  3. Configura il ricevitore senza auth-anonymous=1:Bashpactl load-module module-native-protocol-tcp auth-ip-acl=192.168.1.0/24 auth-cookie=/home/<utente>/.config/pipewire/audio.cookie

Opzione B: Tunnel Crittografato WireGuard (Consigliato per ROC / RTP)

Per incapsulare i pacchetti UDP di ROC in un canale con crittografia ChaCha20-Poly1305 a livello kernel senza impattare la latenza:

  1. Crea un’interfaccia WireGuard punto-punto (wg0) tra le due macchine (es. 10.10.0.1 e 10.10.0.2).
  2. Imposta local.ip = "10.10.0.1" e remote.ip = "10.10.0.1" nelle rispettive configurazioni PipeWire ROC.
  3. Blocca con il firewall ufw qualsiasi traffico verso le porte 10001–10003 che non provenga dall’interfaccia wg0.