2016-12-11 08:51:56 +01:00
# pylint: disable=C0111,R0903
2018-02-14 12:09:11 +01:00
""" Displays volume and mute status and controls for PulseAudio devices. Use wheel up and down to change volume, left click mutes, right click opens pavucontrol.
2016-12-11 08:51:56 +01:00
2018-02-14 12:09:11 +01:00
Aliases : pasink ( use this to control output instead of input ) , pasource
2017-01-05 04:55:14 +01:00
2017-06-15 11:09:00 +02:00
Parameters :
2017-06-15 14:14:16 +02:00
* pulseaudio . autostart : If set to " true " ( default is " false " ) , automatically starts the pulseaudio daemon if it is not running
2018-09-01 15:40:18 +02:00
* pulseaudio . percent_change : How much to change volume by when scrolling on the module ( default is 2 % )
2019-01-19 07:42:11 +01:00
* pulseaudio . limit : Upper limit for setting the volume ( default is 0 % , which means " no limit " )
2017-06-15 11:09:00 +02:00
2017-01-05 04:55:14 +01:00
Requires the following executable :
2018-02-14 12:09:11 +01:00
* pulseaudio
2017-01-05 04:55:14 +01:00
* pactl
2018-02-14 12:09:11 +01:00
* pavucontrol
* pacmd
2016-12-11 08:51:56 +01:00
"""
import re
import bumblebee . util
import bumblebee . input
import bumblebee . output
import bumblebee . engine
2017-10-13 17:06:18 +02:00
ALIASES = [ " pasink " , " pasource " ]
2016-12-11 08:51:56 +01:00
class Module ( bumblebee . engine . Module ) :
def __init__ ( self , engine , config ) :
super ( Module , self ) . __init__ ( engine , config ,
bumblebee . output . Widget ( full_text = self . volume )
)
2017-06-09 11:01:25 +02:00
try :
2018-08-08 01:05:09 +02:00
if bumblebee . util . asbool ( self . parameter ( " autostart " , False ) ) :
bumblebee . util . execute ( " pulseaudio --start " )
2017-06-09 11:01:25 +02:00
except Exception :
pass
2019-01-19 07:42:11 +01:00
self . _change = 2
self . _change = int ( self . parameter ( " percent_change " , " 2 % " ) . strip ( " % " ) )
if self . _change < 0 or self . _change > 100 :
self . _change = 2
self . _limit = 0
self . _limit = int ( self . parameter ( " limit " , 0 ) . strip ( " %s " ) )
if self . _limit < 0 :
self . _limit = 0
2016-12-11 08:51:56 +01:00
self . _left = 0
self . _right = 0
self . _mono = 0
self . _mute = False
2017-06-15 11:09:00 +02:00
self . _failed = False
2019-01-19 07:42:11 +01:00
self . _channel = " sink " if self . name == " pasink " else " source "
2016-12-11 08:51:56 +01:00
2016-12-17 08:06:58 +01:00
self . _patterns = [
2017-10-13 17:06:18 +02:00
{ " 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 } ,
2016-12-17 08:06:58 +01:00
]
2016-12-11 08:51:56 +01:00
engine . input . register_callback ( self , button = bumblebee . input . RIGHT_MOUSE , cmd = " pavucontrol " )
2016-12-17 08:16:10 +01:00
events = [
2019-01-19 07:42:11 +01:00
{ " type " : " mute " , " action " : self . toggle , " button " : bumblebee . input . LEFT_MOUSE } ,
{ " type " : " volume " , " action " : self . increase_volume , " button " : bumblebee . input . WHEEL_UP } ,
{ " type " : " volume " , " action " : self . decrease_volume , " button " : bumblebee . input . WHEEL_DOWN } ,
2016-12-17 08:16:10 +01:00
]
for event in events :
2019-01-19 07:42:11 +01:00
engine . input . register_callback ( self , button = event [ " button " ] , cmd = event [ " action " ] )
def set_volume ( self , amount ) :
bumblebee . util . execute ( " pactl set- {} - {} @DEFAULT_ {} @ {} " . format (
self . _channel , " volume " , self . _channel . upper ( ) , amount ) )
def increase_volume ( self , event ) :
if self . _limit > 0 : # we need to check the limit
if int ( self . _left ) > = self . _limit or int ( self . _right ) > = self . _limit :
return
self . set_volume ( " + {} % " . format ( self . _change ) )
def decrease_volume ( self , event ) :
self . set_volume ( " - {} % " . format ( self . _change ) )
def toggle ( self , event ) :
bumblebee . util . execute ( " pactl set- {} - {} @DEFAULT_ {} @ {} " . format (
self . _channel , " mute " , self . _channel . upper ( ) , " toggle " ) )
2016-12-11 08:51:56 +01:00
2016-12-17 08:06:58 +01:00
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+) %.*r ight:.* \ s* \ / \ s*( \ d+) % ' , line )
if m :
self . _left = m . group ( 1 )
self . _right = m . group ( 2 )
return True
2016-12-11 08:51:56 +01:00
def _default_device ( self ) :
2017-06-05 15:01:10 +02:00
output = bumblebee . util . execute ( " pacmd stat " )
pattern = " Default sink name: " if self . name == " pasink " else " Default source name: "
2016-12-11 08:51:56 +01:00
for line in output . split ( " \n " ) :
if line . startswith ( pattern ) :
return line . replace ( pattern , " " )
return " n/a "
2016-12-11 11:37:24 +01:00
def volume ( self , widget ) :
2017-06-15 11:09:00 +02:00
if self . _failed == True :
return " n/a "
2016-12-11 08:51:56 +01:00
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 ) :
2017-06-15 11:09:00 +02:00
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 " ) :
2018-05-12 14:46:51 +02:00
if " < " + device + " > " in line :
2017-06-15 11:09:00 +02:00
found = True
continue
2018-06-04 14:53:01 +02:00
if found is False :
2016-12-17 08:06:58 +01:00
continue
2017-06-15 11:09:00 +02:00
for pattern in self . _patterns :
if not pattern [ " expr " ] in line :
continue
2018-06-04 14:53:01 +02:00
if pattern [ " callback " ] ( line ) is False and found == True :
2017-06-15 11:09:00 +02:00
return
except Exception :
self . _failed = True
2017-07-08 06:44:08 +02:00
if bumblebee . util . asbool ( self . parameter ( " autostart " , False ) ) :
2017-06-15 11:09:00 +02:00
try :
bumblebee . util . execute ( " pulseaudio --start " )
self . update ( widgets )
except Exception :
pass
2016-12-11 08:51:56 +01:00
def state ( self , widget ) :
if self . _mute :
2017-10-13 17:06:18 +02:00
return [ " warning " , " muted " ]
2018-11-16 12:43:19 +01:00
if int ( self . _left ) > int ( 100 ) :
2018-11-16 12:46:36 +01:00
return [ " critical " , " unmuted " ]
2017-10-13 17:06:18 +02:00
return [ " unmuted " ]
2016-12-11 08:51:56 +01:00
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4