Beispiel #1
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 #2
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 #3
0
 def get(self, key):
     """Read a value from the configuration or get the default."""
     self.check_mtime()
     if key not in _defaults:
         logger.error('Unknown setting %s', key)
         return None
     return self._config.get(key, _defaults[key])
Beispiel #4
0
def set_mute(mixer_name, state):
    """Set if the mixer should be muted or not."""
    if mixer_name not in alsaaudio.mixers():
        logger.error('Could not find mixer %s', mixer_name)
        return
    mixer = alsaaudio.Mixer(mixer_name)
    mixer.setmute(state)
Beispiel #5
0
def set_volume(volume, pcm_type, nonlinear=False):
    """Change the mixer volume.

    Parameters
    ----------
    volume : float
        New value between 0 and 1
    pcm_type : int
        0 for output (PCM_PLAYBACK), 1 for input (PCM_CAPTURE)
    nonlinear : bool
        if True, will apply to_mixer_volume
    """
    if pcm_type == alsaaudio.PCM_PLAYBACK:
        mixer_name = OUTPUT_VOLUME
    elif pcm_type == alsaaudio.PCM_CAPTURE:
        mixer_name = INPUT_VOLUME
    else:
        raise ValueError(f'Unsupported PCM {pcm_type}')

    if mixer_name not in alsaaudio.mixers():
        logger.error('Could not find mixer %s', mixer_name)
        return

    if nonlinear:
        volume = to_mixer_volume(volume)

    mixer_volume = min(100, max(0, round(volume * 100)))

    mixer = alsaaudio.Mixer(mixer_name)

    current_mixer_volume = mixer.getvolume(pcm_type)[0]
    if mixer_volume == current_mixer_volume:
        return

    mixer.setvolume(mixer_volume)
Beispiel #6
0
def get_volume(pcm, nonlinear=False):
    """Get the current mixer volume between 0 and 1.

    Parameters
    ----------
    pcm : int
        0 for output (PCM_PLAYBACK), 1 for input (PCM_CAPTURE)
    nonlinear : bool
        if True, will apply to_perceived_volume
    """
    if pcm == alsaaudio.PCM_PLAYBACK:
        mixer_name = OUTPUT_VOLUME
    elif pcm == alsaaudio.PCM_CAPTURE:
        mixer_name = INPUT_VOLUME
    else:
        raise ValueError(f'Unsupported PCM {pcm}')

    if mixer_name not in alsaaudio.mixers():
        logger.error('Could not find mixer %s', mixer_name)
        # might be due to configuration
        return 100

    mixer = alsaaudio.Mixer(mixer_name)
    mixer_volume = mixer.getvolume(pcm)[0] / 100

    if nonlinear:
        return to_perceived_volume(mixer_volume)

    return mixer_volume
Beispiel #7
0
def get_cards():
    """List all cards, including options such as jack."""
    cards = alsaaudio.cards()
    if services.is_jack_running():
        cards.append('jack')
    if len(cards) == 0:
        logger.error('Could not find any card')
    return cards
Beispiel #8
0
def is_muted(mixer_name=OUTPUT_MUTE):
    """Figure out if the output is muted or not."""
    if mixer_name not in alsaaudio.mixers():
        logger.error('Could not find mixer %s', mixer_name)
        return False

    mixer = alsaaudio.Mixer(mixer_name)
    return mixer.getmute()[0] == 1
Beispiel #9
0
def toggle_mute(mixer_name):
    """Mute or unmute.

    Returns None if it fails.
    """
    if mixer_name not in alsaaudio.mixers():
        logger.error('Could not find mixer %s', mixer_name)
        return None

    mixer = alsaaudio.Mixer(mixer_name)
    if mixer.getmute()[0]:
        mixer.setmute(0)
        return False
    mixer.setmute(1)
    return True
Beispiel #10
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 #11
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 #12
0
    def check_speaker_test(self):
        """Return a tuple of (running, error) for the speaker test."""
        if self.speaker_test_process is None:
            return False, None

        return_code = self.speaker_test_process.poll()
        if return_code is not None:
            if return_code == -15:
                # the test was stopped by hand
                return False, None

            if return_code != 0:
                # speaker-test had an error, try to read it from its output
                logger.error('speaker-test failed (code %d):', return_code)
                msg = []

                stderr = self._read_from_std(self.speaker_test_process.stderr)
                stdout = self._read_from_std(self.speaker_test_process.stdout)

                self.speaker_test_process = None

                if len(stderr) > 0:
                    msg.append('Errors:')
                    for line in stderr:
                        logger.error('speaker-test stderr: %s', line)
                        msg.append(line)

                if len(stdout) > 0:
                    msg += ['', 'Output:']
                    for line in stdout:
                        logger.error('speaker-test stdout: %s', line)
                        msg.append(line)

                if len(msg) == 0:
                    msg = f'Unknown error. Exit code {return_code}'
                else:
                    msg = '\n'.join(msg)

                return False, msg

            if return_code == 0:
                self.speaker_test_process = None
                return False, None

            if return_code is None:
                return True, None

        return True, None
Beispiel #13
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 #14
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.')