summaryrefslogtreecommitdiff
path: root/src/home/sound/amixer.py
blob: 0ab2c640ec4b8b41c243ffeeac8e8b30c2bf36d5 (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
import subprocess

from ..config import config
from threading import Lock
from typing import Union


_lock = Lock()
_default_step = 5


def has_control(s: str) -> bool:
    for control in config['amixer']['controls']:
        if control['name'] == s:
            return True
    return False


def get_caps(s: str) -> list[str]:
    for control in config['amixer']['controls']:
        if control['name'] == s:
            return control['caps']
    raise KeyError(f'control {s} not found')


def get_all() -> list:
    controls = []
    for control in config['amixer']['controls']:
        controls.append({
            'name': control['name'],
            'info': get(control['name']),
            'caps': control['caps']
        })
    return controls


def get(control: str):
    return call('get', control)


def mute(control):
    return call('set', control, 'mute')


def unmute(control):
    return call('set', control, 'unmute')


def cap(control):
    return call('set', control, 'cap')


def nocap(control):
    return call('set', control, 'nocap')


def _get_default_step() -> int:
    if 'step' in config['amixer']:
        return int(config['amixer']['step'])

    return _default_step


def incr(control, step=None):
    if step is None:
        step = _get_default_step()
    return call('set', control, f'{step}%+')


def decr(control, step=None):
    if step is None:
        step = _get_default_step()
    return call('set', control, f'{step}%-')


def call(*args, return_code=False) -> Union[int, str]:
    with _lock:
        result = subprocess.run([config['amixer']['bin'], *args],
                                stdout=subprocess.PIPE,
                                stderr=subprocess.PIPE)
        if return_code:
            return result.returncode

        if result.returncode != 0:
            raise AmixerError(result.stderr.decode().strip())

        return result.stdout.decode().strip()


class AmixerError(OSError):
    pass