xref: /freebsd/lib/libmixer/mixer.3 (revision 1ab62c8d)
1.\"-
2.\" Copyright (c) 2021-2022 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.Dd May 22, 2024
23.Dt MIXER 3
24.Os
25.Sh NAME
26.Nm mixer_open ,
27.Nm mixer_close ,
28.Nm mixer_get_dev ,
29.Nm mixer_get_dev_byname ,
30.Nm mixer_add_ctl ,
31.Nm mixer_add_ctl_s ,
32.Nm mixer_remove_ctl ,
33.Nm mixer_get_ctl ,
34.Nm mixer_get_ctl_byname ,
35.Nm mixer_set_vol ,
36.Nm mixer_set_mute ,
37.Nm mixer_mod_recsrc ,
38.Nm mixer_get_dunit ,
39.Nm mixer_set_dunit ,
40.Nm mixer_get_mode ,
41.Nm mixer_get_nmixers ,
42.Nm mixer_get_path ,
43.Nm MIX_ISDEV ,
44.Nm MIX_ISMUTE ,
45.Nm MIX_ISREC ,
46.Nm MIX_ISRECSRC ,
47.Nm MIX_VOLNORM ,
48.Nm MIX_VOLDENORM
49.Nd interface to OSS mixers
50.Sh LIBRARY
51Mixer library (libmixer, -lmixer)
52.Sh SYNOPSIS
53.In mixer.h
54.Ft struct mixer *
55.Fn mixer_open "const char *name"
56.Ft int
57.Fn mixer_close "struct mixer *m"
58.Ft struct mix_dev *
59.Fn mixer_get_dev "struct mixer *m" "int devno"
60.Ft struct mix_dev *
61.Fn mixer_get_dev_byname "struct mixer *m" "name"
62.Ft int
63.Fn mixer_add_ctl "struct mix_dev *parent" "int id" "const char *name" \
64    "int (*mod)(struct mix_dev *d, void *p)" \
65    "int (*print)(struct mix_dev *d, void *p)"
66.Ft int
67.Fn mixer_add_ctl_s "mix_ctl_t *ctl"
68.Ft int
69.Fn mixer_remove_ctl "mix_ctl_t *ctl"
70.Ft mix_ctl_t *
71.Fn mixer_get_ctl "struct mix_dev *d" "int id"
72.Ft mix_ctl_t *
73.Fn mixer_get_ctl_byname "struct mix_dev *d" "const char *name"
74.Ft int
75.Fn mixer_set_vol "struct mixer *m" "mix_volume_t vol"
76.Ft int
77.Fn mixer_set_mute "struct mixer *m" "int opt"
78.Ft int
79.Fn mixer_mod_recsrc "struct mixer *m" "int opt"
80.Ft int
81.Fn mixer_get_dunit "void"
82.Ft int
83.Fn mixer_set_dunit "struct mixer *m" "int unit"
84.Ft int
85.Fn mixer_get_mode "int unit"
86.Ft int
87.Fn mixer_get_nmixers "void"
88.Ft int
89.Fn mixer_get_path "char * buf" "size_t size" "int unit"
90.Ft int
91.Fn MIX_ISDEV "struct mixer *m" "int devno"
92.Ft int
93.Fn MIX_ISMUTE "struct mixer *m" "int devno"
94.Ft int
95.Fn MIX_ISREC "struct mixer *m" "int devno"
96.Ft int
97.Fn MIX_ISRECSRC "struct mixer *m" "int devno"
98.Ft float
99.Fn MIX_VOLNORM "int v"
100.Ft int
101.Fn MIX_VOLDENORM "float v"
102.Sh DESCRIPTION
103The
104.Nm mixer
105library allows userspace programs to access and manipulate OSS sound mixers in
106a simple way.
107.Ss Mixer
108A mixer is described by the following structure:
109.Bd -literal
110struct mixer {
111	TAILQ_HEAD(mix_devhead, mix_dev) devs;	/* device list */
112	struct mix_dev *dev;			/* selected device */
113	oss_mixerinfo mi;			/* mixer info */
114	oss_card_info ci;			/* audio card info */
115	char name[NAME_MAX];			/* mixer name (e.g /dev/mixer0) */
116	int fd;					/* file descriptor */
117	int unit;				/* audio card unit */
118	int ndev;				/* number of devices */
119	int devmask;				/* supported devices */
120#define MIX_MUTE		0x01
121#define MIX_UNMUTE		0x02
122#define MIX_TOGGLEMUTE		0x04
123	int mutemask;				/* muted devices */
124	int recmask;				/* recording devices */
125#define MIX_ADDRECSRC		0x01
126#define MIX_REMOVERECSRC	0x02
127#define MIX_SETRECSRC		0x04
128#define MIX_TOGGLERECSRC	0x08
129	int recsrc;				/* recording sources */
130#define MIX_MODE_MIXER		0x01
131#define MIX_MODE_PLAY		0x02
132#define MIX_MODE_REC		0x04
133	int mode;				/* dev.pcm.X.mode sysctl */
134	int f_default;				/* default mixer flag */
135};
136.Ed
137.Pp
138The fields are follows:
139.Bl -tag -width "f_default"
140.It Fa devs
141A tail queue structure containing all supported mixer devices.
142.It Fa dev
143A pointer to the currently selected device.
144The device is one of the elements in
145.Ar devs .
146.It Fa mi
147OSS information about the mixer.
148Look at the definition of the
149.Ft oss_mixerinfo
150structure in
151.In sys/soundcard.h
152to see its fields.
153.It Fa ci
154OSS audio card information.
155This structure is also defined in
156.In sys/soundcard.h .
157.It Fa name
158Path to the mixer (e.g /dev/mixer0).
159.It Fa fd
160File descriptor returned when the mixer is opened in
161.Fn mixer_open .
162.It Fa unit
163Audio card unit.
164Since each mixer device maps to a pcmX device,
165.Ar unit
166is always equal to the number of that pcmX device.
167For example, if the audio device's number is 0 (i.e pcm0), then
168.Ar unit
169is 0 as well.
170This number is useful when checking if the mixer's audio card is the default
171one.
172.It Fa ndev
173Number of devices in
174.Ar devs .
175.It Fa devmask
176Bit mask containing all supported devices for the mixer.
177For example, if device 10 is supported, then the 10th bit in the mask will be
178set.
179By default,
180.Fn mixer_open
181stores only the supported devices in devs, so it is very unlikely this mask will
182be needed.
183.It Fa mutemask
184Bit mask containing all muted devices.
185The logic is the same as with
186.Ar devmask .
187.It Fa recmask
188Bit mask containing all recording devices.
189Again, same logic as with the other masks.
190.It Fa recsrc
191Bit mask containing all recording sources.
192Yes, same logic again.
193.It Fa mode
194Bit mask containing the supported modes for this audio device.
195It holds the value of the
196.Ar dev.pcm.X.mode
197sysctl.
198.It Fa f_default
199Flag which tells whether the mixer's audio card is the default one.
200.El
201.Ss Mixer device
202Each mixer device stored in a mixer is described as follows:
203.Bd -literal
204struct mix_dev {
205	struct mixer *parent_mixer;		/* parent mixer */
206	char name[NAME_MAX];			/* device name (e.g "vol") */
207	int devno;				/* device number */
208	struct mix_volume {
209#define MIX_VOLMIN		0.0f
210#define MIX_VOLMAX		1.0f
211#define MIX_VOLNORM(v)		((v) / 100.0f)
212#define MIX_VOLDENORM(v)	((int)((v) * 100.0f + 0.5f))
213		float left;			/* left volume */
214		float right;			/* right volume */
215	} vol;
216	int nctl;				/* number of controls */
217	TAILQ_HEAD(mix_ctlhead, mix_ctl) ctls;	/* control list */
218	TAILQ_ENTRY(mix_dev) devs;
219};
220.Ed
221.Pp
222The fields are follows:
223.Bl -tag -width "parent_mixer"
224.It Fa parent_mixer
225Pointer to the mixer the device is attached to.
226.It Fa name
227Device name given by the OSS API.
228Devices can have one of the following names:
229.Bd -ragged
230vol, bass, treble, synth, pcm, speaker, line, mic, cd, mix,
231pcm2, rec, igain, ogain, line1, line2, line3, dig1, dig2, dig3,
232phin, phout, video, radio, and monitor.
233.Ed
234.It Fa devno
235Device's index in the SOUND_MIXER_NRDEVICES macro defined in
236.In sys/soundcard.h .
237This number is used to check against the masks defined in the
238.Ar mixer
239structure.
240.It Fa left right
241Left and right-ear volumes.
242Although the OSS API stores volumes in integers from 0-100, \
243we normalize them to 32-bit floating point numbers.
244However, the volumes can be denormalized using the
245.Ar MIX_VOLDENORM
246macro if needed.
247.It Fa nctl
248Number of user-defined mixer controls associated with the device.
249.It Fa ctls
250A tail queue containing user-defined mixer controls.
251.El
252.Ss User-defined mixer controls
253Each mixer device can have user-defined controls.
254The control structure is defined as follows:
255.Bd -literal
256struct mix_ctl {
257	struct mix_dev *parent_dev;		/* parent device */
258	int id;					/* control id */
259	char name[NAME_MAX];			/* control name */
260	int (*mod)(struct mix_dev *, void *);	/* modify control values */
261	int (*print)(struct mix_dev *, void *);	/* print control */
262	TAILQ_ENTRY(mix_ctl) ctls;
263};
264.Ed
265.Pp
266The fields are follows:
267.Bl -tag -width "parent_dev"
268.It Fa parent_dev
269Pointer to the device the control is attached to.
270.It Fa id
271Control ID assigned by the caller.
272Even though the library will report it, care has to be taken to not give \
273a control the same ID in case the caller has to choose controls using their ID.
274.It Fa name
275Control name.
276As with
277.Ar id ,
278the caller has to make sure the same name is not used more than once.
279.It Fa mod
280Function pointer to a control modification function.
281As in
282.Xr mixer 8 ,
283each mixer control's values can be modified.
284For example, if we have a volume control, the
285.Ar mod
286function will be responsible for handling volume changes.
287.It Fa print
288Function pointer to a control print function.
289.El
290.Ss Opening and closing the mixer
291The application must first call the
292.Fn mixer_open
293function to obtain a handle to the device, which is used as an argument \
294in most other functions and macros.
295The parameter
296.Ar name
297specifies the path to the mixer.
298OSS mixers are stored under
299.Ar /dev/mixerN
300where
301.Ar N
302is the number of the mixer device.
303Each device maps to an actual
304.Ar pcm
305audio card, so
306.Ar /dev/mixer0
307is the mixer for
308.Ar pcm0 ,
309and so on.
310If
311.Ar name
312is
313.Ar NULL
314or
315.Ar /dev/mixer ,
316.Fn mixer_open
317opens the default mixer (hw.snd.default_unit).
318.Pp
319The
320.Fn mixer_close
321function frees resources and closes the mixer device.
322It is a good practice to always call it when the application is done using the
323mixer.
324.Ss Manipulating the mixer
325The
326.Fn mixer_get_dev
327and
328.Fn mixer_get_dev_byname
329functions select a mixer device, either by its number or by its name
330respectively.
331The mixer structure keeps a list of all the devices, but only one can be
332manipulated at a time.
333Each time a new device is to be manipulated, one of the two functions has to be
334called.
335.Pp
336The
337.Fn mixer_set_vol
338function changes the volume of the selected mixer device.
339The
340.Ar vol
341parameter is a structure that stores the left and right volumes of a given
342device.
343The allowed volume values are between MIX_VOLMIN (0.0) and MIX_VOLMAX (1.0).
344.Pp
345The
346.Fn mixer_set_mute
347function modifies the mute of a selected device.
348The
349.Ar opt
350parameter has to be one of the following options:
351.Bl -tag -width MIX_TOGGLEMUTE -offset indent
352.It Dv MIX_MUTE
353Mute the device.
354.It Dv MIX_UNMUTE
355Unmute the device.
356.It Dv MIX_TOGGLEMUTE
357Toggle the device's mute (e.g mute if unmuted and unmute if muted).
358.El
359.Pp
360The
361.Fn mixer_mod_recsrc
362function modifies a recording device.
363The selected device has to be a recording device, otherwise the function will
364fail.
365The
366.Ar opt
367parameter has to be one of the following options:
368.Bl -tag -width MIX_REMOVERECSRC -offset indent
369.It Dv MIX_ADDRECSRC
370Add device to the recording sources.
371.It Dv MIX_REMOVERECSRC
372Remove device from the recording sources.
373.It Dv MIX_SETRECSRC
374Set device as the only recording source.
375.It Dv MIX_TOGGLERECSRC
376Toggle device from the recording sources.
377.El
378.Pp
379The
380.Fn mixer_get_dunit
381and
382.Fn mixer_set_dunit
383functions get and set the default audio card in the system.
384Although this is not really a mixer feature, it is useful to have instead of \
385having to use the
386.Xr sysctl 3
387controls.
388.Pp
389The
390.Fn mixer_get_mode
391function returns the playback/recording mode of the audio device the mixer \
392belongs to.
393The available values are the following:
394.Bl -tag -width "MIX_STATUS_PLAY | MIX_STATUS_REC" -offset indent
395.It Dv MIX_STATUS_NONE
396Neither playback nor recording.
397.It Dv MIX_STATUS_PLAY
398Playback.
399.It Dv MIX_STATUS_REC
400Recording.
401.It Dv MIX_STATUS_PLAY | MIX_STATUS_REC
402Playback and recording.
403.El
404.Pp
405The
406.Fn mixer_get_nmixers
407function returns the maximum mixer unit number.
408Although this might sound as incorrect behavior, given that one would expect
409"nmixers" to refer to the total number of active mixers, it is more intuitive
410for applications that want to loop through all mixer devices (see the
411.Sx EXAMPLES
412section).
413.Pp
414The
415.Fn mixer_get_path
416function writes the path of the mixer device specified in the
417.Ar unit
418argument to the buffer specified in
419.Ar buf .
420.Ar unit
421can be either -1, in which case
422.Fn mixer_get_path
423will fetch the path of the default mixer, or between 0 and the maximum mixer
424unit.
425.Pp
426The
427.Fn MIX_ISDEV
428macro checks if a device is actually a valid device for a given mixer.
429It is very unlikely that this macro will ever be needed since the library \
430stores only valid devices by default.
431.Pp
432The
433.Fn MIX_ISMUTE
434macro checks if a device is muted.
435.Pp
436The
437.Fn MIX_ISREC
438macro checks if a device is a recording device.
439.Pp
440The
441.Fn MIX_ISRECSRC
442macro checks if a device is a recording source.
443.Pp
444The
445.Fn MIX_VOLNORM
446macro normalizes a value to 32-bit floating point number.
447It is used to normalize the volumes read from the OSS API.
448.Pp
449The
450.Fn MIX_VOLDENORM
451macro denormalizes the left and right volumes stores in the
452.Ft mix_dev
453structure.
454.Ss Defining and using mixer controls
455The
456.Fn mix_add_ctl
457function creates a control and attaches it to the device specified in the
458.Ar parent
459argument.
460.Pp
461The
462.Fn mix_add_ctl_s
463function does the same thing as with
464.Fn mix_add_ctl
465but the caller passes a
466.Ft mix_ctl_t *
467structure instead of each field as a separate argument.
468.Pp
469The
470.Fn mixer_remove_ctl
471functions removes a control from the device its attached to.
472.Pp
473The
474.Fn mixer_get_ctl
475function searches for a control in the device specified in the
476.Ar d
477argument and returns a pointer to it.
478The search is done using the control's ID.
479.Pp
480The
481.Fn mixer_get_ctl_byname
482function is the same as with
483.Fn mixer_get_ctl
484but the search is done using the control's name.
485.Sh RETURN VALUES
486The
487.Fn mixer_open
488function returns the newly created handle on success and NULL on failure.
489.Pp
490The
491.Fn mixer_close ,
492.Fn mixer_set_vol ,
493.Fn mixer_set_mute ,
494.Fn mixer_mod_recsrc ,
495.Fn mixer_get_dunut ,
496.Fn mixer_set_dunit ,
497.Fn mixer_get_nmixers ,
498and
499.Fn mixer_get_path
500functions return 0 or positive values on success and -1 on failure.
501.Pp
502The
503.Fn mixer_get_dev
504and
505.Fn mixer_get_dev_byname
506functions return the selected device on success and NULL on failure.
507.Pp
508All functions set the value of
509.Ar errno
510on failure.
511.Sh EXAMPLES
512.Ss Change the volume of a device
513.Bd -literal
514struct mixer *m;
515mix_volume_t vol;
516char *mix_name, *dev_name;
517
518mix_name = ...;
519if ((m = mixer_open(mix_name)) == NULL)
520	err(1, "mixer_open: %s", mix_name);
521
522dev_name = ...;
523if ((m->dev = mixer_get_dev_byname(m, dev_name)) < 0)
524	err(1, "unknown device: %s", dev_name);
525
526vol.left = ...;
527vol.right = ....;
528if (mixer_set_vol(m, vol) < 0)
529	warn("cannot change volume");
530
531(void)mixer_close(m);
532.Ed
533.Ss Mute all unmuted devices
534.Bd -literal
535struct mixer *m;
536struct mix_dev *dp;
537
538if ((m = mixer_open(NULL)) == NULL)	/* Open the default mixer. */
539	err(1, "mixer_open");
540TAILQ_FOREACH(dp, &m->devs, devs) {
541	m->dev = dp;			/* Select device. */
542	if (M_ISMUTE(m, dp->devno))
543		continue;
544	if (mixer_set_mute(m, MIX_MUTE) < 0)
545		warn("cannot mute device: %s", dp->name);
546}
547
548(void)mixer_close(m);
549.Ed
550.Ss Print all recording sources' names and volumes
551.Bd -literal
552struct mixer *m;
553struct mix_dev *dp;
554
555char *mix_name, *dev_name;
556
557mix_name = ...;
558if ((m = mixer_open(mix_name)) == NULL)
559	err(1, "mixer_open: %s", mix_name);
560
561TAILQ_FOREACH(dp, &m->devs, devs) {
562	if (M_ISRECSRC(m, dp->devno))
563		printf("%s\\t%.2f:%.2f\\n",
564		    dp->name, dp->vol.left, dp->vol.right);
565}
566
567(void)mixer_close(m);
568.Ed
569.Ss Loop through all mixer devices in the system
570.Bd -literal
571struct mixer *m;
572char buf[NAME_MAX];
573int n;
574
575if ((n = mixer_get_nmixers()) < 0)
576	errx(1, "no mixers present in the system");
577for (i = 0; i < n; i++) {
578	(void)mixer_get_path(buf, sizeof(buf), i);
579	if ((m = mixer_open(buf)) == NULL)
580		continue;
581	...
582	(void)mixer_close(m);
583}
584.Ed
585.Sh SEE ALSO
586.Xr queue 3 ,
587.Xr sysctl 3 ,
588.Xr sound 4 ,
589.Xr mixer 8
590and
591.Xr errno 2
592.Sh AUTHORS
593.An Christos Margiolis Aq Mt christos@FreeBSD.org
594