-- Provides:
-- signal::volume
--      percentage (integer)
--      muted (boolean)
local awful = require("awful")

local volume_old = -1
local muted_old = -1
local function emit_volume_info()
    -- Get volume info of the currently active sink
    -- The currently active sink has a star `*` in front of its index
    -- In the output of `pacmd list-sinks`, lines +7 and +11 after "* index:"
    -- contain the volume level and muted state respectively
    -- This is why we are using `awk` to print them.
    awful.spawn.easy_async_with_shell(
        "pacmd list-sinks | awk '/\\* index: /{nr[NR+7];nr[NR+11]}; NR in nr'",
        function(stdout)
            local volume = stdout:match('(%d+)%% /')
            local muted = stdout:match('muted:(%s+)[yes]')
            local muted_int = muted and 1 or 0
            local volume_int = tonumber(volume)
            -- Only send signal if there was a change
            -- We need this since we use `pactl subscribe` to detect
            -- volume events. These are not only triggered when the
            -- user adjusts the volume through a keybind, but also
            -- through `pavucontrol` or even without user intervention,
            -- when a media file starts playing.
            if volume_int ~= volume_old or muted_int ~= muted_old then
                awesome.emit_signal("signal::volume", volume_int, muted)
                volume_old = volume_int
                muted_old = muted_int
            end
        end)
end

-- Run once to initialize widgets
emit_volume_info()

-- Sleeps until pactl detects an event (volume up/down/toggle mute)
local volume_script = [[
    bash -c "
    LANG=C pactl subscribe 2> /dev/null | grep --line-buffered \"Event 'change' on sink #\"
    "]]

-- Kill old pactl subscribe processes
awful.spawn.easy_async({
    "pkill", "--full", "--uid", os.getenv("USER"), "^pactl subscribe"
}, function()
    -- Run emit_volume_info() with each line printed
    awful.spawn.with_line_callback(volume_script, {
        stdout = function(line) emit_volume_info() end
    })
end)
