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