#!/bin/bash # omarchy:summary=Switch between audio outputs while preserving the mute status # Skip the physical sink an active speaker tuning fronts: rotating onto it would # silently bypass the tuning rather than pick a different output. fronted=$(omarchy-audio-tuning fronted-sink 2>/dev/null || true) sinks=$(timeout 2 pactl -f json list sinks | jq --arg fronted "$fronted" '[.[] | select((.ports | length == 0) or ([.ports[]? | .availability != "not available"] | any)) | select($fronted == "" or .name != $fronted)]') sinks_count=$(jq 'length' <<<"$sinks") if (( sinks_count == 0 )); then omarchy-osd -m "No audio devices found" exit 1 fi current_sink_name=$(timeout 2 pactl get-default-sink) current_sink_index=$(jq -r --arg name "$current_sink_name" 'map(.name) | index($name)' <<<"$sinks") if [[ $current_sink_index != "null" ]]; then next_sink_index=$(((current_sink_index + 1) % sinks_count)) else next_sink_index=0 fi next_sink=$(jq -c ".[$next_sink_index]" <<<"$sinks") next_sink_name=$(jq -r '.name' <<<"$next_sink") next_sink_description=$(jq -r '.description // .properties."device.description" // .name' <<<"$next_sink") # A tuning sink sits at a fixed 100% and unmuted while real loudness lives on the # physical sink beneath it, so read the level from whichever sink actually carries # it or the OSD contradicts the volume keys. next_sink_effective=$(omarchy-audio-output-sink "$next_sink_name") next_sink_volume=$(timeout 2 pactl get-sink-volume "$next_sink_effective" 2>/dev/null | awk 'NR == 1 {for (i = 1; i <= NF; i++) if ($i ~ /%$/) {sub("%", "", $i); print $i; exit}}') [[ -n $next_sink_volume ]] || next_sink_volume=$(jq -r '.volume | to_entries[0].value.value_percent | sub("%"; "") | tonumber' <<<"$next_sink") if [[ $(timeout 2 pactl get-sink-mute "$next_sink_effective" 2>/dev/null) == *yes ]]; then next_sink_is_muted=true else next_sink_is_muted=false fi if [[ $next_sink_is_muted == "true" ]] || (( next_sink_volume == 0 )); then icon_state="muted" elif (( next_sink_volume <= 33 )); then icon_state="low" elif (( next_sink_volume <= 66 )); then icon_state="medium" else icon_state="high" fi if [[ $next_sink_name != $current_sink_name ]]; then omarchy-audio-output-set-default "$(jq -r '.index' <<<"$next_sink")" "$next_sink_name" fi omarchy-osd -i "volume-${icon_state}" -m "$next_sink_description"