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 " )
2019-01-20 09:09:11 +01:00
Note : If the left and right channels have different volumes , the limit might not be reached exactly .
2020-01-07 09:28:18 +01:00
* pulseaudio . showbars : 1 for showing volume bars , requires - - markup = pango ;
0 for not showing volume bars ( default )
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
2016-12-11 08:51:56 +01:00
"""
import re
import bumblebee . util
import bumblebee . input
import bumblebee . output
import bumblebee . engine
2020-02-07 21:05:15 +01:00
def autostart_daemon ( ) :
try :
bumblebee . util . execute ( " pulseaudio --check " )
except Exception :
try :
bumblebee . util . execute ( " pulseaudio --start " )
except :
pass
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 )
)
2020-02-07 21:05:15 +01:00
if bumblebee . util . asbool ( self . parameter ( " autostart " , False ) ) :
autostart_daemon ( )
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
2019-01-19 07:47:21 +01:00
self . _limit = int ( self . parameter ( " limit " , " 0 % " ) . strip ( " %s " ) )
2019-01-19 07:42:11 +01:00
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 "
2020-01-07 09:28:18 +01:00
self . _showbars = bumblebee . util . asbool ( self . parameter ( " showbars " , 0 ) )
2016-12-11 08:51:56 +01:00
2016-12-17 08:06:58 +01:00
self . _patterns = [
2019-12-25 13:50:46 +01:00
{ " expr " : " Name: " , " callback " : ( lambda line : False ) } ,
{ " expr " : " Mute: " , " 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
2019-01-20 09:09:11 +01:00
left = int ( self . _left )
right = int ( self . _right )
if left + self . _change > = self . _limit or right + self . _change > = self . _limit :
if left == right :
# easy case, just set to limit
self . set_volume ( " {} % " . format ( self . _limit ) )
return
else :
# don't adjust anymore, since i don't know how to update only one channel
return
2019-01-19 07:42:11 +01:00
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 ) :
2019-12-25 13:50:46 +01:00
output = bumblebee . util . execute ( " pactl info " )
pattern = " Default {} : " . format ( " Sink " if self . name == " pasink " else " Source " )
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 :
2020-01-07 09:28:18 +01:00
vol = " {} % " . format ( self . _mono )
if self . _showbars :
vol = " {} {} " . format (
vol , bumblebee . output . hbar ( float ( self . _mono ) ) )
return vol
2016-12-11 08:51:56 +01:00
elif self . _left == self . _right :
2020-01-07 09:28:18 +01:00
vol = " {} % " . format ( self . _left )
if self . _showbars :
vol = " {} {} " . format (
vol , bumblebee . output . hbar ( float ( self . _left ) ) )
return vol
2016-12-11 08:51:56 +01:00
else :
2020-02-19 23:57:07 +01:00
vol = " {} % / {} % " . format ( self . _left , self . _right )
2020-01-07 09:28:18 +01:00
if self . _showbars :
vol = " {} {} {} " . format (
vol ,
bumblebee . output . hbar ( float ( self . _left ) ) ,
bumblebee . output . hbar ( float ( self . _right ) ) )
return vol
2016-12-11 08:51:56 +01:00
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 ( )
2019-12-25 13:50:46 +01:00
result = bumblebee . util . execute ( " pactl list {} " . format ( channel ) )
2017-06-15 11:09:00 +02:00
found = False
for line in result . split ( " \n " ) :
2019-12-25 13:50:46 +01:00
if " Name: {} " . format ( 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 ) ) :
2020-02-07 21:05:15 +01:00
autostart_daemon ( )
self . update ( widgets )
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