diff options
Diffstat (limited to 'bin/soundswitch')
| -rwxr-xr-x | bin/soundswitch | 305 |
1 files changed, 141 insertions, 164 deletions
diff --git a/bin/soundswitch b/bin/soundswitch index cc1de6c..080f4e0 100755 --- a/bin/soundswitch +++ b/bin/soundswitch @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # # DESCRIPTION: # dmenu-based audio helper @@ -37,16 +37,16 @@ volume_up= usage() { printf "usage: %s [-hIOgfpHRmMvV]\n" "$(basename "$0")" printf "\n" - printf " -O \t(manipulate pulseaudio sinks)\n" - printf " -I \t(manipulate pulseaudio sources)\n" - printf " -g \t(set default sink and switch global output)\n" - printf " -f \t(switch focused container output)\n" + printf " -O \t(manipulate outputs)\n" + printf " -I \t(manipulate inputs)\n" + printf " -g \t(manipulate globally)\n" + # printf " -f \t(manipulate focused container)\n" printf " -p \t(switch card profile)\n" - printf " -H \t(switch card to HDMI profile)\n" - printf " -R \t(switch card to default profile)\n" + # 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 " -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" @@ -95,52 +95,41 @@ done shift $((OPTIND - 1)) # ask mode -_mode_global=" global" -_mode_focused=" focused" -_mode_profile_card=" card profile" -_mode_profile_hdmi=" hdmi profile" -_mode_profile_reset=" reset profile" -_mode_mute=" mute" +_modes=( + " output" + " input" + " profile" + # " focused" + # " hdmi profile" + # " reset profile" + # " mute" +) if [ -z "$mode" ]; then - printf "$_mode_global\n$_mode_focused\n$_mode_profile_card\n$_mode_profile_hdmi\n$_mode_profile_reset\n$_mode_mute\n" | _menu | { - read -r line - case ${line} in - "$_mode_global") exec "$0" -g "$*" ;; - "$_mode_focused") exec "$0" -f "$*" ;; - "$_mode_profile_card") exec "$0" -p "$*" ;; - "$_mode_profile_hdmi") exec "$0" -H "$*" ;; - "$_mode_profile_reset") exec "$0" -R "$*" ;; - "$_mode_mute") exec "$0" -B "$*" ;; - *) - usage - ;; - esac - } - exit $? -fi - -_mode_output=" output" -_mode_input=" input" -if [ -n "$mode" ]; then - # ask target? - if [ -z "$output" ] && [ -z "$input" ]; then - printf "$_mode_output\n$_mode_input\n" | _menu | { + printf "%s\n" "${_modes[@]}" | + _menu | + { read -r line case ${line} in - "$_mode_output") exec "$0" -O $_args ;; - "$_mode_input") exec "$0" -I $_args ;; - *) usage ;; + "${_modes[0]}") exec "$0" -gO "$*" ;; + "${_modes[1]}") exec "$0" -gI "$*" ;; + "${_modes[2]}") exec "$0" -p "$*" ;; + # "${_modes[1]}") exec "$0" -f "$*" ;; + # "${_modes[3]}") exec "$0" -H "$*" ;; + # "${_modes[4]}") exec "$0" -R "$*" ;; + # "${_modes[5]}") exec "$0" -B "$*" ;; + *) + usage + ;; esac } - exit $? - fi + exit $? 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 "$volume_down" ] && exec pactl set-sink-volume '@DEFAULT_SINK@' '-2%' +[ -n "$volume_up" ] && exec pactl set-sink-volume '@DEFAULT_SINK@' '+2%' [ -n "$output" ] && keyword="sink" && what="sink-input" [ -n "$input" ] && keyword="source" && what="source-output" @@ -159,7 +148,7 @@ default() { # e.g. {"i":60,"d":"Built-in Audio Analog Stereo"} __identifier_list() { if [ "$1" = "card" ]; then - pactl --format=json list "${1}s" | jq -c '.[]|{i:.index,d:.properties["api.alsa.card.name"]}' + pactl --format=json list "${1}s" | jq -c '.[]|{i:.index,d:(.properties | .["device.alias"] // .["alsa.card_name"])}' else pactl --format=json list "${1}s" | jq -c '.[]|{i:.index,d:.description}' fi @@ -183,6 +172,9 @@ __identifier_fmt() { } __identifier_fmt_parse() { fmt=$(cat) + if [ -z "${fmt}" ]; then + exit 1 + fi i=$(printf "%s" "$fmt" | tr -s ' ' | cut -d' ' -f1) d=$(printf "%s" "$fmt" | tr -s ' ' | cut -d' ' -f2-) jq -cn --arg i "$i" --arg d "$d" '{i:$i,d:$d}' @@ -191,6 +183,7 @@ __identifier_fmt_parse() { selects() { __identifier_list "$1" | __identifier_fmt | + grep -v "Monitor of" | _menu | __identifier_fmt_parse } @@ -208,11 +201,6 @@ json) ;; global) target=$(selects "${keyword}") - if [ -z "${target}" ]; then - notif "focused" "no target ${what}" error - exit 1 - fi - notif "global" "switch to <i>$(__identifier_desc "${target}")</i>" # set new default pactl "set-default-${keyword}" "$(__identifier_index "${target}")" @@ -222,128 +210,117 @@ global) exit $? ;; -focused) - # parse pid of currently focused container - # then get the sink-inputs for it and parse the sink-input-id - notif "not implemented, do we need it?" error - exit 1 - - focused_binary=$(swq current con | jq -r '.pid' | xargs ps -o comm=) - what_id=$(printf "%s\n" "${focused_binary}" | - 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) - if [ -z "${what_id}" ]; then - notif "focused" "no ${what}" error - exit 1 - fi - - # select where to switch to - target=$(selects "${keyword}") - if [ -z "${target}" ]; then - exit 1 - fi - - notif "${focused_binary}" "switch to <i>${target}</i>" - pactl move-sink-input "${what_id}" "${target}" - exit $? - ;; - +# focused) +# # parse pid of currently focused container +# # then get the sink-inputs for it and parse the sink-input-id +# notif "not implemented, do we need it?" error +# exit 1 +# +# focused_binary=$(swq current con | jq -r '.pid' | xargs ps -o comm=) +# what_id=$(printf "%s\n" "${focused_binary}" | +# 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) +# if [ -z "${what_id}" ]; then +# notif "focused" "no ${what}" error +# exit 1 +# fi +# +# # select where to switch to +# target=$(selects "${keyword}") +# if [ -z "${target}" ]; then +# exit 1 +# fi +# +# notif "${focused_binary}" "switch to <i>${target}</i>" +# pactl move-sink-input "${what_id}" "${target}" +# exit $? +# ;; +# profile) - notif "not implemented, do we need it?" "" error - exit 1 - - target_card=$(selects "card") + target_card=$(selects "card" | jq -r '.i') if [ -z "${target_card}" ]; then exit 1 fi - # [^\r]#([0-9]+).*?Name: ([^\r]+).*?Profiles:\r(.*?)Active.*?(?=Card #|$) - # target_profile=$(pactl list cards | - # tr '\n' '\r' | - # perl -pe 's/[^\r]#([0-9]+).*?Name: ([^\r]+).*?Profiles:\r(.*?)Active.*?(?=Card #|$)/\2~\3`/g' | - # tr -d '\t' | - # tr '`' '\n' | - # grep "${target_card}" | - # cut -d'~' -f2- | - # tr '\r' '\n' | - # xargs -L1 | - # _menu | - # perl -pe 's/^\s*([^\s]+):\s.*$/\1/') - # if [ -z "${target_profile}" ]; then - # exit 1 - # fi - # - # notif "profile" "switch <i>${target_card}</i> to ${target_profile} profile" - # pactl set-card-profile "${target_card}" "${target_profile}" - # exit $? - ;; - -hdmi) - notif "not implemented, do we need it?" "" error - exit 1 - - target_card=$(selects "card") - if [ -z "${target_card}" ]; then - exit 1 - fi - - target_profile=$(pactl list cards | - tr '\n' '\r' | - perl -pe 's/[^\r]#([0-9]+).*?Name: ([^\r]+).*?Profiles:\r(.*?)Active.*?(?=Card #|$)/\2~\3`/g' | - tr -d '\t' | - tr '`' '\n' | - grep "${target_card}" | - cut -d'~' -f2- | - tr '\r' '\n' | - grep -i "hdmi" | - grep -i -v "input" | - xargs -L1 | - _menu | - perl -pe 's/^\s*([^\s]+):\s.*$/\1/') + target_profile=$( + pactl --format=json list cards | + jq -cr --argjson idx "$target_card" '.[] | select(.index == $idx) | .profiles | keys[]' | + _menu + ) if [ -z "${target_profile}" ]; then - target_profile=${HDMI_PROFILE} - fi - - notif "hdmi" "switch <i>${target_card}</i> to HDMI profile\n<i>${target_profile}</i>" - pactl set-card-profile "${target_card}" "${target_profile}" - exit $? - ;; - -reset) - notif "not implemented, do we need it?" "" error - exit 1 - - target_card=$(selects "card") - if [ -z "${target_card}" ]; then exit 1 fi - notif "reset" "switch <i>${target_card}</i> to default profile" - pactl set-card-profile "${target_card}" ${DEFAULT_PROFILE} - exit $? - ;; - -mute) - notif "not implemented, do we need it?" "" error - exit 1 - - _data=$(pw-dump -N | jq -r '.. | select(.type?=="PipeWire:Interface:Node" and .info.props."media.class"?=="Stream/Output/Audio" and .info.props."stream.is-live"?==true) | @text') - _id=$(printf "${_data}" | jq -r '. | [ .info.props."application.name", .info.props."application.process.id", .id ] | @tsv' | - awk '{ system("swaymsg -t get_tree | jq -r \".. | select(.pid?==" $2 ") | .name\" | grep -v Picture-in-Picture | tr -d \"\\n\""); printf " [%s]", $3 }' | - _menu | - perl -pe 's/^.*\[([0-9]+)\]$/\1/') - if [ -z "${_id}" ]; then - exit 1 - fi - - _oid=$(printf "${_data}" | jq -r --argjson id "${_id}" '.. | select(.id?==$id) | .info.props."object.id"') - _target_state=$(printf "${_data}" | jq -r --argjson id "${_id}" '.. | select(.id?==$id) | .info.params.Props[0] | .mute = (.mute | not) | @text') - pw-cli set-param "${_oid}" Props "${_target_state}" - exit $? + notif "profile" "switch <i>${target_card}</i> to ${target_profile} profile" + pactl set-card-profile "${target_card}" "${target_profile}" ;; +# hdmi) +# notif "not implemented, do we need it?" "" error +# exit 1 +# +# target_card=$(selects "card") +# if [ -z "${target_card}" ]; then +# exit 1 +# fi +# +# target_profile=$(pactl list cards | +# tr '\n' '\r' | +# perl -pe 's/[^\r]#([0-9]+).*?Name: ([^\r]+).*?Profiles:\r(.*?)Active.*?(?=Card #|$)/\2~\3`/g' | +# tr -d '\t' | +# tr '`' '\n' | +# grep "${target_card}" | +# cut -d'~' -f2- | +# tr '\r' '\n' | +# grep -i "hdmi" | +# grep -i -v "input" | +# xargs -L1 | +# _menu | +# perl -pe 's/^\s*([^\s]+):\s.*$/\1/') +# if [ -z "${target_profile}" ]; then +# target_profile=${HDMI_PROFILE} +# fi +# +# notif "hdmi" "switch <i>${target_card}</i> to HDMI profile\n<i>${target_profile}</i>" +# pactl set-card-profile "${target_card}" "${target_profile}" +# exit $? +# ;; +# +# reset) +# notif "not implemented, do we need it?" "" error +# exit 1 +# +# target_card=$(selects "card") +# if [ -z "${target_card}" ]; then +# exit 1 +# fi +# +# notif "reset" "switch <i>${target_card}</i> to default profile" +# pactl set-card-profile "${target_card}" ${DEFAULT_PROFILE} +# exit $? +# ;; +# +# mute) +# notif "not implemented, do we need it?" "" error +# exit 1 +# +# _data=$(pw-dump -N | jq -r '.. | select(.type?=="PipeWire:Interface:Node" and .info.props."media.class"?=="Stream/Output/Audio" and .info.props."stream.is-live"?==true) | @text') +# _id=$(printf "${_data}" | jq -r '. | [ .info.props."application.name", .info.props."application.process.id", .id ] | @tsv' | +# awk '{ system("swaymsg -t get_tree | jq -r \".. | select(.pid?==" $2 ") | .name\" | grep -v Picture-in-Picture | tr -d \"\\n\""); printf " [%s]", $3 }' | +# _menu | +# perl -pe 's/^.*\[([0-9]+)\]$/\1/') +# if [ -z "${_id}" ]; then +# exit 1 +# fi +# +# _oid=$(printf "${_data}" | jq -r --argjson id "${_id}" '.. | select(.id?==$id) | .info.props."object.id"') +# _target_state=$(printf "${_data}" | jq -r --argjson id "${_id}" '.. | select(.id?==$id) | .info.params.Props[0] | .mute = (.mute | not) | @text') +# pw-cli set-param "${_oid}" Props "${_target_state}" +# exit $? +# ;; +# esac |