Bir Uygulamanın Sesini Kapatacak Komut Dosyası


14

Amacım tüm sistemi değil Spotify uygulamasını susturabilmektir. Komutunu kullanarak: ps -C spotify -o pid=Spotify'ın işlem kimliğini bulabiliyorum, bu durumda kimlik "22981". Bu işlemle ilgili kimlik ben bu listeden aramak istiyorum: pacmd list-sink-inputs. Bu komut şöyle bir liste döndürür:

eric@eric-desktop:~$ pacmd list-sink-inputs
Welcome to PulseAudio! Use "help" for usage information.
>>> 1 sink input(s) available.
    index: 0
    driver: <protocol-native.c>
    flags: START_CORKED 
    state: RUNNING
    sink: 1 <alsa_output.pci-0000_00_1b.0.analog-stereo>
    volume: 0: 100% 1: 100%
            0: -0.00 dB 1: -0.00 dB
            balance 0.00
    muted: no
    current latency: 1019.80 ms
    requested latency: 371.52 ms
    sample spec: s16le 2ch 44100Hz
    channel map: front-left,front-right
                 Stereo
    resample method: (null)
    module: 8
    client: 10 <Spotify>
    properties:
        media.role = "music"
        media.name = "Spotify"
        application.name = "Spotify"
        native-protocol.peer = "UNIX socket client"
        native-protocol.version = "26"
        application.process.id = "22981"
        application.process.user = "eric"
        application.process.host = "eric-desktop"
        application.process.binary = "spotify"
        window.x11.display = ":0"
        application.language = "en_US.UTF-8"
        application.process.machine_id = "058c89ad77c15e1ce0dd5a7800000012"
        application.process.session_id = "058c89ad77c15e1ce0dd5a7800000012-1345692739.486413-85297109"
        application.icon_name = "spotify-linux-512x512"
        module-stream-restore.id = "sink-input-by-media-role:music"

Şimdi application.process.id = "22981"bu durumda olan lavabo giriş indeksi ile ilişkilendirmek istiyorum index: 0. Şimdi bu indeks numarasıyla bu komutu çalıştırmam gerekir: pacmd set-sink-input-mute 0 1Spotify'ı susturmak ve pacmd set-sink-input-mute 0 0Spotify'ı açmak için. Bu komutlar için, ilk sayının daha önce bulunan dizin numarası ile değiştirilmesi gerekir ve bir sonraki sayı, sesi kapatmak veya kapatmak için boole'dir. Bunu nasıl tamamen bir betiğe koyabilirim, böylece Spotify uygulamasını sessize almak / sesini açmak için bir komut alabilir miyim?

DÜZENLEME: Aşağıdaki komut dosyalarının her ikisi de beklendiği gibi çalışır, biri buna göre kontrol edecek muted: yesveya muted: nodaha sonra sessize alacak veya sesini açacak bir geçiş ekleyebilir mi?

EDIT: Geçiş eklemek için glenn jackman'ın komut dosyasını değiştirmek mümkün:

#!/bin/bash

main() {
    local action=toggle
    while getopts :mu option; do 
        case "$option" in 
            m) action=mute ;;
            u) action=unmute ;;
            ?) usage 1 "invalid option: -$OPTARG" ;;
        esac
    done
    shift $((OPTIND - 1))
    local pid=$(pidof "$1")
    if [[ -z "$pid" ]]; then
        echo "error: no running processes for: $1" >&2
    elif [[ "$1" ]]; then
        $action "$1"
    else
        usage 1 "specify an application name" 
    fi
}

usage() {
    [[ "$2" ]] && echo "error: $2"
    echo "Usage: $0 [-m | -u] appname"
    echo "Default: toggle mute"
    echo "Arguments:"
    echo "-m = mute application"
    echo "-u = unmute application"
    exit $1
}

toggle() {
    local status=$(get_status "$1")
    if [[ "$status" == "yes" ]]; then
      unmute "$1"
    elif [[ "$status" == "no" ]]; then
      mute "$1"
    fi
}

mute()   { adjust_muteness "$1" 1; }
unmute() { adjust_muteness "$1" 0; }

adjust_muteness() { 
    local index=$(get_index "$1")
    local status=$(get_status "$1")
    [[ "$index" ]] && pacmd set-sink-input-mute "$index" $2 >/dev/null 
}

get_index() {
    local pid=$(pidof "$1")
    pacmd list-sink-inputs | 
    awk -v pid=$pid '
    $1 == "index:" {idx = $2} 
    $1 == "application.process.id" && $3 == "\"" pid "\"" {print idx; exit}
    '
}

get_status() {
   local pid=$(pidof "$1")
   pacmd list-sink-inputs | 
   awk -v pid=$pid '
   $1 == "muted:" {idx = $2} 
   $1 == "application.process.id" && $3 == "\"" pid "\"" {print idx; exit}
   '
}

main "$@"

neden kullanmıyorsun pactl list sink-inputs? ağ üzerinde çalışacaktır.
Janus Troelsen

Yanıtlar:


13

İşte ilginç meydan okumaya bakmam:

#!/bin/bash

main() {
    local action=mute
    while getopts :hu option; do 
        case "$option" in 
            h) usage 0 ;;
            u) action=unmute ;;
            ?) usage 1 "invalid option: -$OPTARG" ;;
        esac
    done
    shift $((OPTIND - 1))

    if [[ "$1" ]]; then
        $action "$1"
    else
        usage 1 "specify an application name" 
    fi
}

usage() {
    [[ "$2" ]] && echo "error: $2"
    echo "usage: $0 [-h] [-u] appname"
    echo "where: -u = ummute application (default action is to mute)"
    exit $1
}

mute()   { adjust_muteness "$1" 1; }
unmute() { adjust_muteness "$1" 0; }

adjust_muteness() { 
    local index=$(get_index "$1")
    [[ "$index" ]] && pacmd set-sink-input-mute "$index" $2 >/dev/null 
}

get_index() {
    local pid=$(pidof "$1")
    if [[ -z "$pid" ]]; then
        echo "error: no running processes for: $1" >&2
    else
        pacmd list-sink-inputs | 
        awk -v pid=$pid '
            $1 == "index:" {idx = $2} 
            $1 == "application.process.id" && $3 == "\"" pid "\"" {print idx; exit}
        '
    fi
}

main "$@"

Bu da mükemmel çalışıyor
era878

@ era878, Varsayılan işlem olma geçişini seviyorum. Ancak get_statusfonksiyonunuz, durumun uygun uygulamaya ait olup olmadığını kontrol etmeden yalnızca "sessiz" satırları bulur. get_indexAyrıntılar için işlevimi yeniden okuyun .
glenn jackman

3
güzel awk becerileri :)
hytromo

@glennjackman, Yup, bir süre sonra anladım. Az önce gönderdiğim komut dosyasının şimdi doğru çalıştığına inanıyorum.
era878

1
Detaylar: awk -v var=val. Awk satırları, 1'e 1, $1 == ...ifadelerin herhangi biriyle eşleştirmeye çalışır , kodu maçta parantez içinde yürütür ve devam eder. İlk ifade, ilk sözcüğü olan satırlarla eşleşir index:ve ikinci sözcüğü (SINK INDEX) idxdeğişkende saklar . Yani idxbir sonraki tarafından üzerine yazılır alır index: <SINK INDEX>awk ikinci ifadeyi maçları kadar hatta ( $1= application.process.id, $2= =, $3= <expected pid val>). Bu 2. ifade eşleştiğinde, awk yazdırır idx(ilk ifadeyle eşleşen son satırdır index:) ve çıkar.
KrisWebDev

7

çözüm için teşekkürler! Sorunumu çözmek için burada sağlanan komut dosyalarını kullanmayı başardım. Onları biraz değiştirmem gerektiğinden, burada geliştirilmiş sürüme katıldım.

Orijinal komut dosyalarının benim için çalışmamasının nedeni, bazı uygulamaların birkaç örneğe, yani birkaç PID'ye sahip olabilmesidir, ancak belki de bunlardan sadece biri ses üretmektedir ve bu nedenle aslında Pulseaudio'ya bağlıdır. Komut dosyası yalnızca bulunan ilk PID'yi kullandığı için, genellikle istenen uygulamayı kapatır / kapatır.

Yani burada argüman PulseAudio'da kayıtlı uygulama adıdır. pacmd list-sink-inputsKomutu çalıştırarak bu adı bulabilir ve application.namealanı arayabilirsiniz .

Alternatif bir çözüm, aynı uygulama adına sahip tüm PID'lerin sesini kapatmak / açmak olacaktır.

#!/bin/bash

# Adapter from glenn jackman on http://askubuntu.com/questions/180612/script-to-mute-an-application
# to depend directly on the name of the PulseAudio client
# rather than the application name (several instances of one application could
# run while only one is connected to PulseAudio)

# Possible further improvement: it could be useful to also mute all clients having
# the specified name. Here, only the first one is muted.

#!/bin/bash

main() {
    local action=mute
    while getopts :hu option; do
        case "$option" in
            h) usage 0 ;;
            u) action=unmute ;;
            ?) usage 1 "invalid option: -$OPTARG" ;;
        esac
    done
    shift $((OPTIND - 1))

    if [[ "$1" ]]; then
        $action "$1"
    else
        usage 1 "specify the name of a PulseAudio client"
    fi
}

usage() {
    [[ "$2" ]] && echo "error: $2"
    echo "usage: $0 [-h] [-u] appname"
    echo "where: -u = ummute application (default action is to mute)"
    exit $1
}

mute()   { adjust_muteness "$1" 1; }
unmute() { adjust_muteness "$1" 0; }

adjust_muteness() {
    local index=$(get_index "$1")
    if [[ -z "$index" ]]; then
        echo "error: no PulseAudio sink named $1 was found" >&2
    else
        [[ "$index" ]] && pacmd set-sink-input-mute "$index" $2 >/dev/null
    fi
}

get_index() {
#    local pid=$(pidof "$1")
#    if [[ -z "$pid" ]]; then
#        echo "error: no running processes for: $1" >&2
#    else
        pacmd list-sink-inputs |
        awk -v name=$1 '
            $1 == "index:" {idx = $2}
            $1 == "application.name" && $3 == "\"" name "\"" {print idx; exit}
        '
#    fi
}

main "$@"

6

Soru bir senaryo istemesine rağmen, bunu burada bırakmak istedim.

Bunu Ubuntu'da yapan bir C uygulaması yazdım. Daha da iyisi, gösterge tepsisine oturur (kullanaraklibappindicator ) ve Spotify'ın ne oynadığını kısa aralıklarla kontrol eder. Bir reklam oynatıyorsa (bir kara listeyi kontrol eder) Spotify'ı kapatır. Yeni bir reklam oynatılıyorsa, gösterge menüsünde Sessiz'i tıklamanız yeterlidir ve reklam kara listeye eklenir.

Yaptığı şey, XFetchNamegeri dönen bir X penceresi arar Spotify - Linux Preview. Daha sonra , bu pencerenin biçiminde bir dize döndüren özelliğini XGetWindowPropertysorgulamaya çalışır . Reklamları oynatırken şöyle bir şey döndürür:_NET_WM_ICON_NAME"Spotify – <Artist> – <Song>"

"Spotify – Spotify – Premium Free Trial Cancel Any Time"

Geçerli başlığın listede olup olmadığını verimli bir şekilde kontrol etmek için reklam listesinin Üçlü Arama Ağacı'nı tutar .

Ayrıca kullandığı PulseAudio'nun Asenkron API sorgulamak sink-inputsve set-mute:

pa_context_get_sink_input_info_list()
pa_context_set_sink_input_mute()

Sadece basit C kodu olduğundan hafiftir. Kaynak kodu ve Ubuntu .debpaketini şu adreste bulabilirsiniz: Gösterge-muteads . Muhtemelen bir kabuk senaryosunu 2-3 büyüklükte yenebilirdi.


1.0.11 sürümü ile çalışmaz
Janus Troelsen

4

Her şeyden önce, bir uygulamanın spotify gibi PID'sini bulmanın "daha doğru" yolu kullanmaktır:

pidof spotify

İşi yapan bir senaryo oluşturdum, bunu yapmanın en iyi yolu olup olmadığını bilmiyorum, ama mükemmel çalışıyor:

#!/bin/bash
# Script to mute an application using PulseAudio, depending solely on
# process name, constructed as answer on askubuntu.com: 
# http://askubuntu.com/questions/180612/script-to-mute-an-application

#It works as: mute_application.sh vlc mute OR mute_application.sh vlc unmute

if [ -z "$1" ]; then
   echo "Please provide me with an application name"
   exit 1
fi

if [ -z "$2" ]; then
   echo "Please provide me with an action mute/unmute after the application name"
   exit 1
fi

if ! [[ "$2" == "mute" || "$2" == "unmute" ]]; then
   echo "The 2nd argument must be mute/unmute"
   exit 1
fi

process_id=$(pidof "$1")

if [ $? -ne 0 ]; then
   echo "There is no such process as "$1""
   exit 1
fi

temp=$(mktemp)

pacmd list-sink-inputs > $temp

inputs_found=0;
current_index=-1;

while read line; do
   if [ $inputs_found -eq 0 ]; then
      inputs=$(echo -ne "$line" | awk '{print $2}')
      if [[ "$inputs" == "to" ]]; then
         continue
      fi
      inputs_found=1
   else
      if [[ "${line:0:6}" == "index:" ]]; then
         current_index="${line:7}"
      elif [[ "${line:0:25}" == "application.process.id = " ]]; then
         if [[ "${line:25}" == "\"$process_id\"" ]]; then
            #index found...
            break;
         fi
      fi
   fi
done < $temp

rm -f $temp

if [ $current_index -eq -1 ]; then
   echo "Could not find "$1" in the processes that output sound."
   exit 1
fi

#muting...
if [[ "$2" == "mute" ]]; then
   pacmd set-sink-input-mute "$current_index" 1 > /dev/null 2>&1
else
   pacmd set-sink-input-mute "$current_index" 0 > /dev/null 2>&1
fi

exit 0

İle çalışabilirsiniz:

./mute_application.sh spotify mute

veya

./mute_application.sh spotify unmute

Hem Audacious hem de Vlc çalışırken ve bunlardan sadece bir tanesinin sesini kapatarak / sesini açarak test edilmiştir.


Mükemmel senaryo, beklendiği gibi çalışıyor
era878

1

Gerçekten senaryo yazamıyorum, ancak hakermania'nın senaryosunu başka bir tane oluşturmak için değiştirdim.

Bu, belirli uygulamanın hacmini% 5'lik artışlarla artıracak veya azaltacaktır:

edit: aslında, her zaman son açılan uygulamayı değiştirerek çalışıyor. Fikirler?

#!/bin/bash
# Script to increase or decrease an individual application's volume using PulseAudio, depending solely on
# process name, based on another script by hakermania, constructed as answer on askubuntu.com: 
# http://askubuntu.com/questions/180612/script-to-mute-an-application

# It works as: change_app_volume.sh vlc increase OR change_app_volume.sh vlc decrease
# Set desired increments in lines #66 and #68

if [ -z "$1" ]; then
   echo "Please provide me with an application name"
   exit 1
fi

if [ -z "$2" ]; then
   echo "Please provide me with an action increase/decrease after the application name"
   exit 1
fi

if ! [[ "$2" == "increase" || "$2" == "decrease" ]]; then
   echo "The 2nd argument must be increase/decrease"
   exit 1
fi

process_id=$(pidof "$1")

if [ $? -ne 0 ]; then
   echo "There is no such process as "$1""
   exit 1
fi

temp=$(mktemp)

pacmd list-sink-inputs > $temp

inputs_found=0;
current_index=-1;

while read line; do
   if [ $inputs_found -eq 0 ]; then
      inputs=$(echo -ne "$line" | awk '{print $2}')
      if [[ "$inputs" == "to" ]]; then
         continue
      fi
      inputs_found=1
   else
      if [[ "${line:0:6}" == "index:" ]]; then
         current_index="${line:7}"
      elif [[ "${line:0:25}" == "application.process.id = " ]]; then
         if [[ "${line:25}" == "\"$process_id\"" ]]; then
            #index found...
            break;
         fi
      fi
   fi
done < $temp

rm -f $temp

if [ $current_index -eq -1 ]; then
   echo "Could not find "$1" in the processes that output sound."
   exit 1
fi

#increase/decrease...
if [[ "$2" == "increase" ]]; then
   pactl set-sink-input-volume "$current_index" +5% > /dev/null 2>&1
else
   pactl set-sink-input-volume "$current_index" -5% > /dev/null 2>&1
fi

exit 0

0

Bir uygulamanın tüm girişlerini (birden çok işlem) sessize almak ve varsayılan geçiş yapmak için düzenlenmiş komut dosyası:

#!/bin/bash

main() {
    local action=toggle
    while getopts :hu option; do
        case "$option" in
            h) usage 0 ;;
            m) action=mute ;;
            u) action=unmute ;;
            ?) usage 1 "invalid option: -$OPTARG" ;;
        esac
    done
    shift $((OPTIND - 1))

    if [[ "$1" ]]; then
        $action "$1"
    else
        usage 1 "specify an application name"
    fi
}

usage() {
    [[ "$2" ]] && echo "error: $2"
    echo "usage: $0 [-h] [-u] appname"
    echo "where: -u = ummute , -m = mute (default action is to toggle)"
    exit $1
}

mute()   { adjust_muteness "$1" 1; }
unmute() { adjust_muteness "$1" 0; }
toggle() { adjust_muteness "$1" toggle; }

adjust_muteness() {
    clients=$(pactl list clients short | awk '/[0-9]+.*'$1'.*/{print $1}')
    inputs=$(pactl list sink-inputs short)
    for c in $clients; do
        for i in $(printf '%s' "$inputs" | awk '/[0-9]+\s[0-9]+\s'$c'/{print $1}'); do
            pactl set-sink-input-mute $i $2 &
        done
    done
}

main "$@"
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.