aboutsummaryrefslogtreecommitdiff
path: root/pa.py
diff options
context:
space:
mode:
Diffstat (limited to 'pa.py')
-rw-r--r--pa.py101
1 files changed, 76 insertions, 25 deletions
diff --git a/pa.py b/pa.py
index 014a234..e09565e 100644
--- a/pa.py
+++ b/pa.py
@@ -1,10 +1,14 @@
from collections import namedtuple
import pacmd
-class Sink:
- def __init__(self, pitem):
+class SinkSource:
+ def __init__(self, pitem, kind_of_thing):
assert type(pitem) == pacmd.Item
self._i = pitem
+ self._kind_of_thing = kind_of_thing
+
+ def kind(self):
+ return self._kind_of_thing
def name(self):
return self._i.ch["name"].value
@@ -30,28 +34,57 @@ class Sink:
def set_volume(self, vol):
assert type(vol) == float or type(vol) == int
vol = round(vol * _get_maxvol(self._i))
- pacmd.pacmd("set-sink-volume", str(self.index()), str(vol))
+ pacmd.pacmd("set-{}-volume".format(self._kind_of_thing),
+ str(self.index()), str(vol))
def set_muted(self, yes):
- pacmd.pacmd("set-sink-mute", str(self.index()), "true" if yes else "false")
+ pacmd.pacmd("set-{}-mute".format(self._kind_of_thing),
+ str(self.index()), "true" if yes else "false")
def set_default(self):
- pacmd.pacmd("set-default-sink", str(self.index()))
+ pacmd.pacmd("set-default-{}".format(self._kind_of_thing),
+ str(self.index()))
+
+class Sink(SinkSource):
+ def __init__(self, pitem):
+ super().__init__(pitem, "sink")
-class SinkInput:
+class Source(SinkSource):
def __init__(self, pitem):
+ super().__init__(pitem, "source")
+
+class InputOutput:
+ def __init__(self, pitem, kind_of_thing, linked_kind):
assert type(pitem) == pacmd.Item
self._i = pitem
+ self._kind_of_thing = kind_of_thing
+ self._linked_kind = linked_kind
+
+ # sink-input or source-output
+ def kind(self):
+ return self._kind_of_thing
+
+ # sink or source
+ def linked_kind(self):
+ return self._linked_kind
def name(self):
try:
name = self._i.ch["properties"].ch["media.name"].value
- if "application.process.binary" in self._i.ch["properties"].ch:
- name += " (" + self._i.ch["properties"].ch["application.process.binary"].value + ")"
+ # Append the first that is present, if any
+ for key in ["application.name", "application.process.binary"]:
+ if key in self._i.ch["properties"].ch:
+ name += " (" + self._i.ch["properties"].ch[key].value + ")"
+ break
except Exception as e:
return "???"
return name
+ def linked_index(self):
+ return int(self._i.ch[self._linked_kind].value.split()[0])
+
+ # Don't know if this is ever true; it wouldn't make much sense to have a
+ # 'default' input or output.
def default(self):
return self._i.default
@@ -61,9 +94,6 @@ class SinkInput:
def driver(self):
return self._i.ch["driver"].value
- def sink(self):
- return int(self._i.ch["sink"].value.split()[0])
-
def muted(self):
return _parse_muted(self._i)
@@ -73,19 +103,35 @@ class SinkInput:
def set_volume(self, vol):
assert type(vol) == float or type(vol) == int
vol = round(vol * _get_maxvol(self._i))
- pacmd.pacmd("set-sink-input-volume", str(self.index()), str(vol))
+ pacmd.pacmd("set-{}-volume".format(self._kind_of_thing), str(self.index()), str(vol))
def set_muted(self, yes):
- pacmd.pacmd("set-sink-input-mute", str(self.index()), "true" if yes else "false")
+ pacmd.pacmd("set-{}-mute".format(self._kind_of_thing), str(self.index()), "true" if yes else "false")
- def move_to_sink(self, idx):
+ def move_to(self, idx):
assert type(idx) == int
- pacmd.pacmd("move-sink-input", str(self.index()), str(idx))
+ pacmd.pacmd("move-{}".format(self._kind_of_thing), str(self.index()), str(idx))
+
+class SinkInput(InputOutput):
+ def __init__(self, pitem):
+ super().__init__(pitem, "sink-input", "sink")
+
+class SourceOutput(InputOutput):
+ def __init__(self, pitem):
+ super().__init__(pitem, "source-output", "source")
+# TODO: How should one really do this? This is just a collection of hacks that
+# accidentally works for all my devices, but will probably fail the moment you
+# try another.
def _get_maxvol(item):
- if "base volume" in item.ch:
- return int(item.ch["base volume"].value.split("/")[0].strip())
+ if "volume steps" in item.ch:
+ return int(item.ch["volume steps"].value.strip()) - 1
+ elif "base volume" in item.ch:
+ num, perc = item.ch["base volume"].value.split("/")[0:2]
+ num = int(num.strip())
+ perc = int(num.replace("%", "").strip())
+ return num * (100 / perc)
else:
return 65536
@@ -100,14 +146,19 @@ def _parse_muted(item):
elif item.ch["muted"].value == "no": return False
else: assert False
+def _list_things(pacmd_obj, section_name, klass):
+ assert len(pacmd_obj.sections) == 1
+ assert pacmd_obj.sections[0].name == section_name
+ return [klass(item) for item in pacmd_obj.sections[0].items]
+
def list_sinks():
- res = pacmd.list_sinks()
- assert len(res.sections) == 1
- assert res.sections[0].name == "sink"
- return [Sink(item) for item in res.sections[0].items]
+ return _list_things(pacmd.list_sinks(), "sink", Sink)
def list_sink_inputs():
- res = pacmd.list_sink_inputs()
- assert len(res.sections) == 1
- assert res.sections[0].name == "input"
- return [SinkInput(item) for item in res.sections[0].items]
+ return _list_things(pacmd.list_sink_inputs(), "input", SinkInput)
+
+def list_sources():
+ return _list_things(pacmd.list_sources(), "source", Source)
+
+def list_source_outputs():
+ return _list_things(pacmd.list_source_outputs(), "output", SourceOutput)