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