#!/usr/bin/awk -f

function get_parent(pid,   cmd, ppid, arr) {
	cmd = sprintf("/proc/%d/stat", pid)
	ppid = ""
	if ((getline line < cmd) > 0) {
		split(line, arr)
		ppid = arr[4]
	}
	close(cmd)
	return ppid
}

function proc_clients(line,   arr) {
	if (match(line, /^Client #(.*)/, arr)) {
		store_client()
		client_index = arr[1]
		return
	}
	else if (match(line, /^\s*application\.process\.id = "(.*)"/, arr)) {
		process_id = arr[1]
		return
	}
	else if (match(line, /^\s*application\.name = "(.*)"/, arr)) {
		application_name = arr[1]
		return
	}
}

function store_client() {
	if (client_index == "")
		return

	clients[client_index] = 1
	clients[client_index, "pid"] = process_id
	clients[client_index, "parent_pid"] = get_parent(process_id)
	clients[client_index, "name"] = application_name
	client_index = ""
	process_id = ""
}

function proc_sink_inputs(line,   arr) {
	if (match(line, /^Sink Input #(.*)/, arr)) {
		apply_sink_input()
		sink_index = arr[1]
		return
	}
	else if (match(line, /^\s*application\.process\.id = "(.*)"/, arr)) {
		process_id = arr[1]
		return
	}
	else if (match(line, /^\s*Client: (.*)/, arr)) {
		client_index = arr[1]
		return
	}
	else if (match(line, /^\s*Mute: (.*)/, arr)) {
		muted = (arr[1] == "yes")
		return
	}
	else if (match(line, /^\s*Volume:.* ([0-9]+)%/, arr)) {
		volume = strtonum(arr[1])
		return
	}
}

function apply_sink_input(   cmd, header, msg, inc) {
	if (sink_index == "")
		return

	# Do stuff if PID matches
	if (PID == clients[client_index, "pid"] || PID == clients[client_index, "parent_pid"]) {
		switch (ACTION) {
			case "-i":
			case "-d":
				inc = strtonum(ARG)
				if (ACTION == "-i")
					volume += inc
				else
					volume -= inc
				volume = volume > 100 ? 100 : volume
				volume = volume < 0   ? 0   : volume
				cmd = sprintf("pactl set-sink-input-volume '%d' '%d'%", sink_index, volume)
				system(cmd)
                print cmd
				break
			case "-t":
				muted = !muted
				cmd = sprintf("pactl set-sink-input-mute '%d' '%s'", sink_index, muted ? "true" : "false")
				system(cmd)
				print cmd
				break
		}
		# Display a "popup" with new volume
		header = sprintf("Client Volume: %d%%%s", volume, muted ? " MUTED" : "")
		msg = clients[client_index, "name"]
		system(sprintf("notify-send -r 101 -u low -h 'int:value:%d' '%s' '%s'", volume, header, msg))
	}

	sink_index = ""
}

BEGIN {
	# Get arguments
	# ACTION: -d, -i or -t (like pamixer)
	# ARG:    num arg for -d or -i
	ACTION = ARGV[1]
	ARG    = ARGV[2]
	for (i = 1; i < ARGC; i++)
		delete ARGV[i]

	# Get client info
	getline PID
	getline TITLE     # Not used
	getline APPID     # Not used
	getline TAGS      # Not used
	getline GEOMETRY  # Not used

	if (PID == "")
		exit 1

	# Process PulseAudio clients list and store PIDs for each
	cmd = "pactl list clients"
	while ((cmd | getline line) > 0)
		proc_clients(line)
	close(cmd)
	store_client()

	# Process PulseAudio sink inputs list and run apply_sink_input() for each
	cmd = "pactl list sink-inputs"
	while ((cmd | getline line) > 0)
		proc_sink_inputs(line)
	close(cmd)
	apply_sink_input()
}
