xref: /freebsd/lib/libmixer/mixer.c (revision 19e4f2f289fb8d2b14576a65ca9e6f931dbb6a02)
1 /*-
2  * Copyright (c) 2021 Christos Margiolis <christos@FreeBSD.org>
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to deal
6  * in the Software without restriction, including without limitation the rights
7  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8  * copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20  * THE SOFTWARE.
21  *
22  * $FreeBSD$
23  */
24 
25 #include <sys/types.h>
26 #include <sys/ioctl.h>
27 #include <sys/sysctl.h>
28 
29 #include <errno.h>
30 #include <fcntl.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <unistd.h>
35 
36 #include "mixer.h"
37 
38 #define	BASEPATH "/dev/mixer"
39 
40 static int _mixer_readvol(struct mixer *, struct mix_dev *);
41 
42 /*
43  * Fetch volume from the device.
44  */
45 static int
46 _mixer_readvol(struct mixer *m, struct mix_dev *dev)
47 {
48 	int v;
49 
50 	if (ioctl(m->fd, MIXER_READ(dev->devno), &v) < 0)
51 		return (-1);
52 	dev->vol.left = MIX_VOLNORM(v & 0x00ff);
53 	dev->vol.right = MIX_VOLNORM((v >> 8) & 0x00ff);
54 
55 	return (0);
56 }
57 
58 /*
59  * Open a mixer device in `/dev/mixerN`, where N is the number of the mixer.
60  * Each device maps to an actual pcm audio card, so `/dev/mixer0` is the
61  * mixer for pcm0, and so on.
62  *
63  * @param name		path to mixer device. NULL or "/dev/mixer" for the
64  *			the default mixer (i.e `hw.snd.default_unit`).
65  */
66 struct mixer *
67 mixer_open(const char *name)
68 {
69 	struct mixer *m = NULL;
70 	struct mix_dev *dp;
71 	const char *names[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_NAMES;
72 	int i;
73 
74 	if ((m = calloc(1, sizeof(struct mixer))) == NULL)
75 		goto fail;
76 
77 	if (name != NULL) {
78 		/* `name` does not start with "/dev/mixer". */
79 		if (strncmp(name, BASEPATH, strlen(BASEPATH)) != 0) {
80 			errno = EINVAL;
81 			goto fail;
82 		}
83 		/* `name` is "/dev/mixer" so, we'll use the default unit. */
84 		if (strncmp(name, BASEPATH, strlen(name)) == 0)
85 			goto dunit;
86 		m->unit = strtol(name + strlen(BASEPATH), NULL, 10);
87 		(void)strlcpy(m->name, name, sizeof(m->name));
88 	} else {
89 dunit:
90 		if ((m->unit = mixer_get_dunit()) < 0)
91 			goto fail;
92 		(void)snprintf(m->name, sizeof(m->name), "/dev/mixer%d", m->unit);
93 	}
94 
95 	if ((m->fd = open(m->name, O_RDWR)) < 0)
96 		goto fail;
97 
98 	m->devmask = m->recmask = m->recsrc = 0;
99 	m->f_default = m->unit == mixer_get_dunit();
100 	m->mode = mixer_get_mode(m->unit);
101 	/* The unit number _must_ be set before the ioctl. */
102 	m->mi.dev = m->unit;
103 	m->ci.card = m->unit;
104 	if (ioctl(m->fd, SNDCTL_MIXERINFO, &m->mi) < 0 ||
105 	    ioctl(m->fd, SNDCTL_CARDINFO, &m->ci) < 0 ||
106 	    ioctl(m->fd, SOUND_MIXER_READ_DEVMASK, &m->devmask) < 0 ||
107 	    ioctl(m->fd, SOUND_MIXER_READ_MUTE, &m->mutemask) < 0 ||
108 	    ioctl(m->fd, SOUND_MIXER_READ_RECMASK, &m->recmask) < 0 ||
109 	    ioctl(m->fd, SOUND_MIXER_READ_RECSRC, &m->recsrc) < 0)
110 		goto fail;
111 
112 	TAILQ_INIT(&m->devs);
113 	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
114 		if (!MIX_ISDEV(m, i))
115 			continue;
116 		if ((dp = calloc(1, sizeof(struct mix_dev))) == NULL)
117 			goto fail;
118 		dp->parent_mixer = m;
119 		dp->devno = i;
120 		dp->nctl = 0;
121 		if (_mixer_readvol(m, dp) < 0)
122 			goto fail;
123 		(void)strlcpy(dp->name, names[i], sizeof(dp->name));
124 		TAILQ_INIT(&dp->ctls);
125 		TAILQ_INSERT_TAIL(&m->devs, dp, devs);
126 		m->ndev++;
127 	}
128 
129 	/* The default device is always "vol". */
130 	m->dev = TAILQ_FIRST(&m->devs);
131 
132 	return (m);
133 fail:
134 	if (m != NULL)
135 		(void)mixer_close(m);
136 
137 	return (NULL);
138 }
139 
140 /*
141  * Free resources and close the mixer.
142  */
143 int
144 mixer_close(struct mixer *m)
145 {
146 	struct mix_dev *dp;
147 	int r;
148 
149 	r = close(m->fd);
150 	while (!TAILQ_EMPTY(&m->devs)) {
151 		dp = TAILQ_FIRST(&m->devs);
152 		TAILQ_REMOVE(&m->devs, dp, devs);
153 		while (!TAILQ_EMPTY(&dp->ctls))
154 			(void)mixer_remove_ctl(TAILQ_FIRST(&dp->ctls));
155 		free(dp);
156 	}
157 	free(m);
158 
159 	return (r);
160 }
161 
162 /*
163  * Select a mixer device. The mixer structure keeps a list of all the devices
164  * the mixer has, but only one can be manipulated at a time -- this is what
165  * the `dev` in the mixer structure field is for. Each time a device is to be
166  * manipulated, `dev` has to point to it first.
167  *
168  * The caller must manually assign the return value to `m->dev`.
169  */
170 struct mix_dev *
171 mixer_get_dev(struct mixer *m, int dev)
172 {
173 	struct mix_dev *dp;
174 
175 	if (dev < 0 || dev >= m->ndev) {
176 		errno = ERANGE;
177 		return (NULL);
178 	}
179 	TAILQ_FOREACH(dp, &m->devs, devs) {
180 		if (dp->devno == dev)
181 			return (dp);
182 	}
183 	errno = EINVAL;
184 
185 	return (NULL);
186 }
187 
188 /*
189  * Select a device by name.
190  *
191  * @param name		device name (e.g vol, pcm, ...)
192  */
193 struct mix_dev *
194 mixer_get_dev_byname(struct mixer *m, const char *name)
195 {
196 	struct mix_dev *dp;
197 
198 	TAILQ_FOREACH(dp, &m->devs, devs) {
199 		if (!strncmp(dp->name, name, sizeof(dp->name)))
200 			return (dp);
201 	}
202 	errno = EINVAL;
203 
204 	return (NULL);
205 }
206 
207 /*
208  * Add a mixer control to a device.
209  */
210 int
211 mixer_add_ctl(struct mix_dev *parent_dev, int id, const char *name,
212     int (*mod)(struct mix_dev *, void *),
213     int (*print)(struct mix_dev *, void *))
214 {
215 	struct mix_dev *dp;
216 	mix_ctl_t *ctl, *cp;
217 
218 	/* XXX: should we accept NULL name? */
219 	if (parent_dev == NULL) {
220 		errno = EINVAL;
221 		return (-1);
222 	}
223 	if ((ctl = calloc(1, sizeof(mix_ctl_t))) == NULL)
224 		return (-1);
225 	ctl->parent_dev = parent_dev;
226 	ctl->id = id;
227 	if (name != NULL)
228 		(void)strlcpy(ctl->name, name, sizeof(ctl->name));
229 	ctl->mod = mod;
230 	ctl->print = print;
231 	dp = ctl->parent_dev;
232 	/* Make sure the same ID or name doesn't exist already. */
233 	TAILQ_FOREACH(cp, &dp->ctls, ctls) {
234 		if (!strncmp(cp->name, name, sizeof(cp->name)) || cp->id == id) {
235 			errno = EINVAL;
236 			return (-1);
237 		}
238 	}
239 	TAILQ_INSERT_TAIL(&dp->ctls, ctl, ctls);
240 	dp->nctl++;
241 
242 	return (0);
243 }
244 
245 /*
246  * Same as `mixer_add_ctl`.
247  */
248 int
249 mixer_add_ctl_s(mix_ctl_t *ctl)
250 {
251 	if (ctl == NULL)
252 		return (-1);
253 
254 	return (mixer_add_ctl(ctl->parent_dev, ctl->id, ctl->name,
255 	    ctl->mod, ctl->print));
256 }
257 
258 /*
259  * Remove a mixer control from a device.
260  */
261 int
262 mixer_remove_ctl(mix_ctl_t *ctl)
263 {
264 	struct mix_dev *p;
265 
266 	if (ctl == NULL) {
267 		errno = EINVAL;
268 		return (-1);
269 	}
270 	p = ctl->parent_dev;
271 	if (!TAILQ_EMPTY(&p->ctls)) {
272 		TAILQ_REMOVE(&p->ctls, ctl, ctls);
273 		free(ctl);
274 	}
275 
276 	return (0);
277 }
278 
279 /*
280  * Get a mixer control by id.
281  */
282 mix_ctl_t *
283 mixer_get_ctl(struct mix_dev *d, int id)
284 {
285 	mix_ctl_t *cp;
286 
287 	TAILQ_FOREACH(cp, &d->ctls, ctls) {
288 		if (cp->id == id)
289 			return (cp);
290 	}
291 	errno = EINVAL;
292 
293 	return (NULL);
294 }
295 
296 /*
297  * Get a mixer control by name.
298  */
299 mix_ctl_t *
300 mixer_get_ctl_byname(struct mix_dev *d, const char *name)
301 {
302 	mix_ctl_t *cp;
303 
304 	TAILQ_FOREACH(cp, &d->ctls, ctls) {
305 		if (!strncmp(cp->name, name, sizeof(cp->name)))
306 			return (cp);
307 	}
308 	errno = EINVAL;
309 
310 	return (NULL);
311 }
312 
313 /*
314  * Change the mixer's left and right volume. The allowed volume values are
315  * between MIX_VOLMIN and MIX_VOLMAX. The `ioctl` for volume change requires
316  * an integer value between 0 and 100 stored as `lvol | rvol << 8` --  for
317  * that reason, we de-normalize the 32-bit float volume value, before
318  * we pass it to the `ioctl`.
319  *
320  * Volume clumping should be done by the caller.
321  */
322 int
323 mixer_set_vol(struct mixer *m, mix_volume_t vol)
324 {
325 	int v;
326 
327 	if (vol.left < MIX_VOLMIN || vol.left > MIX_VOLMAX ||
328 	    vol.right < MIX_VOLMIN || vol.right > MIX_VOLMAX) {
329 		errno = ERANGE;
330 		return (-1);
331 	}
332 	v = MIX_VOLDENORM(vol.left) | MIX_VOLDENORM(vol.right) << 8;
333 	if (ioctl(m->fd, MIXER_WRITE(m->dev->devno), &v) < 0)
334 		return (-1);
335 	if (_mixer_readvol(m, m->dev) < 0)
336 		return (-1);
337 
338 	return (0);
339 }
340 
341 /*
342  * Manipulate a device's mute.
343  *
344  * @param opt		MIX_MUTE mute device
345  *			MIX_UNMUTE unmute device
346  *			MIX_TOGGLEMUTE toggle device's mute
347  */
348 int
349 mixer_set_mute(struct mixer *m, int opt)
350 {
351 	switch (opt) {
352 	case MIX_MUTE:
353 		m->mutemask |= (1 << m->dev->devno);
354 		break;
355 	case MIX_UNMUTE:
356 		m->mutemask &= ~(1 << m->dev->devno);
357 		break;
358 	case MIX_TOGGLEMUTE:
359 		m->mutemask ^= (1 << m->dev->devno);
360 		break;
361 	default:
362 		errno = EINVAL;
363 		return (-1);
364 	}
365 	if (ioctl(m->fd, SOUND_MIXER_WRITE_MUTE, &m->mutemask) < 0)
366 		return (-1);
367 	if (ioctl(m->fd, SOUND_MIXER_READ_MUTE, &m->mutemask) < 0)
368 		return (-1);
369 
370 	return 0;
371 }
372 
373 /*
374  * Modify a recording device. The selected device has to be a recording device,
375  * otherwise the function will fail.
376  *
377  * @param opt		MIX_ADDRECSRC add device to recording sources
378  *			MIX_REMOVERECSRC remove device from recording sources
379  *			MIX_SETRECSRC set device as the only recording source
380  *			MIX_TOGGLERECSRC toggle device from recording sources
381  */
382 int
383 mixer_mod_recsrc(struct mixer *m, int opt)
384 {
385 	if (!m->recmask || !MIX_ISREC(m, m->dev->devno)) {
386 		errno = ENODEV;
387 		return (-1);
388 	}
389 	switch (opt) {
390 	case MIX_ADDRECSRC:
391 		m->recsrc |= (1 << m->dev->devno);
392 		break;
393 	case MIX_REMOVERECSRC:
394 		m->recsrc &= ~(1 << m->dev->devno);
395 		break;
396 	case MIX_SETRECSRC:
397 		m->recsrc = (1 << m->dev->devno);
398 		break;
399 	case MIX_TOGGLERECSRC:
400 		m->recsrc ^= (1 << m->dev->devno);
401 		break;
402 	default:
403 		errno = EINVAL;
404 		return (-1);
405 	}
406 	if (ioctl(m->fd, SOUND_MIXER_WRITE_RECSRC, &m->recsrc) < 0)
407 		return (-1);
408 	if (ioctl(m->fd, SOUND_MIXER_READ_RECSRC, &m->recsrc) < 0)
409 		return (-1);
410 
411 	return (0);
412 }
413 
414 /*
415  * Get default audio card's number. This is used to open the default mixer
416  * and set the mixer structure's `f_default` flag.
417  */
418 int
419 mixer_get_dunit(void)
420 {
421 	size_t size;
422 	int unit;
423 
424 	size = sizeof(int);
425 	if (sysctlbyname("hw.snd.default_unit", &unit, &size, NULL, 0) < 0)
426 		return (-1);
427 
428 	return (unit);
429 }
430 
431 /*
432  * Change the default audio card. This is normally _not_ a mixer feature, but
433  * it's useful to have, so the caller can avoid having to manually use
434  * the sysctl API.
435  *
436  * @param unit		the audio card number (e.g pcm0, pcm1, ...).
437  */
438 int
439 mixer_set_dunit(struct mixer *m, int unit)
440 {
441 	size_t size;
442 
443 	size = sizeof(int);
444 	if (sysctlbyname("hw.snd.default_unit", NULL, 0, &unit, size) < 0)
445 		return (-1);
446 	/* XXX: how will other mixers get updated? */
447 	m->f_default = m->unit == unit;
448 
449 	return (0);
450 }
451 
452 /*
453  * Get sound device mode (none, play, rec, play+rec). Userland programs can
454  * use the MIX_STATUS_* flags to determine the mode of the device.
455  */
456 int
457 mixer_get_mode(int unit)
458 {
459 	char buf[64];
460 	size_t size;
461 	unsigned int mode;
462 
463 	(void)snprintf(buf, sizeof(buf), "dev.pcm.%d.mode", unit);
464 	size = sizeof(unsigned int);
465 	if (sysctlbyname(buf, &mode, &size, NULL, 0) < 0)
466 		return (-1);
467 
468 	return (mode);
469 }
470 
471 /*
472  * Get the total number of mixers in the system.
473  */
474 int
475 mixer_get_nmixers(void)
476 {
477 	struct mixer *m;
478 	oss_sysinfo si;
479 
480 	/*
481 	 * Open a dummy mixer because we need the `fd` field for the
482 	 * `ioctl` to work.
483 	 */
484 	if ((m = mixer_open(NULL)) == NULL)
485 		return (-1);
486 	if (ioctl(m->fd, OSS_SYSINFO, &si) < 0) {
487 		(void)mixer_close(m);
488 		return (-1);
489 	}
490 	(void)mixer_close(m);
491 
492 	return (si.nummixers);
493 }
494