From 63feeb9f369fc6176e85c1c2d8fcc863caad1946 Mon Sep 17 00:00:00 2001 From: Robert Günzler Date: Tue, 10 Feb 2026 12:32:48 +0100 Subject: start new MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Robert Günzler --- bin/soundswitch | 326 -------------------------------------------------------- 1 file changed, 326 deletions(-) delete mode 100755 bin/soundswitch (limited to 'bin/soundswitch') diff --git a/bin/soundswitch b/bin/soundswitch deleted file mode 100755 index 080f4e0..0000000 --- a/bin/soundswitch +++ /dev/null @@ -1,326 +0,0 @@ -#!/bin/bash -# -# DESCRIPTION: -# dmenu-based audio helper -# - -# TODO -# - auto-select the currently active profile - -set -e -[ -n "$DEBUG" ] && set -x - -# check requirements -for tool in jq swq pactl perl pw-dump; 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" -# DEFAULT_PROFILE="pro-audio" -HDMI_PROFILE="output:hdmi-stereo" - -_menu() { - [ -n "${mode}" ] && prompt="soundswitch (${mode})" || prompt="soundswitch" - export MENU_PROMPT=${MENU_PROMPT:-${prompt}} - menu -l10 --ifne --accept-single -} - -mode= -output= -input= -mute= -volume_down= -volume_up= -usage() { - printf "usage: %s [-hIOgfpHRmMvV]\n" "$(basename "$0")" - printf "\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 "\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 -} -_args="$*" -while getopts hIOgfpHRmMvVBj name; do - case ${name} in - j) mode=json ;; - g) mode=global ;; - f) mode=focused ;; - p) mode=profile output=1 input=1 ;; - H) mode=hdmi output=1 input=1 ;; - R) mode=reset ;; - B) mode=mute ;; - O) output=1 ;; - I) input=1 ;; - # 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)) - -# ask mode -_modes=( - "󰴸 output" - "󰍬 input" - "󱂇 profile" - # "󰻿 focused" - # "󰡁 hdmi profile" - # "󰕍 reset profile" - # "󰂛 mute" -) -if [ -z "$mode" ]; then - printf "%s\n" "${_modes[@]}" | - _menu | - { - read -r line - case ${line} in - "${_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 - -# 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@' '-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" - -# returns the sink_id -default() { - key=$1 - case "$1" in - sink) key="audio.default.sink" ;; - source) key="audio.default.source" ;; - esac - pw-dump | jq -r --arg key "$key" '.[]|select(.type=="PipeWire:Interface:Metadata")|.metadata[]|select(.key==$key)|.value.name' -} - -# __identifier: compacted json containing index and description -# 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 | .["device.alias"] // .["alsa.card_name"])}' - else - pactl --format=json list "${1}s" | jq -c '.[]|{i:.index,d:.description}' - fi -} -__identifier_index() { - if [ -z "$1" ]; then - jq -r '.i' - else - printf "%s" "$1" | __identifier_index - fi -} -__identifier_desc() { - if [ -z "$1" ]; then - jq -r '.d' - else - printf "%s" "$1" | __identifier_desc - fi -} -__identifier_fmt() { - jq -r '[.i,.d]|@csv' | tr -d '"' | column -s ',' -t -} -__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}' -} - -selects() { - __identifier_list "$1" | - __identifier_fmt | - grep -v "Monitor of" | - _menu | - __identifier_fmt_parse -} -notif() { - topic=$1 - mesg=$2 - urgency=normal - [ -n "$3" ] && urgency=critical - notify-send -i /usr/share/icons/mdi/scalable/cast-audio.svg -u ${urgency} -a soundswitch "soundswitch: ${topic}" "${mesg}" -} - -case "${mode}" in -json) - selects "${keyword}" - ;; -global) - target=$(selects "${keyword}") - notif "global" "switch to $(__identifier_desc "${target}")" - # set new default - pactl "set-default-${keyword}" "$(__identifier_index "${target}")" - # move all attached to the new target - pactl list "${what}s" short | cut -f1 | - xargs -i pactl "move-${what}" "{}" "$(__identifier_index "${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 ${target}" -# pactl move-sink-input "${what_id}" "${target}" -# exit $? -# ;; -# -profile) - target_card=$(selects "card" | jq -r '.i') - if [ -z "${target_card}" ]; then - exit 1 - fi - - target_profile=$( - pactl --format=json list cards | - jq -cr --argjson idx "$target_card" '.[] | select(.index == $idx) | .profiles | keys[]' | - _menu - ) - if [ -z "${target_profile}" ]; then - exit 1 - fi - - notif "profile" "switch ${target_card} 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 ${target_card} to HDMI profile\n${target_profile}" -# 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 ${target_card} 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 -- cgit 1.4.1