From abdc0af171d6b7d5ab9adb28d9ffe20852df99bd Mon Sep 17 00:00:00 2001 From: Robert Günzler Date: Mon, 7 Dec 2020 18:58:55 +0100 Subject: bin/soundswitch: restructure; enable options --- bin/soundswitch | 177 ++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 128 insertions(+), 49 deletions(-) diff --git a/bin/soundswitch b/bin/soundswitch index 2436ba4..e2aac39 100755 --- a/bin/soundswitch +++ b/bin/soundswitch @@ -1,20 +1,34 @@ #!/bin/sh +# +# DESCRIPTION: +# dmenu-based pulseaudio helper +# + set -e [ -n "$DEBUG" ] && set -x +# check requirements +for tool in jq swq pactl perl pw-pulse; do + if ! command -v "$tool" >/dev/null; then + printf "%s: %s not installed but required\n" "$(basename "$0")" "$tool" >&2 + exit 1 + fi +done + + + DEFAULT_PROFILE="output:analog-stereo+input:analog-stereo" HDMI_PROFILE="output:hdmi-stereo" export MENU_PROMPT="soundswitch" -global= -focused= -profile= -hdmi= -reset= +mode= output= input= +mute= +volume_down= +volume_up= usage() { - printf "usage: %s [-gfhr]\n" "$(basename "$0")" + printf "usage: %s [-hIOgfpHRmMvV]\n" "$(basename "$0")" printf "\n" printf " -O \t(manipulate pulseaudio sinks)\n" printf " -I \t(manipulate pulseaudio sources)\n" @@ -24,94 +38,147 @@ usage() { printf " -H \t(switch card to HDMI profile)\n" printf " -R \t(switch card to default profile)\n" printf "\n" + printf " -m \t(mute default sink)\n" + printf " -M \t(mute default source)\n" + printf " -v \t(reduce sink volume by 5%%)\n" + printf " -V \t(increase sink volume by 5%%)\n" + printf "\n" printf "Needs swq(1) to work.\n" exit 2 } -while getopts OIfgpHRh name; do +_args="$*" +while getopts hIOgfpHRmMvV name; do case ${name} in - g) global=1 ;; - f) focused=1 ;; - p) profile=1 ;; - H) hdmi=1 ;; - R) reset=1 ;; + g) mode=global ;; + f) mode=focused ;; + p) mode=profile ;; + H) mode=hdmi ;; + R) mode=reset ;; O) output=1 ;; I) input=1 ;; - h|?) usage ;; + # quick actions, to make move to pipewire easier + m) mode=none ; output=1 ; mute=1 ;; + M) mode=none ; input=1 ; mute=1 ;; + v) mode=none ; output=1 ; volume_down=1 ;; + V) mode=none ; output=1 ; volume_up=1 ;; + h|?) echo "$*" ; usage ;; esac done +shift $((OPTIND-1)) -if [ "$#" -lt 1 ]; then +# ask mode +if [ -z "$mode" ]; then printf "global\nfocused\ncard profile\nhdmi profile\nreset profile\n" | menu | { read -r line case ${line} in - global) exec "$0" -g ;; - focused) exec "$0" -f ;; - "card profile") exec "$0" -p ;; - "hdmi profile") exec "$0" -H ;; - "reset profile") exec "$0" -R ;; - *) usage ;; + global) exec "$0" -g "$*" ;; + focused) exec "$0" -f "$*" ;; + "card profile") exec "$0" -p "$*" ;; + "hdmi profile") exec "$0" -H "$*" ;; + "reset profile") exec "$0" -R "$*" ;; + *) usage ;; esac } exit $? fi -if [ -n "$global" ] || [ -n "$focused" ]; then + +# [ "$mode" = "global" ] && args="-g" +# [ "$mode" = "focused" ] && args="-f" + +if [ -n "$mode" ]; then + # ask target? if [ -z "$output" ] && [ -z "$input" ]; then printf "output\ninput\n" | menu | { read -r line case ${line} in - output) exec "$0" -O "$*" ;; - input) exec "$0" -I "$*" ;; - *) usage ;; + output) exec "$0" -O $_args ;; + input) exec "$0" -I $_args ;; + *) usage ;; esac } - exit $? fi fi -[ -n "$output" ] && keyword="sink" && what="sink-input" -[ -n "$input" ] && keyword="source" && what="source-output" +# [ -n "$output" ] && args="-O $args" +# [ -n "$input" ] && args="-I $args" + +# if ! pactl info >&2 2>/dev/null; then +# # try to work with pipewire +# exec pw-pulse "$0" $_args +# fi + +# process quick actions first +[ -n "$output" ] && [ -n "$mute" ] && exec pactl set-sink-mute '@DEFAULT_SINK@' toggle +[ -n "$input" ] && [ -n "$mute" ] && exec pactl set-source-mute '@DEFAULT_SINK@' toggle +[ -n "$volume_down" ] && exec pactl set-sink-volume '@DEFAULT_SINK@' '-5%' +[ -n "$volume_up" ] && exec pactl set-sink-volume '@DEFAULT_SINK@' '+5%' + +[ -n "$output" ] && keyword="sink" && what="sink-input" +[ -n "$input" ] && keyword="source" && what="source-output" # returns the sink_id selects() { pactl list short "${keyword}s" | awk '{print $2}' | menu } +notif() +{ + topic=$1 + mesg=$2 + urgency=normal + [ -n "$3" ] && urgency=critical + notify-send -u ${urgency} -a soundswitch "soundswitch: ${topic}" "${mesg}" +} -if [ -n "${global}" ] -then +case ${mode} in +global) target=$(selects) - notify-send -a soundswitch "soundswitch: global" "switch to ${target}" + if [ -z "${target}" ]; then + notif "focused" "no target ${what}" err + exit 1 + fi + + notif "global" "switch to ${target}" # set new default pactl "set-default-${keyword}" "${target}" # move all attached to the new target pactl list "${what}s" short | cut -f1 \ | xargs -i pactl "move-${what}" "{}" "${target}" + ;; -elif [ -n "${focused}" ] -then +focused) # parse pid of currently focused container # then get the sink-inputs for it and parse the sink-input-id focused_binary=$(swq current con | jq -r '.pid' | xargs ps -o comm=) what_id=$(printf "%s\n" "${focused_binary}" \ - | xargs pacmd "list-${what}s" \ + | xargs pactl list "${what}s" \ | tr '\n' '\r' \ | perl -pe 's/[^\r]*index: ([0-9]+).+?application\.process\.binary = "([^\r]+)"\r.+?(?=index:|$)/\2=\1\r/g' \ | tr '\r' '\n' \ | grep "^{}" \ | cut -d'=' -f2) - [ -z "${what_id}" ] && exit 1 + if [ -z "${what_id}" ]; then + notif "focused" "no ${what}" err + exit 1 + fi # select where to switch to target=$(selects) - [ -z "${what_id}" ] && exit 1 + if [ -z "${target}" ]; then + exit 1 + fi - notify-send -a soundswitch "soundswitch: ${focused_binary}" "switch to ${target}" - pacmd move-sink-input "${what_id}" "${target}" + notif "${focused_binary}" "switch to ${target}" + pactl move-sink-input "${what_id}" "${target}" + ;; -elif [ -n "${profile}" ] -then +profile) target_card=$(pactl list short cards | awk '{print $2}' | menu) - target_profile=$(pacmd list-cards \ + if [ -z "${target_card}" ]; then + exit 1 + fi + + target_profile=$(pactl list cards \ | tr '\n' '\r' \ | perl -pe 's/[^\r]index: ([0-9]+).+?name: \r.+profiles:\r(.+)sinks:.*?(?=index:|$)/\2\r/g' \ | tr -d '\t' \ @@ -119,21 +186,33 @@ then | tail -n+2 \ | menu \ | perl -pe 's/^\s*([^\s]+):\s.*$/\1/') + if [ -z "${target_profile}" ]; then + exit 1 + fi - notify-send -a soundswitch "soundswitch: profile" "switch ${target_card} to ${target_profile} profile" - pactl set-card-profile "${target_card}" ${target_profile} + notif "profile" "switch ${target_card} to ${target_profile} profile" + pactl set-card-profile "${target_card}" "${target_profile}" + ;; -elif [ -n "${hdmi}" ] -then +hdmi) target_card=$(pactl list short cards | awk '{print $2}' | menu) - notify-send -a soundswitch "soundswitch: hdmi" "switch ${target_card} to HDMI profile" + if [ -z "${target_card}" ]; then + exit 1 + fi + + notif "hdmi" "switch ${target_card} to HDMI profile" pactl set-card-profile "${target_card}" ${HDMI_PROFILE} exit $? + ;; -elif [ -n "${reset}" ] -then +reset) target_card=$(pactl list short cards | awk '{print $2}' | menu) - notify-send -a soundswitch "soundswitch: reset" "switch ${target_card} to default profile" + if [ -z "${target_card}" ]; then + exit 1 + fi + + notif "reset" "switch ${target_card} to default profile" pactl set-card-profile "${target_card}" ${DEFAULT_PROFILE} + ;; -fi +esac -- cgit 1.4.1