MIXER(3)
π NAME π
This is MIXER(3) from the Library Functions Manual, and it's literally the whole interface to OSS mixers. The squad is: mixer_open, mixer_close, mixer_get_dev, mixer_get_dev_byname, mixer_add_ctl, mixer_add_ctl_s, mixer_remove_ctl, mixer_get_ctl, mixer_get_ctl_byname, mixer_set_vol, mixer_set_mute, mixer_mod_recsrc, mixer_get_dunit, mixer_set_dunit, mixer_get_mode, mixer_get_nmixers, mixer_get_path, MIX_ISDEV, MIX_ISMUTE, MIX_ISREC, MIX_ISRECSRC, MIX_VOLNORM, and MIX_VOLDENORM. That's the interface to OSS mixers, periodt. π
π LIBRARY π
Mixer library (libmixer, -lmixer) β that's the whole vibe, bestie. π«Ά
β¨ SYNOPSIS β¨
#include <mixer.h>
struct mixer *
mixer_open(const char *name);
int
mixer_close(struct mixer *m);
struct mix_dev *
mixer_get_dev(struct mixer *m, int devno);
struct mix_dev *
mixer_get_dev_byname(struct mixer *m, name);
int
mixer_add_ctl(struct mix_dev *parent, int id, const char *name,
int (*mod)(struct mix_dev *d, void *p),
int (*print)(struct mix_dev *d, void *p));
int
mixer_add_ctl_s(mix_ctl_t *ctl);
int
mixer_remove_ctl(mix_ctl_t *ctl);
mix_ctl_t *
mixer_get_ctl(struct mix_dev *d, int id);
mix_ctl_t *
mixer_get_ctl_byname(struct mix_dev *d, const char *name);
int
mixer_set_vol(struct mixer *m, mix_volume_t vol);
int
mixer_set_mute(struct mixer *m, int opt);
int
mixer_mod_recsrc(struct mixer *m, int opt);
int
mixer_get_dunit(void);
int
mixer_set_dunit(struct mixer *m, int unit);
int
mixer_get_mode(int unit);
int
mixer_get_nmixers(void);
int
mixer_get_path(char * buf, size_t size, int unit);
int
MIX_ISDEV(struct mixer *m, int devno);
int
MIX_ISMUTE(struct mixer *m, int devno);
int
MIX_ISREC(struct mixer *m, int devno);
int
MIX_ISRECSRC(struct mixer *m, int devno);
float
MIX_VOLNORM(int v);
int
MIX_VOLDENORM(float v);
π¦ DESCRIPTION π¦
The mixer library lets userspace programs access and manipulate OSS sound mixers in a simple way. Iconic behavior, honestly. π
π Mixer π
A mixer is described by the following structure β main character energy:
struct mixer {
TAILQ_HEAD(mix_devhead, mix_dev) devs; /* device list */
struct mix_dev *dev; /* selected device */
oss_mixerinfo mi; /* mixer info */
oss_card_info ci; /* audio card info */
char name[NAME_MAX]; /* mixer name (e.g /dev/mixer0) */
int fd; /* file descriptor */
int unit; /* audio card unit */
int ndev; /* number of devices */
int devmask; /* supported devices */
#define MIX_MUTE 0x01
#define MIX_UNMUTE 0x02
#define MIX_TOGGLEMUTE 0x04
int mutemask; /* muted devices */
int recmask; /* recording devices */
#define MIX_ADDRECSRC 0x01
#define MIX_REMOVERECSRC 0x02
#define MIX_SETRECSRC 0x04
#define MIX_TOGGLERECSRC 0x08
int recsrc; /* recording sources */
#define MIX_MODE_MIXER 0x01
#define MIX_MODE_PLAY 0x02
#define MIX_MODE_REC 0x04
int mode; /* dev.pcm.X.mode sysctl */
int f_default; /* default mixer flag */
};
The fields are giving:
devsβ A tail queue structure containing all supported mixer devices.devβ A pointer to the currently selected device. The device is one of the elements indevs.miβ OSS information about the mixer. Look at the definition of theoss_mixerinfostructure in<sys/soundcard.h>to see its fields.ciβ OSS audio card information. This structure is also defined in<sys/soundcard.h>.nameβ Path to the mixer (e.g/dev/mixer0).fdβ File descriptor returned when the mixer is opened inmixer_open().unitβ Audio card unit. Since each mixer device maps to apcmXdevice,unitis always equal to the number of thatpcmXdevice. For example, if the audio device's number is 0 (i.epcm0), thenunitis 0 as well. This number is useful when checking if the mixer's audio card is the default one.ndevβ Number of devices indevs.devmaskβ Bit mask containing all supported devices for the mixer. For example, if device 10 is supported, then the 10th bit in the mask will be set. By default,mixer_open()stores only the supported devices indevs, so it is very unlikely this mask will be needed.mutemaskβ Bit mask containing all muted devices. The logic is the same as withdevmask.recmaskβ Bit mask containing all recording devices. Again, same logic as with the other masks.recsrcβ Bit mask containing all recording sources. Yes, same logic again.modeβ Bit mask containing the supported modes for this audio device. It holds the value of thedev.pcm.X.modesysctl.f_defaultβ Flag which tells whether the mixer's audio card is the default one.
π§ Mixer device π§
Each mixer device stored in a mixer is described as follows β lowkey adorable:
struct mix_dev {
struct mixer *parent_mixer; /* parent mixer */
char name[NAME_MAX]; /* device name (e.g "vol") */
int devno; /* device number */
struct mix_volume {
#define MIX_VOLMIN 0.0f
#define MIX_VOLMAX 1.0f
#define MIX_VOLNORM(v) ((v) / 100.0f)
#define MIX_VOLDENORM(v) ((int)((v) * 100.0f + 0.5f))
float left; /* left volume */
float right; /* right volume */
} vol;
int nctl; /* number of controls */
TAILQ_HEAD(mix_ctlhead, mix_ctl) ctls; /* control list */
TAILQ_ENTRY(mix_dev) devs;
};
The fields are follows:
parent_mixerβ Pointer to the mixer the device is attached to.nameβ Device name given by the OSS API. Devices can have one of the following names:
vol, bass, treble, synth, pcm, speaker, line, mic, cd, mix, pcm2, rec, igain, ogain, line1, line2, line3, dig1, dig2, dig3, phin, phout, video, radio, and monitor.
devnoβ Device's index in theSOUND_MIXER_NRDEVICESmacro defined in<sys/soundcard.h>. This number is used to check against the masks defined in the mixer structure.leftrightβ Left and right-ear volumes. Although the OSS API stores volumes in integers from 0-100, we normalize them to 32-bit floating point numbers. However, the volumes can be denormalized using theMIX_VOLDENORMmacro if needed.nctlβ Number of user-defined mixer controls associated with the device.ctlsβ A tail queue containing user-defined mixer controls.
π§ User-defined mixer controls π§
Each mixer device can have user-defined controls. The control structure is defined as follows β custom-fit, bestie:
struct mix_ctl {
struct mix_dev *parent_dev; /* parent device */
int id; /* control id */
char name[NAME_MAX]; /* control name */
int (*mod)(struct mix_dev *, void *); /* modify control values */
int (*print)(struct mix_dev *, void *); /* print control */
TAILQ_ENTRY(mix_ctl) ctls;
};
The fields are follows:
parent_devβ Pointer to the device the control is attached to.idβ Control ID assigned by the caller. Even though the library will report it, care has to be taken to not give a control the same ID in case the caller has to choose controls using their ID.nameβ Control name. As withid, the caller has to make sure the same name is not used more than once.modβ Function pointer to a control modification function. As inmixer(8), each mixer control's values can be modified. For example, if we have a volume control, themodfunction will be responsible for handling volume changes.printβ Function pointer to a control print function.
πΈ Opening and closing the mixer πΈ
The application must first call the mixer_open() function to obtain a handle to the device, which is used as an argument in most other functions and macros. The parameter name specifies the path to the mixer. OSS mixers are stored under /dev/mixerN where N is the number of the mixer device. Each device maps to an actual pcm audio card, so /dev/mixer0 is the mixer for pcm0, and so on. If name is NULL or /dev/mixer, mixer_open() opens the default mixer (hw.snd.default_unit).
The mixer_close() function frees resources and closes the mixer device. It is a good practice to always call it when the application is done using the mixer. no cap, clean up after yourself. π§Ό
π₯ Manipulating the mixer π₯
The mixer_get_dev() and mixer_get_dev_byname() functions select a mixer device, either by its number or by its name respectively. The mixer structure keeps a list of all the devices, but only one can be manipulated at a time. Each time a new device is to be manipulated, one of the two functions has to be called.
The mixer_set_vol() function changes the volume of the selected mixer device. The vol parameter is a structure that stores the left and right volumes of a given device. The allowed volume values are between MIX_VOLMIN (0.0) and MIX_VOLMAX (1.0). ποΈ
The mixer_set_mute() function modifies the mute of a selected device. The opt parameter has to be one of the following options:
MIX_MUTEβ Mute the device.MIX_UNMUTEβ Unmute the device.MIX_TOGGLEMUTEβ Toggle the device's mute (e.g mute if unmuted and unmute if muted).
The mixer_mod_recsrc() function modifies a recording device. The selected device has to be a recording device, otherwise the function will fail. The opt parameter has to be one of the following options:
MIX_ADDRECSRCβ Add device to the recording sources.MIX_REMOVERECSRCβ Remove device from the recording sources.MIX_SETRECSRCβ Set device as the only recording source.MIX_TOGGLERECSRCβ Toggle device from the recording sources.
okay so, mixer_get_dunit() and mixer_set_dunit() are your get/set besties for the default audio card in the system π§. honestly it's not really a mixer feature, but it's useful to have instead of having to use the sysctl(3) controls. convenience slay.
mixer_get_mode() returns the operating mode of the audio device the mixer belongs to. you can OR these values together in case more than one mode is supported:
MIX_MODE_MIXERβ the audio device has a mixer.MIX_MODE_PLAYβ the audio device supports playback.MIX_MODE_RECβ the audio device supports recording.
mixer_get_nmixers() returns the maximum mixer unit number. and yes bestie, that might sound like incorrect behavior at first β you'd expect βnmixersβ to refer to the total number of active mixers β but it's actually more intuitive for applications that want to loop through all mixer devices (peep the βEXAMPLESβ section π).
mixer_get_path() writes the path of the mixer device specified in the unit argument to the buffer specified in buf. unit can be either -1, in which case mixer_get_path() will fetch the path of the default mixer, or between 0 and the maximum mixer unit.
the MIX_ISDEV() macro checks if a device is actually a valid device for a given mixer. it is very unlikely that this macro will ever be needed, since the library stores only valid devices by default. lowkey iconic of it π
.
the MIX_ISMUTE() macro checks if a device is muted.
the MIX_ISREC() macro checks if a device is a recording device.
the MIX_ISRECSRC() macro checks if a device is a recording source.
the MIX_VOLNORM() macro normalizes a value to a 32-bit floating point number. it is used to normalize the volumes read from the OSS API.
the MIX_VOLDENORM() macro denormalizes the left and right volumes stored in the mix_dev structure.
ποΈ Defining and using mixer controls ποΈ
mix_add_ctl() creates a control and attaches it to the device specified in the parent argument.
mix_add_ctl_s() does the same thing as mix_add_ctl(), but the caller passes a mix_ctl_t * structure instead of each field as a separate argument.
mixer_remove_ctl() removes a control from the device it's attached to.
mixer_get_ctl() searches for a control in the device specified in the d argument and returns a pointer to it. the search is done using the control's ID.
mixer_get_ctl_byname() is the same as mixer_get_ctl(), but the search is done using the control's name.
π RETURN VALUES π
mixer_open() returns the newly created handle on success and NULL on failure.
the mixer_close(), mixer_set_vol(), mixer_set_mute(), mixer_mod_recsrc(), mixer_get_dunut(), mixer_set_dunit(), mixer_get_nmixers(), and mixer_get_path() functions return 0 or positive values on success and -1 on failure.
the mixer_get_dev() and mixer_get_dev_byname() functions return the selected device on success and NULL on failure.
all functions set the value of errno on failure.
πΈ EXAMPLES πΈ
Change the volume of a device
struct mixer *m;
mix_volume_t vol;
char *mix_name, *dev_name;
mix_name = ...;
if ((m = mixer_open(mix_name)) == NULL)
err(1, "mixer_open: %s", mix_name);
dev_name = ...;
if ((m->dev = mixer_get_dev_byname(m, dev_name)) < 0)
err(1, "unknown device: %s", dev_name);
vol.left = ...;
vol.right = ....;
if (mixer_set_vol(m, vol) < 0)
warn("cannot change volume");
(void)mixer_close(m);
Mute all unmuted devices
struct mixer *m;
struct mix_dev *dp;
if ((m = mixer_open(NULL)) == NULL) /* Open the default mixer. */
err(1, "mixer_open");
TAILQ_FOREACH(dp, &m->devs, devs) {
m->dev = dp; /* Select device. */
if (M_ISMUTE(m, dp->devno))
continue;
if (mixer_set_mute(m, MIX_MUTE) < 0)
warn("cannot mute device: %s", dp->name);
}
(void)mixer_close(m);
Print all recording sources' names and volumes
struct mixer *m;
struct mix_dev *dp;
char *mix_name, *dev_name;
mix_name = ...;
if ((m = mixer_open(mix_name)) == NULL)
err(1, "mixer_open: %s", mix_name);
TAILQ_FOREACH(dp, &m->devs, devs) {
if (M_ISRECSRC(m, dp->devno))
printf("%s\t%.2f:%.2f\n",
dp->name, dp->vol.left, dp->vol.right);
}
(void)mixer_close(m);
Loop through all mixer devices in the system
struct mixer *m;
char buf[NAME_MAX];
int n;
if ((n = mixer_get_nmixers()) < 0)
errx(1, "no mixers present in the system");
for (i = 0; i < n; i++) {
(void)mixer_get_path(buf, sizeof(buf), i);
if ((m = mixer_open(buf)) == NULL)
continue;
...
(void)mixer_close(m);
}
π SEE ALSO π
go check out queue(3), sysctl(3), sound(4), mixer(8) and errno(2) π.
π AUTHORS π
the icon behind this page is Christos Margiolis <christos@FreeBSD.org> π«Ά.
and that's the tea ββ¨ β this manual page is the Debian edition, dated August 4, 2024, and it's MIXER(3). byeee bestie ππ
π¦ where this page comes from
- freebsd 14.5: base 14.5
- freebsd 15.1: base 15.1
- Copyright (c) 2021-2022 Christos Margiolis <christos@FreeBSD.org>
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms