def _modify_config(config_contents, key, value): """Return a string representing the modified contents of the config file. Parameters ---------- config_contents : string Contents of the config file in ~/.config/alsacontrol/config. It is not edited in place and the config file is not overwritten. key : string Settings key that should be modified value : string, int Value to write """ logger.info('Setting "%s" to "%s"', key, value) split = config_contents.split('\n') if split[-1] == '': split = split[:-1] found = False setting = f'{key}={value}' for i, line in enumerate(split): strip = line.strip() if strip.startswith('#'): continue if strip.startswith(f'{key}='): # replace the setting logger.debug('Overwriting "%s=%s" in config', key, value) split[i] = setting found = True break if not found: logger.debug('Adding "%s=%s" to config', key, value) split.append(setting) return '\n'.join(split)
def create_config_file(self): """Create an empty config if it doesn't exist.""" if not os.path.exists(os.path.dirname(self._path)): os.makedirs(os.path.dirname(self._path)) if not os.path.exists(self._path): logger.info('Creating config file "%s"', self._path) os.mknod(self._path)
def start_daemon(debug=True): """Start the alsacontrol daemon.""" logger.info('Starting the alsacontrol daemon') cmd = ['alsacontrol-daemon-gtk'] if debug: cmd.append('-d') subprocess.Popen(cmd)
def stop_pulse(): """Stop the pulseaudio service using systemctl.""" if is_pulse_running(): logger.info('Stopping pulseaudio') os.system('systemctl --user stop pulseaudio.service') os.system('systemctl --user stop pulseaudio.socket') os.system('pulseaudio -k') else: logger.info('Pulseaudio is not running')
def create_asoundrc(): """Create and populate ~/.config/alsacontrol/asoundrc.""" pcm_input, pcm_output = get_pcms() if pcm_output == 'jack': last_output_step = 'alsacontrol-plug' elif should_use_dmix(pcm_output): last_output_step = 'alsacontrol-dmix' else: last_output_step = pcm_output # either from asym directly to the last step, or over softvol if get_config().get('output_use_softvol'): output_pcm_asym = 'alsacontrol-output-softvol' output_pcm_softvol = last_output_step else: output_pcm_asym = last_output_step output_pcm_softvol = 'null' if pcm_input == 'jack': last_input_step = 'alsacontrol-plug' elif should_use_dsnoop(pcm_input): last_input_step = 'alsacontrol-dsnoop' else: last_input_step = pcm_input # either from asym directly to the last step, or over softvol if get_config().get('input_use_softvol'): input_pcm_asym = 'alsacontrol-input-softvol' input_pcm_softvol = last_input_step else: input_pcm_asym = last_input_step input_pcm_softvol = 'null' # dmix and dsnoop always have to be the last step asoundrc_config = { 'output_pcm_asym': output_pcm_asym, 'output_pcm_softvol': output_pcm_softvol, 'output_pcm': pcm_output, 'output_channels': get_config().get('output_channels'), 'input_pcm_asym': input_pcm_asym, 'input_pcm_softvol': input_pcm_softvol, 'input_pcm': pcm_input, } template_path = os.path.join(get_data_path(), 'asoundrc-template') with open(template_path, 'r') as template_file: template = template_file.read() asoundrc_content = template.format(**asoundrc_config) with open(alsactl_asoundrc, 'w+') as asoundrc_file: logger.info('Writing file %s', alsactl_asoundrc) asoundrc_file.write(asoundrc_content)
def get_pcms(): """Return the configured input and output pcm string.""" pcm_input = get_config().get('pcm_input') pcm_output = get_config().get('pcm_output') if pcm_input == 'null': logger.warning('No input specified') else: logger.info('Using input %s', pcm_input) if pcm_output == 'null': logger.warning('No output specified') else: logger.info('Using output %s', pcm_output) return pcm_input, pcm_output
def log_new_pcms(self): """Write to the console if new cards are added. Return True if so.""" # using .cards() isntead of .pcms() is MUCH faster cards = set(get_cards()) changes = 0 if self.cards is None: # first time running, don't log yet pass else: for card in self.cards.difference(cards): logger.info('Card "%s" was removed', card) changes += 1 for card in cards.difference(self.cards): logger.info('Found new card "%s"', card) changes += 1 self.cards = cards return changes > 0
def toggle_speaker_test(self): """Run the speaker-test script or stop it, if it is running. Returns the subprocess or False if it has been stopped. """ if self.speaker_test_process is None: num_channels = get_config().get('output_channels') cmd = f'speaker-test -D default -c {num_channels} -twav' logger.info('Testing speakers, %d channels (%s)', num_channels, cmd) process = subprocess.Popen( cmd.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE, preexec_fn=os.setsid ) self.speaker_test_process = process return process self.stop_speaker_test() return False
def stop_speaker_test(self): """Stop the speaker test if it is running.""" if self.speaker_test_process is None: return return_code = self.speaker_test_process.poll() if return_code is None: pid = self.speaker_test_process.pid logger.info('Stopping speaker test') try: os.killpg(os.getpgid(pid), signal.SIGTERM) except ProcessLookupError: logger.debug( 'Tried to stop speaker-test process that has already ' 'been stopped' ) # It has already been stopped if debug_log_on(): stdout = self._read_from_std(self.speaker_test_process.stdout) for line in stdout: logger.debug('speaker-test stdout: %s', line) self.speaker_test_process = None
def check_mtime(self): """Check if the config file has been modified and reload if needed.""" if os.path.getmtime(self._path) != self.mtime: logger.info('Config changed, reloading') self.load_config()
def stop_daemon(): """Stop the alsacontrol daemon.""" # stops alsacontrol-daemon-gtk or alsacontrol-daemon-qt if that should # ever exist in the future logger.info('Stopping the alsacontrol daemon') os.system('pkill -f alsacontrol-daemon')