Как изменить приемник pulseaudio с помощью "pacmd set-default-sink" во время воспроизведения?

Мне нужно переключить сервер pulseaudio на воспроизводимый в данный момент аудиопоток.

Сервер Pulseaudio настроен с IP-адресом 192.168.1.105

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

На стороне источника VLC media player воспроизводит песню.

Я создал новый туннельный приемник с pulseaudio на стороне источника.

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

Но во время воспроизведения звука сервер не мог быть изменен немедленно. Только после остановки проигрывателя и воспроизведения все в порядке.

Из "gnome-volume-control" или "gnome-control-center sound" переключение устройств вывода применяется немедленно.

Как я могу применить переключение выходного приемника непосредственно из командной строки во время воспроизведения звукового файла?

PulseAudio pacmd не способен переключать приемники по умолчанию при активном воспроизведении потока на входе приемника. Однако есть способ добиться этого.

Изменение приемника по умолчанию из командной строки

Сначала нам нужно определить номер индекса приемников, которые мы хотим переключить. Это можно сделать, позвонив:

pacmd list-sinks

В зависимости от нашей системы это даст вам более или менее длинный список приемников и свойств, доступных в настоящее время:

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

То index или в name здесь приведено то, что нам нужно для обращения к приемнику с помощью командной строки. Текущий приемник по умолчанию отмечен звездочкой (здесь 0).

Чтобы иметь возможность переключать приемники по умолчанию из командной строки, нам может потребоваться отключить восстановление целевого устройства потока отредактировав соответствующую строку в /etc/pulse/default.pa к:

load-module module-stream-restore restore_device=false

Чтобы изменить выходной приемник по умолчанию на приемник 1 затем мы запускаем

pacmd set-default-sink 1

Успех можно визуализировать, открыв Настройки звука меню.

Перемещение потока в другой приемник

Изменение приемника по умолчанию, пока у нас есть активный входной поток, воспроизводимый для данного приемника не имеет никакого эффекта. Это скорее следует сделать, переместив этот ввод в другой приемник.

pacmd list-sink-inputs

сообщит нам индекс входного потока

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

Теперь мы знаем, что хотим переместить входной поток 5 чтобы утонуть 1 позвонив

pacmd move-sink-input 5 1

или снова погрузиться в воду 0 если захотим. Это будет сделано немедленно, без необходимости остановки воспроизведения.

Изменение приемника по умолчанию во время воспроизведения

Конечно, мы можем объединить эти две команды, чтобы немедленно переключать приемники по умолчанию во время воспроизведения, например, с помощью

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

Недостатком этого метода является то, что изменение индекса входного потока каждый раз, когда мы останавливаем и перезапускаем музыкальный проигрыватель. Таким образом, мы всегда должны узнать текущий индекс потока, прежде чем мы сможем переключиться с помощью командной строки.

Я написал простой скрипт для автоматического перемещения всех входных данных приемника.

Использование: ./movesinks.sh <sink number>

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

Улучшенная версия @Gaco скрипт

#!/usr/bin/env bashcase "${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

моя копия во время выполнения - это на github и это включает в себя также автоматическое переключение Главный канал для kmix

Основываясь на ответе Гако, я немного переписал его для личного использования. Может быть, кто-то сочтет это полезным. Он предназначен для переключения моих USB-динамиков и 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 lengthif [ $# -eq 0 ]  then    echo "Toggling output devices (Speakers/Headset)"    toggleSinksfi# arg optionswhile 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                        ;;    esacdone

Я собрал материал из нескольких разных мест и придумал этот скрипт для настройки bluetooth JAMBOX после его сопряжения. Конечно, ваш MAC будет другим. Поскольку я контролирую громкость JAMBOX через приложение Clementine, в моем случае лучше всего работает 130% громкости. Возможно, вы захотите изменить это вместе с rhythmbox.png (это было единственное изображение динамика, которое я смог найти на своем компьютере). Проверка ошибок является элементарной, но работает довольно надежно. Я поместил это в настольный лаунчер для удобства на нетбуке 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 hereMAC=00:21:3C:9F:19:AD# Make ready# Convert device address per pulseaudio standardsDEV=$(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 gopactl list short sink-inputs | while read stream; do    streamId=$(echo $stream | cut '-d ' -f1)    pactl move-sink-input "$streamId" bluez_sink.$DEVdonepactl set-default-sink bluez_sink.$DEVpactl set-card-profile bluez_card.$DEV a2dppactl 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

Существует сценарий ruby (который я изначально разветвил и переписал разделы) это позволяет изменять приемники по умолчанию, громкость и статус отключения звука из командной строки.

И вот сценарий, который также будет переключаться между приемниками:

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

Вот сценарий ниже:

#!/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 pacmdPACMD = %w(pacmd)################################################### Usage##################################################def fatal(*msg)    msg.each { |m| $stderr.puts "[#{$0.sub(/.*\//,'')}] ERROR: #{m}" }    exit(-1);enddef usage(*msg)    msg.each { |m| $stderr.puts "ERROR: #{m}" }    $stderr.puts <<-USAGEUsage:  #{$0.sub(/.*\//,'')} [sink]  Switch sound playback device for ALSA/pulseaudio    [sink]   Specify sink number to use (see 'pacmd list-sinks')    USAGE    exit -1;enddef 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    }    optend# 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    }    $?enddef 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,currend################################################### 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    }endmain

Я адаптировал @mpapis к простому "переключению sink0 или sink1" при запуске:

#!/bin/bashSINK_INDEX1=0SINK_INDEX2=1ACTIVE_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_INDEX2else     pacmd set-default-sink $SINK_INDEX1    pacmd list-sink-inputs | awk '/index:/{print $2}' | xargs -r -I{} pacmd move-sink-input {} $SINK_INDEX1fi

РАКОВИНЫ С КРУГОВЫМ ПЕРЕКЛЮЧЕНИЕМ.

Сценарий Gaco с еще одной строкой для кругового переключения между доступными приемниками.

#!/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_sinkpacmd list-sink-inputs | grep index | while read linedoecho "Moving input: ";echo $line | cut -f2 -d' ';echo "to sink: $new_sink";pacmd move-sink-input `echo $line | cut -f2 -d' '` $new_sinkdone

Я думаю, что есть еще один вариант, о котором стоит упомянуть, и он доступен на официальной странице для Часто задаваемые вопросы о PulseAudio около freedesktop.org. Под следующим названием:

Как мне переключить звуковую карту по умолчанию, переместив все приложения?

Для этого они предоставляют следующий сценарий:

#/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 availabletotalsc=$(pacmd "list-sinks" | grep card: | wc -l) # total of sound cards: $totalscif [ $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."  exitfi# $scindex: The Pulseaudio index of the current default sound cardscindex=$(pacmd list-sinks | awk '$1 == "*" && $2 == "index:" {print $3}')# $cards: A list of card Pulseaudio indexescards=$(pacmd list-sinks | sed 's|*||' | awk '$1 == "index:" {print $2}')PICKNEXTCARD=1 # Is true when the previous card is defaultcount=0 # count of number of iterationsfor 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))donepacmd "set-default-sink $nextsc" # switch default sound card to next# $inputs: A list of currently playing inputsinputs=$(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 $nextscdone# $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 withnextscdesc=$(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