Ejemplo n.º 1
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)
Ejemplo n.º 2
0
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)
Ejemplo n.º 3
0
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
Ejemplo n.º 4
0
    def test_toggle_input(self):
        input_row = self.window.input_rows[0]
        input_card_name = self.window.builder.get_object('input_card_name')

        # since the config starts with 'null' as default,
        # no card should be selected
        self.assertEqual(get_config().get('pcm_input'), 'null')
        self.assertIn('No card selected', input_card_name.get_label())

        input_row.select_callback(input_row.card)
        self.assertNotEqual(get_config().get('pcm_input'), 'null')
        self.assertNotIn('No card selected', input_card_name.get_label())

        input_row.select_callback(input_row.card)
        self.assertEqual(get_config().get('pcm_input'), 'null')
        self.assertIn('No card selected', input_card_name.get_label())
Ejemplo n.º 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
Ejemplo n.º 6
0
    def test_select_output(self):
        cards = alsaaudio.cards()
        config = get_config()
        selected_index = 0

        class FakeDropdown:
            """Acts like a Gtk.ComboBoxText object."""
            def get_active_text(self):
                return cards[selected_index]

        self.window.on_output_card_selected(FakeDropdown())
        self.assertEqual(config.get('pcm_output'),
                         f'hw:CARD={cards[selected_index]}')
        with open(alsactl_asoundrc, 'r') as f:
            asoundrc = f.read()
            self.assertIn(config.get('pcm_output'), asoundrc)
            self.assertNotIn(cards[1], asoundrc)

        selected_index = 1
        config.set('output_plugin', 'ab')
        self.window.on_output_card_selected(FakeDropdown())
        self.assertEqual(config.get('pcm_output'),
                         f'ab:CARD={cards[selected_index]}')
        with open(alsactl_asoundrc, 'r') as f:
            asoundrc = f.read()
            self.assertNotIn(cards[0], asoundrc)
            self.assertIn(config.get('pcm_output'), asoundrc)
Ejemplo n.º 7
0
    def test_select_input(self):
        cards = alsaaudio.cards()
        config = get_config()

        # only show the input in the generated asoundrc to make
        # assertIn not get false positives.
        # Since there are some comments and stuff about jack in it, this
        # test avoids to also try to select jack.
        config.set('pcm_output', 'null')

        # first card
        self.window.on_input_card_selected(cards[0])
        self.assertEqual(config.get('pcm_input'), f'hw:CARD={cards[0]}')
        with open(alsactl_asoundrc, 'r') as f:
            asoundrc = f.read()
            self.assertIn(config.get('pcm_input'), asoundrc)
            self.assertNotIn(cards[1], asoundrc)

        # selecting it a second time unselects it
        self.window.on_input_card_selected(cards[0])
        self.assertEqual(config.get('pcm_input'), 'null')
        with open(alsactl_asoundrc, 'r') as f:
            asoundrc = f.read()
            self.assertNotIn(cards[0], asoundrc)
            self.assertNotIn(cards[1], asoundrc)

        # second card
        config.set('input_plugin', 'ab')
        self.window.on_input_card_selected(cards[1])
        self.assertEqual(config.get('pcm_input'), f'ab:CARD={cards[1]}')
        with open(alsactl_asoundrc, 'r') as f:
            asoundrc = f.read()
            self.assertNotIn(cards[0], asoundrc)
            self.assertIn(config.get('pcm_input'), asoundrc)
Ejemplo n.º 8
0
def should_use_dmix(pcm_output):
    """Check if, according to config, dmix should and can be used."""
    # use dmix only for hardware devices,
    # if the config is on and if the plugin is hw
    hardware_device = 'CARD=' in pcm_output
    output_use_dmix = get_config().get('output_use_dmix')
    output_plugin_hw = pcm_output.startswith('hw:')
    return hardware_device and output_use_dmix and output_plugin_hw
Ejemplo n.º 9
0
    def test_null_output(self):
        config = get_config()
        config.set('pcm_output', 'null')

        self.assertFalse(input_exists('test_null_output'))
        self.assertIsNone(get_current_card('pcm_output')[0])
        self.assertIsNone(get_current_card('pcm_output')[1])
        self.assertIsNone(get_card(config.get('pcm_output')))
Ejemplo n.º 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
Ejemplo n.º 11
0
def select_output_pcm(card):
    """Write this pcm to the configuration.

    Parameters
    ----------
    card : string
        "Generic", "jack", ...
    """
    # figure out if this is an actual hardware device or not
    cards = alsaaudio.cards()
    if card is None:
        card = 'null'
    if card in cards:
        plugin = get_config().get('output_plugin')
        pcm_name = f'{plugin}:CARD={card}'
    else:
        pcm_name = card  # otherwise probably jack
    get_config().set('pcm_output', pcm_name)
Ejemplo n.º 12
0
 def mixers():
     config = get_config()
     mixers = []
     if config.get('input_use_softvol'):
         mixers.append('alsacontrol-input-volume')
         mixers.append('alsacontrol-input-mute')
     if config.get('output_use_softvol'):
         mixers.append('alsacontrol-output-volume')
         mixers.append('alsacontrol-output-mute')
     return mixers
Ejemplo n.º 13
0
 def tearDown(self):
     self.window.on_close()
     self.window.window.destroy()
     gtk_iteration()
     self.fakes.restore()
     if os.path.exists(fake_config_path):
         os.remove(fake_config_path)
     config = get_config()
     config.create_config_file()
     config.load_config()
Ejemplo n.º 14
0
def get_error_advice(error):
    """Get some help for errors."""
    if 'resource busy' in error:
        return ('You can try to run `lsof +D /dev/snd/` to '
                'see which process is blocking it. It might be jack'
                'or pulseaudio.')
    if 'No such card' in error:
        pcm_output = get_config().get('pcm_output')
        return (f'The pcm card "{pcm_output}" does not exist. ' +
                'Try to select something different.')
    return None
Ejemplo n.º 15
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
Ejemplo n.º 16
0
 def __init__(self, type, device, *args, **kwargs):
     self.type = type
     config_key = {
         alsaaudio.PCM_CAPTURE: 'pcm_input',
         alsaaudio.PCM_PLAYBACK: 'pcm_output'
     }[type]
     if device is None or device == 'default':
         self.card = get_card(get_config().get(config_key))
         if self.card is None:
             raise ValueError(
                 'I don\'t think the PCM constructor should '
                 'be called when no device is set'
             )
     else:
         self.card = device
Ejemplo n.º 17
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
Ejemplo n.º 18
0
import os
import sys
import unittest

from alsacontrol.config import get_config
from alsacontrol.logger import update_verbosity
from fakes import fake_config_path

if __name__ == "__main__":
    update_verbosity(debug=True)

    if os.path.exists(fake_config_path):
        os.remove(fake_config_path)

    # don't overwrite the users settings in unittests
    get_config(fake_config_path)

    modules = sys.argv[1:]
    # discoverer is really convenient, but it can't find a specific test
    # in all of the available tests like unittest.main() does...,
    # so provide both options.
    if len(modules) > 0:
        # for example `tests/test.py ConfigTest.testFirstLine`
        testsuite = unittest.defaultTestLoader.loadTestsFromNames(
            [f'testcases.{module}' for module in modules])
    else:
        # run all tests by default
        testsuite = unittest.defaultTestLoader.discover('testcases',
                                                        pattern='*.py')
    testrunner = unittest.TextTestRunner(verbosity=1).run(testsuite)
Ejemplo n.º 19
0
def should_use_dsnoop(pcm_input):
    """Check if, according to config, dsnoop should and can be used."""
    hardware_device = 'CARD=' in pcm_input
    input_use_dmix = get_config().get('input_use_dsnoop')
    input_plugin_hw = pcm_input.startswith('hw:')
    return hardware_device and input_use_dmix and input_plugin_hw