1/* tinymix.c
2**
3** Copyright 2011, The Android Open Source Project
4**
5** Redistribution and use in source and binary forms, with or without
6** modification, are permitted provided that the following conditions are met:
7**     * Redistributions of source code must retain the above copyright
8**       notice, this list of conditions and the following disclaimer.
9**     * Redistributions in binary form must reproduce the above copyright
10**       notice, this list of conditions and the following disclaimer in the
11**       documentation and/or other materials provided with the distribution.
12**     * Neither the name of The Android Open Source Project nor the names of
13**       its contributors may be used to endorse or promote products derived
14**       from this software without specific prior written permission.
15**
16** THIS SOFTWARE IS PROVIDED BY The Android Open Source Project ``AS IS'' AND
17** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19** ARE DISCLAIMED. IN NO EVENT SHALL The Android Open Source Project BE LIABLE
20** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
26** DAMAGE.
27*/
28
29#include <tinyalsa/asoundlib.h>
30#include <stdio.h>
31#include <stdlib.h>
32#include <ctype.h>
33
34static void tinymix_list_controls(struct mixer *mixer);
35static void tinymix_detail_control(struct mixer *mixer, unsigned int id,
36                                   int print_all);
37static void tinymix_set_value(struct mixer *mixer, unsigned int id,
38                              char *value);
39static void tinymix_print_enum(struct mixer_ctl *ctl, int print_all);
40
41int main(int argc, char **argv)
42{
43    struct mixer *mixer;
44    int card = 0;
45
46    if ((argc > 2) && (strcmp(argv[1], "-D") == 0)) {
47        argv++;
48        if (argv[1]) {
49            card = atoi(argv[1]);
50            argv++;
51            argc -= 2;
52        } else {
53            argc -= 1;
54        }
55    }
56
57    mixer = mixer_open(card);
58    if (!mixer) {
59        fprintf(stderr, "Failed to open mixer\n");
60        return EXIT_FAILURE;
61    }
62
63    if (argc == 1)
64        tinymix_list_controls(mixer);
65    else if (argc == 2)
66        tinymix_detail_control(mixer, atoi(argv[1]), 1);
67    else if (argc == 3)
68        tinymix_set_value(mixer, atoi(argv[1]), argv[2]);
69    else
70        printf("Usage: tinymix [-D card] [control id] [value to set]\n");
71
72    mixer_close(mixer);
73
74    return 0;
75}
76
77static void tinymix_list_controls(struct mixer *mixer)
78{
79    struct mixer_ctl *ctl;
80    const char *name, *type;
81    unsigned int num_ctls, num_values;
82    unsigned int i;
83
84    num_ctls = mixer_get_num_ctls(mixer);
85
86    printf("Number of controls: %d\n", num_ctls);
87
88    printf("ctl\ttype\tnum\t%-40s value\n", "name");
89    for (i = 0; i < num_ctls; i++) {
90        ctl = mixer_get_ctl(mixer, i);
91
92        name = mixer_ctl_get_name(ctl);
93        type = mixer_ctl_get_type_string(ctl);
94        num_values = mixer_ctl_get_num_values(ctl);
95        printf("%d\t%s\t%d\t%-40s", i, type, num_values, name);
96        tinymix_detail_control(mixer, i, 0);
97    }
98}
99
100static void tinymix_print_enum(struct mixer_ctl *ctl, int print_all)
101{
102    unsigned int num_enums;
103    unsigned int i;
104    const char *string;
105
106    num_enums = mixer_ctl_get_num_enums(ctl);
107
108    for (i = 0; i < num_enums; i++) {
109        string = mixer_ctl_get_enum_string(ctl, i);
110        if (print_all)
111            printf("\t%s%s", mixer_ctl_get_value(ctl, 0) == (int)i ? ">" : "",
112                   string);
113        else if (mixer_ctl_get_value(ctl, 0) == (int)i)
114            printf(" %-s", string);
115    }
116}
117
118static void tinymix_detail_control(struct mixer *mixer, unsigned int id,
119                                   int print_all)
120{
121    struct mixer_ctl *ctl;
122    enum mixer_ctl_type type;
123    unsigned int num_values;
124    unsigned int i;
125    int min, max;
126
127    if (id >= mixer_get_num_ctls(mixer)) {
128        fprintf(stderr, "Invalid mixer control\n");
129        return;
130    }
131
132    ctl = mixer_get_ctl(mixer, id);
133
134    type = mixer_ctl_get_type(ctl);
135    num_values = mixer_ctl_get_num_values(ctl);
136
137    if (print_all)
138        printf("%s:", mixer_ctl_get_name(ctl));
139
140    for (i = 0; i < num_values; i++) {
141        switch (type)
142        {
143        case MIXER_CTL_TYPE_INT:
144            printf(" %d", mixer_ctl_get_value(ctl, i));
145            break;
146        case MIXER_CTL_TYPE_BOOL:
147            printf(" %s", mixer_ctl_get_value(ctl, i) ? "On" : "Off");
148            break;
149        case MIXER_CTL_TYPE_ENUM:
150            tinymix_print_enum(ctl, print_all);
151            break;
152         case MIXER_CTL_TYPE_BYTE:
153            printf(" 0x%02x", mixer_ctl_get_value(ctl, i));
154            break;
155        default:
156            printf(" unknown");
157            break;
158        };
159    }
160
161    if (print_all) {
162        if (type == MIXER_CTL_TYPE_INT) {
163            min = mixer_ctl_get_range_min(ctl);
164            max = mixer_ctl_get_range_max(ctl);
165            printf(" (range %d->%d)", min, max);
166        }
167    }
168    printf("\n");
169}
170
171static void tinymix_set_value(struct mixer *mixer, unsigned int id,
172                              char *string)
173{
174    struct mixer_ctl *ctl;
175    enum mixer_ctl_type type;
176    unsigned int num_values;
177    unsigned int i;
178
179    ctl = mixer_get_ctl(mixer, id);
180    type = mixer_ctl_get_type(ctl);
181    num_values = mixer_ctl_get_num_values(ctl);
182
183    if (isdigit(string[0])) {
184        int value = atoi(string);
185
186        for (i = 0; i < num_values; i++) {
187            if (mixer_ctl_set_value(ctl, i, value)) {
188                fprintf(stderr, "Error: invalid value\n");
189                return;
190            }
191        }
192    } else {
193        if (type == MIXER_CTL_TYPE_ENUM) {
194            if (mixer_ctl_set_enum_by_string(ctl, string))
195                fprintf(stderr, "Error: invalid enum value\n");
196        } else {
197            fprintf(stderr, "Error: only enum types can be set with strings\n");
198        }
199    }
200}
201
202