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