#!/usr/bin/python # (C) 2005 Canonical Ltd. # Author: Martin Pitt # License: GNU General Public License, version 2 or any later version # # Modified by: Thomas Hood # # Get and set configuration parameters in ~/.asoundrc.asoundconf. import sys, re, os.path our_conf_file = os.path.expanduser('~/.asoundrc.asoundconf') asoundrc_file = os.path.expanduser('~/.asoundrc') setting_re_template = '!?\s*%s\s*(?:=|\s)\s*([^;,]+)[;,]?$' our_conf_header = '''# ALSA library configuration file managed by asoundconf(1). # # MANUAL CHANGES TO THIS FILE WILL BE OVERWRITTEN! # # Manual changes to the ALSA library configuration should be implemented # by editing the ~/.asoundrc file, not by editing this file. ''' asoundrc_header = '''# ALSA library configuration file ''' inclusion_comment = '''# Include settings that are under the control of asoundconf(1). # (To disable these settings, comment out this line.)''' usage = '''Usage: asoundconf is-active asoundconf get|delete PARAMETER asoundconf set PARAMETER VALUE asoundconf list ''' def help(): print usage def ensure_our_conf_exists(): '''If it does not exist then generate a default configuration file with no settings. Return: True on success, False if the file could not be created. ''' if os.path.exists(our_conf_file): return True try: open(our_conf_file, 'w').write(our_conf_header) return True except IOError: print >> sys.stderr, 'Error: could not create', our_conf_file return False def ensure_asound_rc_exists(): '''Generate a default user configuration file with only the inclusion line. Return: True on success, False if the file could not be created. ''' if os.path.exists(asoundrc_file): return True try: open(asoundrc_file, 'w').write('%s\n%s\n<%s>\n\n' % (asoundrc_header, inclusion_comment, our_conf_file)) return True except IOError: print >> sys.stderr, 'Error: could not create', asoundrc_file return False def sds_transition(): '''Replace the magic comments added to the user configuration file by the obsolete set-default-soundcard program with the standard inclusion statement for our configuration file. ''' if not os.path.exists(asoundrc_file): return lines = open(asoundrc_file).readlines() start_marker_re = re.compile('### BEGIN set-default-soundcard') end_marker_re = re.compile('### END set-default-soundcard') userconf_lines = [] our_conf_lines = [] # read up to start comment lineno = 0 found = 0 for l in lines: lineno = lineno+1 if start_marker_re.match(l): found = 1 break userconf_lines.append(l) if found: # replace magic comment section with include userconf_lines.append('%s\n<%s>\n\n' % (inclusion_comment, our_conf_file)) else: # no magic comment return # read magic comment section until end marker and add it to asoundconf found = 0 for l in lines[lineno:]: lineno = lineno+1 if end_marker_re.match(l): found = 1 break if not l.startswith('#'): our_conf_lines.append(l) if not found: # no complete magic comment return # add the rest to user conf userconf_lines = userconf_lines + lines[lineno:] # write our configuration file if not ensure_our_conf_exists(): return try: open(our_conf_file, 'a').writelines(our_conf_lines) except IOError: return # panic out # write user configuration file try: open(asoundrc_file, 'w').writelines(userconf_lines) except IOError: pass def is_active(): '''Check whether or not the user configuration file includes the asoundconf configuration file (so that the latter is "active"). Also transition from the legacy set-default-soundcard program. Return True if active, False if not. ''' if not os.path.exists(asoundrc_file): return True sds_transition() # check whether or not the file has the inclusion line include_re = re.compile('\s*<\s*%s\s*>' % our_conf_file) for l in open(asoundrc_file): if include_re.match(l): return True return False def get(prmtr): '''Print the value of the given parameter on stdout Also transition from the legacy set-default-soundcard program. Return True on success, and False if the value is not set. ''' sds_transition() if not os.path.exists(our_conf_file): return False setting_re = re.compile(setting_re_template % prmtr) try: for line in open(our_conf_file): m = setting_re.match(line) if m: print m.group(1).strip() return True return False except IOError: return False def list(): '''Get card names from /proc/asound/cards''' cardspath = '/proc/asound/cards' if not os.path.exists(cardspath): return False procfile = open(cardspath, 'rb') cardline = re.compile('^\d+\s*\[') card_lines = [] lines = procfile.readlines() for l in lines: if cardline.match(l): card_lines.append(re.sub(r'^\d+\s*\[(\w+)\s*\].+','\\1',l)) print "Names of available sound cards:" for cardname in card_lines: print cardname.strip() return True def delete(prmtr): '''Delete the given parameter. Also transition from the legacy set-default-soundcard program. Return True on success, and False on an error. ''' sds_transition() if not os.path.exists(our_conf_file): return False setting_re = re.compile(setting_re_template % prmtr) lines = [] try: lines = open(our_conf_file).readlines() except IOError: return False found = 0 for i in xrange(len(lines)): if setting_re.match(lines[i]): del lines[i] found = 1 break if found: # write back file try: f = open(our_conf_file, 'w') except IOError: return False f.writelines(lines) return True def set(prmtr, value): '''Set the given parameter to the given value Also transition from the legacy set-default-soundcard program. Return True on success, and False on an error. ''' sds_transition() setting_re = re.compile(setting_re_template % prmtr) lines = [] ensure_asound_rc_exists() # N.B. We continue even if asoundrc could not be created # and we do NOT ensure that our configuration is "active" if not ensure_our_conf_exists(): return False try: lines = open(our_conf_file).readlines() except IOError: return False if value.isdigit(): newsetting = '%s %s\n' % (prmtr, value) else: newsetting = '!%s %s\n' % (prmtr, value) # if setting is already present, change it found = 0 for i in xrange(len(lines)): if setting_re.match(lines[i]): lines[i] = newsetting found = 1 break if not found: lines.append(newsetting) # write back file try: f = open(our_conf_file, 'w') except IOError: return False f.writelines(lines) return True def exit_code(result): '''Exit program with code 0 if result is True, otherwise exit with code 1. ''' if result: sys.exit(0) else: sys.exit(1) ## ## main ## if len(sys.argv) < 2 or sys.argv[1] == '--help' or sys.argv[1] == '-h': help() sys.exit(0) if sys.argv[1] == 'is-active': exit_code(is_active()) if sys.argv[1] == 'get': if len(sys.argv) != 3: help() sys.exit(1) exit_code(get(sys.argv[2])) if sys.argv[1] == 'delete': if len(sys.argv) != 3: help() sys.exit(1) exit_code(delete(sys.argv[2])) if sys.argv[1] == 'set': if len(sys.argv) != 4: help() sys.exit(1) exit_code(set(sys.argv[2], sys.argv[3])) if sys.argv[1] == 'list': exit_code(list()) help() sys.exit(1)