~schnouki/pustule

ref: 2e90522e70214bb6d1bb88aef6f7d8c06152a99f pustule/pustule.lua -rw-r--r-- 6.2 KiB
2e90522e — Thomas Jost Expose log functions in Lua 1 year, 1 month ago
                                                                                
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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
-- pustule
-- Copyright 2014-2020 Thomas Jost <schnouki@schnouki.net>
--
-- This file is part of pustule.
--
-- pustule is free software: you can redistribute it and/or modify it under the
-- terms of the GNU General Public License as published by the Free Software
-- Foundation, either version 3 of the License, or (at your option) any later
-- version.
--
-- pustule is distributed in the hope that it will be useful, but WITHOUT ANY
-- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
-- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License along with
-- pustule. If not, see <http://www.gnu.org/licenses/>.


-- Welcome to the Pustule default configuration script! Here's a short
-- explanation of how this works.
--
-- Each application that plays sound using PulseAudio creates one or several
-- inputs (or "sink input" in PulseAudio). The volume of each input can be set
-- independently.
--
-- The sound is then played on one of several devices ("sinks" in PulseAudio).
-- Again, the volume of each of them can be set independently. An input can be
-- bound to a specific device, or use the global default device.
--
-- pustule sends a signal when an input or device is added to or removed from
-- the PulseAudio daemon. There are 4 signals: "input_added", "input_removed",
-- "device_added", "device_removed". Listeners can be added for any of these
-- signals using the `pustule.connect_signal()` and
-- `pustule.disconnect_signal()`.

--
-- The volume of each input and device (a number between 0 and 1) can be set
-- using the `pustule.set_input_volume()` and `pustule.set_device_volume()`
-- functions.
--
-- In the default script, there are a few helpers that provide sane defaults for
-- writing rich rules. For instance everything is logged, including all the
-- properties of each new input. Some fun examples are shown, such as setting
-- different volumes for music and video players and for web browsers.
--
-- In order for pustule to work, you must disable the flat volumes option in the
-- PulseAudio daemon configuration. To do that, add the following line to
-- /etc/pulse/daemon.conf:
--     flat-volumes = no
-- And restart PulseAudio.

local io, string = io, string

local pustule = require("pustule")
local log_d, log_i = pustule.log_debug, pustule.log_info

------------------------------------------------------------------------
-- Helpers
------------------------------------------------------------------------

-- Table of all the active inputs and devices
active_inputs = {}
active_devices = {}

function set_input_volume(idx, vol)
   log_i("[%d] Setting volume to %.2f", idx, vol)
   pustule.set_input_volume(idx, vol)
   active_inputs[idx] = true
end

--- Check if a volume has already been set for an input
function is_input_volume_set(idx)
   return active_inputs[idx] == true
end

function set_device_volume(idx)
   log_i("{%d} Setting volume to %.2f", idx, vol)
   pustule.set_device_volume(idx, vol)
end

function show_input(idx, input)
   local k, v
   for k, v in pairs(input) do
      log_d("  [%d] %s: %s", idx, k, v)
   end
end

function show_device(idx, device)
   local k, v
   for k, v in pairs(device) do
      log_d("  {%d} %s: %s", idx, k, v)
   end
end


------------------------------------------------------------------------
-- Application-specific rules
------------------------------------------------------------------------
--- Set volume for web browsers
function input_added__browser(idx, input)
   if not is_input_volume_set(idx)
      and (input["application.process.binary"] == "firefox"
              or input["application.process.binary"] == "chromium")
   then
      set_input_volume(idx, 0.8)
   end
end
pustule.connect_signal("input_added", input_added__browser)


------------------------------------------------------------------------
-- Media roles
------------------------------------------------------------------------
-- Table mapping idx to role for inputs that have a media.role
roles = {}

--- Set volume for various applications based on their media role
function input_added__media_role(idx, input)
   if is_input_volume_set(idx) then return end

   -- Add role to inputs that should have one but don't
   if input["application.process.binary"] == "mpg123" or input["application.process.binary"] == "ogg123" then
      input["media.role"] = "music"
   end

   local role = input["media.role"]
   if not role then return end
   roles[idx] = role

   -- Set volume depending on the role
   if role == "music" then
      set_input_volume(idx, 0.5)
   elseif role == "video" then
      set_input_volume(idx, 0.8)
   end
end
pustule.connect_signal("input_added", input_added__media_role)

--- Cleanup the roles table
function input_removed__media_role(idx)
   if roles[idx] then roles[idx] = nil end
end
pustule.connect_signal("input_removed", input_removed__media_role)


------------------------------------------------------------------------
-- Default rules: inputs
------------------------------------------------------------------------
function input_added__all(idx, input)
   log_i("[%d] Input added: %s (%s)", idx, input["application.name"], input.name)
   show_input(idx, input)
end
pustule.connect_signal("input_added", input_added__all)

function input_removed__all(idx, input)
   log_i("[%d] Input removed", idx)
   active_inputs[idx] = nil
end
pustule.connect_signal("input_removed", input_removed__all)

--- Set a default value for the volume if it wasn't set by the previous listeners
function input_added__default_volume(idx, input)
   if not is_input_volume_set(idx) then
      set_input_volume(idx, 0.6)
   end
end
pustule.connect_signal("input_added", input_added__default_volume)


------------------------------------------------------------------------
-- Default rules: devices
------------------------------------------------------------------------
function device_added__all(idx, device)
   log_i("{%d} Device added: %s", idx, device.description)
   show_device(idx, device)
   active_devices[idx] = device
end
pustule.connect_signal("device_added", device_added__all)

function device_removed__all(idx)
   log_i("{%d} Device removed", idx)
   active_devices[idx] = nil
end
pustule.connect_signal("device_removed", device_removed__all)