mixer

FreeBSD OSS mixer library implementation and a complete rewrite of mixer(8)
git clone git://git.margiolis.net/mixer.git
Log | Files | Refs | README | LICENSE

mixer.3 (14836B)


      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
     53 Mixer 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
    103 The
    104 .Nm mixer
    105 library allows userspace programs to access and manipulate OSS sound mixers in
    106 a simple way.
    107 .Ss Mixer
    108 A mixer is described by the following structure:
    109 .Bd -literal
    110 struct 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
    138 The fields are follows:
    139 .Bl -tag -width "f_default"
    140 .It Fa devs
    141 A tail queue structure containing all supported mixer devices.
    142 .It Fa dev
    143 A pointer to the currently selected device.
    144 The device is one of the elements in
    145 .Ar devs .
    146 .It Fa mi
    147 OSS information about the mixer.
    148 Look at the definition of the
    149 .Ft oss_mixerinfo
    150 structure in
    151 .In sys/soundcard.h
    152 to see its fields.
    153 .It Fa ci
    154 OSS audio card information.
    155 This structure is also defined in
    156 .In sys/soundcard.h .
    157 .It Fa name
    158 Path to the mixer (e.g /dev/mixer0).
    159 .It Fa fd
    160 File descriptor returned when the mixer is opened in
    161 .Fn mixer_open .
    162 .It Fa unit
    163 Audio card unit.
    164 Since each mixer device maps to a pcmX device,
    165 .Ar unit
    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
    168 .Ar unit
    169 is 0 as well.
    170 This number is useful when checking if the mixer's audio card is the default one.
    171 .It Fa ndev
    172 Number of devices in
    173 .Ar devs .
    174 .It Fa devmask
    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.
    177 By default,
    178 .Fn mixer_open
    179 stores only the supported devices in devs, so it is very unlikely this mask will
    180 be needed.
    181 .It Fa mutemask
    182 Bit mask containing all muted devices.
    183 The logic is the same as with
    184 .Ar devmask .
    185 .It Fa recmask
    186 Bit mask containing all recording devices.
    187 Again, same logic as with the other masks.
    188 .It Fa recsrc
    189 Bit mask containing all recording sources.
    190 Yes, same logic again.
    191 .It Fa mode
    192 Bit mask containing the supported modes for this audio device.
    193 It holds the value of the
    194 .Ar dev.pcm.X.mode
    195 sysctl.
    196 .It Fa f_default
    197 Flag which tells whether the mixer's audio card is the default one.
    198 .El
    199 .Ss Mixer device
    200 Each mixer device stored in a mixer is described as follows:
    201 .Bd -literal
    202 struct 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
    220 The fields are follows:
    221 .Bl -tag -width "parent_mixer"
    222 .It Fa parent_mixer
    223 Pointer to the mixer the device is attached to.
    224 .It Fa name
    225 Device name given by the OSS API.
    226 Devices can have one of the following names:
    227 .Bd -ragged
    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.
    231 .Ed
    232 .It Fa devno
    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
    236 .Ar mixer
    237 structure.
    238 .It Fa left right
    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
    243 .Ar MIX_VOLDENORM
    244 macro if needed.
    245 .It Fa nctl
    246 Number of user-defined mixer controls associated with the device.
    247 .It Fa ctls
    248 A tail queue containing user-defined mixer controls.
    249 .El
    250 .Ss User-defined mixer controls
    251 Each mixer device can have user-defined controls.
    252 The control structure is defined as follows:
    253 .Bd -literal
    254 struct 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
    264 The fields are follows:
    265 .Bl -tag -width "parent_dev"
    266 .It Fa parent_dev
    267 Pointer to the device the control is attached to.
    268 .It Fa id
    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.
    272 .It Fa name
    273 Control name.
    274 As with
    275 .Ar id ,
    276 the caller has to make sure the same name is not used more than once.
    277 .It Fa mod
    278 Function pointer to a control modification function.
    279 As in
    280 .Xr mixer 8 ,
    281 each mixer control's values can be modified.
    282 For example, if we have a volume control, the
    283 .Ar mod
    284 function will be responsible for handling volume changes.
    285 .It Fa print
    286 Function pointer to a control print function.
    287 .El
    288 .Ss Opening and closing the mixer
    289 The application must first call the
    290 .Fn mixer_open
    291 function to obtain a handle to the device, which is used as an argument \
    292 in most other functions and macros.
    293 The parameter
    294 .Ar name
    295 specifies the path to the mixer.
    296 OSS mixers are stored under
    297 .Ar /dev/mixerN
    298 where
    299 .Ar N
    300 is the number of the mixer device.
    301 Each device maps to an actual
    302 .Ar pcm
    303 audio card, so
    304 .Ar /dev/mixer0
    305 is the mixer for
    306 .Ar pcm0 ,
    307 and so on.
    308 If
    309 .Ar name
    310 is
    311 .Ar NULL
    312 or
    313 .Ar /dev/mixer ,
    314 .Fn mixer_open
    315 opens the default mixer (hw.snd.default_unit).
    316 .Pp
    317 The
    318 .Fn mixer_close
    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
    322 The
    323 .Fn mixer_get_dev
    324 and
    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.
    330 .Pp
    331 The
    332 .Fn mixer_set_vol
    333 function changes the volume of the selected mixer device.
    334 The
    335 .Ar vol
    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).
    338 .Pp
    339 The
    340 .Fn mixer_set_mute
    341 function modifies the mute of a selected device.
    342 The
    343 .Ar opt
    344 parameter has to be one of the following options:
    345 .Bl -tag -width MIX_TOGGLEMUTE -offset indent
    346 .It Dv MIX_MUTE
    347 Mute the device.
    348 .It Dv MIX_UNMUTE
    349 Unmute the device.
    350 .It Dv MIX_TOGGLEMUTE
    351 Toggle the device's mute (e.g mute if unmuted and unmute if muted).
    352 .El
    353 .Pp
    354 The
    355 .Fn mixer_mod_recsrc
    356 function modifies a recording device.
    357 The selected device has to be a recording device, otherwise the function will fail.
    358 The
    359 .Ar opt
    360 parameter has to be one of the following options:
    361 .Bl -tag -width MIX_REMOVERECSRC -offset indent
    362 .It Dv MIX_ADDRECSRC
    363 Add device to the recording sources.
    364 .It Dv MIX_REMOVERECSRC
    365 Remove device from the recording sources.
    366 .It Dv MIX_SETRECSRC
    367 Set device as the only recording source.
    368 .It Dv MIX_TOGGLERECSRC
    369 Toggle device from the recording sources.
    370 .El
    371 .Pp
    372 The
    373 .Fn mixer_get_dunit
    374 and
    375 .Fn mixer_set_dunit
    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 \
    378 having to use the
    379 .Xr sysctl 3
    380 controls.
    381 .Pp
    382 The
    383 .Fn mixer_get_mode
    384 function returns the playback/recording mode of the audio device the mixer \
    385 belongs to.
    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
    391 Playback.
    392 .It Dv MIX_STATUS_REC
    393 Recording.
    394 .It Dv MIX_STATUS_PLAY | MIX_STATUS_REC
    395 Playback and recording.
    396 .El
    397 .Pp
    398 The
    399 .Fn mixer_get_nmixers
    400 function returns the total number of mixer devices in the system.
    401 .Pp
    402 The
    403 .Fn MIX_ISDEV
    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.
    407 .Pp
    408 The
    409 .Fn MIX_ISMUTE
    410 macro checks if a device is muted.
    411 .Pp
    412 The
    413 .Fn MIX_ISREC
    414 macro checks if a device is a recording device.
    415 .Pp
    416 The
    417 .Fn MIX_ISRECSRC
    418 macro checks if a device is a recording source.
    419 .Pp
    420 The
    421 .Fn MIX_VOLNORM
    422 macro normalizes a value to 32-bit floating point number.
    423 It is used to normalize the volumes read from the OSS API.
    424 .Pp
    425 The
    426 .Fn MIX_VOLDENORM
    427 macro denormalizes the left and right volumes stores in the
    428 .Ft mix_dev
    429 structure.
    430 .Ss Defining and using mixer controls
    431 The
    432 .Fn mix_add_ctl
    433 function creates a control and attaches it to the device specified in the
    434 .Ar parent
    435 argument.
    436 .Pp
    437 The
    438 .Fn mix_add_ctl_s
    439 function does the same thing as with
    440 .Fn mix_add_ctl
    441 but the caller passes a
    442 .Ft mix_ctl_t *
    443 structure instead of each field as a separate argument.
    444 .Pp
    445 The
    446 .Fn mixer_remove_ctl
    447 functions removes a control from the device its attached to.
    448 .Pp
    449 The
    450 .Fn mixer_get_ctl
    451 function searches for a control in the device specified in the
    452 .Ar d
    453 argument and returns a pointer to it.
    454 The search is done using the control's ID.
    455 .Pp
    456 The
    457 .Fn mixer_get_ctl_byname
    458 function is the same as with
    459 .Fn mixer_get_ctl
    460 but the search is done using the control's name.
    461 .Sh RETURN VALUES
    462 The
    463 .Fn mixer_open
    464 function returns the newly created handle on success and NULL on failure.
    465 .Pp
    466 The
    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
    473 and
    474 .Fn mixer_get_nmixers
    475 functions return 0 or positive values on success and -1 on failure.
    476 .Pp
    477 The
    478 .Fn mixer_get_dev
    479 and
    480 .Fn mixer_get_dev_byname
    481 functions return the selected device on success and NULL on failure.
    482 .Pp
    483 All functions set the value of
    484 .Ar errno
    485 on failure.
    486 .Sh EXAMPLES
    487 .Ss Change the volume of a device
    488 .Bd -literal
    489 struct mixer *m;
    490 mix_volume_t vol;
    491 char *mix_name, *dev_name;
    492 
    493 mix_name = ...;
    494 if ((m = mixer_open(mix_name)) == NULL)
    495 	err(1, "mixer_open: %s", mix_name);
    496 
    497 dev_name = ...;
    498 if ((m->dev = mixer_get_dev_byname(m, dev_name)) < 0)
    499 	err(1, "unknown device: %s", dev_name);
    500 
    501 vol.left = ...;
    502 vol.right = ....;
    503 if (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
    510 struct mixer *m;
    511 struct mix_dev *dp;
    512 
    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))
    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
    527 struct mixer *m;
    528 struct mix_dev *dp;
    529 
    530 char *mix_name, *dev_name;
    531 
    532 mix_name = ...;
    533 if ((m = mixer_open(mix_name)) == NULL)
    534 	err(1, "mixer_open: %s", mix_name);
    535 
    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);
    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
    549 and
    550 .Xr errno 2
    551 .Sh AUTHORS
    552 .An Christos Margiolis Aq Mt christos@FreeBSD.org