2 .\" Copyright (c) 2021-2022 Christos Margiolis <christos@FreeBSD.org>
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:
11 .\" The above copyright notice and this permission notice shall be included in
12 .\" all copies or substantial portions of the Software.
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
32 .Nm mixer_get_dev_byname ,
35 .Nm mixer_remove_ctl ,
37 .Nm mixer_get_ctl_byname ,
40 .Nm mixer_mod_recsrc ,
44 .Nm mixer_get_nmixers ,
51 .Nd interface to OSS mixers
53 Mixer library (libmixer, -lmixer)
57 .Fn mixer_open "const char *name"
59 .Fn mixer_close "struct mixer *m"
61 .Fn mixer_get_dev "struct mixer *m" "int devno"
63 .Fn mixer_get_dev_byname "struct mixer *m" "name"
65 .Fn mixer_add_ctl "struct mix_dev *parent" "int id" "const char *name" \
66 "int (*mod)(struct mix_dev *d, void *p)" \
67 "int (*print)(struct mix_dev *d, void *p)"
69 .Fn mixer_add_ctl_s "mix_ctl_t *ctl"
71 .Fn mixer_remove_ctl "mix_ctl_t *ctl"
73 .Fn mixer_get_ctl "struct mix_dev *d" "int id"
75 .Fn mixer_get_ctl_byname "struct mix_dev *d" "const char *name"
77 .Fn mixer_set_vol "struct mixer *m" "mix_volume_t vol"
79 .Fn mixer_set_mute "struct mixer *m" "int opt"
81 .Fn mixer_mod_recsrc "struct mixer *m" "int opt"
83 .Fn mixer_get_dunit "void"
85 .Fn mixer_set_dunit "struct mixer *m" "int unit"
87 .Fn mixer_get_mode "int unit"
89 .Fn mixer_get_nmixers "void"
91 .Fn MIX_ISDEV "struct mixer *m" "int devno"
93 .Fn MIX_ISMUTE "struct mixer *m" "int devno"
95 .Fn MIX_ISREC "struct mixer *m" "int devno"
97 .Fn MIX_ISRECSRC "struct mixer *m" "int devno"
99 .Fn MIX_VOLNORM "int v"
101 .Fn MIX_VOLDENORM "float v"
105 library allows userspace programs to access and manipulate OSS sound mixers in
108 A mixer is described by the following structure:
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 */
138 The fields are follows:
139 .Bl -tag -width "f_default"
141 A tail queue structure containing all supported mixer devices.
143 A pointer to the currently selected device.
144 The device is one of the elements in
147 OSS information about the mixer.
148 Look at the definition of the
154 OSS audio card information.
155 This structure is also defined in
156 .In sys/soundcard.h .
158 Path to the mixer (e.g /dev/mixer0).
160 File descriptor returned when the mixer is opened in
164 Since each mixer device maps to a pcmX device,
166 is always equal to the number of that pcmX device.
167 For example, if the audio device's number is 0 (i.e pcm0), then
170 This number is useful when checking if the mixer's audio card is the default one.
175 Bit mask containing all supported devices for the mixer.
176 For example, if device 10 is supported, then the 10th bit in the mask will be set.
179 stores only the supported devices in devs, so it is very unlikely this mask will
182 Bit mask containing all muted devices.
183 The logic is the same as with
186 Bit mask containing all recording devices.
187 Again, same logic as with the other masks.
189 Bit mask containing all recording sources.
190 Yes, same logic again.
192 Bit mask containing the supported modes for this audio device.
193 It holds the value of the
197 Flag which tells whether the mixer's audio card is the default one.
200 Each mixer device stored in a mixer is described as follows:
203 struct mixer *parent_mixer; /* parent mixer */
204 char name[NAME_MAX]; /* device name (e.g "vol") */
205 int devno; /* device number */
207 #define MIX_VOLMIN 0.0f
208 #define MIX_VOLMAX 1.0f
209 #define MIX_VOLNORM(v) ((v) / 100.0f)
210 #define MIX_VOLDENORM(v) ((int)((v) * 100.0f + 0.5f))
211 float left; /* left volume */
212 float right; /* right volume */
214 int nctl; /* number of controls */
215 TAILQ_HEAD(mix_ctlhead, mix_ctl) ctls; /* control list */
216 TAILQ_ENTRY(mix_dev) devs;
220 The fields are follows:
221 .Bl -tag -width "parent_mixer"
223 Pointer to the mixer the device is attached to.
225 Device name given by the OSS API.
226 Devices can have one of the following names:
228 vol, bass, treble, synth, pcm, speaker, line, mic, cd, mix,
229 pcm2, rec, igain, ogain, line1, line2, line3, dig1, dig2, dig3,
230 phin, phout, video, radio, and monitor.
233 Device's index in the SOUND_MIXER_NRDEVICES macro defined in
234 .In sys/soundcard.h .
235 This number is used to check against the masks defined in the
239 Left and right-ear volumes.
240 Although the OSS API stores volumes in integers from 0-100, \
241 we normalize them to 32-bit floating point numbers.
242 However, the volumes can be denormalized using the
246 Number of user-defined mixer controls associated with the device.
248 A tail queue containing user-defined mixer controls.
250 .Ss User-defined mixer controls
251 Each mixer device can have user-defined controls.
252 The control structure is defined as follows:
255 struct mix_dev *parent_dev; /* parent device */
256 int id; /* control id */
257 char name[NAME_MAX]; /* control name */
258 int (*mod)(struct mix_dev *, void *); /* modify control values */
259 int (*print)(struct mix_dev *, void *); /* print control */
260 TAILQ_ENTRY(mix_ctl) ctls;
264 The fields are follows:
265 .Bl -tag -width "parent_dev"
267 Pointer to the device the control is attached to.
269 Control ID assigned by the caller.
270 Even though the library will report it, care has to be taken to not give \
271 a control the same ID in case the caller has to choose controls using their ID.
276 the caller has to make sure the same name is not used more than once.
278 Function pointer to a control modification function.
281 each mixer control's values can be modified.
282 For example, if we have a volume control, the
284 function will be responsible for handling volume changes.
286 Function pointer to a control print function.
288 .Ss Opening and closing the mixer
289 The application must first call the
291 function to obtain a handle to the device, which is used as an argument \
292 in most other functions and macros.
295 specifies the path to the mixer.
296 OSS mixers are stored under
300 is the number of the mixer device.
301 Each device maps to an actual
315 opens the default mixer (hw.snd.default_unit).
319 function frees resources and closes the mixer device.
320 It is a good practice to always call it when the application is done using the mixer.
321 .Ss Manipulating the mixer
325 .Fn mixer_get_dev_byname
326 functions select a mixer device, either by its number or by its name respectively.
327 The mixer structure keeps a list of all the devices, but only \
328 one can be manipulated at a time.
329 Each time a new device is to be manipulated, one of the two functions has to be called.
333 function changes the volume of the selected mixer device.
336 parameter is a structure that stores the left and right volumes of a given device.
337 The allowed volume values are between MIX_VOLMIN (0.0) and MIX_VOLMAX (1.0).
341 function modifies the mute of a selected device.
344 parameter has to be one of the following options:
345 .Bl -tag -width MIX_TOGGLEMUTE -offset indent
350 .It Dv MIX_TOGGLEMUTE
351 Toggle the device's mute (e.g mute if unmuted and unmute if muted).
356 function modifies a recording device.
357 The selected device has to be a recording device, otherwise the function will fail.
360 parameter has to be one of the following options:
361 .Bl -tag -width MIX_REMOVERECSRC -offset indent
363 Add device to the recording sources.
364 .It Dv MIX_REMOVERECSRC
365 Remove device from the recording sources.
367 Set device as the only recording source.
368 .It Dv MIX_TOGGLERECSRC
369 Toggle device from the recording sources.
376 functions get and set the default audio card in the system.
377 Although this is not really a mixer feature, it is useful to have instead of \
384 function returns the playback/recording mode of the audio device the mixer \
386 The available values are the following:
387 .Bl -tag -width "MIX_STATUS_PLAY | MIX_STATUS_REC" -offset indent
388 .It Dv MIX_STATUS_NONE
389 Neither playback nor recording.
390 .It Dv MIX_STATUS_PLAY
392 .It Dv MIX_STATUS_REC
394 .It Dv MIX_STATUS_PLAY | MIX_STATUS_REC
395 Playback and recording.
399 .Fn mixer_get_nmixers
400 function returns the total number of mixer devices in the system.
404 macro checks if a device is actually a valid device for a given mixer.
405 It is very unlikely that this macro will ever be needed since the library \
406 stores only valid devices by default.
410 macro checks if a device is muted.
414 macro checks if a device is a recording device.
418 macro checks if a device is a recording source.
422 macro normalizes a value to 32-bit floating point number.
423 It is used to normalize the volumes read from the OSS API.
427 macro denormalizes the left and right volumes stores in the
430 .Ss Defining and using mixer controls
433 function creates a control and attaches it to the device specified in the
439 function does the same thing as with
441 but the caller passes a
443 structure instead of each field as a separate argument.
447 functions removes a control from the device its attached to.
451 function searches for a control in the device specified in the
453 argument and returns a pointer to it.
454 The search is done using the control's ID.
457 .Fn mixer_get_ctl_byname
458 function is the same as with
460 but the search is done using the control's name.
464 function returns the newly created handle on success and NULL on failure.
470 .Fn mixer_mod_recsrc ,
471 .Fn mixer_get_dunut ,
474 .Fn mixer_get_nmixers
475 functions return 0 or positive values on success and -1 on failure.
480 .Fn mixer_get_dev_byname
481 functions return the selected device on success and NULL on failure.
483 All functions set the value of
487 .Ss Change the volume of a device
491 char *mix_name, *dev_name;
494 if ((m = mixer_open(mix_name)) == NULL)
495 err(1, "mixer_open: %s", mix_name);
498 if ((m->dev = mixer_get_dev_byname(m, dev_name)) < 0)
499 err(1, "unknown device: %s", dev_name);
503 if (mixer_set_vol(m, vol) < 0)
504 warn("cannot change volume");
506 (void)mixer_close(m);
508 .Ss Mute all unmuted devices
513 if ((m = mixer_open(NULL)) == NULL) /* Open the default mixer. */
514 err(1, "mixer_open");
515 TAILQ_FOREACH(dp, &m->devs, devs) {
516 m->dev = dp; /* Select device. */
517 if (M_ISMUTE(m, dp->devno))
519 if (mixer_set_mute(m, MIX_MUTE) < 0)
520 warn("cannot mute device: %s", dp->name);
523 (void)mixer_close(m);
525 .Ss Print all recording sources' names and volumes
530 char *mix_name, *dev_name;
533 if ((m = mixer_open(mix_name)) == NULL)
534 err(1, "mixer_open: %s", mix_name);
536 TAILQ_FOREACH(dp, &m->devs, devs) {
537 if (M_ISRECSRC(m, dp->devno))
538 printf("%s\\t%.2f:%.2f\\n",
539 dp->name, dp->vol.left, dp->vol.right);
542 (void)mixer_close(m);
552 .An Christos Margiolis Aq Mt christos@FreeBSD.org