使应用程序静音的脚本

使应用程序静音的脚本

我的目标是能够静音 Spotify 应用程序,而不是整个系统。使用命令:ps -C spotify -o pid=我能够找到 Spotify 的进程 ID,在本例中 ID 为"22981"。使用该进程 ID,我想从以下列表中进行搜索:pacmd list-sink-inputs。该命令返回如下列表:

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"

现在我想将application.process.id = "22981"与接收器输入索引(在本例中为)关联起来index: 0。现在有了该索引号,我需要运行以下命令:pacmd set-sink-input-mute 0 1静音 Spotify 和pacmd set-sink-input-mute 0 0取消静音 Spotify。对于这些命令,第一个数字需要替换为之前找到的索引号,下一个数字是打开或关闭静音的布尔值。我怎样才能将它们全部放入脚本中,以便我可以获取静音/取消静音 Spotify 应用程序的命令?

编辑: 下面的两个脚本都按预期工作,有人可以添加一个切换按钮来检查muted: yes或者muted: no然后相应地静音或取消静音吗?

编辑: 我可以修改 glenn jackman 的脚本来添加切换按钮:

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

答案1

以下是我对您这个有趣挑战的看法:

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

答案2

谢谢你的解决方案!我设法使用这里提供的脚本来解决我的问题。由于我不得不对它们进行一些修改,所以我在这里加入了改进的版本。

原始脚本对我不起作用的原因是,某些应用程序可以有多个实例,即多个 PID,但可能只有其中一个产生声音,因此实际上连接到 Pulseaudio。由于脚本仅使用找到的第一个 PID,因此它通常不会使所需应用程序静音。

因此,这里有一个版本,其中参数是 PulseAudio 中注册的应用程序名称。您可以通过运行命令pacmd list-sink-inputs并查找application.name字段来找到此名称。

另一种解决方案是将所有具有相同应用程序名称的 PID 静音/取消静音。

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

答案3

尽管问题要求提供脚本,但我还是想将其留在这里。

我在 Ubuntu 上编写了一个 C 应用程序来实现这一点。更棒的是,它位于指示器托盘上(使用libappindicator),并在短时间内检查 Spotify 正在播放的内容。如果它正在播放广告(对照黑名单检查),它会将 Spotify 静音。如果正在播放新广告,您只需单击指示器菜单上的静音,它就会将其添加到黑名单中。

它的作用是查找 X 窗口,并XFetchName返回Spotify - Linux Preview。然后它调用XGetWindowProperty查询_NET_WM_ICON_NAME该窗口的属性,并返回格式为 的字符串"Spotify – <Artist> – <Song>"。播放广告时,它会返回如下内容:

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

它保持着三叉搜索树广告列表,以有效地检查当前标题是否在列表中。

它还使用PulseAudio 异步 API查询sink-inputsset-mute

pa_context_get_sink_input_info_list()
pa_context_set_sink_input_mute()

由于它只是简单的 C 代码,因此它很轻量。请查看以下位置的源代码和 Ubuntu.deb软件包:指示剂。它的性能可能比 shell 脚本高出 2-3 个数量级。

答案4

我修改了 Jag 的脚本来切换静音。我将其分配给键盘快捷键以静音/取消静音 Chromium。pidof显然不适用于 Chromium。因此这使用 Pulseaudio 客户端。

#!/bin/bash

# Adapter from glenn Jag on http://askubuntu.com/questions/180612/script-to-mute-an-application
# Toggles muting of all audio streams of an app

main() {
    if [[ "$1" ]]; then
        prev=""; prev2="";
        while read line; do
            if [[ $line = "end" ]]; then
                adjust_muteness $1 $(echo "$prev2 $prev" | tr -d '\n')
                prev=""; prev2="";
            else
                if [[ $prev2 = "" ]]; then prev2=$line; else prev=$line; fi
            fi
        done < <(get_info "$1")
    else
        usage 1 "specify the name of a PulseAudio client"
    fi
}

usage() {
    [[ "$2" ]] && echo "error: $2"
    echo "usage: $0 [-h] [-u] appname"
    exit $1
}

adjust_muteness() {
    # muted or not
    muted=$2
    # process ID
    index=$3

    # muteness value
    if [[ $muted = "yes" ]]; then
        mute=0 # unmute
    else
        mute=1 # mute
    fi

    echo $muted

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

get_info() {
    pacmd list-sink-inputs |
    awk -v name=$1 '
        $1 == "index:" {idx = $2}
        $1 == "muted:" {idm = $2}
        $1 == "application.name" && $3 == "\"" name "\"" {print idm; print idx; print "end";}
    '
}

main "$@"

用法 :

./mute-app.sh Chromium

您可以使用以下方式获取应用程序的名称pacmd list-sink-inputs

相关内容