#!/bin/sh
#---help---
# Usage:
#   $0 [options] <command> [<value>[%]]
#   $0 [options] (+|-)<value>%
#   $0 [options] [=]<value>%
#   $0 -h
#
# Adjust the sound or mic volume using 'pamixer' and show an on-screen
# notification using 'avizo-client'.
#
# Commands:
#   + | up           Increase the volume by <value> percents (defaults to 5).
#   - | down         Decrease the volume by <value> percents (defaults to 5).
#   = | set          Set volume to <value> percents.
#   x | mute         Set mute.
#   u | unmute       Unset mute.
#   % | toggle-mute  Switch between mute and unmute.
#
# Options:
#   -b               Allow volume to go above 100% (boost).
#   -m               Control the source (mic) instead of sink (output).
#   -u               Unmute when changing the volume (+|-|=).
#   -h               Show this message and exit.
#
# This script is part of the avizo package.
#---help---
# This script is POSIX Shell Command Language compliant.
set -eu

if ( set -o pipefail 2>/dev/null ); then
	set -o pipefail
fi

PROGNAME='volumectl'

help() {
	local tag='---help---'
	sed -n "/^#$tag/,/^#$tag/{/^#$tag/d; s/^# \\?//; s|\$0|$0|; p}" "$0"
}

die() {
	printf "$PROGNAME: %s\n" "$1" >&2
	exit 1
}

is_integer() {
	expr "$1" : '[0-9]\+$' >/dev/null
}

playing_dev_id() {
	if command -v pactl >/dev/null; then
		pactl list short ${1}s | grep RUNNING | grep -m1 -o '^[0-9]\+'
	else  # this works since pamixer 1.6
		pamixer --list-${1}s | grep '"Running"' | grep -m1 -o '^[0-9]\+'
	fi
}

set_property_cmd() {
  if [ $1 != "source" ] &&  [ $1 != "sink" ]; then
    die "Unknown stream type: $1"
  fi
  echo "set-$1-$2"
}

get_property_val_cmd() {
  if [ $1 != "source" ] && [ $1 != "sink" ]; then
    die "Unknown stream type: $1"
  fi
  echo "get-$1-$2"
}

is_muted() {
  dev_type_capital=$(echo "$1" | sed 's/.*/\u&/')
  prop_name="Default $dev_type_capital: "
  prop_name_len=$(( ${#prop_name} + 1 ))
  dev_id=$(pactl info | grep "$prop_name" | cut -c $prop_name_len)
  muted=$( pactl list | grep "$dev_id" -A 12 | grep Mute | grep "yes" | wc -l)
  echo $muted
}

allow_boost=false
dev_type='sink'
unmute=false
optind=1
while getopts ':b:p:muh' OPT; do
	case "$OPT" in
		b) allow_boost=true;;
		m) dev_type='source';;
		u) unmute=true;;
		h) help; exit 0;;
		\?) case "$OPTARG" in
		    	[0-9]*) break;;
		    	*) die "unknown option: -$OPTARG";;
		    esac
		;;
	esac
	optind=$OPTIND  # hack to make -<value>% work correctly
done
shift $((optind -1))

if [ $# -lt 1 ] || [ $# -gt 2 ]; then
	die "invalid number of arguments (see '$0 -h')"
fi

case "$1" in
	[=+-][0-9]*%) cmd=${1%%[0-9]*}; value=${1#[=+-]};;
	[0-9]*%) cmd='='; value=$1;;
	*) cmd=$1; value=${2:-5};;
esac
value=${value%\%}

if ! is_integer "$value"; then
	die "invalid value: '$value'"
fi

# Note: 'raise' and 'lower' are only for backward compatibility with
#  the previous version of this script.

cmd_type=""
is_volume_cmd=false
case "$cmd" in
	+ | up | raise) 
    cmd_opt="+$value%"
    is_volume_cmd=true
    cmd_type=$(set_property_cmd "$dev_type" "volume");;
	- | down | lower) 
    cmd_opt="-$value%"
    is_volume_cmd=true
    cmd_type=$(set_property_cmd "$dev_type" "volume");;
	= | set) 
    cmd_opt="$value%"
    is_volume_cmd=true
    cmd_type=$(set_property_cmd "$dev_type" "volume");;
	x | mute) 
    cmd_opt='true' 
    cmd_type=$(set_property_cmd "$dev_type" "mute");;
	u | unmute) 
    cmd_opt='false' 
    cmd_type=$(set_property_cmd "$dev_type" "mute");;
	% | toggle-mute) 
    cmd_opt='toggle'
    cmd_type=$(set_property_cmd "$dev_type" "mute");;
	*) die "invalid command: $cmd (see '$0 -h')";;
esac

dev_type_upper=$(echo $dev_type |tr '[:lower:]' '[:upper:]')
dev_opt="@DEFAULT_$dev_type_upper@"

if $is_volume_cmd && $unmute; then
 pactl "set-$dev_type-mute" $dev_opt false
fi

pactl $cmd_type $dev_opt $cmd_opt

muted=$(is_muted $dev_type)
volume=$(pactl $(get_property_val_cmd $dev_type "volume") $dev_opt | head -n 1| awk '{print substr($5, 1, length($5)-1)}')

if $allow_boost && $is_volume_cmd && [ "$volume" -gt "100" ]; then
  pactl $cmd_type $dev_opt 100%
fi


if ! is_integer "$volume"; then
	die "pactl returned invalid volume level: '$volume'"
fi

case "$dev_type" in
	sink)
		if [ "$muted" -gt "0" ]; then
			image='volume_muted'
		elif [ "$volume" -le 33 ]; then
			image='volume_low'
		elif [ "$volume" -le 66 ]; then
			image='volume_medium'
		else
			image='volume_high'
		fi
	;;
	source)
		if [ "$muted" = 'true' ]; then
			image='mic_muted'
		else
			image='mic_unmuted'
		fi
	;;
esac

progress=$(echo "$volume" | awk '{ printf "%.2f", ($1 > 100 ? 1 : $1 / 100) }')
avizo-client --image-resource="$image" --progress="$progress"
