1 1.3 nia /* $NetBSD: parse.c,v 1.3 2021/05/08 13:03:40 nia Exp $ */ 2 1.1 nia /*- 3 1.1 nia * Copyright (c) 2021 The NetBSD Foundation, Inc. 4 1.1 nia * All rights reserved. 5 1.1 nia * 6 1.1 nia * This code is derived from software contributed to The NetBSD Foundation 7 1.1 nia * by Nia Alarie. 8 1.1 nia * 9 1.1 nia * Redistribution and use in source and binary forms, with or without 10 1.1 nia * modification, are permitted provided that the following conditions 11 1.1 nia * are met: 12 1.1 nia * 1. Redistributions of source code must retain the above copyright 13 1.1 nia * notice, this list of conditions and the following disclaimer. 14 1.1 nia * 2. Redistributions in binary form must reproduce the above copyright 15 1.1 nia * notice, this list of conditions and the following disclaimer in the 16 1.1 nia * documentation and/or other materials provided with the distribution. 17 1.1 nia * 18 1.1 nia * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 19 1.1 nia * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 1.1 nia * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 21 1.1 nia * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 22 1.1 nia * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 1.1 nia * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 1.1 nia * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 1.1 nia * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 1.1 nia * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 1.1 nia * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 1.1 nia * POSSIBILITY OF SUCH DAMAGE. 29 1.1 nia */ 30 1.1 nia #include <sys/audioio.h> 31 1.1 nia #include <sys/ioctl.h> 32 1.1 nia #include <curses.h> 33 1.1 nia #include <stdlib.h> 34 1.1 nia #include "app.h" 35 1.1 nia #include "parse.h" 36 1.1 nia 37 1.1 nia static struct aiomixer_class *get_class(struct aiomixer *, int); 38 1.1 nia static int compare_control(const void *, const void *); 39 1.3 nia static int compare_class(const void *, const void *); 40 1.1 nia 41 1.1 nia static struct aiomixer_class * 42 1.1 nia get_class(struct aiomixer *aio, int class) 43 1.1 nia { 44 1.1 nia size_t i; 45 1.1 nia 46 1.1 nia for (i = 0; i < aio->numclasses; ++i) { 47 1.1 nia if (aio->classes[i].index == class) { 48 1.1 nia return &aio->classes[i]; 49 1.1 nia } 50 1.1 nia } 51 1.1 nia return NULL; 52 1.1 nia } 53 1.1 nia 54 1.1 nia static int 55 1.1 nia compare_control(const void *pa, const void *pb) 56 1.1 nia { 57 1.1 nia const struct aiomixer_control *a = (const struct aiomixer_control *)pa; 58 1.1 nia const struct aiomixer_control *b = (const struct aiomixer_control *)pb; 59 1.1 nia 60 1.2 nia if (a->info.prev != AUDIO_MIXER_LAST || 61 1.1 nia b->info.prev != AUDIO_MIXER_LAST) { 62 1.1 nia if (b->info.prev == a->info.index) 63 1.1 nia return -1; 64 1.1 nia if (a->info.prev == b->info.index) 65 1.1 nia return 1; 66 1.2 nia } else { 67 1.2 nia return strcmp(a->info.label.name, b->info.label.name); 68 1.1 nia } 69 1.2 nia return 0; 70 1.1 nia } 71 1.1 nia 72 1.3 nia static int 73 1.3 nia compare_class(const void *pa, const void *pb) 74 1.3 nia { 75 1.3 nia const struct aiomixer_class *a = (const struct aiomixer_class *)pa; 76 1.3 nia const struct aiomixer_class *b = (const struct aiomixer_class *)pb; 77 1.3 nia 78 1.3 nia if (strcmp(a->name, AudioCoutputs) == 0) 79 1.3 nia return -1; 80 1.3 nia if (strcmp(b->name, AudioCoutputs) == 0) 81 1.3 nia return 1; 82 1.3 nia 83 1.3 nia return strcmp(a->name, b->name); 84 1.3 nia } 85 1.3 nia 86 1.1 nia int 87 1.1 nia aiomixer_parse(struct aiomixer *aio) 88 1.1 nia { 89 1.1 nia size_t i; 90 1.1 nia struct mixer_devinfo info; 91 1.1 nia struct aiomixer_class *class; 92 1.1 nia struct aiomixer_control *control; 93 1.1 nia 94 1.1 nia for (info.index = 0; 95 1.1 nia ioctl(aio->fd, AUDIO_MIXER_DEVINFO, &info) != -1; ++info.index) { 96 1.1 nia if (info.type != AUDIO_MIXER_CLASS) 97 1.1 nia continue; 98 1.1 nia if (aio->numclasses >= __arraycount(aio->classes)) 99 1.1 nia break; 100 1.1 nia class = &aio->classes[aio->numclasses++]; 101 1.1 nia memcpy(class->name, info.label.name, MAX_AUDIO_DEV_LEN); 102 1.1 nia class->index = info.index; 103 1.1 nia class->numcontrols = 0; 104 1.1 nia } 105 1.1 nia for (info.index = 0; 106 1.1 nia ioctl(aio->fd, AUDIO_MIXER_DEVINFO, &info) != -1; ++info.index) { 107 1.1 nia if (info.type == AUDIO_MIXER_CLASS) 108 1.1 nia continue; 109 1.1 nia if (info.type == AUDIO_MIXER_VALUE) { 110 1.1 nia /* XXX workaround for hdaudio(4) bugs */ 111 1.1 nia if (info.un.v.delta > AUDIO_MAX_GAIN) 112 1.1 nia continue; 113 1.1 nia if (info.un.v.num_channels == 0) 114 1.1 nia continue; 115 1.1 nia } 116 1.1 nia class = get_class(aio, info.mixer_class); 117 1.1 nia if (class == NULL) 118 1.1 nia break; 119 1.1 nia if (class->numcontrols >= __arraycount(class->controls)) 120 1.1 nia break; 121 1.1 nia control = &class->controls[class->numcontrols++]; 122 1.1 nia control->info = info; 123 1.1 nia } 124 1.3 nia qsort(aio->classes, aio->numclasses, 125 1.3 nia sizeof(struct aiomixer_class), 126 1.3 nia compare_class); 127 1.1 nia for (i = 0; i < aio->numclasses; ++i) { 128 1.1 nia class = &aio->classes[i]; 129 1.1 nia qsort(class->controls, class->numcontrols, 130 1.1 nia sizeof(struct aiomixer_control), 131 1.1 nia compare_control); 132 1.1 nia } 133 1.1 nia return 0; 134 1.1 nia } 135 1.1 nia 136