You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
362 lines
12 KiB
362 lines
12 KiB
#!/bin/bash
|
|
# Displays the default device, volume, and mute status for i3blocks
|
|
|
|
# default vars {{{ #
|
|
|
|
set -a
|
|
|
|
SINK_SYMB=""
|
|
|
|
AUDIO_HIGH_SYMBOL=${AUDIO_HIGH_SYMBOL:-''}
|
|
|
|
AUDIO_MED_THRESH=${AUDIO_MED_THRESH:-50}
|
|
AUDIO_MED_SYMBOL=${AUDIO_MED_SYMBOL:-''}
|
|
|
|
AUDIO_LOW_THRESH=${AUDIO_LOW_THRESH:-0}
|
|
AUDIO_LOW_SYMBOL=${AUDIO_LOW_SYMBOL:-''}
|
|
|
|
AUDIO_MUTED_SYMBOL=${AUDIO_MUTED_SYMBOL:-''}
|
|
|
|
. "/home/kevin/.cache/wal/colors.sh"
|
|
# DEFAULT_COLOR=${DEFAULT_COLOR:-"#ffffff"}
|
|
DEFAULT_COLOR="$color7"
|
|
MUTED_COLOR=${MUTED_COLOR:-"#a0a0a0"}
|
|
|
|
USE_ALSA_NAME=${USE_ALSA_NAME:-0}
|
|
USE_DESCRIPTION=${USE_DESCRIPTION:-0}
|
|
|
|
SUBSCRIBE=${SUBSCRIBE:-0}
|
|
|
|
MIXER=${MIXER:-""}
|
|
SCONTROL=${SCONTROL:-""}
|
|
|
|
# }}} default vars #
|
|
|
|
AUDIO_DELTA=${AUDIO_DELTA:-3}
|
|
# AUDIO_DELTA=${AUDIO_DELTA:-2}
|
|
# AUDIO_DELTA=${AUDIO_DELTA:-1}
|
|
|
|
# LONG_FORMAT=${LONG_FORMAT:-'${SYMB} ${VOL}% [${INDEX}:${NAME}]'}
|
|
LONG_FORMAT=${SHORT_FORMAT:-'${SINK_SYMB} ${VOL}%'}
|
|
# SHORT_FORMAT=${SHORT_FORMAT:-'${SYMB} ${VOL}%[${INDEX}]'}
|
|
SHORT_FORMAT=${SHORT_FORMAT:-'${SINK_SYMB} ${VOL}%'}
|
|
|
|
# flags {{{ #
|
|
|
|
while getopts F:Sf:adH:M:L:X:T:t:C:c:i:m:s:h opt; do
|
|
case "$opt" in
|
|
S) SUBSCRIBE=1 ;;
|
|
F) LONG_FORMAT="$OPTARG" ;;
|
|
f) SHORT_FORMAT="$OPTARG" ;;
|
|
a) USE_ALSA_NAME=1 ;;
|
|
d) USE_DESCRIPTION=1 ;;
|
|
H) AUDIO_HIGH_SYMBOL="$OPTARG" ;;
|
|
M) AUDIO_MED_SYMBOL="$OPTARG" ;;
|
|
L) AUDIO_LOW_SYMBOL="$OPTARG" ;;
|
|
X) AUDIO_MUTED_SYMBOL="$OPTARG" ;;
|
|
T) AUDIO_MED_THRESH="$OPTARG" ;;
|
|
t) AUDIO_LOW_THRESH="$OPTARG" ;;
|
|
C) DEFAULT_COLOR="$OPTARG" ;;
|
|
c) MUTED_COLOR="$OPTARG" ;;
|
|
i) AUDIO_INTERVAL="$OPTARG" ;;
|
|
m) MIXER="$OPTARG" ;;
|
|
s) SCONTROL="$OPTARG" ;;
|
|
h) printf \
|
|
"Usage: volume-pulseaudio [-S] [-F format] [-f format] [-p] [-a|-d] [-H symb] [-M symb]
|
|
[-L symb] [-X symb] [-T thresh] [-t thresh] [-C color] [-c color] [-i inter]
|
|
[-m mixer] [-s scontrol] [-h]
|
|
Options:
|
|
-F, -f\tOutput format (-F long format, -f short format) to use, with exposed variables:
|
|
\${SYMB}, \${VOL}, \${INDEX}, \${NAME}
|
|
-S\tSubscribe to volume events (requires persistent block, always uses long format)
|
|
-a\tUse ALSA name if possible
|
|
-d\tUse device description instead of name if possible
|
|
-H\tSymbol to use when audio level is high. Default: '$AUDIO_HIGH_SYMBOL'
|
|
-M\tSymbol to use when audio level is medium. Default: '$AUDIO_MED_SYMBOL'
|
|
-L\tSymbol to use when audio level is low. Default: '$AUDIO_LOW_SYMBOL'
|
|
-X\tSymbol to use when audio is muted. Default: '$AUDIO_MUTED_SYMBOL'
|
|
-T\tThreshold for medium audio level. Default: $AUDIO_MED_THRESH
|
|
-t\tThreshold for low audio level. Default: $AUDIO_LOW_THRESH
|
|
-C\tColor for non-muted audio. Default: $DEFAULT_COLOR
|
|
-c\tColor for muted audio. Default: $MUTED_COLOR
|
|
-i\tInterval size of volume increase/decrease. Default: $AUDIO_DELTA
|
|
-m\tUse the given mixer.
|
|
-s\tUse the given scontrol.
|
|
-h\tShow this help text
|
|
" && exit 0;;
|
|
esac
|
|
done
|
|
|
|
# }}} flags #
|
|
|
|
# functions {{{ #
|
|
|
|
if [[ -z "$MIXER" ]] ; then
|
|
MIXER="default"
|
|
if amixer -D pulse info >/dev/null 2>&1 ; then
|
|
MIXER="pulse"
|
|
fi
|
|
fi
|
|
|
|
if [[ -z "$SCONTROL" ]] ; then
|
|
SCONTROL=$(amixer -D "$MIXER" scontrols | sed -n "s/Simple mixer control '\([^']*\)',0/\1/p" | head -n1)
|
|
fi
|
|
|
|
CAPABILITY=$(amixer -D $MIXER get $SCONTROL | sed -n "s/ Capabilities:.*cvolume.*/Capture/p")
|
|
|
|
|
|
function move_sinks_to_new_default {
|
|
DEFAULT_SINK=$1
|
|
pacmd list-sink-inputs | grep index: | grep -o '[0-9]\+' | while read SINK
|
|
do
|
|
pacmd move-sink-input $SINK $DEFAULT_SINK
|
|
done
|
|
}
|
|
|
|
function set_default_playback_device_next {
|
|
inc=${1:-1}
|
|
num_devices=$(pacmd list-sinks | grep -c index:)
|
|
sink_arr=($(pacmd list-sinks | grep index: | grep -o '[0-9]\+'))
|
|
default_sink_index=$(( $(pacmd list-sinks | grep index: | grep -no '*' | grep -o '^[0-9]\+') - 1 ))
|
|
default_sink_index=$(( ($default_sink_index + $num_devices + $inc) % $num_devices ))
|
|
default_sink=${sink_arr[$default_sink_index]}
|
|
pacmd set-default-sink $default_sink
|
|
move_sinks_to_new_default $default_sink
|
|
}
|
|
|
|
# }}} functions #
|
|
|
|
# triggers {{{ #
|
|
|
|
case "$BLOCK_BUTTON" in
|
|
1) set_default_playback_device_next ;;
|
|
# 2) amixer -q -D $MIXER sset $SCONTROL $CAPABILITY toggle ;;
|
|
2) amixer -q -D $MIXER sset $SCONTROL $CAPABILITY 15% ;;
|
|
3) set_default_playback_device_next -1 ;;
|
|
4) amixer -q -D $MIXER sset $SCONTROL $CAPABILITY $AUDIO_DELTA%+ ;;
|
|
5) amixer -q -D $MIXER sset $SCONTROL $CAPABILITY $AUDIO_DELTA%- ;;
|
|
esac
|
|
|
|
# }}} triggers #
|
|
|
|
# print_format {{{ #
|
|
|
|
function print_format {
|
|
case $NAME in
|
|
*"Fiio"*)
|
|
SINK_SYMB=""
|
|
;;
|
|
*"hdmi"*)
|
|
SINK_SYMB=""
|
|
;;
|
|
*"pci"*)
|
|
SINK_SYMB=" "
|
|
;;
|
|
esac
|
|
eval "echo \"$1\""
|
|
}
|
|
|
|
# }}} print_format #
|
|
|
|
# print_block {{{ #
|
|
|
|
function print_block {
|
|
# Use pactl instead of pacmd to get sink information
|
|
SINK_INFO=$(pactl list sinks | awk '
|
|
/^Sink #/{sink=$2}
|
|
/Volume: front-left/{volume=$5}
|
|
/Mute:/{muted=$2}
|
|
/Name:/{name=$2}
|
|
/Description:/{description=$0; sub(/Description: /, "", description)}
|
|
/Active Port:/{port=$3}
|
|
/^\s*$/{if (sink && sink ~ /\*/) {print sink; print name; print volume; print muted; exit}}
|
|
')
|
|
|
|
# Parse the output
|
|
INDEX=$(echo "$SINK_INFO" | sed -n '1p' | tr -d '#*')
|
|
NAME=$(echo "$SINK_INFO" | sed -n '2p')
|
|
VOL=$(echo "$SINK_INFO" | sed -n '3p' | grep -o "[0-9]*%" | head -1)
|
|
VOL="${VOL%?}"
|
|
MUTED=$(echo "$SINK_INFO" | sed -n '4p')
|
|
|
|
if [[ $USE_ALSA_NAME == 1 ]] ; then
|
|
ALSA_NAME=$(pactl list sinks | awk '
|
|
/^Sink #/{sink=$2}
|
|
/alsa.name =/{alsa_name=$3; gsub(/"/, "", alsa_name)}
|
|
/^\s*$/{if (sink && sink ~ /\*/) {print alsa_name; exit}}
|
|
')
|
|
NAME=${ALSA_NAME:-$NAME}
|
|
elif [[ $USE_DESCRIPTION == 1 ]] ; then
|
|
DESCRIPTION=$(pactl list sinks | awk '
|
|
/^Sink #/{sink=$2}
|
|
/Description:/{description=$0; sub(/Description: /, "", description)}
|
|
/^\s*$/{if (sink && sink ~ /\*/) {print description; exit}}
|
|
')
|
|
NAME=${DESCRIPTION:-$NAME}
|
|
fi
|
|
|
|
if [[ $MUTED =~ "no" ]] ; then
|
|
SYMB=$AUDIO_HIGH_SYMBOL
|
|
[[ $VOL -le $AUDIO_MED_THRESH ]] && SYMB=$AUDIO_MED_SYMBOL
|
|
[[ $VOL -le $AUDIO_LOW_THRESH ]] && SYMB=$AUDIO_LOW_SYMBOL
|
|
COLOR=$DEFAULT_COLOR
|
|
else
|
|
SYMB=$AUDIO_MUTED_SYMBOL
|
|
COLOR=$MUTED_COLOR
|
|
fi
|
|
|
|
if [[ $SUBSCRIBE == 1 ]] ; then
|
|
print_format "$LONG_FORMAT"
|
|
else
|
|
print_format "$LONG_FORMAT"
|
|
print_format "$SHORT_FORMAT"
|
|
echo "$COLOR"
|
|
fi
|
|
}
|
|
|
|
# }}} print_block #
|
|
|
|
print_block
|
|
if [[ $SUBSCRIBE == 1 ]] ; then
|
|
while read -r EVENT; do
|
|
print_block
|
|
done < <(pactl subscribe | stdbuf -oL grep change)
|
|
fi
|
|
|
|
# Hardware Configuration
|
|
#CARD=2
|
|
#SINK="alsa_output.pci-0000_30_00.6.analog-stereo"
|
|
#FRONT="Front Playback Switch"
|
|
#REAR="Surround Playback Switch"
|
|
#FRONT_VOL="Front Playback Volume"
|
|
#REAR_VOL="Surround Playback Volume"
|
|
|
|
## Debugging output
|
|
#LOG_FILE=~/.audio-toggle.log
|
|
#echo "=== $(date) ===" >> $LOG_FILE
|
|
|
|
## Get current active output (PulseAudio fallback)
|
|
#get_active_output() {
|
|
## Get full sink info for debugging
|
|
#SINK_INFO=$(pacmd list-sinks)
|
|
#echo "Full sink info:" >> $LOG_FILE
|
|
#echo "$SINK_INFO" >> $LOG_FILE
|
|
|
|
## Try alternative port detection method
|
|
#PORT=$(echo "$SINK_INFO" | awk -v sink="$SINK" '
|
|
#$1 == "name:" && $2 == "<"sink">" {active=1}
|
|
#active && /active port:/ {
|
|
## Extract port name between angle brackets
|
|
#match($0, /<[^>]+>/)
|
|
#port = substr($0, RSTART+1, RLENGTH-2)
|
|
#print port
|
|
#exit
|
|
#}
|
|
#')
|
|
|
|
#echo "Raw port detection: $PORT" >> $LOG_FILE
|
|
|
|
#if [[ "$PORT" == "analog-output-headphones" ]]; then
|
|
#echo "front"
|
|
#elif [[ "$PORT" == "analog-output-lineout" ]]; then
|
|
#echo "rear"
|
|
#else
|
|
#echo "unknown"
|
|
#fi
|
|
#}
|
|
|
|
## Switch outputs with hardware-level control
|
|
#switch_output() {
|
|
#echo "Starting switch to $1" >> $LOG_FILE
|
|
|
|
## First disable both outputs
|
|
#echo "Disabling both outputs" >> $LOG_FILE
|
|
## ALSA controls
|
|
#amixer -c $CARD set "$FRONT" mute >/dev/null
|
|
#amixer -c $CARD set "$FRONT_VOL" 0% >/dev/null
|
|
#amixer -c $CARD set "$REAR" mute >/dev/null
|
|
#amixer -c $CARD set "$REAR_VOL" 0% >/dev/null
|
|
## PulseAudio controls
|
|
#pactl set-sink-mute "$SINK" 1 >/dev/null
|
|
#sleep 0.2
|
|
|
|
#if [[ "$1" == "front" ]]; then
|
|
#echo "Enabling front output" >> $LOG_FILE
|
|
## Check if headphones port exists
|
|
#if echo "$SINK_INFO" | grep -q "analog-output-headphones"; then
|
|
#echo "Attempting to set port to analog-output-headphones" >> $LOG_FILE
|
|
#if ! pacmd set-sink-port "$SINK" "analog-output-headphones" 2>>$LOG_FILE; then
|
|
#echo "Port switch failed, trying alternative method" >> $LOG_FILE
|
|
#pactl set-sink-port "$SINK" "analog-output-headphones" 2>>$LOG_FILE || true
|
|
#fi
|
|
#else
|
|
#echo "Headphones port not available, using hardware controls only" >> $LOG_FILE
|
|
#fi
|
|
## Additional hardware control
|
|
#amixer -c $CARD set 'Headphone' unmute >/dev/null
|
|
#amixer -c $CARD set 'Speaker' mute >/dev/null
|
|
#pactl set-sink-mute "$SINK" 0 >/dev/null
|
|
## ALSA controls
|
|
#amixer -c $CARD set "$FRONT" unmute >/dev/null
|
|
#amixer -c $CARD set "$FRONT_VOL" 100% >/dev/null
|
|
#OUTPUT=" FRONT"
|
|
#else
|
|
#echo "Enabling rear output" >> $LOG_FILE
|
|
## PulseAudio controls
|
|
#echo "Attempting to set port to analog-output-lineout" >> $LOG_FILE
|
|
#if ! pacmd set-sink-port "$SINK" "analog-output-lineout" 2>>$LOG_FILE; then
|
|
#echo "Port switch failed, trying alternative method" >> $LOG_FILE
|
|
#pactl set-sink-port "$SINK" "analog-output-lineout" 2>>$LOG_FILE || true
|
|
#fi
|
|
## Additional hardware control
|
|
#amixer -c $CARD set 'Speaker' unmute >/dev/null
|
|
#amixer -c $CARD set 'Headphone' mute >/dev/null
|
|
#pactl set-sink-mute "$SINK" 0 >/dev/null
|
|
## ALSA controls
|
|
#amixer -c $CARD set "$REAR" unmute >/dev/null
|
|
#amixer -c $CARD set "$REAR_VOL" 100% >/dev/null
|
|
#OUTPUT=" REAR"
|
|
#fi
|
|
|
|
## Reset audio pipeline
|
|
#echo "Resetting audio pipeline" >> $LOG_FILE
|
|
#{ pactl suspend-sink "$SINK" 1 && sleep 0.2 && pactl suspend-sink "$SINK" 0; } >/dev/null 2>&1
|
|
|
|
## Verify switch
|
|
#echo "Verifying switch..." >> $LOG_FILE
|
|
#CURRENT=$(get_active_output)
|
|
#echo "Current output: $CURRENT" >> $LOG_FILE
|
|
#if [[ "$CURRENT" != "$1" ]]; then
|
|
#echo "Switch verification failed!" >> $LOG_FILE
|
|
## Force hardware-level switch
|
|
#echo "Forcing hardware-level switch..." >> $LOG_FILE
|
|
#if [[ "$1" == "front" ]]; then
|
|
#amixer -c $CARD set 'Headphone' unmute >/dev/null
|
|
#amixer -c $CARD set 'Speaker' mute >/dev/null
|
|
#else
|
|
#amixer -c $CARD set 'Speaker' unmute >/dev/null
|
|
#amixer -c $CARD set 'Headphone' mute >/dev/null
|
|
#fi
|
|
#fi
|
|
|
|
#echo "Switch complete" >> $LOG_FILE
|
|
#echo "$OUTPUT" # Output to i3blocks
|
|
#}
|
|
|
|
## Main execution
|
|
#case "${BLOCK_BUTTON:-}" in
|
|
#1)
|
|
#CURRENT=$(get_active_output)
|
|
#if [[ "$CURRENT" == "front" ]]; then
|
|
#switch_output "rear"
|
|
#else
|
|
#switch_output "front"
|
|
#fi
|
|
#;;
|
|
#*)
|
|
#CURRENT=$(get_active_output)
|
|
#[[ "$CURRENT" == "front" ]] && echo " FRONT" || echo " REAR"
|
|
#;;
|
|
#esac
|
|
|
|
#exit 0
|