AUDIO(9) | Kernel Developer's Manual | AUDIO(9) |
audio
— interface
between low and high level audio drivers
The audio device driver is divided into a high level, hardware independent layer, and a low level, hardware dependent layer. The interface between these is the audio_hw_if structure.
struct audio_hw_if { int (*open)(void *, int); void (*close)(void *); int (*set_params)(void *, int, int, struct audio_params *, struct audio_params *); int (*round_blocksize)(void *, int); int (*commit_settings)(void *); int (*init_output)(void *, void *, int); int (*init_input)(void *, void *, int); int (*start_output)(void *, void *, int, void (*)(void *), void *); int (*start_input)(void *, void *, int, void (*)(void *), void *); int (*halt_output)(void *); int (*halt_input)(void *); int (*speaker_ctl)(void *, int); #define SPKR_ON 1 #define SPKR_OFF 0 int (*setfd)(void *, int); int (*set_port)(void *, struct mixer_ctrl *); int (*get_port)(void *, struct mixer_ctrl *); int (*query_devinfo)(void *, struct mixer_devinfo *); void *(*allocm)(void *, int, size_t, int, int); void (*freem)(void *, void *, int); size_t (*round_buffersize)(void *, int, size_t); int (*get_props)(void *); int (*trigger_output)(void *, void *, void *, int, void (*)(void *), void *, struct audio_params *); int (*trigger_input)(void *, void *, void *, int, void (*)(void *), void *, struct audio_params *); void (*copy_output)(void *hdl, size_t bytes); void (*underrun)(void *hdl); int (*set_blksz)(void *, int, struct audio_params *, struct audio_params *, int); int (*set_nblks)(void *, int, int, struct audio_params *, int); }; struct audio_params { u_long sample_rate; /* sample rate */ u_int encoding; /* mu-law, linear, etc */ u_int precision; /* bits/sample */ u_int bps; /* bytes/sample */ u_int msb; /* data alignment */ u_int channels; /* mono(1), stereo(2) */ };
The high level audio driver attaches to the
low level driver when the latter calls
audio_attach_mi
().
This call is:
struct device * audio_attach_mi(struct audio_hw_if *ahwp, void *hdl, struct device *dev);
The audio_hw_if struct is as shown above. The hdl argument is a handle to some low level data structure. It is sent as the first argument to all the functions in ahwp when the high level driver calls them. dev is the device struct for the hardware device.
The upper layer of the audio driver allocates one buffer for playing and one for recording. It handles the buffering of data from the user processes in these. The data is presented to the lower level in smaller chunks, called blocks. During playback, if there is no data available from the user process when the hardware requests another block, a block of silence will be used instead. Similarly, if the user process does not read data quickly enough during recording, data will be thrown away.
The fields of audio_hw_if are described in
some more detail below. Some fields are optional and can be set to
NULL
if not needed.
(*open)
(void *hdl,
int flags)OFLAGS
and FFLAGS
in
<sys/fcntl.h>
). It
initializes the hardware for I/O. Every successful call to
open
() is
matched by a call to
close
().
This function returns 0 on success, otherwise an error code.(*close)
(void *hdl)(*set_params)
(void *hdl,
int setmode, int usemode,
struct audio_params *play, struct
audio_params *rec)AUMODE_RECORD
and
AUMODE_PLAY
flags to indicate which mode(s) are to
be set. usemode is also a combination of these
flags, but indicates the current mode of the device (i.e., the value
corresponding to the flags argument to the
open
() function). The play
and rec structures contain the encoding parameters
that will be set. The values of the structures must also be modified if
the hardware cannot be set to exactly the requested mode (e.g., if the
requested sampling rate is not supported, but one close enough is). Except
the channel count, the same value is passed in both
play and rec.
The machine independent audio driver does some preliminary
parameter checking; it verifies that the precision is compatible with
the encoding, and it translates
AUDIO_ENCODING_[US]LINEAR
to
AUDIO_ENCODING_[US]LINEAR_{LE,BE}
.
This function returns 0 on success, otherwise an error code.
(*round_blocksize)
(void *hdl,
int bs)(*commit_settings)
(void
*hdl)set_params
()
and
set_port
()
are done. A hardware driver that needs to get the hardware in and out of
command mode for each change can save all the changes during previous
calls and do them all here. This function returns 0 on success, otherwise
an error code.(*init_output)
(void *hdl,
void *buffer, int size)(*init_input)
(void *hdl,
void *buffer, int size)(*start_output)
(void *hdl,
void *block, int bsize,
void (*intr)(void *), void
*intrarg)start_output
().
This function returns 0 on success, otherwise an error code.(*start_input)
(void *hdl,
void *block, int bsize,
void (*intr)(void *), void
*intrarg)start_input
().
This function returns 0 on success, otherwise an error code.(*halt_output)
(void *hdl)start_output
()) in progress. This function returns
0 on success, otherwise an error code.(*halt_input)
(void *hdl)start_input
()) in progress. This function returns
0 on success, otherwise an error code.(*speaker_ctl)
(void *hdl,
int on)(*setfd)
(void *hdl,
int fd)AUDIO_PROP_FULLDUPLEX
set. This function returns 0
on success, otherwise an error code.(*set_port)
(void *hdl,
struct mixer_ctrl *mc)AUDIO_MIXER_WRITE
ioctl(2) is used. It takes
data from mc and sets the corresponding mixer
values. This function returns 0 on success, otherwise an error code.(*get_port)
(void *hdl,
struct mixer_ctrl *mc)AUDIO_MIXER_READ
ioctl(2) is used. It fills
mc and returns 0 on success, or it returns an error
code on failure.(*query_devinfo)
(void *hdl,
struct mixer_devinfo *di)AUDIO_MIXER_DEVINFO
ioctl(2) is used. It fills
di and returns 0 on success, or it returns an error
code on failure.(*allocm)
(void *hdl,
int direction, size_t size,
int type, int flags)AUMODE_PLAY
or
AUMODE_RECORD
. This function returns the address
of the buffer on success, or 0 on failure.(*freem)
(void *hdl,
void *addr, int type)allocm
().
If not supplied, free(9) is
used instead.(*round_buffersize)
(void *hdl,
int direction, size_t
bufsize)round_blocksize
()
and
round_buffersize
()
must be consistent.(*get_props)
(void *hdl)AUDIO_PROP_xxx
properties.(*trigger_output)
(void *hdl,
void *start, void *end,
int blksize, void (*intr)(void
*), void *intrarg, struct
audio_params *param)halt_output
().
This function returns 0 on success, otherwise an error code.(*trigger_input)
(void *hdl,
void *start, void *end,
int blksize, void (*intr)(void
*), void *intrarg, struct
audio_params *param)halt_input
().
This function returns 0 on success, otherwise an error code.(*copy_output)
(void *hdl,
size_t bytes)(*underrun)
(void *hdl)(*set_blksz)
(void *hdl,
int mode, struct audio_params
*play, struct audio_params *rec,
int blksz)AUMODE_RECORD
and
AUMODE_PLAY
flags indicating the current mode set
with the open
() function. The
play and rec structures
contain the current encoding set with the
set_params
() function. blksz
is the desired block size in frames. It may be adjusted to match hardware
constraints. This function returns the adjusted block size.(*set_nblks)
(void *hdl,
int dir, int blksz,
struct audio_params *params, int
nblks)AUMODE_RECORD
or the
AUMODE_PLAY
flag, indicating which ring buffer
size is set. The params structure contains the
encoding parameters set by the set_params
()
method. blksz is the current block size in frames
set with the set_params function. The
params structure is the current encoding parameters,
set with the set_params
() function.
nblks is the desired number of blocks in the ring
buffer. It may be lowered to at least two, to match hardware constraints.
This function returns the adjusted number of blocks.If the audio hardware is capable of input from more than one
source it should define AudioNsource
in class
AudioCrecord
. This mixer control should be of type
AUDIO_MIXER_ENUM
or
AUDIO_MIXER_SET
and enumerate the possible input
sources. For each of the named sources there should be a control in the
AudioCinputs
class of type
AUDIO_MIXER_VALUE
if recording level of the source
can be set. If the overall recording level can be changed (i.e., regardless
of the input source) then this control should be named
AudioNrecord
and be of class
AudioCinputs
.
If the audio hardware is capable of output to more than one
destination it should define AudioNoutput
in class
AudioCmonitor
. This mixer control should be of type
AUDIO_MIXER_ENUM
or
AUDIO_MIXER_SET
and enumerate the possible
destinations. For each of the named destinations there should be a control
in the AudioCoutputs
class of type
AUDIO_MIXER_VALUE
if output level of the destination
can be set. If the overall output level can be changed (i.e., regardless of
the destination) then this control should be named
AudioNmaster
and be of class
AudioCoutputs
.
ioctl(2), open(2), sio_open(3), audio(4), free(9), malloc(9)
This audio
interface first appeared in
OpenBSD 1.2.
September 13, 2019 | OpenBSD-6.7 |