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 (14829B)


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