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