CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
orangepi-xunlong

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.

GitHub Repository: orangepi-xunlong/orangepi-build
Path: blob/next/external/cache/sources/tinyalsa/mixer.c
Views: 3959
1
/* mixer.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 <stdio.h>
30
#include <stdlib.h>
31
#include <string.h>
32
#include <unistd.h>
33
#include <fcntl.h>
34
#include <errno.h>
35
#include <ctype.h>
36
37
#include <sys/ioctl.h>
38
39
#include <linux/ioctl.h>
40
#define __force
41
#define __bitwise
42
#define __user
43
#include <sound/asound.h>
44
45
#include <tinyalsa/asoundlib.h>
46
47
struct mixer_ctl {
48
struct mixer *mixer;
49
struct snd_ctl_elem_info *info;
50
char **ename;
51
};
52
53
struct mixer {
54
int fd;
55
struct snd_ctl_card_info card_info;
56
struct snd_ctl_elem_info *elem_info;
57
struct mixer_ctl *ctl;
58
unsigned int count;
59
};
60
61
void mixer_close(struct mixer *mixer)
62
{
63
unsigned int n,m;
64
65
if (!mixer)
66
return;
67
68
if (mixer->fd >= 0)
69
close(mixer->fd);
70
71
if (mixer->ctl) {
72
for (n = 0; n < mixer->count; n++) {
73
if (mixer->ctl[n].ename) {
74
unsigned int max = mixer->ctl[n].info->value.enumerated.items;
75
for (m = 0; m < max; m++)
76
free(mixer->ctl[n].ename[m]);
77
free(mixer->ctl[n].ename);
78
}
79
}
80
free(mixer->ctl);
81
}
82
83
if (mixer->elem_info)
84
free(mixer->elem_info);
85
86
free(mixer);
87
88
/* TODO: verify frees */
89
}
90
91
struct mixer *mixer_open(unsigned int card)
92
{
93
struct snd_ctl_elem_list elist;
94
struct snd_ctl_elem_info tmp;
95
struct snd_ctl_elem_id *eid = NULL;
96
struct mixer *mixer = NULL;
97
unsigned int n, m;
98
int fd;
99
char fn[256];
100
101
snprintf(fn, sizeof(fn), "/dev/snd/controlC%u", card);
102
fd = open(fn, O_RDWR);
103
if (fd < 0)
104
return 0;
105
106
memset(&elist, 0, sizeof(elist));
107
if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_LIST, &elist) < 0)
108
goto fail;
109
110
mixer = calloc(1, sizeof(*mixer));
111
if (!mixer)
112
goto fail;
113
114
mixer->ctl = calloc(elist.count, sizeof(struct mixer_ctl));
115
mixer->elem_info = calloc(elist.count, sizeof(struct snd_ctl_elem_info));
116
if (!mixer->ctl || !mixer->elem_info)
117
goto fail;
118
119
if (ioctl(fd, SNDRV_CTL_IOCTL_CARD_INFO, &mixer->card_info) < 0)
120
goto fail;
121
122
eid = calloc(elist.count, sizeof(struct snd_ctl_elem_id));
123
if (!eid)
124
goto fail;
125
126
mixer->count = elist.count;
127
mixer->fd = fd;
128
elist.space = mixer->count;
129
elist.pids = eid;
130
if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_LIST, &elist) < 0)
131
goto fail;
132
133
for (n = 0; n < mixer->count; n++) {
134
struct snd_ctl_elem_info *ei = mixer->elem_info + n;
135
ei->id.numid = eid[n].numid;
136
if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_INFO, ei) < 0)
137
goto fail;
138
mixer->ctl[n].info = ei;
139
mixer->ctl[n].mixer = mixer;
140
if (ei->type == SNDRV_CTL_ELEM_TYPE_ENUMERATED) {
141
char **enames = calloc(ei->value.enumerated.items, sizeof(char*));
142
if (!enames)
143
goto fail;
144
mixer->ctl[n].ename = enames;
145
for (m = 0; m < ei->value.enumerated.items; m++) {
146
memset(&tmp, 0, sizeof(tmp));
147
tmp.id.numid = ei->id.numid;
148
tmp.value.enumerated.item = m;
149
if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_INFO, &tmp) < 0)
150
goto fail;
151
enames[m] = strdup(tmp.value.enumerated.name);
152
if (!enames[m])
153
goto fail;
154
}
155
}
156
}
157
158
free(eid);
159
return mixer;
160
161
fail:
162
/* TODO: verify frees in failure case */
163
if (eid)
164
free(eid);
165
if (mixer)
166
mixer_close(mixer);
167
else if (fd >= 0)
168
close(fd);
169
return 0;
170
}
171
172
const char *mixer_get_name(struct mixer *mixer)
173
{
174
return (const char *)mixer->card_info.name;
175
}
176
177
unsigned int mixer_get_num_ctls(struct mixer *mixer)
178
{
179
if (!mixer)
180
return 0;
181
182
return mixer->count;
183
}
184
185
struct mixer_ctl *mixer_get_ctl(struct mixer *mixer, unsigned int id)
186
{
187
if (mixer && (id < mixer->count))
188
return mixer->ctl + id;
189
190
return NULL;
191
}
192
193
struct mixer_ctl *mixer_get_ctl_by_name(struct mixer *mixer, const char *name)
194
{
195
unsigned int n;
196
197
if (!mixer)
198
return NULL;
199
200
for (n = 0; n < mixer->count; n++)
201
if (!strcmp(name, (char*) mixer->elem_info[n].id.name))
202
return mixer->ctl + n;
203
204
return NULL;
205
}
206
207
void mixer_ctl_update(struct mixer_ctl *ctl)
208
{
209
ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_INFO, ctl->info);
210
}
211
212
const char *mixer_ctl_get_name(struct mixer_ctl *ctl)
213
{
214
if (!ctl)
215
return NULL;
216
217
return (const char *)ctl->info->id.name;
218
}
219
220
enum mixer_ctl_type mixer_ctl_get_type(struct mixer_ctl *ctl)
221
{
222
if (!ctl)
223
return MIXER_CTL_TYPE_UNKNOWN;
224
225
switch (ctl->info->type) {
226
case SNDRV_CTL_ELEM_TYPE_BOOLEAN: return MIXER_CTL_TYPE_BOOL;
227
case SNDRV_CTL_ELEM_TYPE_INTEGER: return MIXER_CTL_TYPE_INT;
228
case SNDRV_CTL_ELEM_TYPE_ENUMERATED: return MIXER_CTL_TYPE_ENUM;
229
case SNDRV_CTL_ELEM_TYPE_BYTES: return MIXER_CTL_TYPE_BYTE;
230
case SNDRV_CTL_ELEM_TYPE_IEC958: return MIXER_CTL_TYPE_IEC958;
231
case SNDRV_CTL_ELEM_TYPE_INTEGER64: return MIXER_CTL_TYPE_INT64;
232
default: return MIXER_CTL_TYPE_UNKNOWN;
233
};
234
}
235
236
const char *mixer_ctl_get_type_string(struct mixer_ctl *ctl)
237
{
238
if (!ctl)
239
return "";
240
241
switch (ctl->info->type) {
242
case SNDRV_CTL_ELEM_TYPE_BOOLEAN: return "BOOL";
243
case SNDRV_CTL_ELEM_TYPE_INTEGER: return "INT";
244
case SNDRV_CTL_ELEM_TYPE_ENUMERATED: return "ENUM";
245
case SNDRV_CTL_ELEM_TYPE_BYTES: return "BYTE";
246
case SNDRV_CTL_ELEM_TYPE_IEC958: return "IEC958";
247
case SNDRV_CTL_ELEM_TYPE_INTEGER64: return "INT64";
248
default: return "Unknown";
249
};
250
}
251
252
unsigned int mixer_ctl_get_num_values(struct mixer_ctl *ctl)
253
{
254
if (!ctl)
255
return 0;
256
257
return ctl->info->count;
258
}
259
260
static int percent_to_int(struct snd_ctl_elem_info *ei, int percent)
261
{
262
if ((percent > 100) || (percent < 0)) {
263
return -EINVAL;
264
}
265
266
int range = (ei->value.integer.max - ei->value.integer.min);
267
268
return ei->value.integer.min + (range * percent) / 100;
269
}
270
271
static int int_to_percent(struct snd_ctl_elem_info *ei, int value)
272
{
273
int range = (ei->value.integer.max - ei->value.integer.min);
274
275
if (range == 0)
276
return 0;
277
278
return ((value - ei->value.integer.min) / range) * 100;
279
}
280
281
int mixer_ctl_get_percent(struct mixer_ctl *ctl, unsigned int id)
282
{
283
if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_INTEGER))
284
return -EINVAL;
285
286
return int_to_percent(ctl->info, mixer_ctl_get_value(ctl, id));
287
}
288
289
int mixer_ctl_set_percent(struct mixer_ctl *ctl, unsigned int id, int percent)
290
{
291
if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_INTEGER))
292
return -EINVAL;
293
294
return mixer_ctl_set_value(ctl, id, percent_to_int(ctl->info, percent));
295
}
296
297
int mixer_ctl_get_value(struct mixer_ctl *ctl, unsigned int id)
298
{
299
struct snd_ctl_elem_value ev;
300
int ret;
301
302
if (!ctl || (id >= ctl->info->count))
303
return -EINVAL;
304
305
memset(&ev, 0, sizeof(ev));
306
ev.id.numid = ctl->info->id.numid;
307
ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_READ, &ev);
308
if (ret < 0)
309
return ret;
310
311
switch (ctl->info->type) {
312
case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
313
return !!ev.value.integer.value[id];
314
315
case SNDRV_CTL_ELEM_TYPE_INTEGER:
316
return ev.value.integer.value[id];
317
318
case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
319
return ev.value.enumerated.item[id];
320
321
case SNDRV_CTL_ELEM_TYPE_BYTES:
322
return ev.value.bytes.data[id];
323
324
default:
325
return -EINVAL;
326
}
327
328
return 0;
329
}
330
331
int mixer_ctl_get_array(struct mixer_ctl *ctl, void *array, size_t count)
332
{
333
struct snd_ctl_elem_value ev;
334
int ret;
335
size_t size;
336
void *source;
337
338
if (!ctl || (count > ctl->info->count) || !count || !array)
339
return -EINVAL;
340
341
memset(&ev, 0, sizeof(ev));
342
ev.id.numid = ctl->info->id.numid;
343
344
ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_READ, &ev);
345
if (ret < 0)
346
return ret;
347
348
switch (ctl->info->type) {
349
case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
350
case SNDRV_CTL_ELEM_TYPE_INTEGER:
351
size = sizeof(ev.value.integer.value[0]);
352
source = ev.value.integer.value;
353
break;
354
355
case SNDRV_CTL_ELEM_TYPE_BYTES:
356
size = sizeof(ev.value.bytes.data[0]);
357
source = ev.value.bytes.data;
358
break;
359
360
default:
361
return -EINVAL;
362
}
363
364
memcpy(array, source, size * count);
365
366
return 0;
367
}
368
369
int mixer_ctl_set_value(struct mixer_ctl *ctl, unsigned int id, int value)
370
{
371
struct snd_ctl_elem_value ev;
372
int ret;
373
374
if (!ctl || (id >= ctl->info->count))
375
return -EINVAL;
376
377
memset(&ev, 0, sizeof(ev));
378
ev.id.numid = ctl->info->id.numid;
379
ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_READ, &ev);
380
if (ret < 0)
381
return ret;
382
383
switch (ctl->info->type) {
384
case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
385
ev.value.integer.value[id] = !!value;
386
break;
387
388
case SNDRV_CTL_ELEM_TYPE_INTEGER:
389
if ((value < mixer_ctl_get_range_min(ctl)) ||
390
(value > mixer_ctl_get_range_max(ctl))) {
391
return -EINVAL;
392
}
393
394
ev.value.integer.value[id] = value;
395
break;
396
397
case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
398
ev.value.enumerated.item[id] = value;
399
break;
400
401
case SNDRV_CTL_ELEM_TYPE_BYTES:
402
ev.value.bytes.data[id] = value;
403
break;
404
405
default:
406
return -EINVAL;
407
}
408
409
return ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_WRITE, &ev);
410
}
411
412
int mixer_ctl_set_array(struct mixer_ctl *ctl, const void *array, size_t count)
413
{
414
struct snd_ctl_elem_value ev;
415
size_t size;
416
void *dest;
417
418
if (!ctl || (count > ctl->info->count) || !count || !array)
419
return -EINVAL;
420
421
memset(&ev, 0, sizeof(ev));
422
ev.id.numid = ctl->info->id.numid;
423
424
switch (ctl->info->type) {
425
case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
426
case SNDRV_CTL_ELEM_TYPE_INTEGER:
427
size = sizeof(ev.value.integer.value[0]);
428
dest = ev.value.integer.value;
429
break;
430
431
case SNDRV_CTL_ELEM_TYPE_BYTES:
432
size = sizeof(ev.value.bytes.data[0]);
433
dest = ev.value.bytes.data;
434
break;
435
436
default:
437
return -EINVAL;
438
}
439
440
memcpy(dest, array, size * count);
441
442
return ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_WRITE, &ev);
443
}
444
445
int mixer_ctl_get_range_min(struct mixer_ctl *ctl)
446
{
447
if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_INTEGER))
448
return -EINVAL;
449
450
return ctl->info->value.integer.min;
451
}
452
453
int mixer_ctl_get_range_max(struct mixer_ctl *ctl)
454
{
455
if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_INTEGER))
456
return -EINVAL;
457
458
return ctl->info->value.integer.max;
459
}
460
461
unsigned int mixer_ctl_get_num_enums(struct mixer_ctl *ctl)
462
{
463
if (!ctl)
464
return 0;
465
466
return ctl->info->value.enumerated.items;
467
}
468
469
const char *mixer_ctl_get_enum_string(struct mixer_ctl *ctl,
470
unsigned int enum_id)
471
{
472
if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_ENUMERATED) ||
473
(enum_id >= ctl->info->value.enumerated.items))
474
return NULL;
475
476
return (const char *)ctl->ename[enum_id];
477
}
478
479
int mixer_ctl_set_enum_by_string(struct mixer_ctl *ctl, const char *string)
480
{
481
unsigned int i, num_enums;
482
struct snd_ctl_elem_value ev;
483
int ret;
484
485
if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_ENUMERATED))
486
return -EINVAL;
487
488
num_enums = ctl->info->value.enumerated.items;
489
for (i = 0; i < num_enums; i++) {
490
if (!strcmp(string, ctl->ename[i])) {
491
memset(&ev, 0, sizeof(ev));
492
ev.value.enumerated.item[0] = i;
493
ev.id.numid = ctl->info->id.numid;
494
ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_WRITE, &ev);
495
if (ret < 0)
496
return ret;
497
return 0;
498
}
499
}
500
501
return -EINVAL;
502
}
503
504
505