Beispiel #1
0
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)
Beispiel #2
0
 def load_config(self):
     """Read the config file."""
     logger.debug('Loading configuration')
     self._config = {}
     # load config
     self.mtime = os.path.getmtime(self._path)
     with open(self._path, 'r') as config_file:
         for line in config_file:
             line = line.strip()
             if not line.startswith('#'):
                 split = line.split('=', 1)
                 if len(split) == 2:
                     key = split[0]
                     value = split[1]
                 else:
                     key = split[0]
                     value = None
             if value.isdigit():
                 value = int(value)
             else:
                 try:
                     value = float(value)
                 except ValueError:
                     pass
             if value == 'True':
                 value = True
             if value == 'False':
                 value = False
             self._config[key] = value
Beispiel #3
0
    def set(self, key, value):
        """Write a setting into memory and ~/.config/alsacontrol/config."""
        if key not in _defaults:
            logger.error('Unknown setting %s', key)
            return None

        self.check_mtime()

        if key in self._config and self._config[key] == value:
            logger.debug('Setting "%s" is already "%s"', key, value)
            return False

        self._config[key] = value

        with open(self._path, 'r+') as config_file:
            config_contents = config_file.read()
            config_contents = _modify_config(config_contents, key, value)

        # overwrite completely
        with open(self._path, 'w') as config_file:
            if not config_contents.endswith('\n'):
                config_contents += '\n'
            config_file.write(config_contents)

        self.mtime = os.path.getmtime(self._path)
        return True
Beispiel #4
0
def select_input_pcm(card):
    """Write the pcm to the configuration.

    Parameters
    ----------
    card : string
        "Generic", "jack", ...
    """
    # figure out if this is an actual hardware device or not
    if card is None:
        logger.debug('Unselecting the input')
        get_config().set('pcm_input', 'null')
        return

    cards = alsaaudio.cards()
    if card == 'jack':
        pcm_name = 'jack'
    elif card in cards:
        plugin = get_config().get('input_plugin')
        pcm_name = f'{plugin}:CARD={card}'
    else:
        # card unknown, the device is possibly not connected
        logger.warning(
            'Going to write possibly invalid pcm %s to the settings', card)
        # might me something similar to jack, a software pcm
        pcm_name = card

    get_config().set('pcm_input', pcm_name)
Beispiel #5
0
def get_current_card(source):
    """Get a tuple describing the current card selection based on config.

    Parameters
    ----------
    source : string
        one of 'pcm_input' or 'pcm_output'

    Returns
    -------
    A tuple of (d, card) with d being the index in the list of options
    from get_cards.
    """
    pcm_name = get_config().get(source)
    if pcm_name == 'null':
        logger.debug('No input selected')
        return None, None

    cards = get_cards()
    if len(cards) == 0:
        logger.error('Could not find any card')
        return None, None

    card = get_card(pcm_name)
    if card not in cards:
        logger.warning('Found unknown %s "%s" in config', source, pcm_name)
        return None, card

    index = cards.index(card)
    return index, card
Beispiel #6
0
def output_exists(func, testcard=True, testmixer=True):
    """Check if the configured output card and mixer is available."""
    # might be a pcm name with plugin and device
    card = get_card(get_config().get('pcm_output'))
    if testcard:
        if card is None:
            logger.debug('%s, No output selected', func)
            return None
        if not card in get_cards():
            logger.error('%s, Could not find the output card "%s"', func, card)
            return False
    if testmixer and get_config().get('output_use_softvol'):
        if 'alsacontrol-output-volume' not in alsaaudio.mixers():
            logger.error('%s, Could not find the output softvol mixer', func)
            play_silence()
            return False
    return True
Beispiel #7
0
    def __init__(self, path=None):
        """Initialize the interface to the config file.

        Parameters
        ----------
        path : string or None
            If none, will default to '~/.config/alsacontrol/config'
        """
        if path is None:
            path = os.path.expanduser('~/.config/alsacontrol/config')
        logger.debug('Using config file at %s', path)

        self._path = path
        self._config = {}
        self.mtime = 0

        self.create_config_file()

        self.load_config()
Beispiel #8
0
def record_to_nowhere():
    """Similar problem as in play_silence with the input mixer.

    Otherwise 'Unable to find mixer control alsacontrol-input-mute'
    will be thrown at the start.
    """
    logger.debug('Trying to capture sound to make the input mixers visible')
    try:
        pcm = alsaaudio.PCM(type=alsaaudio.PCM_CAPTURE, device='default')
        pcm.read()
    except alsaaudio.ALSAAudioError as error:
        error = str(error)
        logger.error(error)
        if 'resource busy' in error:
            logger.error(
                'Your specified input is currently busy, are jack or pulse'
                'using it?')
        logger.error('Could not initialize input mixer. '
                     'Try setting a different device.')
Beispiel #9
0
def input_exists(func, testcard=True, testmixer=True):
    """Check if the configured input card and mixer is available.

    Returns None if no card is configured, because the existance of 'no' card
    cannot be determined.
    """
    # might be a pcm name with plugin and device
    card = get_card(get_config().get('pcm_input'))
    if testcard:
        if card is None:
            logger.debug('%s, No input selected', func)
            return None
        if not card in alsaaudio.cards():
            logger.error('%s, Could not find the input card "%s"', func, card)
            return False
    if testmixer and get_config().get('input_use_softvol'):
        if 'alsacontrol-input-volume' not in alsaaudio.mixers():
            logger.error('%s, Could not find the input softvol mixer', func)
            record_to_nowhere()
            return False
    return True
Beispiel #10
0
    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
Beispiel #11
0
def play_silence():
    """In order to make alsa see the mixers, play some silent audio.

    Otherwise 'Unable to find mixer control alsacontrol-output-mute'
    will be thrown at the start.
    """
    logger.debug('Trying to play sound to make the output mixers visible')
    try:
        pcm = alsaaudio.PCM(type=alsaaudio.PCM_PLAYBACK,
                            channels=1,
                            periodsize=32,
                            device='default')
        data = b'\x00' * 32
        pcm.write(data)
    except alsaaudio.ALSAAudioError as error:
        error = str(error)
        logger.error(error)
        if 'resource busy' in error:
            logger.error(
                'Your specified output is currently busy, is jack using it?')
        logger.error('Could not initialize output mixer, '
                     'try setting a different device.')