~jocave/checkbox/hybrid-amd-gpu-mods

« back to all changes in this revision

Viewing changes to scripts/audio_settings

  • Committer: Zygmunt Krynicki
  • Date: 2013-05-17 13:54:25 UTC
  • mto: This revision was merged to the branch mainline in revision 2130.
  • Revision ID: zygmunt.krynicki@canonical.com-20130517135425-cxcenxx5t0qrtbxd
checkbox-ng: add CheckBoxNG sub-project

CheckBoxNG (or lowercase as checkbox-ng, pypi:checkbox-ng) is a clean
implementation of CheckBox on top of PlainBox. It provides a new
executable, 'checkbox' that has some of the same commands that were
previously implemented in the plainbox package.

In particular CheckBoxNG comes with the 'checkbox sru' command
(the same one as in plainbox). Later on this sub-command will be removed
from plainbox.

CheckBoxNG depends on plainbox >= 0.3

Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/python3
 
2
 
 
3
import os
 
4
import re
 
5
import sys
 
6
 
 
7
from argparse import ArgumentParser
 
8
from subprocess import check_output, check_call, CalledProcessError
 
9
 
 
10
TYPES = ("source", "sink")
 
11
DIRECTIONS = {"source": "input", "sink": "output"}
 
12
 
 
13
default_pattern = "(?<=Default %s: ).*"
 
14
index_regex = re.compile("(?<=index: )[0-9]*")
 
15
muted_regex = re.compile("(?<=Mute: ).*")
 
16
volume_regex = re.compile("(?<=Volume: 0:)\s*[0-9]*")
 
17
name_regex = re.compile("(?<=Name:).*")
 
18
 
 
19
entry_pattern = "Name: %s.*?(?=Properties)"
 
20
 
 
21
 
 
22
def unlocalized_env(reset={"LANG": "C.UTF-8"}):
 
23
    """
 
24
    Create un-localized environment.
 
25
 
 
26
    Produce an environment that is suitable for subprocess.Popen() and
 
27
    associated subprocess functions. The returned environment is equal to a
 
28
    copy the current environment, updated with the value of the reset argument.
 
29
    """
 
30
    env = dict(os.environ)
 
31
    env.update(reset)
 
32
    return env
 
33
 
 
34
 
 
35
def set_profile_hdmi():
 
36
    """Sets desired device as active profile. This is typically
 
37
    used as a fallback for setting HDMI as the output device.
 
38
    """
 
39
 
 
40
    profile = "output:hdmi-stereo-extra1+input:analog-stereo"
 
41
    output_list = check_output(["pactl", "list"],
 
42
                               universal_newlines=True,
 
43
                               env=unlocalized_env())
 
44
 
 
45
    if profile not in output_list:
 
46
        profile = profile.replace("-extra1", "")
 
47
 
 
48
    # Try and set device as default audio output
 
49
    try:
 
50
        check_call(["pactl", "set-card-profile", "0", profile])
 
51
    except CalledProcessError as error:
 
52
        print("Failed setting audio output to:%s: %s" % (profile, error))
 
53
 
 
54
 
 
55
def get_current_profile_setting():
 
56
    """Captures and Writes current audio profile setting"""
 
57
    output_list = check_output(["pactl", "list"],
 
58
                               universal_newlines=True,
 
59
                               env=unlocalized_env())
 
60
    active_profile = re.findall("Active\sProfile.*", output_list)[0]
 
61
 
 
62
    try:
 
63
        open("active_output", 'w').write(active_profile)
 
64
    except IOError:
 
65
        print("Failed to save active output information: %s" %
 
66
               sys.exc_info()[1])
 
67
 
 
68
 
 
69
def restore_profile_setting():
 
70
    try:
 
71
        setting_info = open("active_output").read()
 
72
        profile = setting_info.split("Active Profile:")[-1]
 
73
    except (IOError, IndexError):
 
74
        print("Failed to retrieve previous profile information")
 
75
        return
 
76
 
 
77
    try:
 
78
        check_call(["pactl", "set-card-profile", "0", profile.strip()])
 
79
    except CalledProcessError as error:
 
80
        print("Failed setting audio output to:%s: %s" % (profile, error))
 
81
 
 
82
 
 
83
def move_sinks(name):
 
84
    sink_inputs = check_output(["pacmd", "list-sink-inputs"],
 
85
                               universal_newlines=True,
 
86
                               env=unlocalized_env())
 
87
    input_indexes = index_regex.findall(sink_inputs)
 
88
 
 
89
    for input_index in input_indexes:
 
90
        try:
 
91
            check_call(["pacmd", "move-sink-input", input_index, name])
 
92
        except CalledProcessError:
 
93
            print("Failed to move input %d to sink %d" % (input_index, name))
 
94
            sys.exit(1)
 
95
 
 
96
 
 
97
def store_audio_settings(file):
 
98
 
 
99
    try:
 
100
        settings_file = open(file, 'w')
 
101
    except IOError:
 
102
        print("Failed to save settings: %s" % sys.exc_info()[1])
 
103
        sys.exit(1)
 
104
 
 
105
    for type in TYPES:
 
106
        pactl_status = check_output(["pactl", "stat"],
 
107
                                    universal_newlines=True,
 
108
                                    env=unlocalized_env())
 
109
        default_regex = re.compile(default_pattern % type.title())
 
110
        default = default_regex.search(pactl_status).group()
 
111
 
 
112
        print("default_%s: %s" % (type, default), file=settings_file)
 
113
 
 
114
        pactl_list = check_output(["pactl", "list", type + 's'],
 
115
                                  universal_newlines=True,
 
116
                                  env=unlocalized_env())
 
117
 
 
118
        entry_regex = re.compile(entry_pattern % default, re.DOTALL)
 
119
        entry = entry_regex.search(pactl_list).group()
 
120
 
 
121
        muted = muted_regex.search(entry)
 
122
        print("%s_muted: %s" % (type, muted.group().strip()),
 
123
                                file=settings_file)
 
124
 
 
125
        volume = int(volume_regex.search(entry).group().strip())
 
126
 
 
127
        print("%s_volume: %s%%" % (type, str(volume)),
 
128
                                 file=settings_file)
 
129
 
 
130
 
 
131
def set_audio_settings(device, mute, volume):
 
132
    print(device, mute, volume)
 
133
 
 
134
    for type in TYPES:
 
135
        pactl_entries = check_output(["pactl", "list", type + 's'],
 
136
                                     universal_newlines=True,
 
137
                                     env=unlocalized_env())
 
138
 
 
139
        # Find the name of the sink/source we want to set
 
140
        names = name_regex.findall(pactl_entries)
 
141
 
 
142
        for name in names:
 
143
            name = name.strip()
 
144
            if device in name and DIRECTIONS[type] in name:
 
145
                try:
 
146
                    check_call(["pacmd", "set-default-%s" % type, name])
 
147
                except CalledProcessError:
 
148
                    print("Failed to set default %s" % type)
 
149
                    sys.exit(1)
 
150
 
 
151
                if type == "sink":
 
152
                    move_sinks(name)
 
153
 
 
154
                try:
 
155
                    check_call(["pactl",
 
156
                                "set-%s-mute" % type, name, str(mute)])
 
157
                except:
 
158
                    print("Failed to set mute for %s" % name)
 
159
                    sys.exit(1)
 
160
 
 
161
                try:
 
162
                    check_call(["pactl", "set-%s-volume" % type,
 
163
                               name, str(volume) + '%'])
 
164
                except:
 
165
                    print("Failed to set volume for %s" % name)
 
166
                    sys.exit(1)
 
167
 
 
168
 
 
169
def restore_audio_settings(file):
 
170
    try:
 
171
        settings_file = open(file).read().split()
 
172
    except IOError:
 
173
        print("Unable to open existing settings file: %s" %
 
174
                sys.exc_info()[1])
 
175
        sys.exit(1)
 
176
 
 
177
    for type in TYPES:
 
178
        #First try to get the three elements we need. If we fail to get any of them, it means
 
179
        #the file's format is incorrect, so we just abort.
 
180
        try:
 
181
            name = settings_file[settings_file.index("default_%s:" % type) + 1]
 
182
            muted = settings_file[settings_file.index("%s_muted:" % type) + 1]
 
183
            volume = settings_file[settings_file.index("%s_volume:" % type) + 1]
 
184
        except ValueError:
 
185
            print("Unable to restore settings because settings file is invalid")
 
186
            sys.exit(1)
 
187
 
 
188
        print(name)
 
189
 
 
190
        try:
 
191
            check_call(["pacmd", "set-default-%s" % type, name])
 
192
        except CalledProcessError:
 
193
            print("Failed to set default %s" % type)
 
194
            sys.exit(1)
 
195
 
 
196
        if type == "sink":
 
197
            move_sinks(name)
 
198
 
 
199
        print(muted)
 
200
 
 
201
        try:
 
202
            check_call(["pactl", "set-%s-mute" % type, name, muted])
 
203
        except:
 
204
            print("Failed to set mute for %s" % device)
 
205
            sys.exit(1)
 
206
 
 
207
        print(volume)
 
208
 
 
209
        try:
 
210
            check_call(["pactl", "set-%s-volume" % type, name, volume])
 
211
        except:
 
212
            print("Failed to set volume for %s" % device)
 
213
            sys.exit(1)
 
214
 
 
215
 
 
216
def main():
 
217
    parser = ArgumentParser("Manipulate PulseAudio settings")
 
218
    parser.add_argument("action",
 
219
                        choices=['store', 'set', 'restore'],
 
220
                        help="Action to perform with the audio settings")
 
221
    parser.add_argument("-d", "--device",
 
222
                        help="The device to apply the new settings to.")
 
223
    parser.add_argument("-m", "--mute",
 
224
                        action="store_true",
 
225
                        help="""The new value for the mute setting
 
226
                                of the specified device.""")
 
227
    parser.add_argument("-v", "--volume",
 
228
                        type=int,
 
229
                        help="""The new value for the volume setting
 
230
                                of the specified device.""")
 
231
    parser.add_argument("-f", "--file",
 
232
                        help="""The file to store settings in or restore
 
233
                                settings from.""")
 
234
    args = parser.parse_args()
 
235
 
 
236
    if args.action == "store":
 
237
        if not args.file:
 
238
            print("No file specified to store audio settings!")
 
239
            return 1
 
240
 
 
241
        store_audio_settings(args.file)
 
242
        get_current_profile_setting()
 
243
    elif args.action == "set":
 
244
        if not args.device:
 
245
            print("No device specified to change settings of!")
 
246
            return 1
 
247
        if not args.volume:
 
248
            print("No volume level specified!")
 
249
            return 1
 
250
 
 
251
        if args.device == "hdmi":
 
252
            set_profile_hdmi()
 
253
        set_audio_settings(args.device, args.mute, args.volume)
 
254
    elif args.action == "restore":
 
255
        restore_audio_settings(args.file)
 
256
        restore_profile_setting()
 
257
    else:
 
258
        print(args.action + "is not a valid action")
 
259
        return 1
 
260
 
 
261
    return 0
 
262
 
 
263
if __name__ == "__main__":
 
264
    sys.exit(main())