Script to Mute an Application
Here's my take on your interesting challenge:
#!/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 "$@"
thanks for the solution! I managed to use the scripts provided here to fix my problem. Since I had to modify them a bit, here I join the improved version.
The reason the original scripts didn't work for me is because some applications can have several instances, i.e. several PID, but maybe only one of them is producing sound, and is thus actually connected to Pulseaudio. Since the script only used the first PID found, it would typically /not/ mute the desired application.
So here is a version where the argument is the application name as registered in PulseAudio. You can find this name by running the pacmd list-sink-inputs
command and look for application.name
field.
An alternative solution would be to mute/unmute all PIDs which have the same application name.
#!/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 "$@"
Even though the question is asking for a script, I wanted to leave this here.
I have written a C application that does this on Ubuntu. Even better, it sits on the indicator tray (using libappindicator
) and checks what Spotify is playing, on short intervals. If it is playing an ad (checks against a blacklist) it mutes the Spotify. If a new ad is being played, you simply click Mute on the indicator menu and it adds it to the blacklist.
What it does, is looks for an X window, for which XFetchName
returns Spotify - Linux Preview
. Then it calls XGetWindowProperty
to query the _NET_WM_ICON_NAME
property of that window, which returns a string in the "Spotify – <Artist> – <Song>"
format. When playing ads, it returns something like this:
"Spotify – Spotify – Premium Free Trial Cancel Any Time"
It maintains a Ternary Search Tree of the list of ads, to efficiently check whether the current title is in the list.
It also uses the PulseAudio Asynchronous API to query the sink-inputs
and set-mute
:
pa_context_get_sink_input_info_list()
pa_context_set_sink_input_mute()
Since it is just simple C code, it is light-weight. Check out the source code and Ubuntu .deb
package at: indicator-muteads. It would probably beat a shell script by 2-3 orders of magnitude.