From ee048953ab2bbd3cf8a8aaeaab07b3115ee48f4b Mon Sep 17 00:00:00 2001 From: Arti Zirk Date: Fri, 2 Jun 2023 15:45:09 +0300 Subject: [PATCH] Hack pipewire to work with i3blocks --- .bin/pipewire-sink.sh | 19 ++++ .config/i3blocks/config | 2 +- .config/i3blocks/volume-pipewire | 171 +++++++++++++++++++++++++++++++ 3 files changed, 191 insertions(+), 1 deletion(-) create mode 100755 .bin/pipewire-sink.sh create mode 100755 .config/i3blocks/volume-pipewire diff --git a/.bin/pipewire-sink.sh b/.bin/pipewire-sink.sh new file mode 100755 index 0000000..826bcff --- /dev/null +++ b/.bin/pipewire-sink.sh @@ -0,0 +1,19 @@ +#!/bin/sh +# src: https://codeberg.org/trill/dotfiles/src/branch/master/.local/bin/i3blocks/pipewire-sink.sh + +# `pactl list sinks` shows sink properties with a mix of english language and local language +# defined by LANG env var, so we unset the var to guarantee only the fallback language is used +unset LANG; +sink_list="$(wpctl status | sed -n '/^Audio/,/Sink endpoints:/p' | sed -n '/Sinks:/,/|\s*$/p' | head -n -2 | tail -n +2 | tr -d '│')" + + +CONTENT="$sink_list" +OPTION_SELECTED=$(echo "$CONTENT" \ + | rofi -dmenu -location 2 \ + | sed -e 's/[^0-9]*\([0-9]*\).*/\1/g') + +echo "" +if ! [[ -z "$OPTION_SELECTED" ]]; then + wpctl set-default "$OPTION_SELECTED" +fi + diff --git a/.config/i3blocks/config b/.config/i3blocks/config index 81756c5..8cc2aed 100644 --- a/.config/i3blocks/config +++ b/.config/i3blocks/config @@ -46,7 +46,7 @@ signal=10 # The second parameter overrides the mixer selection # See the script for details. [volume] -command=~/.config/i3blocks/volume-pulseaudio -d -i 1 -H '' -M '' -L '' -X 'm' +command=~/.config/i3blocks/volume-pipewire -d -i 1 -H '' -M '' -L '' -X 'm' #label=VOL label=♪ #instance=Master diff --git a/.config/i3blocks/volume-pipewire b/.config/i3blocks/volume-pipewire new file mode 100755 index 0000000..c518b25 --- /dev/null +++ b/.config/i3blocks/volume-pipewire @@ -0,0 +1,171 @@ +#!/bin/bash +# Displays the default device, volume, and mute status for i3blocks + +set -a + +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:-' '} + +AUDIO_DELTA=${AUDIO_DELTA:-1} + +DEFAULT_COLOR=${DEFAULT_COLOR:-"#ffffff"} +MUTED_COLOR=${MUTED_COLOR:-"#a0a0a0"} + +LONG_FORMAT=${LONG_FORMAT:-'${SYMB} ${VOL}% [${INDEX}:${NAME}]'} +SHORT_FORMAT=${SHORT_FORMAT:-'${SYMB} ${VOL}% [${INDEX}]'} +USE_ALSA_NAME=${USE_ALSA_NAME:-0} +USE_DESCRIPTION=${USE_DESCRIPTION:-0} + +SUBSCRIBE=${SUBSCRIBE:-0} + +MIXER=${MIXER:-""} +SCONTROL=${SCONTROL:-""} + +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 + +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 + pactl list sink-inputs | grep index: | grep -o '[0-9]\+' | while read SINK + do + pactl move-sink-input $SINK $DEFAULT_SINK + done +} + +function set_default_playback_device_next { + inc=${1:-1} + num_devices=$(pactl list sinks | grep -c 'Sink #') + sink_arr=($(pactl list sinks | grep 'Sink #' | grep -o '[0-9]\+')) + default_sink_index=$(( $(pactl list sinks | grep 'Sink #' | 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]} + pactl set-default-sink $default_sink + move_sinks_to_new_default $default_sink +} + +case "$BLOCK_BUTTON" in + 1) ~/.bin/pipewire-sink.sh ;; + 2) amixer -q -D $MIXER sset $SCONTROL $CAPABILITY toggle ;; + 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 + +function print_format { + echo "$1" | envsubst '${SYMB}${VOL}${INDEX}${NAME}' +} + +function print_block { + ACTIVE=$(pactl list sinks | grep "State: RUNNING" -B4 -A55 | grep "Name:\|Volume: \(front-left\|mono\)\|Mute:\|api.alsa.pcm.card = \|node.nick = ") + for Name in NAME MUTED VOL INDEX NICK; do + read $Name + done < <(echo "$ACTIVE") + INDEX=$(echo "$INDEX" | grep -o '".*"' | sed 's/"//g') + VOL=$(echo "$VOL" | grep -o "[0-9]*%" | head -1 ) + VOL="${VOL%?}" + NAME=$(echo "$NICK" | grep -o '".*"' | sed 's/"//g') + + if [[ $USE_ALSA_NAME == 1 ]] ; then + ALSA_NAME=$(pactl list sinks |\ +awk '/^\s*\*/{f=1}/^\s*index:/{f=0}f' |\ +grep "alsa.name\|alsa.mixer_name" |\ +head -n1 |\ +sed 's/.*= "\(.*\)".*/\1/') + NAME=${ALSA_NAME:-$NAME} + elif [[ $USE_DESCRIPTION == 1 ]] ; then + DESCRIPTION=$(pactl list sinks | grep "State: RUNNING" -B4 -A55 | grep 'Description: ' | sed 's/^.*: //') + 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 [[ $ACTIVE = "" ]] ; then + echo "Sound inactive" + COLOR='#222225' + fi + + if [[ $SUBSCRIBE == 1 ]] ; then + print_format "$LONG_FORMAT" + else + print_format "$LONG_FORMAT" + print_format "$SHORT_FORMAT" + echo "$COLOR" + fi +} + +print_block +if [[ $SUBSCRIBE == 1 ]] ; then + while read -r EVENT; do + print_block + done < <(pactl subscribe | stdbuf -oL grep change) +fi