-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathturbovolume.py
More file actions
87 lines (70 loc) · 2.78 KB
/
Copy pathturbovolume.py
File metadata and controls
87 lines (70 loc) · 2.78 KB
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
"""
Special rotary evdev based volume controller optimised for rate-limited updates.
Publishes volume to an out-of-band channel to bypass slow updates.
Uses absolute volume control, so has to keep/assert volume by itself.
"""
from threading import Thread
from threading import Event
from typing import Dict
import evdev
import logging
from time import monotonic
from time import sleep
from upubsub import publish
log = logging.getLogger()
class Controller(Thread):
def __init__(self, params: Dict[str, str] = None):
super().__init__()
self.volumecontrol = None
self.playercontrol = None
self.name = "Rotary controller"
self.dev = evdev.InputDevice("/dev/input/by-path/platform-rotary@4-event")
log.info("Rotary encoder device: %s", self.dev.name)
# last volume reported by knob or updated by alsa reported volume after
# a delay -- local knob has precedence
self.volume = 0
# event set when rotary encoder moves. Used to set system volume, rate
# limited.
self.local_change = Event()
self.last_change = 0
# TODO make thread runner util to keep these threads alive
Thread(target=self.read_loop, daemon=True).start()
Thread(target=self.write_loop, daemon=True).start()
# audiocontrol2.py hooks
def set_volume_control(self, volumecontrol):
self.volumecontrol = volumecontrol
self.volumecontrol.add_listener(self)
self.volume = self.volumecontrol.current_volume()
publish("volume", self.volume)
def set_player_control(self, playercontrol):
self.playercontrol = playercontrol
def __str__(self):
return self.name
# alsavolume.py listener hook (not run in thread)
def update_volume(self, vol):
if monotonic() - self.last_change > 2.0:
self.volume = vol
# publish on channel for oled display
publish("volume", vol)
def read_loop(self):
for e in self.dev.read_loop():
log.debug("Event: %s", e)
if e.type == evdev.ecodes.EV_REL:
# update local volume in one go
vol = self.volume
vol += e.value
vol = min(vol, 100)
vol = max(vol, 0)
self.volume = vol
self.local_change.set()
# publish on channel for oled display, unthrottled
publish("volume", vol)
def write_loop(self):
# set the volume throttled to twice per second. Any faster, and
# alsavolume.py queues the changes up...
while True:
self.local_change.wait()
self.local_change.clear()
self.last_change = monotonic()
self.volumecontrol.set_volume(self.volume)
sleep(0.5)