summary refs log tree commit diff
path: root/bin/soundswitch
diff options
context:
space:
mode:
Diffstat (limited to 'bin/soundswitch')
-rwxr-xr-xbin/soundswitch305
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