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


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