1 /*
2 * mixer.c, mixer module
3 *
4 * Copyright (C) 1997 Rasca, Berlin
5 * EMail: thron@gmx.de
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 *
21 *
22 * example which sets the volume of all devices to zero:
23 *
24 * int id, no_of_devs, i;
25 *
26 * id = mixer_init ("/dev/mixer");
27 * if (id > 0) {
28 * no_of_devs = mixer_num_of_devs (id);
29 * for (i = 0; i < no_of_devs; i++) {
30 * mixer_set_vol_left (id, i, 0);
31 * if (mixer_is_stereo (id, i)) {
32 * mixer_set_vol_right (id, i, 0);
33 * }
34 * }
35 * mixer_fini (id);
36 * }
37 *
38 */
39
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <fcntl.h>
43 #include <unistd.h>
44 #include <sys/ioctl.h>
45 #ifdef ALSA /* not supported until now */
46 # include <sys/asound.h>
47 #endif
48 #ifdef OSS
49 # include <sys/soundcard.h>
50 #endif
51 #include "mixer.h"
52
53 /* if you have more than two soundcards in your system, adjust the
54 * following accordingly..
55 */
56 #define MAX_MIXER 2
57 #define MIXER_VER "V0.5"
58
59 typedef struct {
60 int id; /* 0 if not used */
61 int no_of_devs; /* number of devices */
62 int stereo_devs;
63 int rec_mask;
64 int rec_source;
65 int caps;
66 int exclusive_input;
67 int device[SOUND_MIXER_NRDEVICES]; /* valid devices */
68 int levels[SOUND_MIXER_NRDEVICES];
69 char *file; /* file name of the device */
70 } MIXER;
71
72 static MIXER mixer[MAX_MIXER];
73 static int must_init = 1;
74
75 /*
76 * mixer_init()
77 * returns an id for the following functions. on the first call
78 * it is '1', so you don't remember if you just use one device.
79 * just call all other functions with '1' as the first argument.
80 */
81 int
mixer_init(char * mixer_dev)82 mixer_init (char *mixer_dev) {
83 int i, id, md;
84 int dev_mask = 0;
85
86 if (!mixer_dev) {
87 return (0);
88 }
89 if (must_init) {
90 /* just called the first time */
91 must_init = 0;
92 for (i = 0; i < MAX_MIXER; i++) {
93 mixer[i].id =0;
94 }
95 }
96 /* find a free structure */
97 for (i = 0; i < MAX_MIXER; i++) {
98 if (mixer[i].id == 0) {
99 mixer[i].id = i+1;
100 id = i;
101 goto CONT;
102 }
103 }
104 return (0);
105 CONT:
106
107 mixer[id].file = (char *) malloc (strlen (mixer_dev)+1);
108 strcpy (mixer[id].file, mixer_dev);
109
110 md = open (mixer[id].file, O_RDWR, 0);
111 if (md == -1) {
112 perror (mixer[id].file);
113 return (0);
114 }
115 if (ioctl (md, SOUND_MIXER_READ_DEVMASK, &dev_mask) == -1) {
116 perror("SOUND_MIXER_READ_DEVMASK");
117 close(md);
118 return (0);
119 }
120
121 if (ioctl (md, SOUND_MIXER_READ_RECMASK, &mixer[id].rec_mask) == -1) {
122 perror("SOUND_MIXER_READ_RECMASK");
123 close(md);
124 return (0);
125 }
126
127 if (ioctl (md, SOUND_MIXER_READ_RECSRC, &mixer[id].rec_source) == -1) {
128 perror("SOUND_MIXER_READ_RECSRC");
129 close(md);
130 return (0);
131 }
132
133 if (ioctl (md, SOUND_MIXER_READ_STEREODEVS, &mixer[id].stereo_devs) == -1) {
134 perror("SOUND_MIXER_READ_STEREODEVS");
135 close(md);
136 return (0);
137 }
138 if (ioctl (md, SOUND_MIXER_READ_CAPS, &mixer[id].caps) == -1) {
139 perror("SOUND_MIXER_READ_CAPS");
140 close(md);
141 return (0);
142 }
143 mixer[id].exclusive_input = mixer[id].caps & SOUND_CAP_EXCL_INPUT;
144
145 mixer[id].no_of_devs =0;
146 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
147 if ((1 << i) & dev_mask) {
148 # ifdef DEBUG2
149 fprintf (stderr, "mixer_init(): %d\n", i);
150 # endif
151 mixer[id].device[mixer[id].no_of_devs] = i;
152 mixer[id].no_of_devs++;
153 ioctl (md, MIXER_READ(i), &mixer[id].levels[i]);
154 }
155 }
156 close (md);
157 return (id+1);
158 }
159
160 /*
161 * mixer_fini()
162 * call this if the mixer is not needed any longer
163 */
164 int
mixer_fini(int mixer_id)165 mixer_fini (int mixer_id) {
166 mixer[mixer_id-1].id = 0; /* mark it as not used */
167 free (mixer[mixer_id-1].file);
168 return (1);
169 }
170
171
172 /*
173 */
174 const char
mixer_get_label(int mixer_id,int dev)175 *mixer_get_label (int mixer_id, int dev) {
176 int id;
177 char *labels[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_LABELS;
178
179 if (dev <= SOUND_MIXER_NRDEVICES) {
180 id = mixer[mixer_id-1].device[dev];
181 return (labels[id]);
182 }
183 return (NULL);
184 }
185
186
187 /*
188 */
189 const char
mixer_get_name(int mixer_id,int dev)190 *mixer_get_name (int mixer_id, int dev) {
191 int id;
192 char *names[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_NAMES;
193
194 if (dev <= SOUND_MIXER_NRDEVICES) {
195 id = mixer[mixer_id-1].device[dev];
196 return (names[id]);
197 }
198 return (NULL);
199 }
200
201
202 /*
203 */
204 int
mixer_is_stereo(int mixer_id,int dev)205 mixer_is_stereo (int mixer_id, int dev) {
206 int id;
207 if (dev <= SOUND_MIXER_NRDEVICES) {
208 id = mixer[mixer_id-1].device[dev];
209 return (!!((1 << id) & mixer[mixer_id-1].stereo_devs));
210 }
211 return (0);
212 }
213
214 /*
215 */
216 int
mixer_get_vol_left(int mixer_id,int dev)217 mixer_get_vol_left (int mixer_id, int dev) {
218 int id, md;
219 if (dev <= SOUND_MIXER_NRDEVICES) {
220 id = mixer[mixer_id-1].device[dev];
221 md = open (mixer[mixer_id-1].file, O_RDWR, 0);
222 if (md < 0) {
223 return (-1);
224 }
225 ioctl (md, MIXER_READ(id), &mixer[mixer_id-1].levels[id]);
226 close (md);
227 return (mixer[mixer_id-1].levels[id] & 0x7F);
228 }
229 return (-1);
230 }
231
232
233 /*
234 */
235 int
mixer_get_vol_right(int mixer_id,int dev)236 mixer_get_vol_right (int mixer_id, int dev) {
237 int id;
238 if (dev <= SOUND_MIXER_NRDEVICES) {
239 id = mixer[mixer_id-1].device[dev];
240 return ((mixer[mixer_id-1].levels[id] >> 8) & 0x7F);
241 }
242 return (-1);
243 }
244
245
246 /*
247 * set the mixer volume of the left channel, returns the
248 * new value or -1 on failure
249 */
250 int
mixer_set_vol_left(int mixer_id,int dev,int val)251 mixer_set_vol_left (int mixer_id, int dev, int val) {
252 int id, fd, level;
253 if (dev <= SOUND_MIXER_NRDEVICES) {
254 id = mixer[mixer_id-1].device[dev];
255 level = mixer[mixer_id-1].levels[id] =
256 (mixer[mixer_id-1].levels[id] & 0x7F00) | val;
257 fd = open (mixer[mixer_id-1].file, O_RDWR, 0);
258 if (fd < 0)
259 return (-1);
260 #ifdef DEBUG2
261 fprintf (stderr, "mixer_set_vol_left() left=%d right=%d\n",
262 level & 0xff, (level >> 8)& 0xff);
263 #endif
264 ioctl (fd, MIXER_WRITE(id), &level);
265 close (fd);
266 return (level & 0x7F);
267 }
268 return (-1);
269 }
270
271
272 /*
273 */
mixer_set_vol_right(int mixer_id,int dev,int val)274 int mixer_set_vol_right (int mixer_id, int dev, int val) {
275 int id, md, level;
276 if (dev <= SOUND_MIXER_NRDEVICES) {
277 id = mixer[mixer_id-1].device[dev];
278 level = mixer[mixer_id-1].levels[id] =
279 (mixer[mixer_id-1].levels[id] & 0x007F) | (val << 8);
280 md = open (mixer[mixer_id-1].file, O_RDWR, 0);
281 if (md == -1)
282 return (0);
283 ioctl (md, MIXER_WRITE(id), &level);
284 close (md);
285 return ((level >>8) & 0x7F);
286 }
287 return (-1);
288 }
289
290
291 /*
292 */
293 int
mixer_is_rec_dev(int mixer_id,int dev)294 mixer_is_rec_dev (int mixer_id, int dev) {
295 int id;
296 if (dev <= SOUND_MIXER_NRDEVICES) {
297 id = mixer[mixer_id-1].device[dev];
298 return ((1 << id) & mixer[mixer_id-1].rec_mask);
299 }
300 return (0);
301 }
302
303
304 /*
305 * check if recording source is active
306 */
307 int
mixer_is_rec_on(int mixer_id,int dev)308 mixer_is_rec_on (int mixer_id, int dev) {
309 int id;
310 if (dev <= SOUND_MIXER_NRDEVICES) {
311 id = mixer[mixer_id-1].device[dev];
312 return (((1 << id) & mixer[mixer_id-1].rec_source)>>id);
313 }
314 return (0);
315 }
316
317
318 /*
319 */
320 int
mixer_set_rec(int mixer_id,int dev,int boolval)321 mixer_set_rec (int mixer_id, int dev, int boolval) {
322 int id, md, recsrc;
323 if (dev <= SOUND_MIXER_NRDEVICES) {
324 id = mixer[mixer_id-1].device[dev];
325 if (boolval) {
326 recsrc = mixer[mixer_id-1].rec_source | (boolval << id);
327 } else {
328 recsrc = mixer[mixer_id-1].rec_source & ~(1 << id);
329 }
330 md = open (mixer[mixer_id-1].file, O_RDWR, 0);
331 if (md == -1)
332 return (0);
333 ioctl (md, SOUND_MIXER_WRITE_RECSRC, &recsrc);
334 close (md);
335 mixer[mixer_id-1].rec_source = recsrc;
336 #ifdef DEBUG2
337 fprintf (stderr, "mixer_set_rec(%d, %d): %d\n", dev, boolval, recsrc);
338 #endif
339 return (1);
340 }
341 return (0);
342 }
343
344
345 /*
346 */
347 int
mixer_num_of_devs(int mixer_id)348 mixer_num_of_devs (int mixer_id) {
349 if (mixer_id > MAX_MIXER)
350 return (0);
351 return (mixer[mixer_id-1].no_of_devs);
352 }
353
354 /*
355 */
356 int
mixer_get_dev_by_name(int mixer_id,char * dev_name)357 mixer_get_dev_by_name (int mixer_id, char *dev_name) {
358 int i;
359 const char *name;
360 char *names[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_NAMES;
361
362 if (mixer_id > MAX_MIXER)
363 return (-1);
364 for (i = 0; i < mixer[mixer_id-1].no_of_devs; i++) {
365 name = names[mixer[mixer_id-1].device[i]];
366 if (strcmp (name, dev_name) == 0) {
367 #ifdef DEBUG2
368 fprintf (stderr, "%s %d\n", name, i);
369 #endif
370 return (i);
371 }
372 }
373 return (-1);
374 }
375
376 /*
377 * only one channel as recording source?
378 * return: 1 yes
379 * 0 no
380 * -1 error
381 */
382 int
mixer_exclusive_input(int mixer_id)383 mixer_exclusive_input (int mixer_id)
384 {
385 if (mixer_id > MAX_MIXER)
386 return (-1);
387 return (mixer[mixer_id-1].exclusive_input);
388 }
389
390