Jak zmienić zlew pulseaudio z „pacmd set-default-sink” podczas odtwarzania?

55

Muszę przełączyć serwer pulseaudio aktualnie odtwarzanego strumienia audio.

Serwer Pulseaudio ma 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
...

Po stronie źródłowej odtwarzacz multimedialny VLC odtwarza utwór.

Stworzyłem nowy zlew tunelowy z pulseaudio po stronie źródła.

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

Ale podczas odtwarzania dźwięku nie można było zmienić serwera natychmiast. Dopiero po zatrzymaniu odtwarzacza i powtórce wszystko jest w porządku.

Z „gnome-volume-control” lub „gnome-control-sound sound” następuje natychmiastowe przełączenie urządzeń wyjściowych.

Jak zastosować przełączanie ujścia wyjściowego natychmiast z wiersza poleceń podczas odtwarzania pliku dźwiękowego?

wasakwasak
źródło

Odpowiedzi:

83

PulseAudio pacmdnie jest w stanie przełączać domyślnych odbiorników, gdy na wejściu odbiornika aktywnie odtwarzany jest strumień. Istnieje jednak sposób, aby to osiągnąć.

Zmiana domyślnego ujścia z wiersza poleceń

Najpierw musimy ustalić numer indeksu zlewów, które chcemy przełączyć. Można to zrobić dzwoniąc:

pacmd list-sinks

W zależności od naszego systemu daje to mniej lub bardziej długą listę zlewów i właściwości, które są obecnie dostępne:

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

indexLub namepodany tutaj jest to, czego potrzebujemy dla Adresowanie zlewu poprzez linię poleceń. Obecny domyślny zlew jest oznaczony gwiazdką (tutaj 0).

Aby móc przełączyć domyślne ujścia z wiersza polecenia, może być konieczne wyłączenie przywracania urządzenia docelowego strumienia poprzez edycję wiersza odpowiadającego w /etc/pulse/default.pa:

load-module module-stream-restore restore_device=false

Aby zmienić domyślny zlew wyjściowy na zlew 1, uruchamiamy

pacmd set-default-sink 1

Sukces można zwizualizować, otwierając menu Ustawienia dźwięku .

Przenoszenie strumienia do innego zlewu

Zmiana domyślnego ujścia, gdy mamy aktywny strumień wejściowy odtwarzany do danego ujścia , nie ma żadnego efektu . Należy to raczej zrobić, przenosząc te dane wejściowe do innego zlewu.

pacmd list-sink-inputs

powie nam indeks strumienia wejściowego

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

Wiemy teraz, że chcemy przenieść strumień wejściowy 5do zatonięcia 1przez wywołanie

pacmd move-sink-input 5 1

lub wróć do zlewu, 0jeśli chcemy. Zostanie to wykonane natychmiast, bez konieczności zatrzymywania odtwarzania.

Zmiana domyślnego zlewu podczas gry

Oczywiście możemy połączyć te dwa polecenia, aby natychmiast przełączać domyślne ujścia podczas odtwarzania, np. Za pomocą

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

Wadą tej metody jest to, że indeks strumienia wejściowego zmienia się za każdym razem, gdy zatrzymujemy i ponownie uruchamiamy odtwarzacz muzyki. Dlatego zawsze musimy znaleźć bieżący indeks strumienia, zanim będziemy mogli przełączyć się za pomocą linii poleceń.

Takkat
źródło
Możesz odwołać się do zlewu według jego indeksu LUB według jego nazwy pactl list short sinks> 4 bluez_sink.FC_A8_9A_2C_EB_0B module-bluez5-device.c s16le 1ch 8000Hz IDLEteraz po prostu odwołaj się do nazwypactl set-default-sink bluez_sink.FC_A8_9A_2C_EB_0B
Leif Liddy
@LeifLiddy: Dziękuję za notatkę. W nowszych wersjach Pulseaudio możesz rzeczywiście odwoływać się do nazwy zlewu, set-default-sinkale nadal będziesz potrzebować numeru indeksu move-sink-input.
Takkat
A co jeśli 0 sink input(s) available.? Ale ten gówniany odtwarzacz Flash wciąż odtwarza dźwięk?
Zhigalin,
I widzę Flash client(s) logged inpacmd list
Playera
@Zhigalin Flash od dawna nie działa w moich systemach, więc nie mogę powiedzieć, że ... może grać bezpośrednio przez ALSA.
Takkat
27

Napisałem prosty skrypt, aby automatycznie przenosić wszystkie wejścia sink.

Stosowanie: ./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
źródło
1
Niesamowite! Rozszerzyłem to nieco dalej na własny użytek: chciałem ikonę na pasku zadań, która przełączałaby się między dwiema kartami audio. Napisałem mały skrypt w Ruby, aby ustalić bieżący ujście i wołam ten skrypt powłoki, aby dokonać zmiany ( pastebin.com/xb3i2ejW ). Następnie umieściłem oba skrypty w ~ / bin i dostosowałem ikonę KDE, aby uruchomić skrypt ruby. Można to zrobić bardziej elegancko lub całkowicie w skrypcie powłoki, ale działa dla mnie.
Patogen
2
Dzięki za to. Oto wersja, która przełącza się na ostatnią (? - mam tylko dwie) nieużywane dane wyjściowe: pastebin.com/raw/sidH7QPb, tzn. Przełącza dane wyjściowe, odpowiednie do mapowania na klawisz skrótu.
Julian
4

Poprawiona wersja skryptu @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

moja kopia środowiska uruchomieniowego znajduje się na github i zawiera również automatyczne przełączanie kanału głównego dlakmix

mpapis
źródło
2

Zebrałem rzeczy z kilku różnych miejsc i wymyśliłem ten skrypt, aby skonfigurować JAMBOX po sparowaniu. Twój MAC będzie oczywiście inny. Ponieważ kontroluję głośność JAMBOX za pośrednictwem aplikacji Clementine, w moim przypadku najlepiej działa 130% głośności. Możesz to zmienić wraz z plikiem rhythmbox.png (był to jedyny obraz głośnika, jaki mogłem znaleźć na komputerze). Sprawdzanie błędów jest szczątkowe, ale działa całkiem niezawodnie. Dla wygody umieściłem to w programie uruchamiającym komputery stacjonarne na netbooku 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
Ray M.
źródło
+1 za użycie pactl list short. Możesz uprościć następujący wiersz, wykonując cięcie bezpośrednio po: pactl list short sink-inputs | cut -f1 | while read streamIddziała dla mnie.
Bod
1

ZLEWY PRZEŁĄCZNIKOWE.

Skrypt Gaco z jeszcze jedną linią do przełączania kół między dostępnymi zlewami.

#!/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
użytkownik512557
źródło
świetny, prosty i skalowalny!
Paul Bastian
1

A oto skrypt, który będzie również przełączał się między zlewami:

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

Oto poniższy skrypt:

#!/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
źródło
1
Witamy w Ask Ubuntu! Chociaż teoretycznie może to odpowiedzieć na pytanie, lepiej byłoby zawrzeć tutaj istotne części odpowiedzi i podać odnośnik.
ζ--
Zrobione, choć niestety oznacza to, że skrypt nie jest aktualizowany tutaj, chyba że pamiętam, że jest tutaj. Na przykład, Ruby zmienił sposób, w jaki obsługuje .each dla ciągów (w części backtick), więc musiałem zaktualizować wiersz 53 powyżej. Lub po prostu pobierz skrypt, aby upewnić się, że jest aktualny.
David Ljung Madison Stellar
1

Opierając się na odpowiedzi Gaco, przepisałem ją trochę na własny użytek. Może ktoś uzna to za przydatne. Służy do przełączania głośników USB i zestawu słuchawkowego USB do gier.

#!/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
źródło
0

Myślę, że jest jeszcze jedna opcja, o której warto wspomnieć i jest ona dostępna na oficjalnej stronie FAQ na temat PulseAudio na freedesktop.org . Pod następującym tytułem:

Jak przełączyć domyślną kartę dźwiękową, przenosząc wszystkie aplikacje?

Udostępniają następujący skrypt:

#/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
źródło
0

Dostosowałem @mpapis do prostego „przełączania sink0 lub sink1” podczas uruchamiania:

#!/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
źródło