¿Cómo cambiar pulseaudio sink con "pacmd set-default-sink" durante la reproducción?

55

Necesito cambiar el servidor pulseaudio de una transmisión de audio que se está reproduciendo actualmente.

El servidor Pulseaudio está configurado 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
...

En el lado de la fuente, el reproductor multimedia VLC está reproduciendo una canción.

Creé un nuevo túnel de sumidero con pulseaudio en el lado de la fuente.

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

Pero mientras se reproduce audio, el servidor no se puede cambiar de inmediato. Solo después de detener al jugador y volver a jugar, está bien.

Desde "gnome-volume-control" o "gnome-control-center sound", la conmutación de dispositivos de salida se aplica inmediatamente.

¿Cómo puedo aplicar el cambio del receptor de salida inmediatamente desde la línea de comandos durante la reproducción de un archivo de sonido?

wasakwasak
fuente

Respuestas:

83

PulseAudio pacmdno es capaz de cambiar los sumideros predeterminados mientras hay una transmisión activa en la entrada del sumidero. Sin embargo, todavía hay una manera de lograr esto.

Cambiar el sumidero predeterminado desde la línea de comando

Primero necesitamos determinar el número de índice de los sumideros que queremos cambiar. Esto se puede hacer llamando a:

pacmd list-sinks

Dependiendo de nuestro sistema, esto le dará una lista más o menos extensa de sumideros y propiedades a las que actualmente se puede acceder:

 >>> 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>

El indexo el namedado aquí es lo que necesitamos para abordar el sumidero por línea de comando. El sumidero predeterminado actual está marcado con un asterisco (aquí 0).

Para poder cambiar los sumideros predeterminados desde la línea de comando, es posible que necesitemos desactivar la restauración del dispositivo de destino de la transmisión editando la línea correspondiente en /etc/pulse/default.pa:

load-module module-stream-restore restore_device=false

Para cambiar el sumidero de salida predeterminado a sumidero 1, ejecutamos

pacmd set-default-sink 1

El éxito se puede visualizar abriendo el menú Configuración de sonido .

Mover una corriente a otro sumidero

Cambiar el sumidero predeterminado mientras tenemos una transmisión de entrada activa que se reproduce en un sumidero dado no tiene ningún efecto . Esto debería hacerse moviendo esta entrada a otro sumidero.

pacmd list-sink-inputs

nos dirá el índice de la secuencia de entrada

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

Ahora sabemos que queremos mover el flujo de entrada 5al receptor 1llamando

pacmd move-sink-input 5 1

o volver a hundirse 0si nos gusta. Esto se realizará de inmediato sin necesidad de detener la reproducción.

Cambiar el sumidero predeterminado mientras se juega

Por supuesto, podemos combinar esos dos comandos para cambiar inmediatamente los sumideros predeterminados durante la reproducción, por ejemplo, con

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

Un inconveniente de este método es que el índice de flujo de entrada cambia cada vez que detenemos y reiniciamos el reproductor de música. Por lo tanto, siempre tenemos que encontrar el índice de flujo actual antes de poder cambiar usando la línea de comando.

Takkat
fuente
Puede hacer referencia a un sumidero por su índice O por su nombre pactl list short sinks> 4 bluez_sink.FC_A8_9A_2C_EB_0B module-bluez5-device.c s16le 1ch 8000Hz IDLEahora solo haga referencia al nombrepactl set-default-sink bluez_sink.FC_A8_9A_2C_EB_0B
Leif Liddy
@LeifLiddy: Gracias por la nota. En las versiones más recientes de Pulseaudio, puede hacer referencia al nombre de un sumidero set-default-sinkpero aún necesitará el número de índice activado move-sink-input.
Takkat
¿Y si 0 sink input(s) available.? ¿Pero ese flash player de mierda todavía reproduce audio?
Zhigalin
Y veo flash player en la client(s) logged insección depacmd list
Zhigalin
@Zhigalin Flash está muerto desde hace mucho tiempo en mis sistemas, así que no puedo decir que ... puede jugar directamente a través de ALSA.
Takkat
27

He escrito un script simple para mover todas las entradas de sumidero automáticamente.

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
Gaco
fuente
1
¡Increíble! Extendí esto un poco más para mi propio uso: quería un icono en mi barra de tareas que alternara entre dos tarjetas de audio. Escribí un pequeño script en Ruby para determinar el sumidero actual y llamo a este script de shell para realizar el cambio ( pastebin.com/xb3i2ejW ). Después de eso, puse ambos scripts en ~ / bin y personalicé un icono de KDE para ejecutar el script ruby. Esto podría hacerse de manera más elegante, o completamente en shell script, pero funciona para mí.
Patógeno el
2
Gracias por esto. Aquí hay una versión que cambia a la última salida (? - Solo tengo dos) sin usar: pastebin.com/raw/sidH7QPb, es decir, alterna la salida, adecuada para asignar a una tecla de acceso rápido.
Julian
4

Versión mejorada del 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

mi copia de tiempo de ejecución está en github e incluye también el cambio automático de canal maestro parakmix

mpapis
fuente
2

Creé cosas de diferentes lugares y se me ocurrió este script para configurar un JAMBOX bluetooth una vez que se ha emparejado. Tu MAC será diferente, por supuesto. Como controlo el volumen JAMBOX a través de la aplicación Clementine, el 130% del volumen funciona mejor en mi caso. Es posible que desee cambiar esto, junto con el rhythmbox.png (fue la única imagen de altavoz que pude encontrar en mi computadora). La comprobación de errores es rudimentaria, pero funciona de manera bastante confiable. Puse esto en un iniciador de escritorio para mayor comodidad en 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
Rayo M
fuente
+1 por usar pactl list short. Puede simplificar la siguiente línea haciendo el corte directamente después: pactl list short sink-inputs | cut -f1 | while read streamIdfunciona para mí.
bodo
1

FREGADEROS DE CÍRCULO.

El script Gaco con solo una línea más para alternar en círculo a través de los sumideros disponibles.

#!/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
usuario512557
fuente
genial, simple y escalable!
Paul Bastian
1

Y aquí hay un script que también alternará entre sumideros:

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

Aquí está el script a continuación:

#!/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
David Ljung Madison Stellar
fuente
1
Bienvenido a Ask Ubuntu! Si bien esto puede responder teóricamente la pregunta, sería preferible incluir aquí las partes esenciales de la respuesta y proporcionar el enlace para referencia.
ζ--
Hecho, aunque desafortunadamente esto significa que el script no se actualiza aquí a menos que recuerde que está aquí. Como ejemplo, ruby ​​cambió la forma en que maneja cada una de las cadenas (en la parte de retroceso), por lo que necesitaba actualizar la línea 53 anterior. O simplemente descargue el script para asegurarse de que esté actualizado.
David Ljung Madison Stellar
1

Basado en la respuesta de Gaco, lo reescribí un poco para mi uso personal. Quizás alguien lo encuentre útil. Es para alternar mis altavoces USB y auriculares USB Gaming.

#!/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
Ole Algoritme
fuente
0

Creo que hay una opción más que vale la pena mencionar y está disponible en la página oficial de preguntas frecuentes sobre PulseAudio en freedesktop.org . Bajo el siguiente título:

¿Cómo cambio la tarjeta de sonido predeterminada, moviendo todas las aplicaciones?

Proporcionan el siguiente script para hacerlo:

#/bin/bash
# paswitch 2011-02-02 by Ng Oon-Ee <[email protected]>
# 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
Doron Behar
fuente
0

Adapté @mpapis a un simple "alternar sink0 o sink1" cuando se ejecutó:

#!/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
OCP001
fuente