2 .\" Copyright (c) 2021 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
25 .Dd September 22, 2021
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
109 A mixer is described by the following structure:
112 TAILQ_HEAD(, 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 */
139 The fields are follows:
140 .Bl -tag -width "f_default"
142 A tail queue structure containing all supported mixer devices.
144 A pointer to the currently selected device. The device is one of the elements in
147 OSS information about the mixer. Look at the definition of the
153 OSS audio card information. This structure is also defined in
154 .In sys/soundcard.h .
156 Path to the mixer (e.g /dev/mixer0).
158 File descriptor returned when the mixer is opened in
161 Audio card unit. Since each mixer device maps to a pcmX device,
163 is always equal to the number of that pcmX device. For example, if the audio
164 device's number is 0 (i.e pcm0), then
166 is 0 as well. This number is useful when checking if the mixer's audio
167 card is the default one.
172 Bit mask containing all supported devices for the mixer. For example
173 if device 10 is supported, then the 10th bit in the mask will be set. By default,
175 stores only the supported devices in devs, so it's very unlikely this mask will
178 Bit mask containing all muted devices. The logic is the same as with
181 Bit mask containing all recording devices. Again, same logic as with the
184 Bit mask containing all recording sources. Yes, same logic again.
186 Bit mask containing the supported modes for this audio device. It holds the value
191 Flag which tells whether the mixer's audio card is the default one.
195 Each mixer device stored in a mixer is described as follows:
198 struct mixer *parent_mixer; /* parent mixer */
199 char name[NAME_MAX]; /* device name (e.g "vol") */
200 int devno; /* device number */
202 #define MIX_VOLMIN 0.0f
203 #define MIX_VOLMAX 1.0f
204 #define MIX_VOLNORM(v) ((v) / 100.0f)
205 #define MIX_VOLDENORM(v) ((int)((v) * 100.0f + 0.5f))
206 float left; /* left volume */
207 float right; /* right volume */
209 int nctl; /* number of controls */
210 TAILQ_HEAD(, mix_ctl) ctls; /* control list */
211 TAILQ_ENTRY(mix_dev) devs;
215 The fields are follows:
216 .Bl -tag -width "parent_mixer"
218 Pointer to the mixer the device is attached to.
220 Device name given by the OSS API. Devices can have one of the following names:
222 vol, bass, treble, synth, pcm, speaker, line, mic, cd, mix,
223 pcm2, rec, igain, ogain, line1, line2, line3, dig1, dig2, dig3,
224 phin, phout, video, radio, and monitor.
227 Device's index in the SOUND_MIXER_NRDEVICES macro defined in
228 .In sys/soundcard.h .
229 This number is used to check against the masks defined in the
233 Left and right-ear volumes. Although the OSS API stores volumes in integers from
234 0-100, we normalize them to 32-bit floating point numbers. However, the volumes
235 can be denormalized using the
239 Number of user-defined mixer controls associated with the device.
241 A tail queue containing user-defined mixer controls.
243 .Ss User-defined mixer controls
245 Each mixer device can have user-defined controls. The control structure
246 is defined as follows:
249 struct mix_dev *parent_dev; /* parent device */
250 int id; /* control id */
251 char name[NAME_MAX]; /* control name */
252 int (*mod)(struct mix_dev *, void *); /* modify control values */
253 int (*print)(struct mix_dev *, void *); /* print control */
254 TAILQ_ENTRY(mix_ctl) ctls;
258 The fields are follows:
259 .Bl -tag -width "parent_dev"
261 Pointer to the device the control is attached to.
263 Control ID assigned by the caller. Even though the library will
264 report it, care has to be taken to not give a control the same ID in case
265 the caller has to choose controls using their ID.
267 Control name. As with
269 the caller has to make sure the same name is not used more than once.
271 Function pointer to a control modification function. As in
273 each mixer control's values can be modified. For example, if we have a
276 function will be responsible for handling volume changes.
278 Function pointer to a control print function.
280 .Ss Opening and closing the mixer
282 The application must first call the
284 function to obtain a handle to the device, which is used as an argument
285 in most other functions and macros. The parameter
287 specifies the path to the mixer. OSS mixers are stored under
291 is the number of the mixer device. Each device maps to an actual
304 opens the default mixer (hw.snd.defaul_unit).
308 function frees resources and closes the mixer device. It's a good practice to
309 always call it when the application is done using the mixer.
310 .Ss Manipulating the mixer
315 .Fn mixer_get_dev_byname
316 functions select a mixer device, either by its number or by its name
317 respectively. The mixer structure keeps a list of all the devices, but only
318 one can be manipulated at a time. Each time a new device is to be manipulated,
319 one of the two functions has to be called.
323 function changes the volume of the selected mixer device. The
325 parameter is a structure that stores the left and right volumes of a given
326 device. The allowed volume values are between MIX_VOLMIN (0.0) and
331 function modifies the mute of a selected device. The
333 parameter has to be one of the following options:
334 .Bl -tag -width MIX_TOGGLEMUTE -offset indent
339 .It Dv MIX_TOGGLEMUTE
340 Toggle the device's mute (e.g mute if unmuted and unmute if muted).
345 function modifies a recording device. The selected device has to be
346 a recording device, otherwise the function will fail. The
348 parameter has to be one of the following options:
349 .Bl -tag -width MIX_REMOVERECSRC -offset indent
351 Add device to the recording sources.
352 .It Dv MIX_REMOVERECSRC
353 Remove device from the recording sources.
355 Set device as the only recording source.
356 .It Dv MIX_TOGGLERECSRC
357 Toggle device from the recording sources.
364 functions get and set the default audio card in the system. Although this is
365 not really a mixer feature, it's useful to have instead of having to use
372 function returns the playback/recording mode of the audio device the mixer
373 belongs to. The available values are the following:
374 .Bl -tag -width "MIX_STATUS_PLAY | MIX_STATUS_REC" -offset indent
375 .It Dv MIX_STATUS_NONE
376 Neither playback nor recording.
377 .It Dv MIX_STATUS_PLAY
379 .It Dv MIX_STATUS_REC
381 .It Dv MIX_STATUS_PLAY | MIX_STATUS_REC
382 Playback and recording.
386 .Fn mixer_get_nmixers
387 function returns the total number of mixer devices in the system.
391 macro checks if a device is actually a valid device for a given mixer. It's very
392 unlikely that this macro will ever be needed since the library stores only
393 valid devices by default.
397 macro checks if a device is muted.
401 macro checks if a device is a recording device.
405 macro checks if a device is a recording source.
409 macro normalizes a value to 32-bit floating point number. It's used
410 to normalize the volumes read from the OSS API.
414 macro denormalizes the left and right volumes stores in the
417 .Ss Defining and using mixer controls
421 function creates a control and attaches it to the device specified in the
427 function does the same thing as with
429 but the caller passes a
431 structure instead of each field as a seperate argument.
435 functions removes a control from the device its attached to.
439 function searches for a control in the device specified in the
441 argument and returns a pointer to it. The search is done using the control's ID.
444 .Fn mixer_get_ctl_byname
445 function is the same as with
447 but the search is done using the control's name.
452 function returns the newly created handle on success and NULL on failure.
458 .Fn mixer_mod_recsrc ,
459 .Fn mixer_get_dunut ,
462 .Fn mixer_get_nmixers
463 functions return 0 or positive values on success and -1 on failure.
468 .Fn mixer_get_dev_byname
469 functions return the selected device on success and NULL on failure.
471 All functions set the value of
475 .Ss Change the volume of a device
479 char *mix_name, *dev_name;
482 if ((m = mixer_open(mix_name)) == NULL)
483 err(1, "mixer_open: %s", mix_name);
486 if ((m->dev = mixer_get_dev_byname(m, dev_name)) < 0)
487 err(1, "unknown device: %s", dev_name);
491 if (mixer_set_vol(m, vol) < 0)
492 warn("cannot change volume");
494 (void)mixer_close(m);
496 .Ss Mute all unmuted devices
501 if ((m = mixer_open(NULL)) == NULL) /* Open the default mixer. */
502 err(1, "mixer_open");
503 TAILQ_FOREACH(dp, &m->devs, devs) {
504 m->dev = dp; /* Select device. */
505 if (M_ISMUTE(m, dp->devno))
507 if (mixer_set_mute(m, MIX_MUTE) < 0)
508 warn("cannot mute device: %s", dp->name);
511 (void)mixer_close(m);
513 .Ss Print all recording sources' names and volumes
518 char *mix_name, *dev_name;
521 if ((m = mixer_open(mix_name)) == NULL)
522 err(1, "mixer_open: %s", mix_name);
524 TAILQ_FOREACH(dp, &m->devs, devs) {
525 if (M_ISRECSRC(m, dp->devno))
526 printf("%s\\t%.2f:%.2f\\n",
527 dp->name, dp->vol.left, dp->vol.right);
530 (void)mixer_close(m);
540 .An Christos Margiolis Aq Mt christos@FreeBSD.org