470 lines
15 KiB
Groff
470 lines
15 KiB
Groff
.\" $NetBSD: audio.9,v 1.16 2000/07/24 15:00:07 ad Exp $
|
|
.\"
|
|
.\" Copyright (c) 1999, 2000 The NetBSD Foundation, Inc.
|
|
.\" All rights reserved.
|
|
.\"
|
|
.\" This code is derived from software contributed to The NetBSD Foundation
|
|
.\" by Lennart Augustsson.
|
|
.\"
|
|
.\" Redistribution and use in source and binary forms, with or without
|
|
.\" modification, are permitted provided that the following conditions
|
|
.\" are met:
|
|
.\" 1. Redistributions of source code must retain the above copyright
|
|
.\" notice, this list of conditions and the following disclaimer.
|
|
.\" 2. Redistributions in binary form must reproduce the above copyright
|
|
.\" notice, this list of conditions and the following disclaimer in the
|
|
.\" documentation and/or other materials provided with the distribution.
|
|
.\" 3. All advertising materials mentioning features or use of this software
|
|
.\" must display the following acknowledgement:
|
|
.\" This product includes software developed by the NetBSD
|
|
.\" Foundation, Inc. and its contributors.
|
|
.\" 4. Neither the name of The NetBSD Foundation nor the names of its
|
|
.\" contributors may be used to endorse or promote products derived
|
|
.\" from this software without specific prior written permission.
|
|
.\"
|
|
.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
|
.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
|
.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
.\" POSSIBILITY OF SUCH DAMAGE.
|
|
.\"
|
|
.Dd February 11, 2000
|
|
.Dt AUDIO 9
|
|
.Os
|
|
.Sh NAME
|
|
.Nm audio
|
|
.Nd interface between low and high level audio drivers
|
|
.Sh DESCRIPTION
|
|
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
|
|
.Va audio_hw_if
|
|
structure.
|
|
.Bd -literal
|
|
struct audio_hw_if {
|
|
int (*open)__P((void *, int));
|
|
void (*close)__P((void *));
|
|
int (*drain)__P((void *));
|
|
|
|
int (*query_encoding)__P((void *, struct audio_encoding *));
|
|
int (*set_params)__P((void *, int, int,
|
|
struct audio_params *, struct audio_params *));
|
|
int (*round_blocksize)__P((void *, int));
|
|
|
|
int (*commit_settings)__P((void *));
|
|
|
|
int (*init_output)__P((void *, void *, int));
|
|
int (*init_input)__P((void *, void *, int));
|
|
int (*start_output)__P((void *, void *, int,
|
|
void (*)(void *), void *));
|
|
int (*start_input)__P((void *, void *, int,
|
|
void (*)(void *), void *));
|
|
int (*halt_output)__P((void *));
|
|
int (*halt_input)__P((void *));
|
|
|
|
int (*speaker_ctl)__P((void *, int));
|
|
#define SPKR_ON 1
|
|
#define SPKR_OFF 0
|
|
|
|
int (*getdev)__P((void *, struct audio_device *));
|
|
int (*setfd)__P((void *, int));
|
|
|
|
int (*set_port)__P((void *, mixer_ctrl_t *));
|
|
int (*get_port)__P((void *, mixer_ctrl_t *));
|
|
|
|
int (*query_devinfo)__P((void *, mixer_devinfo_t *));
|
|
|
|
void *(*allocm)__P((void *, int, size_t, int, int));
|
|
void (*freem)__P((void *, void *, int));
|
|
size_t (*round_buffersize)__P((void *, int, size_t));
|
|
int (*mappage)__P((void *, void *, int, int));
|
|
|
|
int (*get_props)__P((void *));
|
|
|
|
int (*trigger_output)__P((void *, void *, void *, int,
|
|
void (*)(void *), void *, struct audio_params *));
|
|
int (*trigger_input)__P((void *, void *, void *, int,
|
|
void (*)(void *), void *, struct audio_params *));
|
|
};
|
|
|
|
struct audio_params {
|
|
u_long sample_rate; /* sample rate */
|
|
u_int encoding; /* ulaw, linear, etc */
|
|
u_int precision; /* bits/sample */
|
|
u_int channels; /* mono(1), stereo(2) */
|
|
/* Software en/decode functions, set if SW coding required by HW */
|
|
void (*sw_code)__P((void *, u_char *, int));
|
|
int factor; /* coding space change */
|
|
};
|
|
.Ed
|
|
.Pp
|
|
The high level audio driver attaches to the low level driver
|
|
when the latter calls
|
|
.Va audio_attach_mi .
|
|
This call should be
|
|
.Bd -literal
|
|
void
|
|
audio_attach_mi(ahwp, hdl, dev)
|
|
struct audio_hw_if *ahwp;
|
|
void *hdl;
|
|
struct device *dev;
|
|
.Ed
|
|
.Pp
|
|
The
|
|
.Va audio_hw_if
|
|
struct is as shown above. The
|
|
.Va hdl
|
|
argument is a handle to some low level data structure.
|
|
It is sent as the first argument to all the functions
|
|
in
|
|
.Va audio_hw_if
|
|
when the high level driver calls them.
|
|
.Va dev
|
|
is the device struct for the hardware device.
|
|
.Pp
|
|
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. If there, during playback, is
|
|
no data available from the user process when the hardware request
|
|
another block a block of silence will be used instead. Furthermore,
|
|
if the user process does not read data quickly enough during recording
|
|
data will be thrown away.
|
|
.Pp
|
|
The fields of
|
|
.Va audio_hw_if
|
|
are described in some more detail below.
|
|
Some fields are optional and can be set to 0 if not needed.
|
|
.Bl -tag -width indent
|
|
.It Dv int open(void *hdl, int flags)
|
|
is called when the audio device is opened. It should initialize
|
|
the hardware for I/O. Every successful call to
|
|
.Va open
|
|
is matched by a call to
|
|
.Va close .
|
|
Return 0 on success, otherwise an error code.
|
|
.It Dv void close(void *hdl)
|
|
is called when the audio device is closed.
|
|
.It Dv int drain(void *hdl)
|
|
optional, is called before the device is closed or when
|
|
.Dv AUDIO_DRAIN
|
|
is called. It should make sure that no samples remain
|
|
in to be played that could be lost when
|
|
.Va close
|
|
is called.
|
|
Return 0 on success, otherwise an error code.
|
|
.It Dv int query_encoding(void *hdl, struct audio_encoding *ae)
|
|
is used when
|
|
.Dv AUDIO_GETENC
|
|
is called. It should fill the
|
|
.Va audio_encoding
|
|
structure and return 0 or, if there is no encoding with the
|
|
given number, return EINVAL.
|
|
.It Dv int set_params(void *hdl, int setmode, int usemode,
|
|
.Dv "struct audio_params *play, struct audio_params *rec)"
|
|
.br
|
|
Called to set the audio encoding mode.
|
|
.Va setmode
|
|
is a combination of the
|
|
.Dv AUMODE_RECORD
|
|
and
|
|
.Dv AUMODE_PLAY
|
|
flags to indicate which mode(s) are to be set.
|
|
.Va usemode
|
|
is also a combination of these flags, but indicates the current
|
|
mode of the device (i.e. the value of
|
|
.Va mode
|
|
in the
|
|
.Va audio_info
|
|
struct).
|
|
The
|
|
.Va play
|
|
and
|
|
.Va rec
|
|
structures contain the encoding parameters that should be set.
|
|
If the hardware requires software assistance with some encoding
|
|
(e.g., it might be lacking mulaw support) it should fill the
|
|
.Va sw_code
|
|
and
|
|
.Va factor
|
|
fields of these structures.
|
|
The values of the structures may 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).
|
|
If the device does not have the
|
|
.Dv AUDIO_PROP_INDEPENDENT
|
|
property the same value is passed in both
|
|
.Va play
|
|
and
|
|
.Va rec
|
|
and the encoding parameters from
|
|
.Va play
|
|
is copied into
|
|
.Va rec
|
|
after the call to
|
|
.Va set_params .
|
|
Return 0 on success, otherwise an error code.
|
|
.It Dv int round_blocksize(void *hdl, int bs)
|
|
optional, is called with the block size,
|
|
.Va bs ,
|
|
that has been computed by the upper layer. It should return
|
|
a block size, possibly changed according to the needs of the
|
|
hardware driver.
|
|
.It Dv int commit_settings(void *hdl)
|
|
optional, is called after all calls to
|
|
.Va set_params ,
|
|
and
|
|
.Va 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.
|
|
Return 0 on success, otherwise an error code.
|
|
.It Dv int init_output(void *hdl, void *buffer, int size)
|
|
optional, is called before any output starts, but when the total
|
|
.Va size
|
|
of the output
|
|
.Va buffer
|
|
has been determined. It can be used to initialize looping DMA
|
|
for hardware that needs that.
|
|
Return 0 on success, otherwise an error code.
|
|
.It Dv int init_input(void *hdl, void *buffer, int size)
|
|
optional, is called before any input starts, but when the total
|
|
.Va size
|
|
of the input
|
|
.Va buffer
|
|
has been determined. It can be used to initialize looping DMA
|
|
for hardware that needs that.
|
|
Return 0 on success, otherwise an error code.
|
|
.It Dv int start_output(void *hdl, void *block, int blksize,
|
|
.Dv "void (*intr)(void*), void *intrarg)"
|
|
.br
|
|
is called to start the transfer of
|
|
.Va blksize
|
|
bytes from
|
|
.Va block
|
|
to the audio hardware. The call should return when the data
|
|
transfer has been initiated (normally with DMA). When the
|
|
hardware is ready to accept more samples the function
|
|
.Va intr
|
|
should be called with the argument
|
|
.Va intrarg .
|
|
Calling
|
|
.Va intr
|
|
will normally initiate another call to
|
|
.Va start_output .
|
|
Return 0 on success, otherwise an error code.
|
|
.It Dv int start_input(void *hdl, void *block, int blksize,
|
|
.Dv "void (*intr)(void*), void *intrarg)"
|
|
.br
|
|
is called to start the transfer of
|
|
.Va blksize
|
|
bytes to
|
|
.Va block
|
|
from the audio hardware. The call should return when the data
|
|
transfer has been initiated (normally with DMA). When the
|
|
hardware is ready to deliver more samples the function
|
|
.Va intr
|
|
should be called with the argument
|
|
.Va intrarg .
|
|
Calling
|
|
.Va intr
|
|
will normally initiate another call to
|
|
.Va start_input.
|
|
Return 0 on success, otherwise an error code.
|
|
.It Dv int halt_output(void *hdl)
|
|
is called to abort the output transfer (started by
|
|
.Va start_output )
|
|
in progress.
|
|
Return 0 on success, otherwise an error code.
|
|
.It Dv int halt_input(void *hdl)
|
|
is called to abort the input transfer (started by
|
|
.Va start_input )
|
|
in progress.
|
|
Return 0 on success, otherwise an error code.
|
|
.It Dv int speaker_ctl(void *hdl, int on)
|
|
optional, is called when a half duplex device changes between
|
|
playing and recording. It can, e.g., be used to turn on
|
|
and off the speaker.
|
|
Return 0 on success, otherwise an error code.
|
|
.It Dv int getdev(void *hdl, struct audio_device *ret)
|
|
Should fill the
|
|
.Va audio_device
|
|
struct with relevant information about the driver.
|
|
Return 0 on success, otherwise an error code.
|
|
.It Dv int setfd(void *hdl, int fd)
|
|
optional, is called when
|
|
.Dv AUDIO_SETFD
|
|
is used, but only if the device has AUDIO_PROP_FULLDUPLEX set.
|
|
Return 0 on success, otherwise an error code.
|
|
.It Dv int set_port(void *hdl, mixer_ctl_t *mc)
|
|
is called in when
|
|
.Dv AUDIO_MIXER_WRITE
|
|
is used. It should take data from the
|
|
.Va mixer_ctl_t
|
|
struct at set the corresponding mixer values.
|
|
Return 0 on success, otherwise an error code.
|
|
.It Dv int get_port(void *hdl, mixer_ctl_t *mc)
|
|
is called in when
|
|
.Dv AUDIO_MIXER_READ
|
|
is used. It should fill the
|
|
.Va mixer_ctl_t
|
|
struct.
|
|
Return 0 on success, otherwise an error code.
|
|
.It Dv int query_devinfo(void *hdl, mixer_devinfo_t *di)
|
|
is called in when
|
|
.Dv AUDIO_MIXER_DEVINFO
|
|
is used. It should fill the
|
|
.Va mixer_devinfo_t
|
|
struct.
|
|
Return 0 on success, otherwise an error code.
|
|
.It Dv "void *allocm(void *hdl, int direction, size_t size, int type, int flags)"
|
|
.br
|
|
optional, is called to allocate the device buffers. If not present
|
|
.Xr malloc 9
|
|
is used instead (with the same arguments but the first two).
|
|
The reason for using a device dependent routine instead of
|
|
.Xr malloc 9
|
|
is that some buses need special allocation to do DMA.
|
|
Returns the address of the buffer, or 0 on failure.
|
|
.It Dv void freem(void *hdl, void *addr, int type)
|
|
optional, is called to free memory allocated by
|
|
.Va alloc .
|
|
If not supplied
|
|
.Xr free 9
|
|
is used.
|
|
.It Dv size_t round_buffersize(void *hdl, int direction, size_t bufsize)
|
|
optional, is called at startup to determine the audio
|
|
buffer size. The upper layer supplies the suggested
|
|
size in
|
|
.Va bufsize ,
|
|
which the hardware driver can then change if needed.
|
|
E.g., DMA on the ISA bus cannot exceed 65536 bytes.
|
|
.It Dv "int mappage(void *hdl, void *addr, int offs, int prot)"
|
|
.br
|
|
optional, is called for
|
|
.Xr mmap 2 .
|
|
Should return the map value for the page at offset
|
|
.Va offs
|
|
from address
|
|
.Va addr
|
|
mapped with protection
|
|
.Va prot .
|
|
Returns -1 on failure, or a machine dependent opaque value
|
|
on success.
|
|
.It Dv int get_props(void *hdl)
|
|
Should return the device properties; i.e. a combination of
|
|
AUDIO_PROP_xxx.
|
|
.It Dv int trigger_output(void *hdl, void *start, void *end,
|
|
.Dv "int blksize, void (*intr)(void*), void *intrarg,"
|
|
.br
|
|
.Dv "stuct audio_params *param)"
|
|
.br
|
|
optional, is called to start the transfer of data from the circular buffer
|
|
delimited by
|
|
.Va start
|
|
and
|
|
.Va end
|
|
to the audio hardware, parameterized as in
|
|
.Va param .
|
|
The call should return when the data transfer has been initiated
|
|
(normally with DMA). When the hardware is finished transferring
|
|
each
|
|
.Va blksize
|
|
sized block, the function
|
|
.Va intr
|
|
should be called with the argument
|
|
.Va intrarg
|
|
(typically from the audio hardware interrupt service routine).
|
|
Once started the transfer may be stopped using
|
|
.Va halt_output .
|
|
Return 0 on success, otherwise an error code.
|
|
.It Dv int trigger_input(void *hdl, void *start, void *end,
|
|
.Dv "int blksize, void (*intr)(void*), void *intrarg,"
|
|
.br
|
|
.Dv "stuct audio_params *param)"
|
|
.br
|
|
optional, is called to start the transfer of data from the audio hardware,
|
|
parameterized as in
|
|
.Va param ,
|
|
to the circular buffer delimited by
|
|
.Va start
|
|
and
|
|
.Va end .
|
|
The call should return when the data transfer has been initiated
|
|
(normally with DMA). When the hardware is finished transferring
|
|
each
|
|
.Va blksize
|
|
sized block, the function
|
|
.Va intr
|
|
should be called with the argument
|
|
.Va intrarg
|
|
(typically from the audio hardware interrupt service routine).
|
|
Once started the transfer may be stopped using
|
|
.Va halt_input .
|
|
Return 0 on success, otherwise an error code.
|
|
.El
|
|
.Pp
|
|
The
|
|
.Va query_devinfo
|
|
method should define certain mixer controls for
|
|
.Dv AUDIO_SETINFO
|
|
to be able to change the port and gain.
|
|
.Pp
|
|
If the audio hardware is capable of input from more
|
|
than one source it should define
|
|
.Dv AudioNsource
|
|
in class
|
|
.Dv AudioCrecord .
|
|
This mixer control should be of type
|
|
.Dv AUDIO_MIXER_ENUM
|
|
or
|
|
.Dv AUDIO_MIXER_SET
|
|
and enumerate the possible input sources.
|
|
For each of the named sources there should be
|
|
a control in the
|
|
.Dv AudioCinputs
|
|
class of type
|
|
.Dv 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
|
|
.Dv AudioNrecord
|
|
and be of class
|
|
.Dv AudioCinputs .
|
|
.Pp
|
|
If the audio hardware is capable of output to more than
|
|
one destination it should define
|
|
.Dv AudioNoutput
|
|
in class
|
|
.Dv AudioCmonitor .
|
|
This mixer control should be of type
|
|
.Dv AUDIO_MIXER_ENUM
|
|
or
|
|
.Dv AUDIO_MIXER_SET
|
|
and enumerate the possible destinations.
|
|
For each of the named destinations there should be
|
|
a control in the
|
|
.Dv AudioCoutputs
|
|
class of type
|
|
.Dv 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
|
|
.Dv AudioNmaster
|
|
and be of class
|
|
.Dv AudioCoutputs .
|
|
.Sh SEE ALSO
|
|
.Xr audio 4
|
|
.Sh HISTORY
|
|
This
|
|
.Nm
|
|
interface first appeared in
|
|
.Nx 1.3 .
|