bumblebee-status/bumblebee/modules/pulseaudio.py
Tobias Witek 68e0b51178 [modules/pulseaudio] Automatically restart pulseaudio daemon
If the current volume and mute status cannot be retrieved, the most
likely explanation is that the pulseaudio daemon is not running.
Automatically start it in such a case.

Also, add a parameter "autostart" to the pulseaudio module to disable
this behaviour in case it causes issues.

see #108
2017-06-15 11:09:00 +02:00

126 lines
4.1 KiB
Python

# pylint: disable=C0111,R0903
"""Displays volume and mute status of PulseAudio devices.
Aliases: pasink, pasource
Parameters:
* pulseaudio.autostart: If set to "true" (default), automatically starts the pulseaudio daemon if it is not running
Requires the following executable:
* pactl
"""
import re
import bumblebee.util
import bumblebee.input
import bumblebee.output
import bumblebee.engine
ALIASES = [ "pasink", "pasource" ]
class Module(bumblebee.engine.Module):
def __init__(self, engine, config):
super(Module, self).__init__(engine, config,
bumblebee.output.Widget(full_text=self.volume)
)
try:
bumblebee.util.execute("pulseaudio --start")
except Exception:
pass
self._left = 0
self._right = 0
self._mono = 0
self._mute = False
self._failed = False
channel = "sink" if self.name == "pasink" else "source"
self._patterns = [
{ "expr": "name:", "callback": (lambda line: False) },
{ "expr": "muted:", "callback": (lambda line: self.mute(False if " no" in line.lower() else True)) },
{ "expr": "volume:", "callback": self.getvolume },
]
engine.input.register_callback(self, button=bumblebee.input.RIGHT_MOUSE, cmd="pavucontrol")
events = [
{ "type": "mute", "action": "toggle", "button": bumblebee.input.LEFT_MOUSE },
{ "type": "volume", "action": "+2%", "button": bumblebee.input.WHEEL_UP },
{ "type": "volume", "action": "-2%", "button": bumblebee.input.WHEEL_DOWN },
]
for event in events:
engine.input.register_callback(self, button=event["button"],
cmd="pactl set-{}-{} @DEFAULT_{}@ {}".format(channel, event["type"],
channel.upper(), event["action"]))
def mute(self, value):
self._mute = value
def getvolume(self, line):
if "mono" in line:
m = re.search(r'mono:.*\s*\/\s*(\d+)%', line)
if m:
self._mono = m.group(1)
else:
m = re.search(r'left:.*\s*\/\s*(\d+)%.*right:.*\s*\/\s*(\d+)%', line)
if m:
self._left = m.group(1)
self._right = m.group(2)
return True
def _default_device(self):
output = bumblebee.util.execute("pacmd stat")
pattern = "Default sink name: " if self.name == "pasink" else "Default source name: "
for line in output.split("\n"):
if line.startswith(pattern):
return line.replace(pattern, "")
return "n/a"
def volume(self, widget):
if self._failed == True:
return "n/a"
if int(self._mono) > 0:
return "{}%".format(self._mono)
elif self._left == self._right:
return "{}%".format(self._left)
else:
return "{}%/{}%".format(self._left, self._right)
def update(self, widgets):
try:
self._failed = False
channel = "sinks" if self.name == "pasink" else "sources"
device = self._default_device()
result = bumblebee.util.execute("pacmd list-{}".format(channel))
found = False
for line in result.split("\n"):
if device in line:
found = True
continue
if found == False:
continue
for pattern in self._patterns:
if not pattern["expr"] in line:
continue
if pattern["callback"](line) == False and found == True:
return
except Exception:
self._failed = True
if self.parameter("autostart", "true") == "true":
try:
bumblebee.util.execute("pulseaudio --start")
self.update(widgets)
except Exception:
pass
def state(self, widget):
if self._mute:
return [ "warning", "muted" ]
return [ "unmuted" ]
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4