aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/alsa.py
blob: 26a4d33c42eced0bb3de5d657e11aaa4f1cedf7d (plain) (blame)
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
147
148
149
150
# -*- python -*-
'''
xpybar – xmobar replacement written in python
Copyright © 2014, 2015, 2016, 2017, 2018, 2019  Mattias Andrée (maandree@kth.se)

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
'''

import alsaaudio


class ALSA:
    '''
    ALSA volume controller
    
    @variable  cardindex:int          The index of the audio card
    @variable  cardname:str           The name of the audio card, will be
                                      'default' if the default audio card is selected
                                      using it's logical name or logical index
    @variable  mixername:str          The name of the mixer
    @variable  mixer:alsaaudio.Mixer  The mixer object used internally by this class
    '''
    
    
    ALL_CHANNELS = -1
    '''
    :int  Channel index that selects all available channels
    '''

    DEFAULT_CARD = -1
    '''
    :int  Logical index of the default audio card
    '''
    
    
    def __init__(self, card = -1, mixername = 'Master', *, cardindex = None):
        '''
        Constructor
        
        @param  card:int|str   The index or name of the audio card,
                               `ALSA.DEFAULT_CARD` (-1) or 'default' for the default card
        @param  mixername:str  The name of the mixer
        '''
        if card == -1 and cardindex is not None: # For backwards compatibility
            card = cardindex
        if isinstance(card, str):
            if card == 'default':
                card = -1
            else:
                card = alsaaudio.cards().index(card)
        self.cardindex = card
        self.mixername = mixername
        self.mixer = alsaaudio.Mixer(self.mixername, 0, self.cardindex)
        self.cardname = self.mixer.cardname
    
    
    def get_volume(self):
        '''
        Get the volume for each channel on the mixer
        
        @return  :list<int?>  The [0, 100] volume for each channel, `None` on a channel indicate that it is muted
        '''
        self.mixer = alsaaudio.Mixer(self.mixername, 0, self.cardindex)
        vs = self.mixer.getvolume()
        try:
            ms = self.mixer.getmute()
        except:
            ms = [0] * len(vs)
        return [v if m == 0 else None for (v, m) in zip(vs, ms)]
    
    
    def set_volume(self, volume, channel = -1):
        '''
        Set the volume for a channel on the mixer
        
        @param  volume:int?  The [0, 100] volume for the channel, `None` to mute the channel
        @param  channel:int  The index of the channel, `ALSA.ALL_CHANNELS` (-1) for all channels
        '''
        if volume is None:
            self.mixer.setmute(1, channel)
        else:
            self.mixer.setvolume(volume, channel)
            try:
                self.mixer.setmute(0, channel)
            except:
                pass # some mixers do not have mute switch
    
    
    def get_mute(self):
        '''
        Get the mute status for each channel on the mixer
        
        @return  :list<bool>  Whether mixer is muted for each channel
        '''
        self.mixer = alsaaudio.Mixer(self.mixername, 0, self.cardindex)
        try:
            return [m == 1 for m in self.mixer.getmute()]
        except:
            return [False] * len(self.mixer.getvolume())
    
    
    def set_mute(self, mute, channel = -1):
        '''
        Set the mute status on the mixer
        
        @param  mute:bool    Whether the mixer should be muted on the channel
        @param  channel:int  The index of the channel, `ALSA.ALL_CHANNELS` (-1) for all channels
        '''
        self.mixer.setmute(mute, channel)
    
    
    @staticmethod
    def get_cards():
        '''
        Get the names of all available audio cards
        
        @return  :list<str>  The names of all available audio cards
        '''
        return alsaaudio.cards()
    
    
    @staticmethod
    def get_mixers(card = -1, *, cardindex = None):
        '''
        Get the names of all available mixers for an audio card
        
        @param   card:int|str   The index or name of the audio card,
                                `ALSA.DEFAULT_CARD` (-1) or 'default' for the default card
        @return  :list<str>     The names of all available mixers for an audio card
        '''
        if card == -1 and cardindex is not None: # For backwards compatibility
            card = cardindex
        if isinstance(card, str):
            if card == 'default':
                card = -1
            else:
                card = alsaaudio.cards().index(card)
        return alsaaudio.mixers(card)