From 9796a3d1928a5293e85928cf74e68b88d2871510 Mon Sep 17 00:00:00 2001 From: Christopher Arndt Date: Fri, 23 Oct 2015 16:47:51 +0200 Subject: [PATCH] Use procfs to get list of ALSA PCM devices --- src/alsainfo.py | 85 +++++++++++++++++++++++++++++++++++++++++++++ src/jacksettings.py | 30 ++++------------ 2 files changed, 92 insertions(+), 23 deletions(-) create mode 100644 src/alsainfo.py diff --git a/src/alsainfo.py b/src/alsainfo.py new file mode 100644 index 0000000..6e4a5cc --- /dev/null +++ b/src/alsainfo.py @@ -0,0 +1,85 @@ +# -*- coding: utf-8 -*- +"""Get ALSA card and device list.""" + +import re + +from io import open +from collections import namedtuple +from functools import partial +from os.path import exists + +__all__ = ( + 'AlsaCardInfo', + 'AlsaPcmInfo', + 'get_cards', + 'get_capture_devices', + 'get_playback_devices', + 'get_pcm_devices' +) + +PROC_CARDS = '/proc/asound/cards' +PROC_DEVICES = '/proc/asound/pcm' + +AlsaCardInfo = namedtuple('AlsaCardInfo', 'card_num id name') +AlsaPcmInfo = namedtuple('AlsaPcmInfo', + 'card_num dev_num id name playback capture') + + +def get_cards(): + """Get card info from /proc/asound/cards.""" + + if not exists(PROC_CARDS): + raise IOError("'%s' does not exist. ALSA not loaded?" % PROC_CARDS) + + with open(PROC_CARDS, 'r', encoding='utf-8') as procfile: + # capture card number, id and name + cardline = re.compile( + r'^\s*(?P\d+)\s*' # card number + r'\[(?P\w+)\s*\]:' # card ID + r'.*-\s(?P.*)$') # card name + + for line in procfile: + match = cardline.match(line) + + if match: + yield AlsaCardInfo(card_num=int(match.group('num')), + id=match.group('id').strip(), + name=match.group('name').strip()) + + +def get_pcm_devices(): + """Get PCM device numbers and names from /proc/asound/pcm.""" + + if not exists(PROC_DEVICES): + raise IOError("'%s' does not exist. ALSA not loaded?" % PROC_DEVICES) + + with open(PROC_DEVICES, 'r', encoding='utf-8') as procfile: + devnum = re.compile(r'(?P\d+)-(?P\d+)') + + for line in procfile: + fields = [l.strip() for l in line.split(':')] + + if len(fields) >= 3: + match = devnum.match(fields[0]) + + if match: + yield AlsaPcmInfo(card_num=int(match.group('card_num')), + dev_num=int(match.group('dev_num')), + id=fields[1], + name=fields[2], + playback='playback 1' in fields, + capture='capture 1' in fields) + + +def get_devices(playback=True, capture=True): + """Return iterable of (device string, card name, device name) tuples.""" + cards = {c.card_num: c for c in get_cards()} + + for dev in get_pcm_devices(): + card = cards[dev.card_num] + if (playback and dev.playback) or (capture and dev.capture): + yield ("hw:%s,%i" % (card.id, dev.dev_num), card.name, dev.name) + + +get_playback_devices = partial(get_devices, capture=False) +get_capture_devices = partial(get_devices, playback=False) diff --git a/src/jacksettings.py b/src/jacksettings.py index 69e9f75..3107011 100755 --- a/src/jacksettings.py +++ b/src/jacksettings.py @@ -33,6 +33,7 @@ else: # ------------------------------------------------------------------------------------------------------------ # Imports (Custom Stuff) +import alsainfo import ui_settings_jack # ------------------------------------------------------------------------------------------------------------ @@ -700,26 +701,9 @@ class JackSettingsW(QDialog): # ----------------------------------------------------------------- # Helper functions - def getAlsaDeviceList(self): - alsaDeviceList = [] - - aplay_out = getoutput("env LANG=C LC_ALL=C aplay -l").split("\n") - for line in aplay_out: - line = line.strip() - if line.startswith("card "): - cardInfo = line.split(", ", 1)[0].split(": ") - cardIndex = cardInfo[0].replace("card ", "") - cardName = cardInfo[1].split(" [")[0] - - deviceInfo = line.split(", ", 1)[1].split(": ") - deviceIndex = deviceInfo[0].replace("device ", "") - deviceName = deviceInfo[1].split(" [")[0] - - if cardName != "Loopback": - fullName = "hw:%s,%s [%s]" % (cardName, deviceIndex, deviceName) - alsaDeviceList.append(fullName) - - return alsaDeviceList + def getAlsaDeviceList(self, **kwargs): + return ["%s [%s - %s]" % dev + for dev in alsainfo.get_devices(**kwargs)] def setComboBoxValue(self, box, text, split=False): for i in range(box.count()): @@ -786,10 +770,10 @@ class JackSettingsW(QDialog): self.ui.obj_driver_playback.addItem("none") if LINUX: - dev_list = self.getAlsaDeviceList() - for dev in dev_list: - self.ui.obj_driver_capture.addItem(dev) + for dev in self.getAlsaDeviceList(capture=False): self.ui.obj_driver_playback.addItem(dev) + for dev in self.getAlsaDeviceList(playback=False): + self.ui.obj_driver_capture.addItem(dev) else: dev_list = gJackctl.GetParameterConstraint(["driver", "device"])[3] for i in range(len(dev_list)):