Script để tắt tiếng một ứng dụng


14

Mục tiêu của tôi là có thể tắt tiếng ứng dụng Spotify chứ không phải toàn bộ hệ thống. Sử dụng lệnh: ps -C spotify -o pid=Tôi có thể tìm ID tiến trình của Spotify, trong trường hợp này là ID "22981". Với ID tiến trình đó, tôi muốn tìm kiếm từ danh sách này : pacmd list-sink-inputs. Lệnh đó trả về một danh sách như thế này:

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"

Bây giờ tôi muốn tương quan application.process.id = "22981"với chỉ số đầu vào chìm trong trường hợp này là index: 0. Bây giờ với số chỉ mục đó, sau đó tôi sẽ cần chạy lệnh này: pacmd set-sink-input-mute 0 1tắt tiếng Spotify và pacmd set-sink-input-mute 0 0tắt tiếng Spotify. Đối với các lệnh đó, số đầu tiên sẽ cần được thay thế bằng số chỉ mục được tìm thấy trước đó và số tiếp theo là boolean để bật hoặc tắt tiếng. Làm cách nào tôi có thể đặt hoàn toàn điều này vào một tập lệnh, để tôi có thể nhận lệnh tắt tiếng / bật tiếng ứng dụng Spotify?

EDIT: Cả hai tập lệnh bên dưới đều hoạt động như mong đợi, ai đó có thể thêm một nút chuyển đổi sẽ kiểm tra muted: yeshoặc muted: nosau đó tắt tiếng hoặc bật tiếng cho phù hợp không?

EDIT: Tôi đã có thể sửa đổi tập lệnh của glenn jackman để thêm chuyển đổi:

#!/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 "$@"

tại sao không sử dụng pactl list sink-inputs? sau đó nó sẽ hoạt động qua mạng.
Janus Troelsen

Câu trả lời:


13

Đây là thách thức thú vị của bạn:

#!/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 "$@"

Điều này cũng hoạt động hoàn hảo
age878

@ age878, tôi thích ý tưởng chuyển đổi thành hành động mặc định. Tuy nhiên, get_statuschức năng của bạn sẽ chỉ tìm thấy các dòng "tắt tiếng" mà không kiểm tra chéo trạng thái đó thuộc về ứng dụng phù hợp. Đọc lại get_indexchức năng của tôi để biết chi tiết.
glenn jackman

3
kỹ năng awk đẹp :)
hytromo

@glennjackman, Yup, tôi đã tìm ra điều đó sau một thời gian. Tôi tin rằng kịch bản mà tôi vừa đăng hoạt động chính xác.
age878

1
Chi tiết : awk -v var=val. Các vòng lặp Awk trên các dòng, 1 trên 1, cố gắng khớp bất kỳ $1 == ...câu lệnh nào, thực thi mã trong ngoặc trên khớp và tiếp tục. Câu lệnh đầu tiên khớp với các dòng có từ đầu tiên index:và lưu trữ từ thứ hai (SINK INDEX) trong idxbiến. Vì vậy, idxđược ghi đè bởi index: <SINK INDEX>dòng tiếp theo cho đến khi awk khớp với câu lệnh thứ hai ( $1= application.process.id, $2= =, $3= <expected pid val>). Khi câu lệnh thứ 2 này khớp, in awk idx(là dòng cuối cùng khớp với câu lệnh đầu tiên index:) và thoát.
KrisWebDev

7

cảm ơn giải pháp! Tôi quản lý để sử dụng các tập lệnh được cung cấp ở đây để khắc phục vấn đề của tôi. Vì tôi phải sửa đổi chúng một chút, ở đây tôi tham gia phiên bản cải tiến.

Lý do các tập lệnh gốc không hoạt động với tôi là vì một số ứng dụng có thể có một số trường hợp, ví dụ như một số PID, nhưng có lẽ chỉ một trong số chúng tạo ra âm thanh và do đó thực sự được kết nối với Pulseaudio. Do tập lệnh chỉ sử dụng bộ PID đầu tiên được tìm thấy, nên nó thường / không / tắt tiếng ứng dụng mong muốn.

Vì vậy, đây là một phiên bản trong đó đối số là tên ứng dụng như đã đăng ký trong PulseAudio. Bạn có thể tìm thấy tên này bằng cách chạy pacmd list-sink-inputslệnh và tìm kiếmapplication.name trường.

Một giải pháp thay thế sẽ là tắt tiếng / bật tiếng tất cả các bộ vi xử lý có cùng tên ứng dụng.

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

Mặc dù câu hỏi là yêu cầu một kịch bản, tôi muốn để nó ở đây.

Tôi đã viết một ứng dụng C thực hiện điều này trên Ubuntu. Thậm chí tốt hơn, nó nằm trên khay chỉ báo (đang sử dụng libappindicator) và kiểm tra xem Spotify đang phát gì, trong các khoảng thời gian ngắn. Nếu nó đang phát một quảng cáo (kiểm tra đối với một danh sách đen), nó sẽ tắt tiếng Spotify. Nếu một quảng cáo mới đang được phát, bạn chỉ cần nhấp vào Tắt tiếng trên menu chỉ báo và nó sẽ thêm nó vào danh sách đen.

Những gì nó làm, là tìm kiếm một cửa sổ X, XFetchNametrả về Spotify - Linux Preview. Sau đó, nó gọi XGetWindowPropertyđể truy vấn thuộc _NET_WM_ICON_NAMEtính của cửa sổ đó, trả về một chuỗi ở "Spotify – <Artist> – <Song>"định dạng. Khi phát quảng cáo, nó sẽ trả về một cái gì đó như thế này:

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

Nó duy trì Cây Tìm kiếm Ternary của danh sách quảng cáo, để kiểm tra hiệu quả xem tiêu đề hiện tại có trong danh sách hay không.

Nó cũng sử dụng API không đồng bộ PulseAudio để truy vấn sink-inputsset-mute:

pa_context_get_sink_input_info_list()
pa_context_set_sink_input_mute()

Vì nó chỉ là mã C đơn giản, nó có trọng lượng nhẹ. Kiểm tra mã nguồn và .debgói Ubuntu tại: mut-Indicator . Nó có thể sẽ đánh bại một kịch bản shell bằng 2-3 bậc độ lớn.


không hoạt động với phiên bản 1.0.11
Janus Troelsen

4

Trước hết, cách "chính xác hơn" để tìm PID của ứng dụng như spotify, là sử dụng:

pidof spotify

Tôi đã xây dựng một kịch bản thực hiện công việc, tôi không biết liệu đó có phải là cách tốt nhất để thực hiện hay không, nhưng nó hoạt động hoàn hảo:

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

Bạn có thể làm việc với là:

./mute_application.sh spotify mute

hoặc là

./mute_application.sh spotify unmute

Đã thử nghiệm với cả Audacity và Vlc đang chạy và tắt tiếng / tắt tiếng chỉ một trong số họ.


Kịch bản hoàn hảo, hoạt động như mong đợi
age878

1

Tôi thực sự không thể viết kịch bản, nhưng tôi đã sửa đổi kịch bản của hakermania để tạo kịch bản khác.

Điều này sẽ tăng hoặc giảm âm lượng của ứng dụng cụ thể với mức tăng 5%:

chỉnh sửa: thực sự, nó hoạt động trong việc luôn thay đổi ứng dụng đã mở cuối cùng. Ý tưởng?

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

Tập lệnh được chỉnh sửa để tắt tiếng tất cả các đầu vào của một ứng dụng (nhiều quy trình) và mặc định để chuyển đổi:

#!/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 "$@"
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.