My goal is to be able to mute the Spotify application, not the entire system. Using the command: ps -C spotify -o pid=
I am able to find the process ID of Spotify, in this case the ID is "22981"
. With that process ID I would like to search from this list: pacmd list-sink-inputs
. That command returns a list like this:
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"
Now I would like to correlate the application.process.id = "22981"
to the sink input index which in this case is index: 0
. Now with that index number I would then need to to run this command: pacmd set-sink-input-mute 0 1
to mute Spotify and pacmd set-sink-input-mute 0 0
to unmute Spotify. For those commands, the first number would need to be replaced with the index number found earlier, and the next number is the boolean to turn on or off the mute. How can I put this altogether into a script, so I can get a command to mute/unmute the Spotify application?
EDIT:
Both of the scripts below work as expected, can somebody add a toggle which would check muted: yes
or muted: no
and then mute or unmute accordingly?
EDIT: I was able to modify glenn jackman's script to add the toggle:
#!/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 "$@"
Here's my take on your interesting challenge:
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 forapplication.name
field.An alternative solution would be to mute/unmute all PIDs which have the same application name.
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
returnsSpotify - Linux Preview
. Then it callsXGetWindowProperty
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: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
andset-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.First of all, the "more correct" way to find an application's PID like spotify, is to use:
I've built up a script that does the job, I don't know if it is the best way to do it, but it works perfectly:
You can work with is as:
or
Tested with both Audacious and Vlc running and muting/unmuting only one of them.
I modified Jag's script to do a toggle of muting. I assigned this to a keyboard shortcut to mute/unmute Chromium.
pidof
doesn't work with Chromium apparently. So this uses Pulseaudio client.Usage :
You can get the name of apps with
pacmd list-sink-inputs
I really can't script, but I have modified hakermania's script to create another.
This one will increase or decrease the specific application's volume at increments of 5%:
edit: actually, it's working in always changing last opened app. Ideas?
Edited script to mute all the inputs of an app (multiple processes) and defaults to toggle: