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
|