aboutsummaryrefslogtreecommitdiff
path: root/pacmd.py
blob: e9e019e0cae1f1c5efc39fe19dc2678c61932797 (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
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
import subprocess, re
from collections import namedtuple

class PacmdSection:
    def __init__(self, name, items):
        self.name = name  # string
        self.items = items  # [PacmdItem]

class PacmdItem:
    def __init__(self, index, children):
        self.index = index  # int
        self.children = children  # {key: PacmdNode}

class PacmdNode:
    def __init__(self, value, children):
        self.value = value  # None | string | [string]
        self.children = children  # {key: PacmdNode}

class Pacmd:
    def __init__(self, full_output):
        lines = full_output.decode("utf-8").split("\n")
        self.infos = []  # [string]
        self.sections = []  # [PacmdSection]

        currsect = None
        curritem = None
        currpath = []

        def close_curritem():
            nonlocal curritem, currsect, currpath
            if curritem:
                currsect.items.append(curritem)
                curritem = None
                currpath = []

        def close_currsect():
            nonlocal self, currsect
            if currsect:
                close_curritem()
                self.sections.append(currsect)

        def q_is_key_value(ln):
            return ln.find("=") != -1 or ln.find(": ") != -1

        def q_get_key_value(ln):
            if ln.find("=") != -1:
                m = re.search(r"^\s*([^=]*?)\s*=\s*(.*)$", ln)
            else:
                m = re.search(r"^\s*([^:]*):\s*(.*)$", ln)
            return m.group(1), m.group(2)

        for line in lines:
            line = line.rstrip()
            if len(line) == 0:
                continue

            line = line.replace("\t", "        ")
            m = re.match(r"^( *(\* )?)([^ ].*)", line)
            is_default = m.group(2) is not None  # TODO use is_default
            indent = len(m.group(1))
            line = m.group(3)

            #  print(currpath)
            #  print(indent, line)

            if indent == 0:
                if line[0].isdigit():
                    close_currsect()

                    name = re.search(r" ([^ ]*)\(s\)", line).group(1)
                    currsect = PacmdSection(name, [])
                else:
                    self.infos.append(line)

            elif indent == 4:
                close_curritem()

                index = re.search(r"index: ([0-9]*)$", line).group(1)
                curritem = PacmdItem(int(index), {})

            elif indent >= 8:
                assert curritem != None

                is_aligned = indent % 8 == 0
                indent_depth = (indent + 7) // 8 - 1

                if is_aligned and indent_depth < len(currpath):
                    currpath = currpath[:indent_depth]

                parentval, thisval = None, curritem
                for k in currpath:
                    parentval, thisval = thisval, thisval.children[k]

                if q_is_key_value(line):
                    key, value = q_get_key_value(line)
                    thisval.children[key] = PacmdNode(value, {})
                    currpath.append(key)

                elif re.search(r":$", line) is not None:
                    key = line[:-1]
                    thisval.children[key] = PacmdNode(None, {})
                    currpath.append(key)

                elif indent_depth >= len(currpath):
                    if type(thisval.value) != list:
                        thisval.value = [thisval.value]
                    thisval.value.append(line)

                else:
                    print("line = " + line)
                    assert False

            else:
                print("indent = " + str(indent))
                assert False

        close_currsect()

def pacmd(*args):
    return Pacmd(subprocess.check_output(["pacmd"] + list(args)))

def list_all():
    return pacmd("list")

def list_sinks():
    return pacmd("list-sinks")

def list_sink_inputs():
    return pacmd("list-sink-inputs")


def _make_indent(n):
    return "    " * n

def dump_section(sect):
    print("Section " + sect.name + ":")
    for item in sect.items:
        print(_make_indent(1) + "Item " + str(item.index) + ":")
        for key, node in item.children.items():
            dump_node(node, key, 2);

def dump_node(node, key, indent):
    print(_make_indent(indent) + key + ":" +
                ("" if node.value is None else " " + str(node.value)))
    for k2, n2 in node.children.items():
        dump_node(n2, k2, indent + 1)