Skip to content

Instantly share code, notes, and snippets.

@00sapo
Last active September 27, 2022 09:49
Show Gist options
  • Save 00sapo/9f88f6994029b7eeac3a6b9063d87352 to your computer and use it in GitHub Desktop.
Save 00sapo/9f88f6994029b7eeac3a6b9063d87352 to your computer and use it in GitHub Desktop.
PulseAudio Solo Mode
#!/bin/sh
SLEEP_TIME=0.1
print_help() {
cat << EOF
This script can be used to run any shell command so that it's the only
process that can play sounds using PulseAudio. It continuously mutes all the
new streams that are not connected to the command passed as argument. Once
muted, it won't be managed by this script anymore (so that it will stay
unmuted if you want)
A typical use-case scenario is video-calling, when you want to avoid that
other apps unexpectedly play sounds (e.g. various websites do this)
Syntax:
$0 [-r regex] [-h] <yourcommand -with --yours --options>
Options:
-r : allows the usage of an awk regex; instead of non-muting children
processes, patterns that match the regex will be not muted; this
is useful for processes that internally use nohup or similar methods,
spawining processes that are not children. E.g.
$0 -r skype skypeforlinux
-h : show this help
Usage:
Just run the command. To exit, use ctrl+c.
EOF
}
get_stream_pid_list() {
pactl list sink-inputs | awk '
/application.process.id/ {
gsub("\"", "", $3)
print $3
}'
}
get_stream_index_from_pid() {
pid=$1
pactl list sink-inputs | awk '
/^Sink Input #[0-9]+$/ {
sub("#", "", $3)
x=$3
}
/application.process.id = "'"$pid"'"/ {
print x
}'
}
daemon_mute_except() {
except_pid=$1
regex=$2
echo "Muting all streams except $except_pid and its children!"
already_toggled=""
old_stream_list=""
while true; do
stream_list=$(get_stream_pid_list)
if test "$stream_list" == "$old_stream_list":
then
continue
sleep $SLEEP_TIME
fi
if test -z "$regex"
then
# get the target pid's children
children=$(pstree "$except_pid" -p)
else
# if there is a regex, get the processes matching the regex
children=$(pstree -ap | awk "/.*${regex}.*/{print}")
fi
children=$(echo "$children" | awk -v FPAT='([0-9]+)' '{$1=$1;print}')
for pid in $stream_list; do
case "$children" in
*${pid}*)
# this is the target pid or a child
continue
sleep $SLEEP_TIME
;;
esac
case "$already_toggled" in
*${pid}*)
# this pid was already toggled
continue
sleep $SLEEP_TIME
;;
esac
# mute the stream
index=$(get_stream_index_from_pid "$pid")
echo "Muting stream index $index"
pactl set-sink-input-mute "$index" 1
already_toggled="$already_toggled:$pid"
done
old_stream_list=$stream_list
sleep $SLEEP_TIME
done
}
# run our command and take its PID
option=$1
case "$option" in
"-r")
regex=$2
shift 2
;;
"-h")
print_help
exit
;;
"")
print_help
exit
;;
*)
regex=""
;;
esac
echo "Running command" "$@"
"$@" &
except_pid=$!
# start the daemon: continuously mute streams
daemon_mute_except $except_pid "$regex"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment