2021-09-22 15:42:51 +02:00
|
|
|
.\"-
|
2022-03-18 12:08:55 +01:00
|
|
|
.\" Copyright (c) 2021-2022 Christos Margiolis <christos@FreeBSD.org>
|
2021-09-22 15:42:51 +02:00
|
|
|
.\"
|
|
|
|
.\" Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
.\" of this software and associated documentation files (the "Software"), to deal
|
|
|
|
.\" in the Software without restriction, including without limitation the rights
|
|
|
|
.\" to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
|
.\" copies of the Software, and to permit persons to whom the Software is
|
|
|
|
.\" furnished to do so, subject to the following conditions:
|
|
|
|
.\"
|
|
|
|
.\" The above copyright notice and this permission notice shall be included in
|
|
|
|
.\" all copies or substantial portions of the Software.
|
|
|
|
.\"
|
|
|
|
.\" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
.\" IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
.\" FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
.\" AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
.\" LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
|
.\" OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
|
|
.\" THE SOFTWARE.
|
|
|
|
.\"
|
sound: Handle unavailable devices in various OSS IOCTLs
mixer(8)'s -a option is used to print information about all mixer
devices in the system. To do this, it loops from 0 to
mixer_get_nmixers(), and tries to open "/dev/mixer%d". However, this
approach doesn't work when there are disabled/unregistered mixers in the
system, or when an audio device simply doesn't have a mixer.
mixer_get_nmixers() calls SNDCTL_SYSINFO and returns
oss_sysinfo->nummixers, whose value is the number of currently _enabled_
mixers only. Taking the bug report mentioned below (277615) as an
example, suppose a system with 8 mixer devices total, but 3 of them are
either disabled or non-existent, which means they will not show up under
/dev, meaning we have 5 enabled mixer devices, which is also what the
value of oss_sysinfo->nummixers will be. What mixer(8) will do is loop
from 0 to 5 (instead of 8), and start calling mixer_open() on
/dev/mixer0, up to /dev/mixer4, and as is expected, the first call will
fail right away, hence the error shown in the bug report.
To fix this, modify oss_sysinfo->nummixers to hold the value of the
maximum unit in the system, which, although not necessarily "correct",
is more intuitive for applications that will want to use this value to
loop through all mixer devices.
Additionally, notify applications that a device is
unavailable/unregistered instead of skipping it. The current
implementations of SNDCTL_AUDIOINFO, SNDCTL_MIXERINFO and
SNDCTL_CARDINFO break applications that expect to get information about
a device that is skipped. Related discussion can be found here:
https://reviews.freebsd.org/D45135#1029526
It has to be noted, that other applications, apart from mixer(8), suffer
from this.
PR: 277615
Sponsored by: The FreeBSD Foundation
MFC after: 1 day
Reviewed by: dev_submerge.ch
Differential Revision: https://reviews.freebsd.org/D45256
2024-05-23 02:57:17 +02:00
|
|
|
.Dd May 22, 2024
|
2021-11-20 08:58:36 +01:00
|
|
|
.Dt MIXER 3
|
2021-09-22 15:42:51 +02:00
|
|
|
.Os
|
|
|
|
.Sh NAME
|
|
|
|
.Nm mixer_open ,
|
|
|
|
.Nm mixer_close ,
|
|
|
|
.Nm mixer_get_dev ,
|
|
|
|
.Nm mixer_get_dev_byname ,
|
|
|
|
.Nm mixer_add_ctl ,
|
|
|
|
.Nm mixer_add_ctl_s ,
|
|
|
|
.Nm mixer_remove_ctl ,
|
|
|
|
.Nm mixer_get_ctl ,
|
|
|
|
.Nm mixer_get_ctl_byname ,
|
|
|
|
.Nm mixer_set_vol ,
|
|
|
|
.Nm mixer_set_mute ,
|
|
|
|
.Nm mixer_mod_recsrc ,
|
|
|
|
.Nm mixer_get_dunit ,
|
|
|
|
.Nm mixer_set_dunit ,
|
2022-03-20 20:13:00 +01:00
|
|
|
.Nm mixer_get_mode ,
|
2021-09-22 15:42:51 +02:00
|
|
|
.Nm mixer_get_nmixers ,
|
2024-05-23 02:57:36 +02:00
|
|
|
.Nm mixer_get_path ,
|
2021-09-22 15:42:51 +02:00
|
|
|
.Nm MIX_ISDEV ,
|
|
|
|
.Nm MIX_ISMUTE ,
|
|
|
|
.Nm MIX_ISREC ,
|
|
|
|
.Nm MIX_ISRECSRC ,
|
|
|
|
.Nm MIX_VOLNORM ,
|
|
|
|
.Nm MIX_VOLDENORM
|
|
|
|
.Nd interface to OSS mixers
|
|
|
|
.Sh LIBRARY
|
|
|
|
Mixer library (libmixer, -lmixer)
|
|
|
|
.Sh SYNOPSIS
|
|
|
|
.In mixer.h
|
|
|
|
.Ft struct mixer *
|
|
|
|
.Fn mixer_open "const char *name"
|
|
|
|
.Ft int
|
|
|
|
.Fn mixer_close "struct mixer *m"
|
|
|
|
.Ft struct mix_dev *
|
|
|
|
.Fn mixer_get_dev "struct mixer *m" "int devno"
|
|
|
|
.Ft struct mix_dev *
|
|
|
|
.Fn mixer_get_dev_byname "struct mixer *m" "name"
|
|
|
|
.Ft int
|
|
|
|
.Fn mixer_add_ctl "struct mix_dev *parent" "int id" "const char *name" \
|
|
|
|
"int (*mod)(struct mix_dev *d, void *p)" \
|
2022-03-20 20:13:00 +01:00
|
|
|
"int (*print)(struct mix_dev *d, void *p)"
|
2021-09-22 15:42:51 +02:00
|
|
|
.Ft int
|
|
|
|
.Fn mixer_add_ctl_s "mix_ctl_t *ctl"
|
|
|
|
.Ft int
|
|
|
|
.Fn mixer_remove_ctl "mix_ctl_t *ctl"
|
|
|
|
.Ft mix_ctl_t *
|
|
|
|
.Fn mixer_get_ctl "struct mix_dev *d" "int id"
|
|
|
|
.Ft mix_ctl_t *
|
|
|
|
.Fn mixer_get_ctl_byname "struct mix_dev *d" "const char *name"
|
|
|
|
.Ft int
|
|
|
|
.Fn mixer_set_vol "struct mixer *m" "mix_volume_t vol"
|
|
|
|
.Ft int
|
|
|
|
.Fn mixer_set_mute "struct mixer *m" "int opt"
|
|
|
|
.Ft int
|
|
|
|
.Fn mixer_mod_recsrc "struct mixer *m" "int opt"
|
|
|
|
.Ft int
|
|
|
|
.Fn mixer_get_dunit "void"
|
|
|
|
.Ft int
|
|
|
|
.Fn mixer_set_dunit "struct mixer *m" "int unit"
|
|
|
|
.Ft int
|
|
|
|
.Fn mixer_get_mode "int unit"
|
|
|
|
.Ft int
|
|
|
|
.Fn mixer_get_nmixers "void"
|
|
|
|
.Ft int
|
2024-05-23 02:57:36 +02:00
|
|
|
.Fn mixer_get_path "char * buf" "size_t size" "int unit"
|
|
|
|
.Ft int
|
2021-09-22 15:42:51 +02:00
|
|
|
.Fn MIX_ISDEV "struct mixer *m" "int devno"
|
|
|
|
.Ft int
|
|
|
|
.Fn MIX_ISMUTE "struct mixer *m" "int devno"
|
|
|
|
.Ft int
|
|
|
|
.Fn MIX_ISREC "struct mixer *m" "int devno"
|
|
|
|
.Ft int
|
|
|
|
.Fn MIX_ISRECSRC "struct mixer *m" "int devno"
|
|
|
|
.Ft float
|
|
|
|
.Fn MIX_VOLNORM "int v"
|
|
|
|
.Ft int
|
|
|
|
.Fn MIX_VOLDENORM "float v"
|
|
|
|
.Sh DESCRIPTION
|
|
|
|
The
|
|
|
|
.Nm mixer
|
|
|
|
library allows userspace programs to access and manipulate OSS sound mixers in
|
|
|
|
a simple way.
|
|
|
|
.Ss Mixer
|
|
|
|
A mixer is described by the following structure:
|
|
|
|
.Bd -literal
|
|
|
|
struct mixer {
|
2023-01-24 15:10:49 +01:00
|
|
|
TAILQ_HEAD(mix_devhead, mix_dev) devs; /* device list */
|
2021-09-22 15:42:51 +02:00
|
|
|
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 */
|
|
|
|
};
|
|
|
|
.Ed
|
|
|
|
.Pp
|
|
|
|
The fields are follows:
|
|
|
|
.Bl -tag -width "f_default"
|
|
|
|
.It Fa devs
|
|
|
|
A tail queue structure containing all supported mixer devices.
|
|
|
|
.It Fa dev
|
2022-03-20 20:13:00 +01:00
|
|
|
A pointer to the currently selected device.
|
|
|
|
The device is one of the elements in
|
2021-09-22 15:42:51 +02:00
|
|
|
.Ar devs .
|
|
|
|
.It Fa mi
|
2022-03-20 20:13:00 +01:00
|
|
|
OSS information about the mixer.
|
|
|
|
Look at the definition of the
|
2021-09-22 15:42:51 +02:00
|
|
|
.Ft oss_mixerinfo
|
|
|
|
structure in
|
|
|
|
.In sys/soundcard.h
|
|
|
|
to see its fields.
|
|
|
|
.It Fa ci
|
2022-03-20 20:13:00 +01:00
|
|
|
OSS audio card information.
|
|
|
|
This structure is also defined in
|
2021-09-22 15:42:51 +02:00
|
|
|
.In sys/soundcard.h .
|
|
|
|
.It Fa name
|
|
|
|
Path to the mixer (e.g /dev/mixer0).
|
|
|
|
.It Fa fd
|
|
|
|
File descriptor returned when the mixer is opened in
|
|
|
|
.Fn mixer_open .
|
|
|
|
.It Fa unit
|
2022-03-20 20:13:00 +01:00
|
|
|
Audio card unit.
|
|
|
|
Since each mixer device maps to a pcmX device,
|
2021-09-22 15:42:51 +02:00
|
|
|
.Ar unit
|
2022-03-20 20:13:00 +01:00
|
|
|
is always equal to the number of that pcmX device.
|
|
|
|
For example, if the audio device's number is 0 (i.e pcm0), then
|
2021-09-22 15:42:51 +02:00
|
|
|
.Ar unit
|
2022-03-20 20:13:00 +01:00
|
|
|
is 0 as well.
|
2024-05-23 02:57:49 +02:00
|
|
|
This number is useful when checking if the mixer's audio card is the default
|
|
|
|
one.
|
2021-09-22 15:42:51 +02:00
|
|
|
.It Fa ndev
|
|
|
|
Number of devices in
|
|
|
|
.Ar devs .
|
|
|
|
.It Fa devmask
|
2022-03-20 20:13:00 +01:00
|
|
|
Bit mask containing all supported devices for the mixer.
|
2024-05-23 02:57:49 +02:00
|
|
|
For example, if device 10 is supported, then the 10th bit in the mask will be
|
|
|
|
set.
|
2022-03-20 20:13:00 +01:00
|
|
|
By default,
|
2021-09-22 15:42:51 +02:00
|
|
|
.Fn mixer_open
|
2022-03-20 20:13:00 +01:00
|
|
|
stores only the supported devices in devs, so it is very unlikely this mask will
|
2021-09-22 15:42:51 +02:00
|
|
|
be needed.
|
|
|
|
.It Fa mutemask
|
2022-03-20 20:13:00 +01:00
|
|
|
Bit mask containing all muted devices.
|
|
|
|
The logic is the same as with
|
2021-09-22 15:42:51 +02:00
|
|
|
.Ar devmask .
|
|
|
|
.It Fa recmask
|
2022-03-20 20:13:00 +01:00
|
|
|
Bit mask containing all recording devices.
|
|
|
|
Again, same logic as with the other masks.
|
2021-09-22 15:42:51 +02:00
|
|
|
.It Fa recsrc
|
2022-03-20 20:13:00 +01:00
|
|
|
Bit mask containing all recording sources.
|
|
|
|
Yes, same logic again.
|
2021-09-22 15:42:51 +02:00
|
|
|
.It Fa mode
|
2022-03-20 20:13:00 +01:00
|
|
|
Bit mask containing the supported modes for this audio device.
|
|
|
|
It holds the value of the
|
2021-09-22 15:42:51 +02:00
|
|
|
.Ar dev.pcm.X.mode
|
|
|
|
sysctl.
|
|
|
|
.It Fa f_default
|
|
|
|
Flag which tells whether the mixer's audio card is the default one.
|
|
|
|
.El
|
|
|
|
.Ss Mixer device
|
|
|
|
Each mixer device stored in a mixer is described as follows:
|
|
|
|
.Bd -literal
|
|
|
|
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 */
|
2023-01-24 15:10:49 +01:00
|
|
|
TAILQ_HEAD(mix_ctlhead, mix_ctl) ctls; /* control list */
|
2021-09-22 15:42:51 +02:00
|
|
|
TAILQ_ENTRY(mix_dev) devs;
|
|
|
|
};
|
|
|
|
.Ed
|
|
|
|
.Pp
|
|
|
|
The fields are follows:
|
|
|
|
.Bl -tag -width "parent_mixer"
|
|
|
|
.It Fa parent_mixer
|
|
|
|
Pointer to the mixer the device is attached to.
|
|
|
|
.It Fa name
|
2022-03-20 20:13:00 +01:00
|
|
|
Device name given by the OSS API.
|
|
|
|
Devices can have one of the following names:
|
2021-09-22 15:42:51 +02:00
|
|
|
.Bd -ragged
|
|
|
|
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.
|
|
|
|
.Ed
|
|
|
|
.It Fa devno
|
|
|
|
Device's index in the SOUND_MIXER_NRDEVICES macro defined in
|
|
|
|
.In sys/soundcard.h .
|
|
|
|
This number is used to check against the masks defined in the
|
|
|
|
.Ar mixer
|
|
|
|
structure.
|
2022-03-20 20:13:00 +01:00
|
|
|
.It Fa left right
|
|
|
|
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 the
|
2021-09-22 15:42:51 +02:00
|
|
|
.Ar MIX_VOLDENORM
|
|
|
|
macro if needed.
|
|
|
|
.It Fa nctl
|
|
|
|
Number of user-defined mixer controls associated with the device.
|
|
|
|
.It Fa ctls
|
|
|
|
A tail queue containing user-defined mixer controls.
|
|
|
|
.El
|
|
|
|
.Ss User-defined mixer controls
|
2022-03-20 20:13:00 +01:00
|
|
|
Each mixer device can have user-defined controls.
|
|
|
|
The control structure is defined as follows:
|
2021-09-22 15:42:51 +02:00
|
|
|
.Bd -literal
|
|
|
|
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;
|
|
|
|
};
|
|
|
|
.Ed
|
|
|
|
.Pp
|
|
|
|
The fields are follows:
|
|
|
|
.Bl -tag -width "parent_dev"
|
|
|
|
.It Fa parent_dev
|
|
|
|
Pointer to the device the control is attached to.
|
|
|
|
.It Fa id
|
2022-03-20 20:13:00 +01:00
|
|
|
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.
|
2021-09-22 15:42:51 +02:00
|
|
|
.It Fa name
|
2022-03-20 20:13:00 +01:00
|
|
|
Control name.
|
|
|
|
As with
|
2021-09-22 15:42:51 +02:00
|
|
|
.Ar id ,
|
|
|
|
the caller has to make sure the same name is not used more than once.
|
|
|
|
.It Fa mod
|
2022-03-20 20:13:00 +01:00
|
|
|
Function pointer to a control modification function.
|
|
|
|
As in
|
2021-09-22 15:42:51 +02:00
|
|
|
.Xr mixer 8 ,
|
2022-03-20 20:13:00 +01:00
|
|
|
each mixer control's values can be modified.
|
|
|
|
For example, if we have a volume control, the
|
2021-09-22 15:42:51 +02:00
|
|
|
.Ar mod
|
|
|
|
function will be responsible for handling volume changes.
|
|
|
|
.It Fa print
|
|
|
|
Function pointer to a control print function.
|
|
|
|
.El
|
|
|
|
.Ss Opening and closing the mixer
|
|
|
|
The application must first call the
|
|
|
|
.Fn mixer_open
|
2022-03-20 20:13:00 +01:00
|
|
|
function to obtain a handle to the device, which is used as an argument \
|
|
|
|
in most other functions and macros.
|
|
|
|
The parameter
|
2021-09-22 15:42:51 +02:00
|
|
|
.Ar name
|
2022-03-20 20:13:00 +01:00
|
|
|
specifies the path to the mixer.
|
|
|
|
OSS mixers are stored under
|
2021-09-22 15:42:51 +02:00
|
|
|
.Ar /dev/mixerN
|
|
|
|
where
|
|
|
|
.Ar N
|
2022-03-20 20:13:00 +01:00
|
|
|
is the number of the mixer device.
|
|
|
|
Each device maps to an actual
|
2021-09-22 15:42:51 +02:00
|
|
|
.Ar pcm
|
|
|
|
audio card, so
|
|
|
|
.Ar /dev/mixer0
|
|
|
|
is the mixer for
|
|
|
|
.Ar pcm0 ,
|
2022-03-20 20:13:00 +01:00
|
|
|
and so on.
|
|
|
|
If
|
2021-09-22 15:42:51 +02:00
|
|
|
.Ar name
|
|
|
|
is
|
|
|
|
.Ar NULL
|
|
|
|
or
|
|
|
|
.Ar /dev/mixer ,
|
|
|
|
.Fn mixer_open
|
2022-03-18 12:08:55 +01:00
|
|
|
opens the default mixer (hw.snd.default_unit).
|
2021-09-22 15:42:51 +02:00
|
|
|
.Pp
|
|
|
|
The
|
|
|
|
.Fn mixer_close
|
2022-03-20 20:13:00 +01:00
|
|
|
function frees resources and closes the mixer device.
|
2024-05-23 02:57:49 +02:00
|
|
|
It is a good practice to always call it when the application is done using the
|
|
|
|
mixer.
|
2021-09-22 15:42:51 +02:00
|
|
|
.Ss Manipulating the mixer
|
|
|
|
The
|
|
|
|
.Fn mixer_get_dev
|
|
|
|
and
|
|
|
|
.Fn mixer_get_dev_byname
|
2024-05-23 02:57:49 +02:00
|
|
|
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.
|
2021-09-22 15:42:51 +02:00
|
|
|
.Pp
|
|
|
|
The
|
|
|
|
.Fn mixer_set_vol
|
2022-03-20 20:13:00 +01:00
|
|
|
function changes the volume of the selected mixer device.
|
|
|
|
The
|
2021-09-22 15:42:51 +02:00
|
|
|
.Ar vol
|
2024-05-23 02:57:49 +02:00
|
|
|
parameter is a structure that stores the left and right volumes of a given
|
|
|
|
device.
|
2022-03-20 20:13:00 +01:00
|
|
|
The allowed volume values are between MIX_VOLMIN (0.0) and MIX_VOLMAX (1.0).
|
2021-09-22 15:42:51 +02:00
|
|
|
.Pp
|
|
|
|
The
|
|
|
|
.Fn mixer_set_mute
|
2022-03-20 20:13:00 +01:00
|
|
|
function modifies the mute of a selected device.
|
|
|
|
The
|
2021-09-22 15:42:51 +02:00
|
|
|
.Ar opt
|
|
|
|
parameter has to be one of the following options:
|
|
|
|
.Bl -tag -width MIX_TOGGLEMUTE -offset indent
|
|
|
|
.It Dv MIX_MUTE
|
|
|
|
Mute the device.
|
|
|
|
.It Dv MIX_UNMUTE
|
|
|
|
Unmute the device.
|
|
|
|
.It Dv MIX_TOGGLEMUTE
|
|
|
|
Toggle the device's mute (e.g mute if unmuted and unmute if muted).
|
|
|
|
.El
|
|
|
|
.Pp
|
|
|
|
The
|
|
|
|
.Fn mixer_mod_recsrc
|
2022-03-20 20:13:00 +01:00
|
|
|
function modifies a recording device.
|
2024-05-23 02:57:49 +02:00
|
|
|
The selected device has to be a recording device, otherwise the function will
|
|
|
|
fail.
|
2022-03-20 20:13:00 +01:00
|
|
|
The
|
2021-09-22 15:42:51 +02:00
|
|
|
.Ar opt
|
|
|
|
parameter has to be one of the following options:
|
|
|
|
.Bl -tag -width MIX_REMOVERECSRC -offset indent
|
|
|
|
.It Dv MIX_ADDRECSRC
|
|
|
|
Add device to the recording sources.
|
|
|
|
.It Dv MIX_REMOVERECSRC
|
|
|
|
Remove device from the recording sources.
|
|
|
|
.It Dv MIX_SETRECSRC
|
|
|
|
Set device as the only recording source.
|
|
|
|
.It Dv MIX_TOGGLERECSRC
|
|
|
|
Toggle device from the recording sources.
|
|
|
|
.El
|
|
|
|
.Pp
|
|
|
|
The
|
|
|
|
.Fn mixer_get_dunit
|
|
|
|
and
|
|
|
|
.Fn mixer_set_dunit
|
2022-03-20 20:13:00 +01:00
|
|
|
functions get and set the default audio card in the system.
|
|
|
|
Although this is not really a mixer feature, it is useful to have instead of \
|
|
|
|
having to use the
|
2021-09-22 15:42:51 +02:00
|
|
|
.Xr sysctl 3
|
|
|
|
controls.
|
|
|
|
.Pp
|
|
|
|
The
|
|
|
|
.Fn mixer_get_mode
|
2022-03-20 20:13:00 +01:00
|
|
|
function returns the playback/recording mode of the audio device the mixer \
|
|
|
|
belongs to.
|
|
|
|
The available values are the following:
|
2021-09-22 15:42:51 +02:00
|
|
|
.Bl -tag -width "MIX_STATUS_PLAY | MIX_STATUS_REC" -offset indent
|
|
|
|
.It Dv MIX_STATUS_NONE
|
|
|
|
Neither playback nor recording.
|
|
|
|
.It Dv MIX_STATUS_PLAY
|
|
|
|
Playback.
|
|
|
|
.It Dv MIX_STATUS_REC
|
|
|
|
Recording.
|
|
|
|
.It Dv MIX_STATUS_PLAY | MIX_STATUS_REC
|
|
|
|
Playback and recording.
|
|
|
|
.El
|
|
|
|
.Pp
|
|
|
|
The
|
|
|
|
.Fn mixer_get_nmixers
|
sound: Handle unavailable devices in various OSS IOCTLs
mixer(8)'s -a option is used to print information about all mixer
devices in the system. To do this, it loops from 0 to
mixer_get_nmixers(), and tries to open "/dev/mixer%d". However, this
approach doesn't work when there are disabled/unregistered mixers in the
system, or when an audio device simply doesn't have a mixer.
mixer_get_nmixers() calls SNDCTL_SYSINFO and returns
oss_sysinfo->nummixers, whose value is the number of currently _enabled_
mixers only. Taking the bug report mentioned below (277615) as an
example, suppose a system with 8 mixer devices total, but 3 of them are
either disabled or non-existent, which means they will not show up under
/dev, meaning we have 5 enabled mixer devices, which is also what the
value of oss_sysinfo->nummixers will be. What mixer(8) will do is loop
from 0 to 5 (instead of 8), and start calling mixer_open() on
/dev/mixer0, up to /dev/mixer4, and as is expected, the first call will
fail right away, hence the error shown in the bug report.
To fix this, modify oss_sysinfo->nummixers to hold the value of the
maximum unit in the system, which, although not necessarily "correct",
is more intuitive for applications that will want to use this value to
loop through all mixer devices.
Additionally, notify applications that a device is
unavailable/unregistered instead of skipping it. The current
implementations of SNDCTL_AUDIOINFO, SNDCTL_MIXERINFO and
SNDCTL_CARDINFO break applications that expect to get information about
a device that is skipped. Related discussion can be found here:
https://reviews.freebsd.org/D45135#1029526
It has to be noted, that other applications, apart from mixer(8), suffer
from this.
PR: 277615
Sponsored by: The FreeBSD Foundation
MFC after: 1 day
Reviewed by: dev_submerge.ch
Differential Revision: https://reviews.freebsd.org/D45256
2024-05-23 02:57:17 +02:00
|
|
|
function returns the maximum mixer unit number.
|
|
|
|
Although this might sound as incorrect behavior, given that one would expect
|
|
|
|
"nmixers" to refer to the total number of active mixers, it is more intuitive
|
2024-05-23 02:57:36 +02:00
|
|
|
for applications that want to loop through all mixer devices (see the
|
|
|
|
.Sx EXAMPLES
|
|
|
|
section).
|
|
|
|
.Pp
|
|
|
|
The
|
|
|
|
.Fn mixer_get_path
|
|
|
|
function writes the path of the mixer device specified in the
|
|
|
|
.Ar unit
|
|
|
|
argument to the buffer specified in
|
|
|
|
.Ar buf .
|
|
|
|
.Ar unit
|
|
|
|
can be either -1, in which case
|
|
|
|
.Fn mixer_get_path
|
|
|
|
will fetch the path of the default mixer, or between 0 and the maximum mixer
|
|
|
|
unit.
|
2021-09-22 15:42:51 +02:00
|
|
|
.Pp
|
|
|
|
The
|
|
|
|
.Fn MIX_ISDEV
|
2022-03-20 20:13:00 +01:00
|
|
|
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.
|
2021-09-22 15:42:51 +02:00
|
|
|
.Pp
|
|
|
|
The
|
|
|
|
.Fn MIX_ISMUTE
|
|
|
|
macro checks if a device is muted.
|
|
|
|
.Pp
|
|
|
|
The
|
|
|
|
.Fn MIX_ISREC
|
|
|
|
macro checks if a device is a recording device.
|
|
|
|
.Pp
|
|
|
|
The
|
|
|
|
.Fn MIX_ISRECSRC
|
|
|
|
macro checks if a device is a recording source.
|
|
|
|
.Pp
|
|
|
|
The
|
|
|
|
.Fn MIX_VOLNORM
|
2022-03-20 20:13:00 +01:00
|
|
|
macro normalizes a value to 32-bit floating point number.
|
|
|
|
It is used to normalize the volumes read from the OSS API.
|
2021-09-22 15:42:51 +02:00
|
|
|
.Pp
|
|
|
|
The
|
|
|
|
.Fn MIX_VOLDENORM
|
|
|
|
macro denormalizes the left and right volumes stores in the
|
|
|
|
.Ft mix_dev
|
|
|
|
structure.
|
|
|
|
.Ss Defining and using mixer controls
|
|
|
|
The
|
|
|
|
.Fn mix_add_ctl
|
|
|
|
function creates a control and attaches it to the device specified in the
|
|
|
|
.Ar parent
|
|
|
|
argument.
|
|
|
|
.Pp
|
|
|
|
The
|
|
|
|
.Fn mix_add_ctl_s
|
|
|
|
function does the same thing as with
|
|
|
|
.Fn mix_add_ctl
|
|
|
|
but the caller passes a
|
|
|
|
.Ft mix_ctl_t *
|
2022-03-20 20:13:00 +01:00
|
|
|
structure instead of each field as a separate argument.
|
2021-09-22 15:42:51 +02:00
|
|
|
.Pp
|
|
|
|
The
|
|
|
|
.Fn mixer_remove_ctl
|
|
|
|
functions removes a control from the device its attached to.
|
|
|
|
.Pp
|
|
|
|
The
|
|
|
|
.Fn mixer_get_ctl
|
|
|
|
function searches for a control in the device specified in the
|
|
|
|
.Ar d
|
2022-03-20 20:13:00 +01:00
|
|
|
argument and returns a pointer to it.
|
|
|
|
The search is done using the control's ID.
|
2021-09-22 15:42:51 +02:00
|
|
|
.Pp
|
|
|
|
The
|
|
|
|
.Fn mixer_get_ctl_byname
|
|
|
|
function is the same as with
|
|
|
|
.Fn mixer_get_ctl
|
|
|
|
but the search is done using the control's name.
|
|
|
|
.Sh RETURN VALUES
|
|
|
|
The
|
|
|
|
.Fn mixer_open
|
|
|
|
function returns the newly created handle on success and NULL on failure.
|
|
|
|
.Pp
|
|
|
|
The
|
|
|
|
.Fn mixer_close ,
|
|
|
|
.Fn mixer_set_vol ,
|
|
|
|
.Fn mixer_set_mute ,
|
|
|
|
.Fn mixer_mod_recsrc ,
|
|
|
|
.Fn mixer_get_dunut ,
|
2024-05-23 02:57:36 +02:00
|
|
|
.Fn mixer_set_dunit ,
|
|
|
|
.Fn mixer_get_nmixers ,
|
2021-09-22 15:42:51 +02:00
|
|
|
and
|
2024-05-23 02:57:36 +02:00
|
|
|
.Fn mixer_get_path
|
2021-09-22 15:42:51 +02:00
|
|
|
functions return 0 or positive values on success and -1 on failure.
|
|
|
|
.Pp
|
|
|
|
The
|
|
|
|
.Fn mixer_get_dev
|
|
|
|
and
|
|
|
|
.Fn mixer_get_dev_byname
|
|
|
|
functions return the selected device on success and NULL on failure.
|
|
|
|
.Pp
|
|
|
|
All functions set the value of
|
|
|
|
.Ar errno
|
|
|
|
on failure.
|
|
|
|
.Sh EXAMPLES
|
|
|
|
.Ss Change the volume of a device
|
|
|
|
.Bd -literal
|
|
|
|
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);
|
|
|
|
.Ed
|
|
|
|
.Ss Mute all unmuted devices
|
|
|
|
.Bd -literal
|
|
|
|
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);
|
|
|
|
.Ed
|
|
|
|
.Ss Print all recording sources' names and volumes
|
|
|
|
.Bd -literal
|
|
|
|
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);
|
|
|
|
.Ed
|
2024-05-23 02:57:36 +02:00
|
|
|
.Ss Loop through all mixer devices in the system
|
|
|
|
.Bd -literal
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
.Ed
|
2021-09-22 15:42:51 +02:00
|
|
|
.Sh SEE ALSO
|
2022-03-20 20:13:00 +01:00
|
|
|
.Xr queue 3 ,
|
2021-09-22 15:42:51 +02:00
|
|
|
.Xr sysctl 3 ,
|
2022-03-20 20:13:00 +01:00
|
|
|
.Xr sound 4 ,
|
|
|
|
.Xr mixer 8
|
2021-09-22 15:42:51 +02:00
|
|
|
and
|
|
|
|
.Xr errno 2
|
|
|
|
.Sh AUTHORS
|
2021-09-22 22:01:12 +02:00
|
|
|
.An Christos Margiolis Aq Mt christos@FreeBSD.org
|