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