SIO_OPEN(3) OpenBSD Programmer's Manual SIO_OPEN(3)NAME
sio_open, sio_close, sio_setpar, sio_getpar, sio_getcap, sio_start,
sio_stop, sio_read, sio_write, sio_onmove, sio_nfds, sio_pollfd,
sio_revents, sio_eof, sio_setvol, sio_onvol, sio_initpar - interface to
bidirectional audio streams
SYNOPSIS
#include <sndio.h>
struct sio_hdl *
sio_open(const char *name, unsigned mode, int nbio_flag);
void
sio_close(struct sio_hdl *hdl);
int
sio_setpar(struct sio_hdl *hdl, struct sio_par *par);
int
sio_getpar(struct sio_hdl *hdl, struct sio_par *par);
int
sio_getcap(struct sio_hdl *hdl, struct sio_cap *cap);
int
sio_start(struct sio_hdl *hdl);
int
sio_stop(struct sio_hdl *hdl);
size_t
sio_read(struct sio_hdl *hdl, void *addr, size_t nbytes);
size_t
sio_write(struct sio_hdl *hdl, const void *addr, size_t nbytes);
void
sio_onmove(struct sio_hdl *hdl, void (*cb)(void *arg, int delta), void
*arg);
int
sio_nfds(struct sio_hdl *hdl);
int
sio_pollfd(struct sio_hdl *hdl, struct pollfd *pfd, int events);
int
sio_revents(struct sio_hdl *hdl, struct pollfd *pfd);
int
sio_eof(struct sio_hdl *hdl);
int
sio_setvol(struct sio_hdl *hdl, unsigned vol);
int
sio_onvol(struct sio_hdl *hdl, void (*cb)(void *arg, unsigned vol), void
*arg);
void
sio_initpar(struct sio_par *par);
DESCRIPTION
The sndio library allows user processes to access audio(4) hardware and
the aucat(1) audio server in a uniform way. It supports full-duplex
operation, and when used with the aucat(1) server it supports resampling
and format conversions on the fly.
Opening and closing an audio stream
First the application must call the sio_open() function to obtain a
handle representing the newly created stream; later it will be passed as
the hdl argument of most other functions. The sio_open() function first
tries to connect to the aucat(1) audio server. If that fails, it then
tries to use the audio(4) hardware device. The name parameter gives the
device string discussed in sndio(7). In most cases it should be set to
NULL to allow the user to select it using the AUDIODEVICE environment
variable.
The mode parameter gives the direction of the stream. The following are
supported:
SIO_PLAY The stream is play-only; data written to the stream
will be played by the hardware.
SIO_REC The stream is record-only; recorded samples by the
hardware must be read from the stream.
SIO_PLAY | SIO_REC The stream plays and records synchronously; this
means that the n-th recorded sample was physically
sampled exactly when the n-th played sample was
actually played.
If the nbio_flag argument is true (i.e. non-zero), then the sio_read()
and sio_write() functions (see below) will be non-blocking.
The sio_close() function closes the stream and frees all allocated
resources associated with the libsndio handle. If the stream is not
stopped it will be stopped first as if sio_stop() is called.
Negotiating audio parameters
Audio streams always use linear interleaved encoding. A frame consists
of one sample for each channel in the stream. For example, a 16-bit
stereo stream has two samples per frame and, typically, two bytes per
sample (thus 4 bytes per frame).
The set of parameters of the stream that can be controlled is given by
the following structure:
struct sio_par {
unsigned bits; /* bits per sample */
unsigned bps; /* bytes per sample */
unsigned sig; /* 1 = signed, 0 = unsigned */
unsigned le; /* 1 = LE, 0 = BE byte order */
unsigned msb; /* 1 = MSB, 0 = LSB aligned */
unsigned rchan; /* number channels for recording */
unsigned pchan; /* number channels for playback */
unsigned rate; /* frames per second */
unsigned appbufsz; /* minimum buffer size without xruns */
unsigned bufsz; /* end-to-end buffer size (read-only) */
unsigned round; /* optimal buffer size divisor */
#define SIO_IGNORE 0 /* pause during xrun */
#define SIO_SYNC 1 /* resync after xrun */
#define SIO_ERROR 2 /* terminate on xrun */
unsigned xrun; /* what to do on overrun/underrun */
};
The parameters are as follows:
bits Number of bits per sample: must be between 1 and 32.
bps Bytes per samples; if specified, it must be large enough to
hold all bits. By default it's set to the smallest power of
two large enough to hold bits.
sig If set (i.e. non-zero) then the samples are signed, else
unsigned.
le If set, then the byte order is little endian, else big endian;
it's meaningful only if bps > 1.
msb If set, then the bits bits are aligned in the packet to the
most significant bit (i.e. lower bits are padded), else to the
least significant bit (i.e. higher bits are padded); it's
meaningful only if bits < bps * 8.
rchan The number of recorded channels; meaningful only if SIO_REC
mode was selected.
pchan The number of played channels; meaningful only if SIO_PLAY mode
was selected.
rate The sampling frequency in Hz.
bufsz The maximum number of frames that may be buffered. This
parameter takes into account any buffers, and can be used for
latency calculations. It is read-only.
appbufsz Size of the buffer in frames the application must maintain non
empty (on the play end) or non full (on the record end) by
calling sio_write() or sio_read() fast enough to avoid overrun
or underrun conditions. The audio subsystem may use additional
buffering, thus this parameter cannot be used for latency
calculations
round Optimal number of frames that the application buffers should be
a multiple of, to get best performance. Applications can use
this parameter to round their block size.
xrun The action when the client doesn't accept recorded data or
doesn't provide data to play fast enough; it can be set to one
of the SIO_IGNORE, SIO_SYNC or SIO_ERROR constants.
The following approach is recommended to negotiate parameters of the
stream:
o Initialize a sio_par structure using sio_initpar() and fill it with
the desired parameters. If the application supports any value for a
given parameter, then the corresponding parameter should be left
unset. Then call sio_setpar() to request the stream to use them.
o Call sio_getpar() to retrieve the actual parameters of the stream and
check that they are usable. If they are not, then fail or set up a
conversion layer. Sometimes the rate set can be slightly different
to what was requested. A difference of about 0.5% is not audible and
should be ignored.
Parameters cannot be changed while the stream is in a waiting state; if
sio_start() has been called, sio_stop() must be called before parameters
can be changed.
If libsndio is used to connect to the aucat(1) server, a transparent
emulation layer will automatically be set up, and in this case any
parameters are supported.
To ease filling the sio_par structure, the following macros can be used:
SIO_BPS(bits) Return the smallest value for bps that is a power of two
and that is large enough to hold bits.
SIO_LE_NATIVE Can be used to set the le parameter when native byte order
is required.
Getting stream capabilities
There's no way to get an exhaustive list of all parameter combinations
the stream supports. Applications that need to have a set of working
parameter combinations in advance can use the sio_getcap() function.
The sio_cap structure contains the list of parameter configurations.
Each configuration contains multiple parameter sets. The application
must examine all configurations, and choose its parameter set from one of
the configurations. Parameters of different configurations are not
usable together.
struct sio_cap {
struct sio_enc { /* allowed encodings */
unsigned bits;
unsigned bps;
unsigned sig;
unsigned le;
unsigned msb;
} enc[SIO_NENC];
unsigned rchan[SIO_NCHAN]; /* allowed rchans */
unsigned pchan[SIO_NCHAN]; /* allowed pchans */
unsigned rate[SIO_NRATE]; /* allowed rates */
unsigned nconf; /* num. of confs[] */
struct sio_conf {
unsigned enc; /* bitmask of enc[] indexes */
unsigned rchan; /* bitmask of rchan[] indexes */
unsigned pchan; /* bitmask of pchan[] indexes */
unsigned rate; /* bitmask of rate[] indexes */
} confs[SIO_NCONF];
};
The parameters are as follows:
enc[SIO_NENC] Array of supported encodings. The tuple of bits, bps,
sig, le and msb parameters are usable in the
corresponding parameters of the sio_par structure.
rchan[SIO_NCHAN] Array of supported channel numbers for recording usable
in the sio_par structure.
pchan[SIO_NCHAN] Array of supported channel numbers for playback usable
in the sio_par structure.
rate[SIO_NRATE] Array of supported sample rates usable in the sio_par
structure.
nconf Number of different configurations available, i.e.
number of filled elements of the confs[] array.
confs[SIO_NCONF] Array of available configurations. Each configuration
contains bitmasks indicating which elements of the
above parameter arrays are valid for the given
configuration. For instance, if the second bit of rate
is set, in the sio_conf structure, then the second
element of the rate[SIO_NRATE] array of the sio_cap
structure is valid for this configuration.
Starting and stopping the stream
The sio_start() function puts the stream in a waiting state: the stream
will wait for playback data to be provided (using the sio_write()
function). Once enough data is queued to ensure that play buffers will
not underrun, actual playback is started automatically. If record mode
only is selected, then recording starts immediately. In full-duplex
mode, playback and recording will start synchronously as soon as enough
data to play is available.
The sio_stop() function stops playback and recording and puts the audio
subsystem in the same state as after sio_open() is called. Samples in
the play buffers are not discarded, and will continue to be played after
sio_stop() returns. If samples to play are queued but playback hasn't
started yet then playback is forced immediately; the stream will actually
stop once the buffer is drained.
Playing and recording
When record mode is selected, the sio_read() function must be called to
retrieve recorded data; it must be called often enough to ensure that
internal buffers will not overrun. It will store at most nbytes bytes at
the addr location and return the number of bytes stored. Unless the
nbio_flag flag is set, it will block until data becomes available and
will return zero only on error.
Similarly, when play mode is selected, the sio_write() function must be
called to provide data to play. Unless the nbio_flag is set, sio_write()
will block until the requested amount of data is written.
Non-blocking mode operation
If the nbio_flag is set on sio_open(), then the sio_read() and
sio_write() functions will never block; if no data is available, they
will return zero immediately.
Note that non-blocking mode must be used on bidirectional streams. For
instance, if recording is blocked in sio_read() then, even if samples can
be played, sio_write() cannot be called and the play buffers may
underrun.
To avoid busy loops when non-blocking mode is used, the poll(2) system
call can be used to check if data can be read from or written to the
stream. The sio_pollfd() function fills the array pfd of pollfd
structures, used by poll(2), with events; the latter is a bit-mask of
POLLIN and POLLOUT constants; refer to poll(2) for more details.
sio_pollfd() returns the number of pollfd structures filled. The
sio_revents() function returns the bit-mask set by poll(2) in the pfd
array of pollfd structures. If POLLIN is set, sio_read() can be called
without blocking. If POLLOUT is set, sio_write() can be called without
blocking. POLLHUP may be set if an error occurs, even if it is not
selected with sio_pollfd().
The sio_nfds() function returns the number of pollfd structures the
caller must preallocate in order to be sure that sio_pollfd() will never
overrun.
Synchronizing non-audio events to the stream in real-time
In order to perform actions at precise positions of the stream, such as
displaying video in sync with the audio stream, the application must be
notified in real-time of the exact position in the stream the hardware is
processing.
The sio_onmove() function can be used to register the cb callback
function that will be called by the sndio library at regular time
intervals to notify the application the position in the stream changed.
The delta argument contains the number of frames the hardware moved in
the stream since the last call of cb. When the stream starts, the
callback is invoked with a zero delta argument. The value of the arg
pointer is passed to the callback and can contain anything.
If desired, the application can maintain the current position by starting
from zero (when sio_start() is called) and adding to the current position
delta every time cb() is called.
Measuring the latency and buffers usage
The playback latency is the delay it will take for the frame just written
to become audible, expressed in number of frames. The exact playback
latency can be obtained by subtracting the current position from the
number of frames written. Once playback is actually started (first
sample audible) the latency will never exceed the bufsz parameter (see
the sections above). There's a phase during which sio_write() only
queues data; once there's enough data, actual playback starts. During
this phase talking about latency is meaningless.
In any cases, at most bufsz frames are buffered. This value takes into
account all buffers, including device, kernel and socket buffers. The
number of frames stored is equal to the number of frames written minus
the current position.
The recording latency is obtained similarly, by subtracting the number of
frames read from the current position.
It is strongly discouraged to use the latency and/or the buffer usage for
anything but monitoring. Especially, note that sio_write() might block
even if there is buffer space left; using the buffer usage to guess if
sio_write() would block is false and leads to unreliable programs -
consider using poll(2) for this.
Handling buffer overruns and underruns
When the application cannot accept recorded data fast enough, the record
buffer (of size appbufsz) might overrun; in this case recorded data is
lost. Similarly if the application cannot provide data to play fast
enough, the play buffer underruns and silence is played instead.
Depending on the xrun parameter of the sio_par structure, the audio
subsystem will behave as follows:
SIO_IGNORE The stream is paused during overruns and underruns, thus the
current position (obtained through sio_onmove) stops being
incremented. Once the overrun and/or underrun condition is
gone, the stream is unpaused; play and record are always kept
in sync. With this mode, the application cannot notice
underruns and/or overruns and shouldn't care about them.
This mode is the default. It's suitable for applications,
like audio players and telephony, where time is not important
and overruns or underruns are not short.
SIO_SYNC If the play buffer underruns, then silence is played, but in
order to reach the right position in time, the same amount of
written samples will be discarded once the application is
unblocked. Similarly, if the record buffer overruns, then
samples are discarded, but the same amount of silence will be
returned later. The current position (obtained through
sio_onmove) is still incremented. When the play buffer
underruns the play latency might become negative; when the
record buffer overruns, the record latency might become
larger than bufsz.
This mode is suitable for applications, like music
production, where time is important and where underruns or
overruns are short and rare.
SIO_ERROR With this mode, on the first play buffer underrun or record
buffer overrun, the stream is terminated and no other
function than sio_close() will succeed.
This mode is mostly useful for testing; portable applications
shouldn't depend on it, since it's not available on other
systems.
Controlling the volume
The sio_setvol() function can be used to set playback attenuation. The
vol parameter takes a value between 0 (maximum attenuation) and
SIO_MAXVOL (no attenuation). It specifies the weight the audio subsystem
will give to this stream. It is not meant to control hardware parameters
like speaker gain; the mixerctl(1) interface should be used for that
purpose instead.
An application can use the sio_onvol() function to register a callback
function that will be called each time the volume is changed, including
when sio_setvol() is used. The callback is always invoked when
sio_onvol() is called in order to provide the initial volume. An
application can safely assume that once sio_onvol() has returned a non-
zero value, the callback has been invoked and thus the current volume is
available. If there's no volume setting available, sio_onvol() returns 0
and the callback is never invoked and calls to sio_setvol() are ignored.
The sio_onvol() function can be called with a NULL argument to check
whether a volume knob is available.
Error handling
Errors related to the audio subsystem (like hardware errors, dropped
connections) and programming errors (e.g. call to sio_read() on a play-
only stream) are considered fatal. Once an error occurs, all functions
taking a sio_hdl argument, except sio_close() and sio_eof(), stop working
(i.e. always return 0).
The sio_eof() function can be used at any stage; it returns 0 if there's
no pending error, and a non-zero value if there's an error.
RETURN VALUES
The sio_open() function returns the newly created handle on success or
NULL on failure. The sio_setpar(), sio_getpar(), sio_getcap(),
sio_start(), sio_stop(), sio_pollfd() and sio_setvol() functions return 1
on success and 0 on failure. The sio_read() and sio_write() functions
return the number of bytes transferred.
ENVIRONMENT
AUDIODEVICE Device to use if sio_open() is called with a NULL name
argument.
SIO_DEBUG The debug level: may be a value between 0 and 2.
FILES
/tmp/aucat-<uid>/softaudio0 Default path to aucat(1) socket to connect
to.
/dev/audio Default audio(4) device to use.
SEE ALSOaucat(1), audio(4), sndio(7), audio(9)BUGS
The audio(4) driver cannot drain playback buffers in the background, thus
if libsndio is used to directly access an audio(4) device, the sio_stop()
function will stop playback immediately.
The aucat(1) server doesn't implement flow control (for performance
reasons). If the application doesn't consume recorded data fast enough
then ``control messages'' are delayed and consequently sio_onmove
callback or volume changes may be delayed.
The sio_open(), sio_setpar(), sio_getpar(), sio_getcap(), sio_start() and
sio_stop() functions may block for a very short period of time, thus they
should be avoided in code sections where blocking is not desirable.
OpenBSD 4.9 November 6, 2010 OpenBSD 4.9