1/* 2 * card_select.c - select a card by list or device name 3 * Copyright (c) Clemens Ladisch <clemens@ladisch.de> 4 * 5 * This program is free software: you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation, either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 */ 18 19#include "aconfig.h" 20#include <stdio.h> 21#include <stdlib.h> 22#include <assert.h> 23#include <alsa/asoundlib.h> 24#include <menu.h> 25#include "gettext_curses.h" 26#include "die.h" 27#include "mem.h" 28#include "utils.h" 29#include "colors.h" 30#include "widget.h" 31#include "menu_widget.h" 32#include "mixer_widget.h" 33#include "device_name.h" 34#include "card_select.h" 35 36struct card { 37 struct card *next; 38 char *indexstr; 39 char *name; 40 char *device_name; 41}; 42 43static struct widget list_widget; 44static struct card first_card; 45static ITEM **items; 46static MENU *menu; 47static ITEM *initial_item; 48 49static void on_key_enter(void) 50{ 51 ITEM *item = current_item(menu); 52 if (item) { 53 struct card *card = item_userptr(item); 54 if (card->device_name) { 55 if (select_card_by_name(card->device_name)) 56 list_widget.close(); 57 } else { 58 create_device_name_form(); 59 } 60 } 61} 62 63static void on_handle_key(int key) 64{ 65 switch (menu_widget_handle_key(menu, key)) { 66 case KEY_ENTER: 67 on_key_enter(); 68 break; 69 case KEY_CANCEL: 70 list_widget.close(); 71 break; 72 } 73} 74 75static void create(void) 76{ 77 menu_widget_create(&list_widget, menu, _("Sound Card")); 78} 79 80void close_card_select_list(void) 81{ 82 unsigned int i; 83 struct card *card, *next_card; 84 85 unpost_menu(menu); 86 free_menu(menu); 87 for (i = 0; items[i]; ++i) 88 free_item(items[i]); 89 free(items); 90 for (card = first_card.next; card; card = next_card) { 91 next_card = card->next; 92 free(card->indexstr); 93 free(card->name); 94 free(card->device_name); 95 free(card); 96 } 97 widget_free(&list_widget); 98} 99 100static struct widget list_widget = { 101 .handle_key = on_handle_key, 102 .window_size_changed = create, 103 .close = close_card_select_list, 104}; 105 106static int get_cards(void) 107{ 108 int count, number, err; 109 snd_ctl_t *ctl; 110 snd_ctl_card_info_t *info; 111 char buf[32]; 112 struct card *card, *prev_card; 113 114 first_card.indexstr = "-"; 115 first_card.name = _("(default)"); 116 first_card.device_name = "default"; 117 count = 1; 118 119 snd_ctl_card_info_alloca(&info); 120 prev_card = &first_card; 121 number = -1; 122 for (;;) { 123 err = snd_card_next(&number); 124 if (err < 0) 125 fatal_alsa_error(_("cannot enumerate sound cards"), err); 126 if (number < 0) 127 break; 128#if defined(SND_LIB_VER) && SND_LIB_VER(1, 2, 5) <= SND_LIB_VERSION 129 sprintf(buf, "sysdefault:%d", number); 130#else 131 sprintf(buf, "hw:%d", number); 132#endif 133 err = snd_ctl_open(&ctl, buf, 0); 134 if (err < 0) 135 continue; 136 err = snd_ctl_card_info(ctl, info); 137 snd_ctl_close(ctl); 138 if (err < 0) 139 continue; 140 card = ccalloc(1, sizeof *card); 141 card->device_name = cstrdup(buf); 142 card->indexstr = cstrdup(buf + 3); 143 card->name = cstrdup(snd_ctl_card_info_get_name(info)); 144 prev_card->next = card; 145 prev_card = card; 146 ++count; 147 } 148 149 card = ccalloc(1, sizeof *card); 150 card->indexstr = cstrdup(" "); 151 card->name = cstrdup(_("enter device name...")); 152 prev_card->next = card; 153 ++count; 154 155 return count; 156} 157 158static void create_list_items(int cards) 159{ 160 int i; 161 struct card *card; 162 ITEM *item; 163 164 initial_item = NULL; 165 items = ccalloc(cards + 1, sizeof(ITEM*)); 166 i = 0; 167 for (card = &first_card; card; card = card->next) { 168 item = new_item(card->indexstr, card->name); 169 if (!item) 170 fatal_error("cannot create menu item"); 171 set_item_userptr(item, card); 172 items[i++] = item; 173 if (!initial_item && 174 mixer_device_name && 175 (!card->device_name || 176 !strcmp(card->device_name, mixer_device_name))) 177 initial_item = item; 178 } 179 assert(i == cards); 180} 181 182void create_card_select_list(void) 183{ 184 int cards; 185 186 cards = get_cards(); 187 create_list_items(cards); 188 189 menu = new_menu(items); 190 if (!menu) 191 fatal_error("cannot create menu"); 192 set_menu_fore(menu, attrs.menu_selected); 193 set_menu_back(menu, attrs.menu); 194 set_menu_mark(menu, NULL); 195 if (initial_item) 196 set_current_item(menu, initial_item); 197 set_menu_spacing(menu, 2, 1, 1); 198 menu_opts_on(menu, O_SHOWDESC); 199 200 create(); 201} 202