summaryrefslogtreecommitdiff
path: root/lib/pavolctld.lua
blob: b6b6237122bb52166671b7bc285d299803455fc5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
local awful = require("awful")
local naughty = require("naughty")

-- Gio is used to handle the subprocess instead of awful.spawn.
-- Gio is more flexible and allows writing to stdin.
-- also, awful.spawn.with_line_callback does not play nicely with pavolctld, as
-- it seems to feed the stdout back into its stdin and kill performance.
local lgi = require("lgi")
local Gio = lgi.Gio

-- start subprocess
local p = Gio.Subprocess.new({ "pavolctld" }, Gio.SubprocessFlags.STDIN_PIPE + Gio.SubprocessFlags.STDOUT_PIPE)

local stdout = p:get_stdout_pipe()
local stdin  = p:get_stdin_pipe()

-- state vars
local sinks = {
	default = nil,
	command = nil, -- sink being modified by commands
	sinks = {},
}

function sinks.get(i)
	if sinks.sinks[i] == nil then
		sinks.sinks[i] = {
			vol  = 0,
			db   = 0.0,
			mute = 0,
			name = "",
			desc = "",
		}
	end
	return sinks.sinks[i]
end

-- return table
local pavolctld = { _cb = {}, sinks = sinks }

-- callbacks
function pavolctld.set_volume_change_callback(cb)       pavolctld._cb['v'] = cb end
function pavolctld.set_sink_change_callback(cb)         pavolctld._cb['s'] = cb end
function pavolctld.set_default_sink_change_callback(cb) pavolctld._cb['f'] = cb end
function pavolctld.set_sink_remove_callback(cb)         pavolctld._cb['x'] = cb end

-- parse output
function parse_csv(csv)
	return (csv .. ","):gmatch("(.-),")
end

awful.spawn.read_lines(stdout, function(s)
	local cmd = s:sub(1, 1) -- first char of output
	-- volume change
	if cmd == 'v' then
		local v = parse_csv(s:sub(2))
		local i = tonumber(v())
		local sink = sinks.get(i)
		sink.vol  = tonumber(v())
		sink.db   = tonumber(v())
		sink.mute = tonumber(v())
	-- sink description change
	elseif cmd == 's' then
		local v = parse_csv(s:sub(2))
		local i = tonumber(v())
		local sink = sinks.get(i)
		sink.name = v()
		sink.desc = v()
	-- default sink change
	elseif cmd == 'f' then
		local f = tonumber(s:sub(2))
		sinks.default = sinks.get(f)
		-- set command sink to default sink for now TODO change later
		send_cmd("s")
	-- sink removed
	elseif cmd == 'x' then
		local x = tonumber(s:sub(2))
		table.remove(sinks.sinks, x)
	-- unrecognized cmd
	else
		naughty.notify({
			preset = naughty.config.presets.critical,
			title = "pavolctld error",
			text = s
		})
	end
	-- run command callback
	if pavolctld._cb[cmd] then
		pavolctld._cb[cmd]()
	end
end)

-- pavolctld takes commands in using stdin
function send_cmd(cmd)
	local _, err = stdin:write_all(cmd .. "\n", nil)

	if err then return nil end
	return true
end

function pavolctld.volume_inc(vol) return send_cmd("v+" .. vol) end
function pavolctld.volume_dec(vol) return send_cmd("v-" .. vol) end
function pavolctld.volume_set(vol) return send_cmd("v"  .. vol) end
function pavolctld.mute_set(muted) return send_cmd("m" .. muted and 1 or 0) end
function pavolctld.mute_toggle()   return send_cmd("m") end
function pavolctld.default_sink_set(i) return send_cmd("f" .. i) end

return pavolctld