xref: /freebsd/lib/libmixer/mixer.3 (revision 7937bfbc0ca53fe7cdd0d54414f9296e273a518e)
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 August 4, 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 operating mode of the audio device the mixer belongs to.
392The following values can be OR'ed in case more than one mode is supported:
393.Bl -tag -width "MIX_MODE_MIXER" -offset indent
394.It Dv MIX_MODE_MIXER
395The audio device has a mixer.
396.It Dv MIX_MODE_PLAY
397The audio device supports playback.
398.It Dv MIX_MODE_REC
399The audio device supports recording.
400.El
401.Pp
402The
403.Fn mixer_get_nmixers
404function returns the maximum mixer unit number.
405Although this might sound as incorrect behavior, given that one would expect
406"nmixers" to refer to the total number of active mixers, it is more intuitive
407for applications that want to loop through all mixer devices (see the
408.Sx EXAMPLES
409section).
410.Pp
411The
412.Fn mixer_get_path
413function writes the path of the mixer device specified in the
414.Ar unit
415argument to the buffer specified in
416.Ar buf .
417.Ar unit
418can be either -1, in which case
419.Fn mixer_get_path
420will fetch the path of the default mixer, or between 0 and the maximum mixer
421unit.
422.Pp
423The
424.Fn MIX_ISDEV
425macro checks if a device is actually a valid device for a given mixer.
426It is very unlikely that this macro will ever be needed since the library \
427stores only valid devices by default.
428.Pp
429The
430.Fn MIX_ISMUTE
431macro checks if a device is muted.
432.Pp
433The
434.Fn MIX_ISREC
435macro checks if a device is a recording device.
436.Pp
437The
438.Fn MIX_ISRECSRC
439macro checks if a device is a recording source.
440.Pp
441The
442.Fn MIX_VOLNORM
443macro normalizes a value to 32-bit floating point number.
444It is used to normalize the volumes read from the OSS API.
445.Pp
446The
447.Fn MIX_VOLDENORM
448macro denormalizes the left and right volumes stores in the
449.Ft mix_dev
450structure.
451.Ss Defining and using mixer controls
452The
453.Fn mix_add_ctl
454function creates a control and attaches it to the device specified in the
455.Ar parent
456argument.
457.Pp
458The
459.Fn mix_add_ctl_s
460function does the same thing as with
461.Fn mix_add_ctl
462but the caller passes a
463.Ft mix_ctl_t *
464structure instead of each field as a separate argument.
465.Pp
466The
467.Fn mixer_remove_ctl
468functions removes a control from the device its attached to.
469.Pp
470The
471.Fn mixer_get_ctl
472function searches for a control in the device specified in the
473.Ar d
474argument and returns a pointer to it.
475The search is done using the control's ID.
476.Pp
477The
478.Fn mixer_get_ctl_byname
479function is the same as with
480.Fn mixer_get_ctl
481but the search is done using the control's name.
482.Sh RETURN VALUES
483The
484.Fn mixer_open
485function returns the newly created handle on success and NULL on failure.
486.Pp
487The
488.Fn mixer_close ,
489.Fn mixer_set_vol ,
490.Fn mixer_set_mute ,
491.Fn mixer_mod_recsrc ,
492.Fn mixer_get_dunut ,
493.Fn mixer_set_dunit ,
494.Fn mixer_get_nmixers ,
495and
496.Fn mixer_get_path
497functions return 0 or positive values on success and -1 on failure.
498.Pp
499The
500.Fn mixer_get_dev
501and
502.Fn mixer_get_dev_byname
503functions return the selected device on success and NULL on failure.
504.Pp
505All functions set the value of
506.Ar errno
507on failure.
508.Sh EXAMPLES
509.Ss Change the volume of a device
510.Bd -literal
511struct mixer *m;
512mix_volume_t vol;
513char *mix_name, *dev_name;
514
515mix_name = ...;
516if ((m = mixer_open(mix_name)) == NULL)
517	err(1, "mixer_open: %s", mix_name);
518
519dev_name = ...;
520if ((m->dev = mixer_get_dev_byname(m, dev_name)) < 0)
521	err(1, "unknown device: %s", dev_name);
522
523vol.left = ...;
524vol.right = ....;
525if (mixer_set_vol(m, vol) < 0)
526	warn("cannot change volume");
527
528(void)mixer_close(m);
529.Ed
530.Ss Mute all unmuted devices
531.Bd -literal
532struct mixer *m;
533struct mix_dev *dp;
534
535if ((m = mixer_open(NULL)) == NULL)	/* Open the default mixer. */
536	err(1, "mixer_open");
537TAILQ_FOREACH(dp, &m->devs, devs) {
538	m->dev = dp;			/* Select device. */
539	if (M_ISMUTE(m, dp->devno))
540		continue;
541	if (mixer_set_mute(m, MIX_MUTE) < 0)
542		warn("cannot mute device: %s", dp->name);
543}
544
545(void)mixer_close(m);
546.Ed
547.Ss Print all recording sources' names and volumes
548.Bd -literal
549struct mixer *m;
550struct mix_dev *dp;
551
552char *mix_name, *dev_name;
553
554mix_name = ...;
555if ((m = mixer_open(mix_name)) == NULL)
556	err(1, "mixer_open: %s", mix_name);
557
558TAILQ_FOREACH(dp, &m->devs, devs) {
559	if (M_ISRECSRC(m, dp->devno))
560		printf("%s\\t%.2f:%.2f\\n",
561		    dp->name, dp->vol.left, dp->vol.right);
562}
563
564(void)mixer_close(m);
565.Ed
566.Ss Loop through all mixer devices in the system
567.Bd -literal
568struct mixer *m;
569char buf[NAME_MAX];
570int n;
571
572if ((n = mixer_get_nmixers()) < 0)
573	errx(1, "no mixers present in the system");
574for (i = 0; i < n; i++) {
575	(void)mixer_get_path(buf, sizeof(buf), i);
576	if ((m = mixer_open(buf)) == NULL)
577		continue;
578	...
579	(void)mixer_close(m);
580}
581.Ed
582.Sh SEE ALSO
583.Xr queue 3 ,
584.Xr sysctl 3 ,
585.Xr sound 4 ,
586.Xr mixer 8
587and
588.Xr errno 2
589.Sh AUTHORS
590.An Christos Margiolis Aq Mt christos@FreeBSD.org
591