Come cambiare il sink di pulseaudio con "pacmd set-default-sink" durante la riproduzione?


55

Devo cambiare il server pulseaudio di un flusso audio attualmente in riproduzione.

Il server Pulseaudio è configurato con IP 192.168.1.105

$>cat /etc/pulse/default.pa
...
load-module module-esound-protocol-tcp auth-anonymous=1
load-module module-native-protocol-tcp auth-anonymous=1
load-module module-zeroconf-publish
...

Sul lato sorgente VLC media player sta riproducendo una canzone.

Ho creato un nuovo sink di tunnel con pulseaudio sul lato sorgente.

pacmd load-module module-tunnel-sink server=192.168.1.105
pacmd set-default-sink 1

Ma durante la riproduzione audio il server non può essere modificato immediatamente. Solo dopo aver fermato il giocatore e riprodotto, va bene.

Da "gnome-volume-control" o "gnome-control-center sound" la commutazione dei dispositivi di uscita viene immediatamente applicata.

Come posso applicare la commutazione immediata del sink di output dalla riga di comando durante la riproduzione di un file audio?

Risposte:


83

PulseAudio pacmdnon è in grado di commutare i sink predefiniti mentre è presente un flusso in riproduzione attiva sull'ingresso sink. Tuttavia, c'è ancora un modo per raggiungere questo obiettivo.

Modifica del sink predefinito dalla riga di comando

Innanzitutto dobbiamo determinare il numero di indice dei lavandini che vogliamo cambiare. Questo può essere fatto chiamando:

pacmd list-sinks

A seconda del nostro sistema, questo ti fornirà un elenco più o meno lungo di lavandini e proprietà attualmente accessibili:

 >>> 2 sink(s) available.
      * index: 0
            name: <alsa_output.pci-0000_01_00.1.hdmi-stereo-extra1>
            driver: <module-alsa-card.c>
    :
    :
        index: 1
            name: <alsa_output.pci-0000_00_14.2.analog-stereo>
            driver: <module-alsa-card.c>

Il indexo il namedato qui è ciò di cui abbiamo bisogno per indirizzare il sink dalla riga di comando. L'attuale lavandino predefinito è contrassegnato da un asterisco (qui 0).

Per poter cambiare i sink predefiniti dalla riga di comando, potrebbe essere necessario disabilitare il ripristino del dispositivo di destinazione dello stream modificando la riga corrispondente in /etc/pulse/default.pa:

load-module module-stream-restore restore_device=false

1Quindi, per modificare il sink di output predefinito in sink, eseguiamo

pacmd set-default-sink 1

Il successo può essere visualizzato aprendo il menu Impostazioni audio .

Spostamento di un flusso su un altro lavandino

La modifica del sink predefinito mentre è attivo un flusso di input in riproduzione su un determinato sink non ha alcun effetto . Questo dovrebbe piuttosto essere fatto spostando questo input su un altro sink.

pacmd list-sink-inputs

ci dirà l'indice del flusso di input

>>> 1 sink input(s) available.
    index: 5
    driver: <protocol-native.c>

Ora sappiamo che vogliamo spostare il flusso di input 5per affondare 1chiamando

pacmd move-sink-input 5 1

o torna ad affondare 0se ci piace. Ciò verrà fatto immediatamente senza la necessità di interrompere la riproduzione.

Modifica del sink predefinito durante la riproduzione

Naturalmente possiamo combinare questi due comandi per cambiare immediatamente i sink di default durante la riproduzione, ad es. Con

pacmd set-default-sink 1 & pacmd move-sink-input 5 1

Uno svantaggio di questo metodo è che l' indice del flusso di input cambia ogni volta che ci fermiamo e riavviamo il lettore musicale. Quindi dobbiamo sempre scoprire l'indice di flusso corrente prima di poter cambiare utilizzando la linea di comando.


Puoi fare riferimento a un lavandino tramite il suo indice O con il suo nome pactl list short sinks> 4 bluez_sink.FC_A8_9A_2C_EB_0B module-bluez5-device.c s16le 1ch 8000Hz IDLEora fai solo riferimento al nomepactl set-default-sink bluez_sink.FC_A8_9A_2C_EB_0B
Leif Liddy

@LeifLiddy: grazie per la nota. Nelle versioni più recenti di Pulseaudio puoi effettivamente fare riferimento al nome di un sink attivo, set-default-sinkma avrai comunque bisogno del numero di indice attivo move-sink-input.
Takkat,

E se 0 sink input(s) available.? Ma quel flash player di merda sta ancora riproducendo l'audio?
Zhigalin,

E vedo flash player nella client(s) logged insezione dipacmd list
Zhigalin

@Zhigalin Flash è morto da molto tempo sui miei sistemi, quindi non posso dirlo ... potrebbe suonare direttamente tramite ALSA.
Takkat,

27

Ho scritto un semplice script per spostare automaticamente tutti gli input del sink.

Uso: ./movesinks.sh <sink number>

#!/bin/bash 
echo "Setting default sink to: $1";
pacmd set-default-sink $1
pacmd list-sink-inputs | grep index | while read line
do
echo "Moving input: ";
echo $line | cut -f2 -d' ';
echo "to sink: $1";
pacmd move-sink-input `echo $line | cut -f2 -d' '` $1

done

1
Eccezionale! L'ho esteso un po 'di più per il mio uso personale: volevo un'icona sulla mia barra delle applicazioni che potesse alternare tra due schede audio. Ho scritto un piccolo script in Ruby per determinare l'attuale sink e chiamare questo script della shell per apportare la modifica ( pastebin.com/xb3i2ejW ). Successivamente, ho inserito entrambi gli script in ~ / bin e ho personalizzato un'icona di KDE per eseguire lo script ruby. Questo potrebbe essere fatto in modo più elegante, o interamente in script shell, ma funziona per me.
Pathogen,

2
Grazie per questo. Ecco una versione che passa all'ultimo (? - ne ho solo due) output inutilizzato: pastebin.com/raw/sidH7QPb ovvero attiva / disattiva l'output, adatto per il mapping a un tasto di scelta rapida.
Julian

4

Versione migliorata dello script @Gaco

#!/usr/bin/env bash

case "${1:-}" in
  (""|list)
    pacmd list-sinks |
      grep -E 'index:|name:'
    ;;
  ([0-9]*)
    echo switching default
    pacmd set-default-sink $1 ||
      echo failed
    echo switching applications
    pacmd list-sink-inputs |
      awk '/index:/{print $2}' |
      xargs -r -I{} pacmd move-sink-input {} $1 ||
        echo failed
    ;;
  (*)
    echo "Usage: $0 [|list|<sink name to switch to>]"
    ;;
esac

la mia copia di runtime è su github e include anche la commutazione automatica del canale principale perkmix



2

Ho messo insieme cose da diversi posti e ho creato questo script per creare un JAMBOX bluetooth una volta che è stato accoppiato. Il tuo MAC sarà diverso ovviamente. Dal momento che controllo il volume JAMBOX tramite l'app Clementine, nel mio caso il volume del 130% funziona meglio. Potresti voler cambiare questo, insieme a rhythmbox.png (era l'unica immagine dell'altoparlante che ho trovato sul mio computer). Il controllo degli errori è rudimentale, ma funziona in modo abbastanza affidabile. L'ho messo in un desktop launcher per comodità su un netbook ASUS.

#!/bin/bash
# setjambox connection setup
# Find the particulars of your environment with 'pactl list sinks'
# This script uses the sink name instead of the index number
# You also need libnotify-bin to run this script

# Enter the bluetooth MAC address of your device here
MAC=00:21:3C:9F:19:AD

# Make ready
# Convert device address per pulseaudio standards
DEV=$(echo $MAC|tr ':' '_')
TITLE="JAMBOX $MAC"
CONNECTED="Audio connection updated."
PROBLEM="Unable to update settings."
JBLOGO=/usr/share/icons/hicolor/48x48/apps/rhythmbox.png

# And go

pactl list short sink-inputs | while read stream; do
    streamId=$(echo $stream | cut '-d ' -f1)
    pactl move-sink-input "$streamId" bluez_sink.$DEV
done

pactl set-default-sink bluez_sink.$DEV
pactl set-card-profile bluez_card.$DEV a2dp
pactl set-sink-volume  bluez_sink.$DEV 130%

if [ $? -eq 0 ]
then
   notify-send -i $JBLOGO -t 3000 "$TITLE" "$CONNECTED" 
else
   notify-send -i gtk-dialog-warning -t 3000 "$TITLE" "$PROBLEM"
fi

+1 per l'utilizzo pactl list short. Puoi semplificare la seguente riga eseguendo il taglio direttamente dopo: pactl list short sink-inputs | cut -f1 | while read streamIdfunziona per me.
bodo,

1

LAVELLI CIRCLE-TOGGLE.

Lo script Gaco con solo un'altra riga per passare da un lavandino all'altro al cerchio.

#!/bin/bash 

new_sink=$(pacmd list-sinks | grep index | tee /dev/stdout | grep -m1 -A1 "* index" | tail -1 | cut -c12-)

echo "Setting default sink to: $new_sink";
pacmd set-default-sink $new_sink
pacmd list-sink-inputs | grep index | while read line
do
echo "Moving input: ";
echo $line | cut -f2 -d' ';
echo "to sink: $new_sink";
pacmd move-sink-input `echo $line | cut -f2 -d' '` $new_sink

done

ottimo, semplice e ridimensionante!
Paul Bastian,

1

Ed ecco uno script che commuta anche tra i lavandini:

http://marginalhacks.com/index.0.html#pulse-switch-out

Ecco lo script qui sotto:

#!/usr/bin/ruby
# Filename: pulse-switch-out
# Author:   David Ljung Madison <DaveSource.com>
# See License:  http://MarginalHacks.com/License/
# Description:  Switch pulse audio output (sink) using pacmd

PACMD = %w(pacmd)

##################################################
# Usage
##################################################
def fatal(*msg)
    msg.each { |m| $stderr.puts "[#{$0.sub(/.*\//,'')}] ERROR: #{m}" }
    exit(-1);
end

def usage(*msg)
    msg.each { |m| $stderr.puts "ERROR: #{m}" }
    $stderr.puts <<-USAGE

Usage:  #{$0.sub(/.*\//,'')} [sink]
  Switch sound playback device for ALSA/pulseaudio

    [sink]   Specify sink number to use (see 'pacmd list-sinks')

    USAGE
    exit -1;
end

def parseArgs
    opt = Hash.new
    loop {
        if (arg=ARGV.shift)==nil then break
        elsif arg == '-h' then usage
        elsif arg == '-?' then usage
        #elsif arg == '-arg' then opt[:arg] = true
        elsif arg =~ /^(\d)$/ then opt[:sink] = arg.to_i
        else
            usage("Unknown arg [#{arg}]")
        end
    }

    opt
end

# Unfortunately you can't return or break from the yield without leaving
# the pipe open, maybe use some sort of ensure and figure out how to close?
def pipe(cmd)
        # This is leaving files open
    #IO.popen(cmd.join(' ')).each { |l|
    a = `#{cmd.join(' ')}`
    ret = $?
    a.split("\n").each { |l|
        yield l
    }
    $?
end

def getSinks(ins=false)
    cmd = PACMD.dup
    cmd.push(ins ? 'list-sink-inputs' : 'list-sinks')
    curr = nil
    sinks = Array.new
    pipe(cmd) { |l|
        next unless l=~/\s*(\*)?\s*index:\s+(\d+)/
        i = $2.to_i
        sinks.push(i)
        curr = i if $1
    }
    return sinks,curr
end

##################################################
# Main code
##################################################
def main
    opt = parseArgs

    sinks,curr = getSinks

    usage("No sinks found?") if sinks.empty?
    usage("Only one sink found") if sinks.size==1

    if opt[:sink]
        usage("Unknown sink [#{opt[:sink]}] (out of #{sinks.join(' ')})") unless sinks.index(opt[:sink])
    else
        # Find next sink after curr
        opt[:sink] = sinks[0]
        sinks.each { |s|
            next unless s>curr
            opt[:sink] = s
            break
        }
    end

    # Set default sink
## For some reason this doesn't change the behavior of new apps.
    puts "Set sink: #{opt[:sink]}"
    system("#{PACMD} set-default-sink #{opt[:sink]} > /dev/null")
    usage("Couldn't set default sink [#{opt[:sink]}]") unless $?==0

    # And move all sink-inputs to the new sink
    ins,ignore = getSinks(true)
    ins.each { |i|
        puts "Move playback #{i} to sink #{opt[:sink]}"
        system("#{PACMD} move-sink-input #{i} #{opt[:sink]} > /dev/null")
        usage("Couldn't move playback #{i} to sink [#{opt[:sink]}]") unless $?==0
    }
end
main

1
Benvenuti in Ask Ubuntu! Sebbene ciò possa teoricamente rispondere alla domanda, sarebbe preferibile includere qui le parti essenziali della risposta e fornire il collegamento come riferimento.
ζ--

Fatto, anche se sfortunatamente questo significa che lo script non viene aggiornato qui se non ricordo che è qui. Ad esempio, ruby ​​ha cambiato il modo in cui gestisce .each per le stringhe (nella parte backtick), quindi ho dovuto aggiornare la riga 53 sopra. Oppure scarica semplicemente lo script per assicurarti che sia aggiornato.
David Ljung Madison Stellar

1

Sulla base della risposta di Gaco, l'ho riscritta un po 'per uso personale. Forse qualcuno lo trova utile. Serve per attivare gli altoparlanti USB e l'auricolare per giochi USB.

#!/bin/bash

# get list of sinks/cards (for settings CARD1/CARD2)
# pacmd list-sinks | awk '/name:/ {print $0};' | awk '{ print $2}' | sed 's/<//g; s/>//g'

CARD1="alsa_output.usb-C-Media_INC._C-Media_USB_Audio-00"
CARD2="alsa_output.usb-Kingston_HyperX_Virtual_Surround_Sound_00000000-00"

CURRENT_SINK=$(pacmd stat | awk -F": " '/^Default sink name: /{print $2}' | awk 'BEGIN{FS=OFS="."} NF--' | sed 's/alsa_output/alsa_output/g')


function setCard() {

  if [ "$CURRENT_SINK" == "$1" ]
   then
     echo "Already using this Sink"
     exit 1
  fi

  NEW_SINK=$(pacmd list-sinks | awk '/index:/ {print $1 $2 $3} /name:/ {print $0};' | grep -m1 -B1 $1 | grep index | awk '{print $1}' | cut -d ":" -f2)
  SINK=$(pacmd set-default-sink $NEW_SINK)
  INPUT=$(pacmd list-sink-inputs | grep index | awk '{print $2}')

  pacmd move-sink-input $INPUT $NEW_SINK
  echo "Moving input: $INPUT to sink: $NEW_SINK";
  echo "Setting default sink to: $NEW_SINK";

  notify-send --urgency=low "Audio Switching" "SINK: $NEW_SINK"
}

function toggleSinks() {
  if [ "$CURRENT_SINK" == "$CARD1" ]
    then
      setCard $CARD2
    else
      setCard $CARD1
    fi
}


function showHelp() {
  echo "------------------------------------"
  echo "AUDIO SINK SWITCHER"
  echo " "
  echo "$0 [options]"
  echo " "
  echo "options:"
  echo "-h  --help        What you are looking at.."
  echo "-g, --gaming      Sets Gaming headset as output device"
  echo "-s, --speakers    Sets Speakers as output device"
  echo "-t, --toggle      Toggles the different output devices"
  echo " "
  echo "------------------------------------"
}

# check args length
if [ $# -eq 0 ]
  then
    echo "Toggling output devices (Speakers/Headset)"
    toggleSinks
fi


# arg options
while test $# -gt 0; do
    case "$1" in

                -h|--help)
                        showHelp
                        exit 1
                        ;;

                -g|--gaming)
                        setCard $CARD2
                        exit 1
                        ;;

                -s|--speakers)
                        setCard $CARD1
                        exit 1
                        ;;

                -t|--toggle)
                        toggleSinks
                        echo "Toggling output devices (Speakers/Headset)"
                        exit 1
                        ;;
                 *)
                        showHelp
                        exit 1
                        ;;
    esac
done

0

Penso che ci sia un'altra opzione degna di nota ed è disponibile sulla pagina ufficiale per le FAQ su PulseAudio su freedesktop.org . Con il seguente titolo:

Come posso cambiare la scheda audio predefinita, spostando tutte le applicazioni?

Forniscono il seguente script per farlo:

#/bin/bash
# paswitch 2011-02-02 by Ng Oon-Ee <ngoonee@gmail.com>
# I can't remember where I found this script, can't locate the original author.
# Please inform me if you know, so that I can give proper attribution.
# CHANGES: Added auto-move all inputs to new default sound card.
# WAS: Pulse Audio Sound Card Switcher v1.0 2010-01-13
#   Switches between soundcards when run. All streams are moved to the new default sound-card.

# $totalsc: Number of sound cards available
totalsc=$(pacmd "list-sinks" | grep card: | wc -l) # total of sound cards: $totalsc
if [ $totalsc -le 1 ]; then # Check whether there are actually multiple cards available
  notify-send -u critical -t 5000 "Nothing to switch, system only has one sound card."
  exit
fi
# $scindex: The Pulseaudio index of the current default sound card
scindex=$(pacmd list-sinks | awk '$1 == "*" && $2 == "index:" {print $3}')
# $cards: A list of card Pulseaudio indexes
cards=$(pacmd list-sinks | sed 's|*||' | awk '$1 == "index:" {print $2}')
PICKNEXTCARD=1 # Is true when the previous card is default
count=0 # count of number of iterations
for CARD in $cards; do
  if [ $PICKNEXTCARD == 1 ]; then
# $nextsc: The pulseaudio index of the next sound card (to be switched to)
    nextsc=$CARD
    PICKNEXTCARD=0
# $nextind: The numerical index (1 to totalsc) of the next card
    nextind=$count
  fi
  if [ $CARD == $scindex ]; then # Choose the next card as default
    PICKNEXTCARD=1
  fi
  count=$((count+1))
done
pacmd "set-default-sink $nextsc" # switch default sound card to next

# $inputs: A list of currently playing inputs
inputs=$(pacmd list-sink-inputs | awk '$1 == "index:" {print $2}')
for INPUT in $inputs; do # Move all current inputs to the new default sound card
  pacmd move-sink-input $INPUT $nextsc
done
# $nextscdec: The device.description of the new default sound card
# NOTE: This is the most likely thing to break in future, the awk lines may need playing around with
nextscdesc=$(pacmd list-sinks | awk '$1 == "device.description" {print substr($0,5+length($1 $2))}' \
                         | sed 's|"||g' | awk -F"," 'NR==v1{print$0}' v1=$((nextind+1)))
notify-send "Default sound-card changed to $nextscdesc"
exit
# Below text was from original author and remains unaltered
# CC BY - creative commons
# Thanks God for help :) and guys lhunath, geirha, Tramp and others from irc #bash on freenode.net

0

Ho adattato @mpapis a un semplice "toggle sink0 o sink1" durante l'esecuzione:

#!/bin/bash
SINK_INDEX1=0
SINK_INDEX2=1
ACTIVE_SINK=$(pacmd list-sinks | grep '* index:' | grep -o '[0-9]*')
if [ "$ACTIVE_SINK" = $SINK_INDEX1 ] ; then
    pacmd set-default-sink $SINK_INDEX2
    pacmd list-sink-inputs | awk '/index:/{print $2}' | xargs -r -I{} pacmd move-sink-input {} $SINK_INDEX2
else 
    pacmd set-default-sink $SINK_INDEX1
    pacmd list-sink-inputs | awk '/index:/{print $2}' | xargs -r -I{} pacmd move-sink-input {} $SINK_INDEX1
fi
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.